From fc1ab46d8ac7353bf04c878059bdf39a94d672a3 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 3 Mar 2024 18:19:36 +0100 Subject: [PATCH 01/17] docs rs attribute --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index da1c5bf..662b08b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ //! //! `pt` is a project consisting of multiple smaller crates, all bundled together in this //! "main crate". Most crates will only show up if you activate their feature. +#[cfg_attr(docsrs, doc(cfg(feature = "full")))] #[cfg(feature = "bintols")] pub use libpt_bintols as bintols; From c95a9191075d620f2fb0c973a767ba3d630cd2f5 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 3 Mar 2024 18:19:36 +0100 Subject: [PATCH 02/17] docs rs attribute --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index da1c5bf..662b08b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ //! //! `pt` is a project consisting of multiple smaller crates, all bundled together in this //! "main crate". Most crates will only show up if you activate their feature. +#[cfg_attr(docsrs, doc(cfg(feature = "full")))] #[cfg(feature = "bintols")] pub use libpt_bintols as bintols; From ab9029fcedea3f52b203d7d2d708302db4983e88 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 3 Mar 2024 17:20:44 +0000 Subject: [PATCH 03/17] automatic cargo CI changes --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 662b08b..02b30f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ //! `pt` is a project consisting of multiple smaller crates, all bundled together in this //! "main crate". Most crates will only show up if you activate their feature. #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[cfg(feature = "bintols")] pub use libpt_bintols as bintols; #[cfg(feature = "core")] From c918fbf19606ef925d8442b0833015c1e559de88 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 10 Mar 2024 19:38:51 +0100 Subject: [PATCH 04/17] logger configuration throigh struct --- Cargo.toml | 4 +- members/libpt-log/Cargo.toml | 2 +- members/libpt-log/src/lib.rs | 346 +++++++++++++++++++++++++++++++- members/libpt-py/Cargo.toml | 2 +- members/libpt-py/src/log/mod.rs | 12 +- 5 files changed, 356 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bc3dc60..3ba4279 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ default-members = [".", "members/libpt-core"] [workspace.package] publish = true -version = "0.4.2" +version = "0.4.3" edition = "2021" authors = ["Christoph J. Scherr "] license = "MIT" @@ -30,7 +30,7 @@ anyhow = "1.0.79" thiserror = "1.0.56" libpt-core = { version = "0.4.0", path = "members/libpt-core" } libpt-bintols = { version = "0.4.0", path = "members/libpt-bintols" } -libpt-log = { version = "0.4.1", path = "members/libpt-log" } +libpt-log = { version = "0.4.2", path = "members/libpt-log" } [package] name = "libpt" diff --git a/members/libpt-log/Cargo.toml b/members/libpt-log/Cargo.toml index f41b6d6..1a73ddd 100644 --- a/members/libpt-log/Cargo.toml +++ b/members/libpt-log/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libpt-log" publish.workspace = true -version = "0.4.1" +version = "0.4.2" edition.workspace = true authors.workspace = true license.workspace = true diff --git a/members/libpt-log/src/lib.rs b/members/libpt-log/src/lib.rs index 1a06b08..e794b8b 100644 --- a/members/libpt-log/src/lib.rs +++ b/members/libpt-log/src/lib.rs @@ -37,20 +37,346 @@ pub const DEFAULT_LOG_DIR: &str = "/dev/null"; static INITIALIZED: AtomicBool = AtomicBool::new(false); -/// ## Logger for [`pt`](../libpt/index.html) +/// Builder for a well configured [Logger] /// -/// This struct exists mainly for the python module, so that we can use the same logger with both -/// python and rust. +/// This struct helps configure a global logger that can be used with either macros or methods, see +/// [Logger]. +/// +/// ## Examples +/// +/// ``` +/// # use libpt_log::{Logger, info}; +/// # fn main() { +/// Logger::builder() +/// .uptime(true) +/// .build(); +/// info!("hello world"); +/// # } +/// +/// ``` +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct LoggerBuilder { + /// create and log to logfiles + log_to_file: bool, + /// logfiles would be created here + log_dir: PathBuf, + /// use ANSI control sequences + ansi: bool, + /// show which source file produces a log + display_filename: bool, + /// show the log level of the message + display_level: bool, + /// show target context + display_target: bool, + /// sets the maximum verbosity level. + /// + /// For example, if set to [Error](Level::ERROR), logs at [Info](Level::INFO) will not be + /// printed. If set to [Debug](Level::DEBUG), logs at [Info](Level::INFO) will be printed. + max_level: Level, + /// show the id of the thread that created this message + display_thread_ids: bool, + /// show the name of the thread that created this message + display_thread_names: bool, + /// show which line in the source file produces a log + display_line_number: bool, + /// splits a log over multiple lines, looks like a python traceback + pretty: bool, + /// show when the log was created + show_time: bool, + /// show timestamps as uptime (duration since the logger was initialized) + uptime: bool, +} + +impl LoggerBuilder { + /// use the configured settings to build and initialize a new global [Logger] + /// + /// This will build a functional [Logger]. You don't need to use the [Logger] struct, it's + /// better to use the macros: + /// + /// * `error!` + /// * `warn!` + /// * `info!` + /// * `debug!` + /// * `trace!` + /// + /// instead of the methods of the [Logger] struct. You can however use the [Logger] struct in + /// cases where usage of a macro is bad or you are somehow working with multiple loggers. + /// + /// ## Examples + /// + /// ``` + /// # use libpt_log::{Logger, info}; + /// # fn main() { + /// Logger::builder() + /// .uptime(true) + /// .build(); + /// info!("hello world"); + /// # } + /// + /// ``` + /// # Errors + /// + /// This function will return an error if a global Logger was aready initialized. This module + /// uses the [tracing] crate for logging, so if a [tracing] logger is initialized elsewhere, + /// this method will error. + pub fn build(self) -> Result { + // only init if no init has been performed yet + if INITIALIZED.load(Ordering::Relaxed) { + warn!("trying to reinitialize the logger, ignoring"); + bail!(Error::Usage("logging is already initialized".to_string())); + } + let subscriber = tracing_subscriber::fmt::Subscriber::builder() + .with_level(self.display_level) + .with_max_level(self.max_level) + .with_ansi(self.ansi) + .with_target(self.display_target) + .with_file(self.display_filename) + .with_thread_ids(self.display_thread_ids) + .with_line_number(self.display_line_number) + .with_thread_names(self.display_thread_names) + .with_span_events(FmtSpan::FULL); + // I know this is hacky, but I couldn't get it any other way. I couldn't even find a + // project that could do it any other way. You can't apply one after another, because the + // type is changed every time. When using `Box`, some methods complain about + // not being in trait bounds. + // TODO: somehow find a better solution for this + match (self.log_to_file, self.show_time, self.pretty, self.uptime) { + (true, true, true, true) => { + let subscriber = subscriber + .with_writer(new_file_appender(self.log_dir)) + .with_timer(time::uptime()) + .pretty() + .finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (true, true, true, false) => { + let subscriber = subscriber + .with_writer(new_file_appender(self.log_dir)) + .pretty() + .finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (true, false, true, _) => { + let subscriber = subscriber + .with_writer(new_file_appender(self.log_dir)) + .without_time() + .pretty() + .finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (true, true, false, true) => { + let subscriber = subscriber + .with_writer(new_file_appender(self.log_dir)) + .with_timer(time::uptime()) + .finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (true, true, false, false) => { + let subscriber = subscriber + .with_writer(new_file_appender(self.log_dir)) + .finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (true, false, false, _) => { + let file_appender = tracing_appender::rolling::daily(self.log_dir.clone(), "log"); + let (file_writer, _guard) = tracing_appender::non_blocking(file_appender); + let subscriber = subscriber.with_writer(file_writer).without_time().finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (false, true, true, true) => { + let subscriber = subscriber.pretty().with_timer(time::uptime()).finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (false, true, true, false) => { + let subscriber = subscriber.pretty().with_timer(time::uptime()).finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (false, false, true, _) => { + let subscriber = subscriber.without_time().pretty().finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (false, true, false, true) => { + let subscriber = subscriber.with_timer(time::uptime()).finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (false, true, false, false) => { + let subscriber = subscriber.finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + (false, false, false, _) => { + let subscriber = subscriber.without_time().finish(); + tracing::subscriber::set_global_default(subscriber)?; + } + } + INITIALIZED.store(true, Ordering::Relaxed); + Ok(Logger {}) + } + + /// enable or disable logging to and creating of logfiles + pub fn log_to_file(mut self, log_to_file: bool) -> Self { + self.log_to_file = log_to_file; + self + } + + /// set a directory where logfiles would be created in + /// + /// Enable or disable creation and logging to logfiles with [log_to_file](Self::log_to_file). + /// + /// The default logdir is [DEFAULT_LOG_DIR]. + pub fn log_dir(mut self, log_dir: PathBuf) -> Self { + self.log_dir = log_dir; + self + } + + /// enable or disable ANSI control sequences + /// + /// Disabling ANSI control sequences might improve compatibility and readability when the logs + /// are displayed by a program that does not interpret them. + /// + /// Keeping ANSI control sequences enabled has the disadvantage of added colors for the logs. + pub fn ansi(mut self, ansi: bool) -> Self { + self.ansi = ansi; + self + } + + /// when making a log, display the source file in which a log was crated in + pub fn display_filename(mut self, display_filename: bool) -> Self { + self.display_filename = display_filename; + self + } + + /// when making a log, display the log level of the message + pub fn display_level(mut self, display_level: bool) -> Self { + self.display_level = display_level; + self + } + + /// show target context + pub fn display_target(mut self, display_target: bool) -> Self { + self.display_target = display_target; + self + } + + /// set the maximum verbosity level. + pub fn max_level(mut self, max_level: Level) -> Self { + self.max_level = max_level; + self + } + + /// show the id of the thread that created this message + pub fn display_thread_ids(mut self, display_thread_ids: bool) -> Self { + self.display_thread_ids = display_thread_ids; + self + } + + /// show the name of the thread that created this message + pub fn display_thread_names(mut self, display_thread_names: bool) -> Self { + self.display_thread_names = display_thread_names; + self + } + + /// show which line in the source file produces a log + pub fn display_line_number(mut self, display_line_number: bool) -> Self { + self.display_line_number = display_line_number; + self + } + + /// splits a log over multiple lines, looks like a python traceback + pub fn pretty(mut self, pretty: bool) -> Self { + self.pretty = pretty; + self + } + + /// show a timestamp describing when the log was created + pub fn show_time(mut self, show_time: bool) -> Self { + self.show_time = show_time; + self + } + + /// show timestamps as uptime (duration since the logger was initialized) + pub fn uptime(mut self, uptime: bool) -> Self { + self.uptime = uptime; + self + } +} + +impl Default for LoggerBuilder { + fn default() -> Self { + Self { + log_to_file: false, + log_dir: PathBuf::from(DEFAULT_LOG_DIR), + ansi: true, + display_filename: false, + display_level: true, + display_target: false, + max_level: DEFAULT_LOG_LEVEL, + display_thread_ids: false, + display_thread_names: false, + display_line_number: false, + pretty: false, + show_time: true, + uptime: false, + } + } +} + +/// ## Logger for [`pt`](libpt) +/// +/// A logger is generally a functionality that let's you write information from your library or +/// application in a more structured manner than if you just wrote all information to `stdout` or +/// `stderr` with the likes of `println!` or `eprintln!`. +/// +/// It offers writing to multiple targets, such as both the terminal and a log file, and allows +/// users to choose the verbosity of the information that gets printed by selecting a +/// [Loglevel](Level). +/// +/// ## Levels +/// +/// TODO: add levels desc and ascii art +/// +/// ## Usage +/// +/// You don't need to use the [Logger] struct, it's better to use the macros instead: +/// +/// * `error!` +/// * `warn!` +/// * `info!` +/// * `debug!` +/// * `trace!` +/// +/// You can however use the [Logger] struct in cases where usage of a macro is bad or +/// you are somehow working with multiple loggers. The macros offer additional functionalities, +/// suck as full `format!` support and context, see [`tracing`], which we use as backend. +/// +/// ## Examples +/// +/// ``` +/// # use libpt_log::{Logger, info}; +/// # fn main() { +/// Logger::builder() +/// .uptime(true) +/// .build(); +/// info!("hello world"); +/// # } +/// +/// ``` pub struct Logger; /// ## Main implementation impl Logger { + /// Get a new [LoggerBuilder] + pub fn builder() -> LoggerBuilder { + LoggerBuilder::default() + } + /// ## initializes the logger /// /// Will enable the logger to be used. /// /// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control + #[deprecated(since = "0.4.1", note = "use Logger::builder() instead")] pub fn build(log_dir: Option, max_level: Option, uptime: bool) -> Result { + #[allow(deprecated)] Self::build_customized( log_dir.is_some(), log_dir.unwrap_or(PathBuf::from(DEFAULT_LOG_DIR)), @@ -74,7 +400,9 @@ impl Logger { /// useful in cases with only one sender to the logging framework. /// /// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control + #[deprecated(since = "0.4.1", note = "use Logger::builder() instead")] pub fn build_mini(max_level: Option) -> Result { + #[allow(deprecated)] Self::build_customized( false, PathBuf::from(DEFAULT_LOG_DIR), @@ -92,11 +420,11 @@ impl Logger { ) } - // TODO: make the args a struct for easy access - // /// ## initializes the logger /// /// Will enable the logger to be used. + #[deprecated(since = "0.4.1", note = "use Logger::builder() instead")] + #[allow(clippy::too_many_arguments)] pub fn build_customized( log_to_file: bool, log_dir: PathBuf, @@ -250,6 +578,14 @@ impl fmt::Debug for Logger { } } +impl Default for Logger { + fn default() -> Self { + LoggerBuilder::default() + .build() + .expect("building a Logger failed") + } +} + fn new_file_appender(log_dir: PathBuf) -> NonBlocking { let file_appender = tracing_appender::rolling::daily(log_dir.clone(), "log"); tracing_appender::non_blocking(file_appender).0 diff --git a/members/libpt-py/Cargo.toml b/members/libpt-py/Cargo.toml index bc0084a..a318bda 100644 --- a/members/libpt-py/Cargo.toml +++ b/members/libpt-py/Cargo.toml @@ -19,7 +19,7 @@ name = "libpt" crate-type = ["cdylib", "rlib"] [dependencies] -libpt = { version = "0.4.2", path = "../.." } +libpt = { version = "0.4.3", path = "../.." } pyo3 = { version = "0.19.0", features = ["full"] } anyhow.workspace = true diff --git a/members/libpt-py/src/log/mod.rs b/members/libpt-py/src/log/mod.rs index ff47c92..6cc817f 100644 --- a/members/libpt-py/src/log/mod.rs +++ b/members/libpt-py/src/log/mod.rs @@ -47,7 +47,17 @@ impl Logger { ) -> anyhow::Result { // concert our wrapper type let max_level = max_level.map(origin::Level::from); - Ok(origin::Logger::build(log_dir, max_level, uptime.unwrap_or(false))?.into()) + let mut builder = origin::Logger::builder(); + if log_dir.is_some() { + builder = builder.log_dir(log_dir.unwrap()); + } + if max_level.is_some() { + builder = builder.max_level(max_level.unwrap()); + } + if uptime.is_some() { + builder = builder.uptime(uptime.unwrap()); + } + Ok(builder.build()?.into()) } /// ## logging at [`Level::ERROR`] From 0eb64908540d6b62323823616b1d42fda14a8417 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 02:24:23 +0200 Subject: [PATCH 05/17] feat: split unsigned numbers into bytes #76 --- members/libpt-bintols/src/lib.rs | 1 + members/libpt-bintols/src/split_numbers.rs | 28 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 members/libpt-bintols/src/split_numbers.rs diff --git a/members/libpt-bintols/src/lib.rs b/members/libpt-bintols/src/lib.rs index ca13f78..54a907f 100644 --- a/members/libpt-bintols/src/lib.rs +++ b/members/libpt-bintols/src/lib.rs @@ -25,3 +25,4 @@ pub const YOBI: u128 = 2u128.pow(80); // use libpt_core; pub mod datalayout; pub mod display; +pub mod split_numbers; diff --git a/members/libpt-bintols/src/split_numbers.rs b/members/libpt-bintols/src/split_numbers.rs new file mode 100644 index 0000000..84a29cb --- /dev/null +++ b/members/libpt-bintols/src/split_numbers.rs @@ -0,0 +1,28 @@ +//! # Split numbers into bits and bytes +//! +//! Sometimes, you need a large integer in the form of many bytes, so split into [u8]. +//! Rust provides + +use num_traits::Unsigned; + +/// split an integer into it's bytes, ignoring those bytes that would be all zero. +/// +/// If the integer is zero, the Vec contains a single null byte. +pub fn unsigned_to_vec(mut num: T) -> Vec +where + T: Unsigned, + T: std::ops::ShrAssign, + T: std::cmp::PartialOrd, + u8: std::convert::From, + T: Copy, +{ + if num == 0 { + return vec![0]; + } + let mut buf: Vec = Vec::new(); + while num > 0 { + buf.push(num.into()); + num >>= 8; + } + buf +} From dc506de8aa22d06ea455e6d3747d944e1f3cc03b Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 02:47:12 +0200 Subject: [PATCH 06/17] test: split-numbers #76 test if splitting of numbers into Vec works correctly --- members/libpt-bintols/tests/split_numbers.rs | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 members/libpt-bintols/tests/split_numbers.rs diff --git a/members/libpt-bintols/tests/split_numbers.rs b/members/libpt-bintols/tests/split_numbers.rs new file mode 100644 index 0000000..52b5ac5 --- /dev/null +++ b/members/libpt-bintols/tests/split_numbers.rs @@ -0,0 +1,35 @@ +use libpt_bintols::split_numbers::*; + +#[test] +fn split_u128() { + let source = [16, 255, 256, 0, u128::MAX, u64::MAX as u128]; + let correct = [ + vec![16], + vec![255], + vec![255, 1], + vec![0], + vec![ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + ], + vec![255, 255, 255, 255, 255, 255, 255, 255], + ]; + for (i, n) in source.iter().enumerate() { + assert_eq!(unsigned_to_vec(*n), correct[i]); + } +} + +#[test] +fn split_u64() { + let source = [16, 255, 256, 0, u64::MAX, u32::MAX as u64]; + let correct = [ + vec![16], + vec![255], + vec![255, 1], + vec![0], + vec![255, 255, 255, 255, 255, 255, 255, 255], + vec![255, 255, 255, 255], + ]; + for (i, n) in source.iter().enumerate() { + assert_eq!(unsigned_to_vec(*n), correct[i]); + } +} From 77d473e22c0a9587e98016093b375d4843b0786f Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 02:47:40 +0200 Subject: [PATCH 07/17] refactor: split-numbers generic by converting to u128 #76 --- members/libpt-bintols/src/split_numbers.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/members/libpt-bintols/src/split_numbers.rs b/members/libpt-bintols/src/split_numbers.rs index 84a29cb..20cefa6 100644 --- a/members/libpt-bintols/src/split_numbers.rs +++ b/members/libpt-bintols/src/split_numbers.rs @@ -3,25 +3,20 @@ //! Sometimes, you need a large integer in the form of many bytes, so split into [u8]. //! Rust provides -use num_traits::Unsigned; - /// split an integer into it's bytes, ignoring those bytes that would be all zero. /// /// If the integer is zero, the Vec contains a single null byte. -pub fn unsigned_to_vec(mut num: T) -> Vec +pub fn unsigned_to_vec(num: T) -> Vec where - T: Unsigned, - T: std::ops::ShrAssign, - T: std::cmp::PartialOrd, - u8: std::convert::From, - T: Copy, + u128: std::convert::From { + let mut num: u128 = num.into(); if num == 0 { return vec![0]; } let mut buf: Vec = Vec::new(); while num > 0 { - buf.push(num.into()); + buf.push(num as u8); num >>= 8; } buf From 9da3c584cdad09d41a80e4e5457af473c6bbfc33 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:13:18 +0200 Subject: [PATCH 08/17] refactor: add doc comment for split numbers and change order to msb first #76 --- members/libpt-bintols/src/split_numbers.rs | 20 ++++++++++++++++++-- members/libpt-bintols/tests/split_numbers.rs | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/members/libpt-bintols/src/split_numbers.rs b/members/libpt-bintols/src/split_numbers.rs index 20cefa6..1405cbf 100644 --- a/members/libpt-bintols/src/split_numbers.rs +++ b/members/libpt-bintols/src/split_numbers.rs @@ -3,9 +3,24 @@ //! Sometimes, you need a large integer in the form of many bytes, so split into [u8]. //! Rust provides -/// split an integer into it's bytes, ignoring those bytes that would be all zero. + +/// Split unsigned integers into a [Vec] of [u8]s /// -/// If the integer is zero, the Vec contains a single null byte. +/// Say you have the [u32] 1717 (binary: `00000000 00000000 00000110 10110101 `). This number would +/// be splitted to `vec![0b00000110, 0b10110101]`. +/// +/// The 0 bytes of the numbers will be discarded (unless the number is 0, then the Vec contains a +/// single Null byte.) and the remaining parts of the numbers are inserted into a Vec as [u8]. +/// +/// # Examples +/// +/// ``` +/// # use libpt_bintols::split_numbers::*; +/// +/// let x: u32 = 1717; +/// +/// assert_eq!(unsigned_to_vec(x), vec![0b00000110, 0b10110101]); +/// ``` pub fn unsigned_to_vec(num: T) -> Vec where u128: std::convert::From @@ -19,5 +34,6 @@ where buf.push(num as u8); num >>= 8; } + buf.reverse(); buf } diff --git a/members/libpt-bintols/tests/split_numbers.rs b/members/libpt-bintols/tests/split_numbers.rs index 52b5ac5..2ee6a13 100644 --- a/members/libpt-bintols/tests/split_numbers.rs +++ b/members/libpt-bintols/tests/split_numbers.rs @@ -24,7 +24,7 @@ fn split_u64() { let correct = [ vec![16], vec![255], - vec![255, 1], + vec![1, 255], vec![0], vec![255, 255, 255, 255, 255, 255, 255, 255], vec![255, 255, 255, 255], From 73d291a47723aef04b2a2daee33e77619ef812ce Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:19:42 +0200 Subject: [PATCH 09/17] fix: split-numbers test solutions were wrong #76 --- members/libpt-bintols/tests/split_numbers.rs | 28 +++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/members/libpt-bintols/tests/split_numbers.rs b/members/libpt-bintols/tests/split_numbers.rs index 2ee6a13..3f461a3 100644 --- a/members/libpt-bintols/tests/split_numbers.rs +++ b/members/libpt-bintols/tests/split_numbers.rs @@ -2,16 +2,25 @@ use libpt_bintols::split_numbers::*; #[test] fn split_u128() { - let source = [16, 255, 256, 0, u128::MAX, u64::MAX as u128]; + let source = [ + 16, + 255, + 256, + 0, + u128::MAX, + u64::MAX as u128, + u64::MAX as u128 + 1, + ]; let correct = [ vec![16], vec![255], - vec![255, 1], + vec![1, 0], vec![0], vec![ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, ], vec![255, 255, 255, 255, 255, 255, 255, 255], + vec![1, 0, 0, 0, 0, 0, 0, 0, 0], ]; for (i, n) in source.iter().enumerate() { assert_eq!(unsigned_to_vec(*n), correct[i]); @@ -20,14 +29,25 @@ fn split_u128() { #[test] fn split_u64() { - let source = [16, 255, 256, 0, u64::MAX, u32::MAX as u64]; + let source = [ + 16, + 255, + 256, + 0, + u64::MAX, + u32::MAX as u64, + 0b1_00000001, + 0b10011011_10110101_11110000_00110011, + ]; let correct = [ vec![16], vec![255], - vec![1, 255], + vec![1, 0], vec![0], vec![255, 255, 255, 255, 255, 255, 255, 255], vec![255, 255, 255, 255], + vec![1, 1], + vec![0b10011011, 0b10110101, 0b11110000, 0b00110011], ]; for (i, n) in source.iter().enumerate() { assert_eq!(unsigned_to_vec(*n), correct[i]); From 75feb7b2b022baf03fa47bd51a343034f7c9e68a Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 15:22:49 +0000 Subject: [PATCH 10/17] automatic cargo CI changes --- members/libpt-bintols/src/split_numbers.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/members/libpt-bintols/src/split_numbers.rs b/members/libpt-bintols/src/split_numbers.rs index 1405cbf..7b3bda2 100644 --- a/members/libpt-bintols/src/split_numbers.rs +++ b/members/libpt-bintols/src/split_numbers.rs @@ -3,7 +3,6 @@ //! Sometimes, you need a large integer in the form of many bytes, so split into [u8]. //! Rust provides - /// Split unsigned integers into a [Vec] of [u8]s /// /// Say you have the [u32] 1717 (binary: `00000000 00000000 00000110 10110101 `). This number would @@ -23,7 +22,7 @@ /// ``` pub fn unsigned_to_vec(num: T) -> Vec where - u128: std::convert::From + u128: std::convert::From, { let mut num: u128 = num.into(); if num == 0 { From 7f45020511cbca60ca1ad1717473452672f5f1ac Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:26:06 +0200 Subject: [PATCH 11/17] add doctests to CI --- .gitea/workflows/cargo.yaml | 4 +--- .github/workflows/cargo.yaml | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/cargo.yaml b/.gitea/workflows/cargo.yaml index 5232d11..6b9afbb 100644 --- a/.gitea/workflows/cargo.yaml +++ b/.gitea/workflows/cargo.yaml @@ -36,10 +36,8 @@ jobs: run: cargo clippy --fix --all-features --all-targets --workspace - name: cargo fmt run: cargo fmt --all - - name: install python - run: apt update && apt install libpython3-dev -y - name: cargo test - run: cargo test --all-features --all-targets --workspace + run: cargo test --all-features --all-targets --workspace && cargo test --all-features --workspace --doc - name: commit back to repository uses: https://github.com/stefanzweifel/git-auto-commit-action@v5 with: diff --git a/.github/workflows/cargo.yaml b/.github/workflows/cargo.yaml index 541a626..d2c9936 100644 --- a/.github/workflows/cargo.yaml +++ b/.github/workflows/cargo.yaml @@ -37,12 +37,8 @@ jobs: run: cargo clippy --fix --all-features --all-targets --workspace - name: cargo fmt run: cargo fmt --all - - name: install python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - name: cargo test - run: cargo test --all-features --all-targets --workspace + run: cargo test --all-features --all-targets --workspace && cargo test --all-features --workspace --doc - name: commit back to repository uses: stefanzweifel/git-auto-commit-action@v5 with: From 401faca4db128a00fd3cadd1510a540760ed8b7c Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:36:26 +0200 Subject: [PATCH 12/17] ci install python --- .github/workflows/cargo.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/cargo.yaml b/.github/workflows/cargo.yaml index d2c9936..7d29156 100644 --- a/.github/workflows/cargo.yaml +++ b/.github/workflows/cargo.yaml @@ -22,6 +22,10 @@ jobs: run: | rustup component add rustfmt rustup component add clippy + - name: install python + uses: actions/setup-python@v5 + with: + python-version: '3.11' - name: config custom registry run: | mkdir -p ~/.cargo/ From c41328d0934f35afc39eab4f33663aa5fffadc53 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:36:26 +0200 Subject: [PATCH 13/17] ci install python --- .gitea/workflows/cargo.yaml | 2 ++ .github/workflows/cargo.yaml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/.gitea/workflows/cargo.yaml b/.gitea/workflows/cargo.yaml index 6b9afbb..d1f1664 100644 --- a/.gitea/workflows/cargo.yaml +++ b/.gitea/workflows/cargo.yaml @@ -21,6 +21,8 @@ jobs: run: | rustup component add rustfmt rustup component add clippy + - name: install python + run: apt update && apt install libpython3-dev -y - name: config custom registry run: | mkdir -p ~/.cargo/ diff --git a/.github/workflows/cargo.yaml b/.github/workflows/cargo.yaml index d2c9936..7d29156 100644 --- a/.github/workflows/cargo.yaml +++ b/.github/workflows/cargo.yaml @@ -22,6 +22,10 @@ jobs: run: | rustup component add rustfmt rustup component add clippy + - name: install python + uses: actions/setup-python@v5 + with: + python-version: '3.11' - name: config custom registry run: | mkdir -p ~/.cargo/ From 33260726a162b2597749a6eb41b508ad3eb41a2d Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:58:02 +0200 Subject: [PATCH 14/17] chore: bump versions for v0.5.0 --- Cargo.toml | 4 ++-- members/libpt-bintols/Cargo.toml | 2 +- members/libpt-py/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ba4279..a1423a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ default-members = [".", "members/libpt-core"] [workspace.package] publish = true -version = "0.4.3" +version = "0.5.0" edition = "2021" authors = ["Christoph J. Scherr "] license = "MIT" @@ -29,7 +29,7 @@ categories = [ anyhow = "1.0.79" thiserror = "1.0.56" libpt-core = { version = "0.4.0", path = "members/libpt-core" } -libpt-bintols = { version = "0.4.0", path = "members/libpt-bintols" } +libpt-bintols = { version = "0.5.0", path = "members/libpt-bintols" } libpt-log = { version = "0.4.2", path = "members/libpt-log" } [package] diff --git a/members/libpt-bintols/Cargo.toml b/members/libpt-bintols/Cargo.toml index 3ccc699..b349052 100644 --- a/members/libpt-bintols/Cargo.toml +++ b/members/libpt-bintols/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libpt-bintols" publish.workspace = true -version = "0.4.0" +version = "0.5.0" edition.workspace = true authors.workspace = true license.workspace = true diff --git a/members/libpt-py/Cargo.toml b/members/libpt-py/Cargo.toml index a318bda..0422edc 100644 --- a/members/libpt-py/Cargo.toml +++ b/members/libpt-py/Cargo.toml @@ -19,7 +19,7 @@ name = "libpt" crate-type = ["cdylib", "rlib"] [dependencies] -libpt = { version = "0.4.3", path = "../.." } +libpt = { version = "0.5.0", path = "../.." } pyo3 = { version = "0.19.0", features = ["full"] } anyhow.workspace = true From 20b8f7a58280bfbb9653b8a05bd08c7e829a76f7 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:58:31 +0200 Subject: [PATCH 15/17] refactor: rename split_numbers to split --- members/libpt-bintols/src/lib.rs | 2 +- members/libpt-bintols/src/{split_numbers.rs => split.rs} | 5 +++-- members/libpt-bintols/tests/{split_numbers.rs => split.rs} | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) rename members/libpt-bintols/src/{split_numbers.rs => split.rs} (92%) rename members/libpt-bintols/tests/{split_numbers.rs => split.rs} (96%) diff --git a/members/libpt-bintols/src/lib.rs b/members/libpt-bintols/src/lib.rs index 54a907f..30dec09 100644 --- a/members/libpt-bintols/src/lib.rs +++ b/members/libpt-bintols/src/lib.rs @@ -25,4 +25,4 @@ pub const YOBI: u128 = 2u128.pow(80); // use libpt_core; pub mod datalayout; pub mod display; -pub mod split_numbers; +pub mod split; diff --git a/members/libpt-bintols/src/split_numbers.rs b/members/libpt-bintols/src/split.rs similarity index 92% rename from members/libpt-bintols/src/split_numbers.rs rename to members/libpt-bintols/src/split.rs index 7b3bda2..c996ef7 100644 --- a/members/libpt-bintols/src/split_numbers.rs +++ b/members/libpt-bintols/src/split.rs @@ -3,6 +3,7 @@ //! Sometimes, you need a large integer in the form of many bytes, so split into [u8]. //! Rust provides + /// Split unsigned integers into a [Vec] of [u8]s /// /// Say you have the [u32] 1717 (binary: `00000000 00000000 00000110 10110101 `). This number would @@ -14,7 +15,7 @@ /// # Examples /// /// ``` -/// # use libpt_bintols::split_numbers::*; +/// # use libpt_bintols::split::*; /// /// let x: u32 = 1717; /// @@ -22,7 +23,7 @@ /// ``` pub fn unsigned_to_vec(num: T) -> Vec where - u128: std::convert::From, + u128: std::convert::From { let mut num: u128 = num.into(); if num == 0 { diff --git a/members/libpt-bintols/tests/split_numbers.rs b/members/libpt-bintols/tests/split.rs similarity index 96% rename from members/libpt-bintols/tests/split_numbers.rs rename to members/libpt-bintols/tests/split.rs index 3f461a3..14d006c 100644 --- a/members/libpt-bintols/tests/split_numbers.rs +++ b/members/libpt-bintols/tests/split.rs @@ -1,4 +1,4 @@ -use libpt_bintols::split_numbers::*; +use libpt_bintols::split::*; #[test] fn split_u128() { From 0a6072c478c0bd1fa52a49ba7514040a5cceb759 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 17:58:55 +0200 Subject: [PATCH 16/17] feat: add bintols split to libpt-py --- members/libpt-py/src/bintols/mod.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/members/libpt-py/src/bintols/mod.rs b/members/libpt-py/src/bintols/mod.rs index ea0403f..72f19be 100644 --- a/members/libpt-py/src/bintols/mod.rs +++ b/members/libpt-py/src/bintols/mod.rs @@ -2,10 +2,29 @@ use pyo3::prelude::*; use libpt::bintols as origin; -mod display { +mod split { + use libpt::bintols::split as origin; use pyo3::prelude::*; + #[pyfunction] + pub fn split_int(data: u128) -> Vec { + origin::unsigned_to_vec(data) + } + + /// implement a python module in Rust + pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> { + let module = PyModule::new(py, "split")?; + + module.add_function(wrap_pyfunction!(split_int, module)?)?; + + parent.add_submodule(module)?; + Ok(()) + } +} + +mod display { use libpt::bintols::display as origin; + use pyo3::prelude::*; #[pyfunction] pub fn bytes_to_bin(data: &[u8]) -> String { @@ -50,6 +69,7 @@ pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> { module.add("YOBI", origin::YOBI)?; display::submodule(py, module)?; + split::submodule(py, module)?; parent.add_submodule(module)?; Ok(()) From 86e1cc917d0fdee9bed4d2fde959bb3276610239 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 16:21:23 +0000 Subject: [PATCH 17/17] automatic cargo CI changes --- members/libpt-bintols/src/split.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/members/libpt-bintols/src/split.rs b/members/libpt-bintols/src/split.rs index c996ef7..3fb3a7d 100644 --- a/members/libpt-bintols/src/split.rs +++ b/members/libpt-bintols/src/split.rs @@ -3,7 +3,6 @@ //! Sometimes, you need a large integer in the form of many bytes, so split into [u8]. //! Rust provides - /// Split unsigned integers into a [Vec] of [u8]s /// /// Say you have the [u32] 1717 (binary: `00000000 00000000 00000110 10110101 `). This number would @@ -23,7 +22,7 @@ /// ``` pub fn unsigned_to_vec(num: T) -> Vec where - u128: std::convert::From + u128: std::convert::From, { let mut num: u128 = num.into(); if num == 0 {