ADDED .efiles Index: .efiles ================================================================== --- /dev/null +++ .efiles @@ -0,0 +1,5 @@ +Cargo.toml +README.md +www/index.md +www/changelog.md +src/lib.rs ADDED .fossil-settings/ignore-glob Index: .fossil-settings/ignore-glob ================================================================== --- /dev/null +++ .fossil-settings/ignore-glob @@ -0,0 +1,3 @@ +.*.swp +Cargo.lock +target Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "limq" -version = "0.1.0" +version = "0.1.1" edition = "2021" license = "0BSD" # https://crates.io/category_slugs categories = [ "data-structures" ] keywords = [ "queue", "bounded" ] @@ -12,10 +12,11 @@ exclude = [ ".fossil-settings", ".efiles", ".fslckout", "www", + "bacon.toml", "rustfmt.toml" ] # https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section [badges] @@ -24,5 +25,11 @@ [dependencies] [package.metadata.docs.rs] rustdoc-args = ["--generate-link-to-definition"] +[lints.clippy] +all = { level = "deny", priority = -1 } +pedantic = { level = "warn", priority = -1 } +nursery = { level = "warn", priority = -1 } +cargo = { level = "warn", priority = -1 } + ADDED bacon.toml Index: bacon.toml ================================================================== --- /dev/null +++ bacon.toml @@ -0,0 +1,102 @@ +# This is a configuration file for the bacon tool +# +# Bacon repository: https://github.com/Canop/bacon +# Complete help on configuration: https://dystroy.org/bacon/config/ +# You can also check bacon's own bacon.toml file +# as an example: https://github.com/Canop/bacon/blob/main/bacon.toml + +#default_job = "check" +default_job = "clippy-all" + +[jobs.check] +command = ["cargo", "check", "--color", "always"] +need_stdout = false + +[jobs.check-all] +command = ["cargo", "check", "--all-targets", "--color", "always"] +need_stdout = false + +# Run clippy on the default target +[jobs.clippy] +command = [ + "cargo", "clippy", + "--color", "always", +] +need_stdout = false + +# Run clippy on all targets +# To disable some lints, you may change the job this way: +# [jobs.clippy-all] +# command = [ +# "cargo", "clippy", +# "--all-targets", +# "--color", "always", +# "--", +# "-A", "clippy::bool_to_int_with_if", +# "-A", "clippy::collapsible_if", +# "-A", "clippy::derive_partial_eq_without_eq", +# ] +# need_stdout = false +[jobs.clippy-all] +command = [ + "cargo", "clippy", + "--all-targets", + "--color", "always", +] +need_stdout = false + +# This job lets you run +# - all tests: bacon test +# - a specific test: bacon test -- config::test_default_files +# - the tests of a package: bacon test -- -- -p config +[jobs.test] +command = [ + "cargo", "test", "--color", "always", + "--", "--color", "always", # see https://github.com/Canop/bacon/issues/124 +] +need_stdout = true + +[jobs.doc] +command = ["cargo", "doc", "--color", "always", "--no-deps"] +need_stdout = false + +# If the doc compiles, then it opens in your browser and bacon switches +# to the previous job +[jobs.doc-open] +command = ["cargo", "doc", "--color", "always", "--no-deps", "--open"] +need_stdout = false +on_success = "back" # so that we don't open the browser at each change + +# You can run your application and have the result displayed in bacon, +# *if* it makes sense for this crate. +# Don't forget the `--color always` part or the errors won't be +# properly parsed. +# If your program never stops (eg a server), you may set `background` +# to false to have the cargo run output immediately displayed instead +# of waiting for program's end. +[jobs.run] +command = [ + "cargo", "run", + "--color", "always", + # put launch parameters for your program behind a `--` separator +] +need_stdout = true +allow_warnings = true +background = true + +# This parameterized job runs the example of your choice, as soon +# as the code compiles. +# Call it as +# bacon ex -- my-example +[jobs.ex] +command = ["cargo", "run", "--color", "always", "--example"] +need_stdout = true +allow_warnings = true + +# You may define here keybindings that would be specific to +# a project, for example a shortcut to launch a specific job. +# Shortcuts to internal functions (scrolling, toggling, etc.) +# should go in your personal global prefs.toml file instead. +[keybindings] +# alt-m = "job:my-job" +c = "job:clippy-all" # comment this to have 'c' run clippy on only the default target Index: src/lib.rs ================================================================== --- src/lib.rs +++ src/lib.rs @@ -1,10 +1,10 @@ -//! _LimQ_ is a queue (implemented as a wrapper around [`VecDeque`]) that +//! `LimQ` is a queue (implemented as a wrapper around [`VecDeque`]) that //! supports an optional maximum number of elements constraint. //! //! Rather than supplying the traditional `push()` method to add elements to -//! the queue, _LimQ_ implements [`LimQ::try_push()`] and +//! the queue, `LimQ` implements [`LimQ::try_push()`] and //! [`LimQ::force_push()`]. If no queue limit has been enabled, both of these //! act exactly like a traditional `push()` would. When a limit has been set, //! and reached, `try_push()` will fail, returning the input element. //! `force_push()` will forcibly add the new element while dropping the next //! element in line to be pulled off the queue. @@ -44,19 +44,20 @@ /// /// Passning `None` to `max_len` will disable the limit. /// /// # Panics /// A zero-limit will cause a panic. + #[must_use] pub fn new(max_len: Option) -> Self { - assert!(!matches!(max_len, Some(0))); - - let q = if let Some(max_len) = max_len { - VecDeque::with_capacity(max_len) - } else { - VecDeque::new() - }; - Self { max_len, q } + assert!( + !matches!(max_len, Some(0)), + "A zero-length limit is forbidden" + ); + + let q = max_len.map_or_else(VecDeque::new, VecDeque::with_capacity); + + Self { q, max_len } } /// Change the limit of the queue. /// /// Does not drain overflow elements if the new limit is lower than the @@ -64,28 +65,34 @@ /// calling [`LimQ::purge_overflow()`]. /// /// # Panics /// A zero-limit will cause a panic. pub fn set_max_len(&mut self, max_len: Option) { - assert!(!matches!(max_len, Some(0))); + assert!( + !matches!(max_len, Some(0)), + "A zero-length limit is forbidden" + ); self.max_len = max_len; } /// Return the maximum number of elements in queue. #[inline] - pub fn max_len(&self) -> Option { + #[must_use] + pub const fn max_len(&self) -> Option { self.max_len } /// Return the current number of elements in the queue. #[inline] + #[must_use] pub fn len(&self) -> usize { self.q.len() } /// Return a boolean indicating whether the queue is empty or not. #[inline] + #[must_use] pub fn is_empty(&self) -> bool { self.q.is_empty() } /// Drop elements that overflow the queue limit (if a limit has been set). @@ -136,10 +143,13 @@ /// /// // No room for new nodes -- try_push should return Err() containing /// // the node /// assert_eq!(q.try_push(11), Err(11)); /// ``` + /// + /// # Errors + /// The node will be returned if the queue is full. #[inline] pub fn try_push(&mut self, n: T) -> Result<(), T> { if let Some(max_len) = self.max_len { if self.q.len() < max_len { self.q.push_back(n); @@ -205,14 +215,21 @@ #[cfg(test)] mod tests { use super::LimQ; #[test] - #[should_panic] + #[should_panic(expected = "A zero-length limit is forbidden")] fn zero_len() { let _q: LimQ<()> = LimQ::new(Some(0)); } + + #[test] + #[should_panic(expected = "A zero-length limit is forbidden")] + fn set_zero_len() { + let mut q: LimQ<()> = LimQ::new(Some(11)); + q.set_max_len(Some(0)); + } #[test] fn try_exceed() { let mut q: LimQ = LimQ::new(Some(1)); q.try_push(42).unwrap(); Index: www/changelog.md ================================================================== --- www/changelog.md +++ www/changelog.md @@ -3,10 +3,12 @@ ## [Unreleased] [Details](/vdiff?from=limq-0.1.0&to=trunk) ### Added + +- Add an assertion message when a zero maximum length has been specified. ### Changed ### Removed