calc_rational

CLI calculator for rational numbers.
git clone https://git.philomathiclife.com/repos/calc_rational
Log | Files | Refs | README

commit a70d7ab80b7d012f8fafc531b6f83a7bba9b32c5
parent f553f55703f3681704c9193a1404f61c8a190b4a
Author: Zack Newman <zack@philomathiclife.com>
Date:   Tue, 25 Jul 2023 18:49:16 -0600

integrate priv_sep for OpenBSD

Diffstat:
MCargo.toml | 8+++++---
MREADME.md | 63+++++++++++++++++++++++++++++++++++----------------------------
Msrc/cache.rs | 10+++++++---
Msrc/lending_iterator.rs | 8++++++--
Msrc/lib.rs | 9+++++++--
Msrc/main.rs | 74+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
6 files changed, 125 insertions(+), 47 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" name = "calc_rational" readme = "README.md" repository = "https://git.philomathiclife.com/repos/calc_rational/" -version = "0.4.0" +version = "0.5.0" [lib] name = "calc_lib" @@ -23,13 +23,15 @@ path = "src/main.rs" num-bigint = { version = "0.4.3", default-features = false } num-integer = { version = "0.1.45", default-features = false } num-rational = { version = "0.4.1", default-features = false, features = ["num-bigint"] } -num-traits = { version = "0.2.15", default-features = false } +num-traits = { version = "0.2.16", default-features = false } +priv_sep = { version = "0.2.0", default-features = false, features = ["openbsd"], optional = true } rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"], optional = true } [build-dependencies] rustc_version = "0.4.0" [features] +priv_sep = ["dep:priv_sep"] rand = ["dep:rand", "std"] std = [] default = ["std"] @@ -44,4 +46,4 @@ maintenance = { status = "actively-developed" } [profile.release] lto = true panic = 'abort' -strip = 'symbols' +strip = true diff --git a/README.md b/README.md @@ -150,7 +150,9 @@ lead to an error message. Errors due to a language violation (e.g., dividing by `0`) manifest into an error message. `panic!`s and [`io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)s caused by writing to the global -standard output stream lead to program abortion. +standard output stream lead to program abortion. On OpenBSD-stable when compiled with the `priv_sep` feature, +it will error if [`pledge(2)`](https://man.openbsd.org/amd64/pledge.2) errors with the promise of `"stdio"` +returning the corresponding [`cint`](https://doc.rust-lang.org/core/ffi/type.c_int.html). ## Exiting @@ -165,7 +167,7 @@ be an unambiguous context-free grammar with expression precedence and binary ope associativity embedded within. Last, the language will only deal with the field of rational numbers. -The crates are only tested on the `x86_64-unknown-linux-gnu` target, but +The crates are only tested on the `x86_64-unknown-linux-gnu` and `x86_64-unknown-openbsd` targets, but they should work on any [Tier 1 with Host Tools](https://doc.rust-lang.org/beta/rustc/platform-support.html) target. Note one must be aware of the ASCII encoding requirement. In particular there are platforms (e.g., Windows) where the default text encoding is not a superset of ASCII. @@ -203,69 +205,73 @@ Cloning into 'calc_rational'... [zack@laptop calc_rational]$ cargo build --release --all-features Updating crates.io index Compiling autocfg v1.1.0 - Compiling libc v0.2.142 + Compiling semver v1.0.18 + Compiling libc v0.2.147 Compiling cfg-if v1.0.0 Compiling ppv-lite86 v0.2.17 - Compiling num-traits v0.2.15 + Compiling num-traits v0.2.16 Compiling num-integer v0.1.45 Compiling num-bigint v0.4.3 Compiling num-rational v0.4.1 - Compiling getrandom v0.2.9 + Compiling rustc_version v0.4.0 + Compiling priv_sep v0.2.0 + Compiling calc_rational v0.5.0 (/home/zack/calc_rational) + Compiling getrandom v0.2.10 Compiling rand_core v0.6.4 Compiling rand_chacha v0.3.1 Compiling rand v0.8.5 - Compiling calc_rational v0.4.0 (/home/zack/calc_rational) - Finished release [optimized] target(s) in 8.25s - [zack@laptop calc_rational]$ cargo t --all-features + Finished release [optimized] target(s) in 6.10s +[zack@laptop calc_rational]$ cargo t --all-features Compiling autocfg v1.1.0 - Compiling libc v0.2.142 - Compiling semver v1.0.17 + Compiling semver v1.0.18 + Compiling libc v0.2.147 Compiling cfg-if v1.0.0 Compiling ppv-lite86 v0.2.17 - Compiling num-traits v0.2.15 + Compiling num-traits v0.2.16 Compiling num-integer v0.1.45 Compiling num-bigint v0.4.3 Compiling num-rational v0.4.1 Compiling rustc_version v0.4.0 - Compiling calc_rational v0.4.0 (/home/zack/calc_rational) - Compiling getrandom v0.2.9 + Compiling priv_sep v0.2.0 + Compiling calc_rational v0.5.0 (/home/zack/calc_rational) + Compiling getrandom v0.2.10 Compiling rand_core v0.6.4 Compiling rand_chacha v0.3.1 Compiling rand v0.8.5 - Finished test [unoptimized + debuginfo] target(s) in 2.80s - Running unittests src/lib.rs (target/debug/deps/calc_lib-71003fccf12c1022) + Finished test [unoptimized + debuginfo] target(s) in 2.38s + Running unittests src/lib.rs (target/debug/deps/calc_lib-cd811ad9fff78426) running 26 tests -test cache::tests::test_push ... ok test cache::tests::test_get ... ok +test cache::tests::test_index ... ok test cache::tests::test_is_empty ... ok +test cache::tests::test_new ... ok test cache::tests::test_get_unsafe ... ok -test cache::tests::test_len ... ok -test cache::tests::test_index ... ok +test cache::tests::test_push ... ok test tests::abs ... ok -test cache::tests::test_new ... ok -test tests::exit ... ok +test tests::add ... ok +test cache::tests::test_len ... ok test cache::tests::test_index_panic - should panic ... ok +test tests::exit ... ok +test tests::rand_uni ... ignored +test tests::eval_iter ... ok test tests::factorial ... ok +test tests::neg ... ok test tests::empty ... ok -test tests::rand_uni ... ignored -test tests::add ... ok +test tests::recall_expression ... ok +test tests::round ... ok test tests::store ... ok -test tests::neg ... ok test tests::par ... ok -test tests::eval_iter ... ok -test tests::recall_expression ... ok test tests::eval ... ok -test tests::round ... ok test tests::number_literal ... ok test tests::term ... ok test tests::exp ... ok test tests::mult ... ok test tests::rand ... ok -test result: ok. 25 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s +test result: ok. 25 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s - Running unittests src/main.rs (target/debug/deps/calc-1d58b73f30400d2f) + Running unittests src/main.rs (target/debug/deps/calc-36458944d29cbbaf) running 0 tests @@ -276,6 +282,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; fini running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + ``` #### Formal language specification diff --git a/src/cache.rs b/src/cache.rs @@ -4,15 +4,19 @@ warnings, clippy::all, clippy::cargo, + clippy::complexity, + clippy::correctness, clippy::nursery, clippy::pedantic, - clippy::restriction + clippy::perf, + clippy::restriction, + clippy::style, + clippy::suspicious )] #![allow( clippy::arithmetic_side_effects, clippy::blanket_clippy_restriction_lints, - clippy::implicit_return, - clippy::integer_arithmetic + clippy::implicit_return )] use core::ops::Index; /// A cache of `N` `T`s. When the cache is filled up, diff --git a/src/lending_iterator.rs b/src/lending_iterator.rs @@ -4,15 +4,19 @@ warnings, clippy::all, clippy::cargo, + clippy::complexity, + clippy::correctness, clippy::nursery, clippy::pedantic, - clippy::restriction + clippy::perf, + clippy::restriction, + clippy::style, + clippy::suspicious )] #![allow( clippy::arithmetic_side_effects, clippy::blanket_clippy_restriction_lints, clippy::implicit_return, - clippy::integer_arithmetic, clippy::missing_trait_methods, clippy::question_mark_used, clippy::single_char_lifetime_names diff --git a/src/lib.rs b/src/lib.rs @@ -115,18 +115,23 @@ warnings, clippy::all, clippy::cargo, + clippy::complexity, + clippy::correctness, clippy::nursery, clippy::pedantic, - clippy::restriction + clippy::perf, + clippy::restriction, + clippy::style, + clippy::suspicious )] #![allow( clippy::arithmetic_side_effects, clippy::blanket_clippy_restriction_lints, clippy::implicit_return, - clippy::integer_arithmetic, clippy::into_iter_on_ref, clippy::missing_trait_methods, clippy::question_mark_used, + clippy::ref_patterns, clippy::single_char_lifetime_names, clippy::unseparated_literal_suffix )] diff --git a/src/main.rs b/src/main.rs @@ -149,7 +149,9 @@ //! //! Errors due to a language violation (e.g., dividing by `0`) manifest into an error message. `panic!`s //! and [`io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)s caused by writing to the global -//! standard output stream lead to program abortion. +//! standard output stream lead to program abortion. On OpenBSD-stable when compiled with the `priv_sep` feature, +//! it will error if [`pledge(2)`](https://man.openbsd.org/amd64/pledge.2) errors with the promise of +//! `"stdio"` returning the corresponding [`cint`](https://doc.rust-lang.org/core/ffi/type.c_int.html). //! //! ## Exiting //! @@ -159,34 +161,88 @@ //! //! For a more precise specification of the “calc language”, one can read the //! [calc language specification](https://git.philomathiclife.com/calc_rational/lang.pdf). +#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))] #![deny( unsafe_code, unused, warnings, clippy::all, clippy::cargo, + clippy::complexity, + clippy::correctness, clippy::nursery, clippy::pedantic, - clippy::restriction + clippy::perf, + clippy::restriction, + clippy::style, + clippy::suspicious )] #![allow( clippy::blanket_clippy_restriction_lints, clippy::implicit_return, + clippy::missing_trait_methods, clippy::question_mark_used )] use calc_lib::lending_iterator::LendingIterator; use calc_lib::EvalIter; +#[cfg(all(feature = "priv_sep", target_os = "openbsd"))] +use core::ffi::c_int; +use core::fmt::{self, Display, Formatter}; +#[cfg(all(feature = "priv_sep", target_os = "openbsd"))] +use priv_sep::{self, Promise}; use std::io::{self, Error, Write}; +/// Error returned by [`main`]. +#[allow(clippy::exhaustive_enums)] +#[derive(Debug)] +pub enum Err { + // Error returned from [`writeln`]. + Error(Error), + #[cfg(all(feature = "priv_sep", target_os = "openbsd"))] + // Error returned from [`pledge`]. + Pledge(c_int), +} +impl Display for Err { + #[allow(clippy::ref_patterns)] + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match *self { + Self::Error(ref e) => e.fmt(f), + #[cfg(all(feature = "priv_sep", target_os = "openbsd"))] + Self::Pledge(c) => write!(f, "pledge(2)ing 'stdio' failed with {c}"), + } + } +} +impl std::error::Error for Err {} /// Entry point to the calc program. - +/// /// # Errors /// /// Returns [`Error`] iff [`writeln`] returns one when writing -/// to the global standard output stream. -fn main() -> Result<(), Error> { - let mut out = io::stdout().lock(); - EvalIter::new(io::stdin().lock()).lend_try_fold((), |_, res| match res { - Ok(o) => writeln!(&mut out, "{o}"), - Err(e) => writeln!(&mut out, "{e}"), +/// to the global standard output stream. Returns [`c_int`](https://doc.rust-lang.org/stable/core/ffi/type.c_int.html) iff +/// [`pledge`](https://docs.rs/priv_sep/latest/priv_sep/fn.pledge.html) does when compiled with the `priv_sep` feature which +/// currently only works on OpenBSD-stable. +fn main() -> Result<(), Err> { + /// Calls `pledge(2)` with the "stdio" promise. + #[cfg(all(feature = "priv_sep", target_os = "openbsd"))] + #[inline] + fn privsep() -> Result<(), Err> { + priv_sep::pledge(&[Promise::Stdio]).map_err(Err::Pledge) + } + /// Returns Ok. + #[allow(clippy::unnecessary_wraps)] + #[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))] + #[inline] + const fn privsep() -> Result<(), Err> { + Ok(()) + } + privsep().and_then(|_| { + let mut out = io::stdout().lock(); + EvalIter::new(io::stdin().lock()).lend_try_fold((), |_, res| { + match res { + Ok(o) => writeln!(&mut out, "{o}"), + Err(e) => writeln!(&mut out, "{e}"), + } + .map_err(Err::Error) + }) }) }