diff --git a/src/rule/collection.rs b/src/rule/collection.rs index 2142f6f..45bb13b 100644 --- a/src/rule/collection.rs +++ b/src/rule/collection.rs @@ -6,6 +6,7 @@ mod init; mod last; mod reverse; mod skip; +mod tail; pub use exists::*; pub use for_all::*; @@ -15,3 +16,4 @@ pub use init::*; pub use last::*; pub use reverse::*; pub use skip::*; +pub use tail::*; diff --git a/src/rule/collection/tail.rs b/src/rule/collection/tail.rs new file mode 100644 index 0000000..f5e64be --- /dev/null +++ b/src/rule/collection/tail.rs @@ -0,0 +1,78 @@ +use crate::rule::{Rule, SkipFirst, SkipRule}; +use crate::Refined; +use std::collections::VecDeque; + +/// A type that holds a value satisfying the `TailRule` +pub type Tail = Refined>; + +/// A type that holds a `Vec` value satisfying the `TailRule` +pub type TailVec = Tail::Item>, ::Item>; + +/// A type that holds a `VecDeque` value satisfying the `TailRule` +pub type TailVecDeque = Tail::Item>, ::Item>; + +/// A type that holds a `String` value satisfying the `TailRule` +pub type TailString = Tail; + +/// Rule where the data in the collection satisfies the condition after skipping the first element +pub type TailRule = SkipRule>; + +/// Rule where the data in the `Vec` satisfies the condition after skipping the first element +pub type TailVecRule = TailRule::Item>, ::Item>; + +/// Rule where the data in the `VecDeque` satisfies the condition after skipping the first element +pub type TailVecDequeRule = + TailRule::Item>, ::Item>; + +/// Rule where the data in the `String` satisfies the condition after skipping the first element +pub type TailStringRule = TailRule; + +#[cfg(test)] +mod tests { + use crate::result::Error; + use crate::rule::{NonEmptyStringRule, TailVec}; + + #[test] + fn test_tail_valid() -> Result<(), Error>> { + let table = vec![ + ( + vec!["hey".to_string(), "hello".to_string(), "world".to_string()], + vec!["hey".to_string(), "hello".to_string(), "world".to_string()], + ), + ( + vec!["".to_string(), "hello".to_string(), "world".to_string()], + vec!["".to_string(), "hello".to_string(), "world".to_string()], + ), + (vec!["".to_string()], vec!["".to_string()]), + (vec![], vec![]), + ]; + + for (input, expected) in table { + let refined = TailVec::::new(input.clone())?; + assert_eq!(refined.into_value(), expected); + } + + Ok(()) + } + + #[test] + fn test_tail_invalid() -> Result<(), Error>> { + let table = vec![ + vec!["hey".to_string(), "hello".to_string(), "".to_string()], + vec!["hey".to_string(), "".to_string(), "".to_string()], + vec!["".to_string(), "hello".to_string(), "".to_string()], + vec!["".to_string(), "".to_string(), "".to_string()], + vec!["hey".to_string(), "hello".to_string(), "".to_string()], + vec!["hey".to_string(), "".to_string(), "".to_string()], + vec!["".to_string(), "hello".to_string(), "".to_string()], + vec!["".to_string(), "".to_string(), "".to_string()], + ]; + + for input in table { + let refined = TailVec::::new(input.clone()); + assert!(refined.is_err()); + } + + Ok(()) + } +}