Skip to content

Commit 9770164

Browse files
committed
implement less_than
1 parent 5ce188c commit 9770164

File tree

5 files changed

+166
-14
lines changed

5 files changed

+166
-14
lines changed

src/refined.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use crate::result::Error;
2-
use crate::rule::Rule;
3-
use serde::{Deserialize, Deserializer, Serialize, Serializer};
41
use std::fmt::{Display, Formatter};
52
use std::marker::PhantomData;
6-
use std::ops::Deref;
3+
4+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
5+
6+
use crate::result::Error;
7+
use crate::rule::Rule;
78

89
/// Refined is a versatile type in ensuring that `T` satisfies the conditions of `RULE` (predicate type)
910
/// # Example
@@ -96,11 +97,12 @@ where
9697

9798
#[cfg(test)]
9899
mod test {
100+
use serde::{Deserialize, Serialize};
101+
use serde_json::json;
102+
99103
use crate::refined::Refined;
100104
use crate::result::Error;
101105
use crate::rule::{NonEmptyString, NonEmptyStringRule, NonEmptyVec};
102-
use serde::{Deserialize, Serialize};
103-
use serde_json::json;
104106

105107
#[test]
106108
fn test_unsafe_new_success() {

src/rule.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1+
pub use empty::*;
2+
pub use exists::*;
3+
pub use for_all::*;
4+
pub use length::*;
5+
pub use non_empty::*;
6+
pub use number::*;
7+
pub use string::*;
8+
9+
use crate::result::Error;
10+
111
pub mod composer;
212
mod empty;
313
mod exists;
414
mod for_all;
15+
mod length;
516
mod non_empty;
617
mod number;
718
mod string;
819

9-
use crate::result::Error;
10-
pub use empty::*;
11-
pub use exists::*;
12-
pub use for_all::*;
13-
pub use non_empty::*;
14-
pub use number::*;
15-
pub use string::*;
16-
1720
/// This is a `trait` that specifies the conditions a type `T` should satisfy
1821
pub trait Rule {
1922
type Item;

src/rule/length.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub use length_definition::*;
2+
3+
mod length_definition;
4+
mod less_than;
5+

src/rule/length/length_definition.rs

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
pub trait LengthDefinition {
2+
fn length(&self) -> usize;
3+
}
4+
5+
impl LengthDefinition for str {
6+
fn length(&self) -> usize {
7+
self.chars().count()
8+
}
9+
}
10+
11+
impl LengthDefinition for &str {
12+
fn length(&self) -> usize {
13+
self.chars().count()
14+
}
15+
}
16+
17+
impl LengthDefinition for String {
18+
fn length(&self) -> usize {
19+
self.chars().count()
20+
}
21+
}
22+
23+
impl<T> LengthDefinition for Vec<T> {
24+
fn length(&self) -> usize {
25+
self.len()
26+
}
27+
}
28+
29+
// Implementions of Iteration
30+
impl<T> LengthDefinition for [T] {
31+
fn length(&self) -> usize {
32+
self.len()
33+
}
34+
}
35+
36+
impl<K, V> LengthDefinition for std::collections::HashMap<K, V> {
37+
fn length(&self) -> usize {
38+
self.len()
39+
}
40+
}
41+
42+
impl<K, V> LengthDefinition for std::collections::BTreeMap<K, V> {
43+
fn length(&self) -> usize {
44+
self.len()
45+
}
46+
}
47+
48+
impl<T> LengthDefinition for std::collections::HashSet<T> {
49+
fn length(&self) -> usize {
50+
self.len()
51+
}
52+
}
53+
54+
impl<T> LengthDefinition for std::collections::BTreeSet<T> {
55+
fn length(&self) -> usize {
56+
self.len()
57+
}
58+
}
59+
60+
impl<T> LengthDefinition for std::collections::LinkedList<T> {
61+
fn length(&self) -> usize {
62+
self.len()
63+
}
64+
}
65+
66+
impl<T> LengthDefinition for std::collections::VecDeque<T> {
67+
fn length(&self) -> usize {
68+
self.len()
69+
}
70+
}
71+
72+
impl<T> LengthDefinition for std::collections::BinaryHeap<T> {
73+
fn length(&self) -> usize {
74+
self.len()
75+
}
76+
}

src/rule/length/less_than.rs

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#[macro_export]
2+
macro_rules! length_less_than {
3+
($length:literal) => {
4+
paste::item! {
5+
#[allow(dead_code)]
6+
pub type [<LengthLessThan $length>]<ITEM> = $crate::Refined<[<LengthLessThanRule $length>]<ITEM>>;
7+
8+
#[allow(dead_code)]
9+
pub struct [<LengthLessThanRule $length>]<ITEM> {
10+
_phantom: ::std::marker::PhantomData<ITEM>,
11+
}
12+
13+
impl<ITEM> $crate::rule::Rule for [<LengthLessThanRule $length>]<ITEM> where ITEM: $crate::rule::LengthDefinition {
14+
type Item = ITEM;
15+
fn validate(target: &Self::Item) -> Result<(), $crate::result::Error> {
16+
if target.length() < $length {
17+
Ok(())
18+
} else {
19+
Err(Error::new(format!("target length is not less than {}", $length)))
20+
}
21+
}
22+
}
23+
}
24+
};
25+
($length:literal, $($lengths:literal),+) => {
26+
length_less_than!($length);
27+
length_less_than!($($lengths),+);
28+
};
29+
}
30+
31+
#[cfg(test)]
32+
mod tests {
33+
use crate::result::Error;
34+
35+
length_less_than!(5, 10);
36+
37+
#[test]
38+
fn test_length_less_than_5() -> Result<(), Error> {
39+
let target = "1234";
40+
let refined = LengthLessThan5::new(target)?;
41+
assert_eq!(refined.into_value(), "1234");
42+
Ok(())
43+
}
44+
45+
#[test]
46+
fn test_length_less_than_5_fail() {
47+
let target = "12345";
48+
let refined = LengthLessThan5::new(target);
49+
assert!(refined.is_err());
50+
}
51+
52+
#[test]
53+
fn test_length_less_than_10() -> Result<(), Error> {
54+
let target = "123456789";
55+
let refined = LengthLessThan10::new(target)?;
56+
assert_eq!(refined.into_value(), "123456789");
57+
Ok(())
58+
}
59+
60+
#[test]
61+
fn test_length_less_than_10_fail() {
62+
let target = "1234567890";
63+
let refined = LengthLessThan10::new(target);
64+
assert!(refined.is_err());
65+
}
66+
}

0 commit comments

Comments
 (0)