Skip to content

Commit 64d4b00

Browse files
authored
Merge pull request #38 from tomoikey/v0.6.0
Release v0.6.0
2 parents 3969f57 + 2b1c07e commit 64d4b00

File tree

10 files changed

+727
-21
lines changed

10 files changed

+727
-21
lines changed

Cargo.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ repository = "https://github.com/tomoikey/refined_type"
66
readme = "README.md"
77
categories = ["accessibility", "development-tools", "rust-patterns"]
88
license = "MIT"
9-
version = "0.5.20"
9+
version = "0.6.0"
1010
edition = "2021"
1111

1212
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1313

1414
[dependencies]
1515
paste = "1.0.15"
1616
regex = "1.11.1"
17-
serde = { version = "1.0.214", features = ["derive"] }
17+
serde = { version = "1.0.215", features = ["derive"] }
1818

1919
[dev-dependencies]
20-
anyhow = "1.0.92"
21-
serde_json = "1.0.128"
20+
anyhow = "1.0.93"
21+
serde_json = "1.0.133"

README.md

+135-12
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
<h2 align="center">Refined Type</h2>
22

33
<div align="center">
4-
<img src="https://github.com/tomoikey/refined_type/actions/workflows/ci.yml/badge.svg"/>
5-
<img src="https://github.com/tomoikey/refined_type/actions/workflows/publish.yml/badge.svg"/>
6-
<br/>
4+
<div>
5+
<img src="https://img.shields.io/crates/v/refined_type.svg"/>
6+
<img src="https://img.shields.io/crates/d/refined_type"/>
7+
</div>
78
<i>Code More simply, More safely, for all Rustaceans.🦀</i>
89
<br/>
910
<img width=550 src="https://github.com/user-attachments/assets/2ae4bfee-1d42-4ed7-820a-b13260d359ef">
1011
<br/>
11-
<a href="https://github.com/tomoikey/refined_type/stargazers">
12-
<img src="https://img.shields.io/github/stars/tomoikey/refined_type" alt="Stars Badge"/>
13-
</a>
14-
<a href="https://github.com/tomoikey/refined_type/network/members">
15-
<img src="https://img.shields.io/github/forks/tomoikey/refined_type" alt="Forks Badge"/>
16-
</a>
12+
<div>
13+
<a href="https://github.com/tomoikey/refined_type/stargazers">
14+
<img src="https://img.shields.io/github/stars/tomoikey/refined_type" alt="Stars Badge"/>
15+
</a>
16+
<a href="https://github.com/tomoikey/refined_type/network/members">
17+
<img src="https://img.shields.io/github/forks/tomoikey/refined_type" alt="Forks Badge"/>
18+
</a>
19+
</div>
1720
<a href="https://github.com/tomoikey/refined_type/pulls">
1821
<img src="https://img.shields.io/github/issues-pr/tomoikey/refined_type" alt="Pull Requests Badge"/>
1922
</a>
@@ -132,9 +135,11 @@ By using Rule Composer, composite rules can be easily created.
132135

133136
`And` Rule Composer is a rule that satisfies both of the two rules.
134137
It is generally effective when you want to narrow down the condition range.
138+
135139
```rust
136140
type Target = Refined<And![EvenRuleU8, MinMaxRuleU8<0, 100>]>;
137141
```
142+
138143
```rust
139144
fn and_example() -> Result<(), Error<u8>> {
140145
let target = Target::new(50)?;
@@ -155,6 +160,7 @@ It is generally effective when you want to expand the condition range.
155160
```rust
156161
type Target = Refined<Or![LessRuleU8<10>, GreaterRuleU8<50>]>;
157162
```
163+
158164
```rust
159165
fn or_example() -> Result<(), Error<u8>> {
160166
let target = Target::new(5)?;
@@ -181,6 +187,7 @@ It is generally effective when you want to discard only certain situations.
181187
```rust
182188
type Target = Refined<Not<EqualRuleU8<50>>>;
183189
```
190+
184191
```rust
185192
fn not_example() -> Result<(), Error<u8>> {
186193
let target = Target::new(49)?;
@@ -222,7 +229,8 @@ fn if_example() -> Result<(), Error<i8>> {
222229

223230
### 5: `IfElse` Rule Composer
224231

225-
`IfElse` Rule Composer is a rule that applies a specific rule when a certain condition is met and another rule when it is not met.
232+
`IfElse` Rule Composer is a rule that applies a specific rule when a certain condition is met and another rule when it
233+
is not met.
226234

227235
```rust
228236
type Target = Refined<IfElse<GreaterEqualRuleI8<10>, EvenRuleI8, OddRuleI8>>;
@@ -393,7 +401,6 @@ fn range_example() -> Result<(), Error<u8>> {
393401
}
394402
```
395403

396-
397404
# Iterator
398405

399406
`refined_type` has several useful refined types for Iterators.
@@ -552,9 +559,121 @@ fn example_17() -> anyhow::Result<()> {
552559
}
553560
```
554561

562+
## `CountEqual`
563+
564+
`CountEqual` is a type that signifies the number of elements that satisfy the rule is a specific number.
565+
566+
```rust
567+
fn count_equal_example() -> Result<(), Error<Vec<i32>>> {
568+
let table = vec![
569+
(vec!["good morning".to_string(), "hello".to_string()], false),
570+
(vec!["good morning".to_string(), "".to_string()], true),
571+
(vec!["".to_string(), "hello".to_string()], true),
572+
(vec!["".to_string(), "".to_string()], false),
573+
];
574+
575+
for (value, expected) in table {
576+
let refined = CountEqualVec::<1, NonEmptyStringRule>::new(value.clone());
577+
assert_eq!(refined.is_ok(), expected);
578+
}
579+
580+
Ok(())
581+
}
582+
```
583+
584+
## `CountLess`
585+
586+
`CountLess` is a type that signifies the number of elements that satisfy the rule is less than a specific number.
587+
588+
```rust
589+
fn count_less_example() -> Result<(), Error<Vec<i32>>> {
590+
let table = vec![
591+
(vec!["good morning".to_string(), "hello".to_string()], false),
592+
(vec!["good morning".to_string(), "".to_string()], true),
593+
(vec!["".to_string(), "hello".to_string()], true),
594+
(vec!["".to_string(), "".to_string()], true),
595+
];
596+
597+
for (value, expected) in table {
598+
let refined = CountLessVec::<2, NonEmptyStringRule>::new(value.clone());
599+
assert_eq!(refined.is_ok(), expected);
600+
}
601+
602+
Ok(())
603+
}
604+
```
605+
606+
## `CountGreater`
607+
608+
`CountGreater` is a type that signifies the number of elements that satisfy the rule is greater than a specific number.
609+
610+
```rust
611+
fn count_greater_example() -> Result<(), Error<Vec<i32>>> {
612+
let table = vec![
613+
(vec!["good morning".to_string(), "hello".to_string()], true),
614+
(vec!["good morning".to_string(), "".to_string()], false),
615+
(vec!["".to_string(), "hello".to_string()], false),
616+
(vec!["".to_string(), "".to_string()], false),
617+
];
618+
619+
for (value, expected) in table {
620+
let refined = CountGreaterVec::<1, NonEmptyStringRule>::new(value.clone());
621+
assert_eq!(refined.is_ok(), expected);
622+
}
623+
624+
Ok(())
625+
}
626+
```
627+
628+
## `CountLessEqual`
629+
630+
`CountLessEqual` is a type that signifies the number of elements that satisfy the rule is less than or equal to a
631+
specific number.
632+
633+
```rust
634+
fn count_less_equal_example() -> Result<(), Error<Vec<i32>>> {
635+
let table = vec![
636+
(vec!["good morning".to_string(), "hello".to_string()], true),
637+
(vec!["good morning".to_string(), "".to_string()], true),
638+
(vec!["".to_string(), "hello".to_string()], true),
639+
(vec!["".to_string(), "".to_string()], true),
640+
];
641+
642+
for (value, expected) in table {
643+
let refined = CountLessEqualVec::<2, NonEmptyStringRule>::new(value.clone());
644+
assert_eq!(refined.is_ok(), expected);
645+
}
646+
647+
Ok(())
648+
}
649+
```
650+
651+
## `CountGreaterEqual`
652+
653+
`CountGreaterEqual` is a type that signifies the number of elements that satisfy the rule is greater than or equal to a
654+
specific number.
655+
656+
```rust
657+
fn count_greater_equal_example() -> Result<(), Error<Vec<i32>>> {
658+
let table = vec![
659+
(vec!["good morning".to_string(), "hello".to_string()], true),
660+
(vec!["good morning".to_string(), "".to_string()], true),
661+
(vec!["".to_string(), "hello".to_string()], true),
662+
(vec!["".to_string(), "".to_string()], false),
663+
];
664+
665+
for (value, expected) in table {
666+
let refined = CountGreaterEqualVec::<1, NonEmptyStringRule>::new(value.clone());
667+
assert_eq!(refined.is_ok(), expected);
668+
}
669+
670+
Ok(())
671+
}
672+
```
673+
555674
## `Reverse`
556675

557-
`Reverse` is a rule that applies a specific rule to all elements in the Iterator in reverse order.
676+
`Reverse` is a rule that applies a specific rule to all elements in the Iterator in reverse order.
558677

559678
```rust
560679
fn example_18() -> Result<(), Error<Vec<i32>>> {
@@ -622,6 +741,7 @@ impl<ITEM> SkipOption for NoSkip<ITEM> {
622741
You can impose constraints on objects that have a length, such as `String` or `Vec`.
623742

624743
## `LengthMinMax`
744+
625745
`LengthMinMax` is a type that signifies the target has a length between a certain number and another number.
626746

627747
```rust
@@ -642,6 +762,7 @@ fn length_min_max_example() -> Result<(), Error<String>> {
642762
```
643763

644764
## `LengthGreater`
765+
645766
`LengthGreater` is a type that signifies the target has a length greater than a certain number.
646767

647768
```rust
@@ -659,6 +780,7 @@ fn length_greater_example() -> Result<(), Error<String>> {
659780
```
660781

661782
## `LengthLess`
783+
662784
`LengthLess` is a type that signifies the target has a length less than a certain number.
663785

664786
```rust
@@ -676,6 +798,7 @@ fn length_less_example() -> Result<(), Error<String>> {
676798
```
677799

678800
## `LengthEqual`
801+
679802
`LengthEqual` is a type that signifies the target has a length equal to a certain number.
680803

681804
```rust

src/rule/collection.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod count;
12
mod exists;
23
mod for_all;
34
mod head;
@@ -10,6 +11,7 @@ mod reverse;
1011
mod skip;
1112
mod tail;
1213

14+
pub use count::*;
1315
pub use exists::*;
1416
pub use for_all::*;
1517
pub use head::*;

src/rule/collection/count.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
mod equal;
2+
mod grater_equal;
3+
mod greater;
4+
mod less;
5+
mod less_equal;
6+
7+
pub use equal::*;
8+
pub use grater_equal::*;
9+
pub use greater::*;
10+
pub use less::*;
11+
pub use less_equal::*;

src/rule/collection/count/equal.rs

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use crate::result::Error;
2+
use crate::rule::{Iterable, Rule};
3+
use crate::Refined;
4+
use std::collections::VecDeque;
5+
6+
/// A type that holds a value satisfying the `CountEqualRule`
7+
pub type CountEqual<const N: usize, RULE, ITERABLE> = Refined<CountEqualRule<N, RULE, ITERABLE>>;
8+
9+
/// A type that holds a `Vec` value satisfying the `CountEqualRule`
10+
pub type CountEqualVec<const N: usize, RULE> = Refined<CountEqualVecRule<N, RULE>>;
11+
12+
/// A type that holds a `VecDeque` value satisfying the `CountEqualRule`
13+
pub type CountEqualVecDeque<const N: usize, RULE> = Refined<CountEqualVecDequeRule<N, RULE>>;
14+
15+
/// A type that holds a `HashMap` value satisfying the `CountEqualRule`
16+
pub type CountEqualHashMap<const N: usize, RULE, K> = Refined<CountEqualHashMapRule<N, RULE, K>>;
17+
18+
/// A type that holds a `HashSet` value satisfying the `CountEqualRule`
19+
pub type CountEqualHashSet<const N: usize, RULE, K> = Refined<CountEqualHashSetRule<N, RULE, K>>;
20+
21+
/// A type that holds a `String` value satisfying the `CountEqualRule`
22+
pub type CountEqualString<const N: usize, RULE> = Refined<CountEqualStringRule<N, RULE>>;
23+
24+
/// A type that holds a `&'a str` value satisfying the `CountEqualRule`
25+
pub type CountEqualStr<'a, const N: usize, RULE> = Refined<CountEqualStrRule<'a, N, RULE>>;
26+
27+
/// Rule where the count of items that satisfy the condition is equal to `N`.
28+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29+
pub struct CountEqualRule<const N: usize, RULE: Rule, ITERABLE: Iterable>
30+
where
31+
ITERABLE: Iterable<Item = RULE::Item>,
32+
{
33+
_phantom: std::marker::PhantomData<(RULE, ITERABLE)>,
34+
}
35+
36+
impl<const N: usize, ITERABLE, RULE> Rule for CountEqualRule<N, RULE, ITERABLE>
37+
where
38+
ITERABLE: Iterable<Item = RULE::Item> + FromIterator<ITERABLE::Item>,
39+
RULE: Rule,
40+
{
41+
type Item = ITERABLE;
42+
fn validate(target: Self::Item) -> crate::Result<Self::Item> {
43+
let mut count = 0;
44+
let mut deque = VecDeque::new();
45+
for item in target.into_iterator() {
46+
match RULE::validate(item) {
47+
Ok(item) => {
48+
deque.push_back(item);
49+
count += 1
50+
}
51+
Err(e) => {
52+
deque.push_back(e.into_value());
53+
}
54+
}
55+
}
56+
let target = ITERABLE::from_iter(deque);
57+
if count == N {
58+
Ok(target)
59+
} else {
60+
Err(Error::new(
61+
target,
62+
format!("count is not equal to {}, actual count is {}", N, count),
63+
))
64+
}
65+
}
66+
}
67+
68+
/// Rule where the count of items in the `Vec` that satisfy the condition is equal to `N`.
69+
pub type CountEqualVecRule<const N: usize, RULE> =
70+
CountEqualRule<N, RULE, Vec<<RULE as Rule>::Item>>;
71+
72+
/// Rule where the count of items in the `VecDeque` that satisfy the condition is equal to `N`.
73+
pub type CountEqualVecDequeRule<const N: usize, RULE> =
74+
CountEqualRule<N, RULE, VecDeque<<RULE as Rule>::Item>>;
75+
76+
/// Rule where the count of items in the `HashMap` that satisfy the condition is equal to `N`.
77+
pub type CountEqualHashMapRule<const N: usize, RULE, K> =
78+
CountEqualRule<N, RULE, std::collections::HashMap<K, <RULE as Rule>::Item>>;
79+
80+
/// Rule where the count of items in the `HashSet` that satisfy the condition is equal to `N`.
81+
pub type CountEqualHashSetRule<const N: usize, RULE, K> =
82+
CountEqualRule<N, RULE, std::collections::HashSet<K>>;
83+
84+
/// Rule where the count of items in the `String` that satisfy the condition is equal to `N`.
85+
pub type CountEqualStringRule<const N: usize, RULE> = CountEqualRule<N, RULE, String>;
86+
87+
/// Rule where the count of items in the `&'a str` that satisfy the condition is equal to `N`.
88+
pub type CountEqualStrRule<'a, const N: usize, RULE> = CountEqualRule<N, RULE, &'a str>;
89+
90+
#[cfg(test)]
91+
mod tests {
92+
use crate::result::Error;
93+
use crate::rule::{CountEqualVec, NonEmptyStringRule};
94+
95+
#[test]
96+
fn count_equal_1() -> Result<(), Error<Vec<String>>> {
97+
let value = vec!["good morning".to_string(), "hello".to_string()];
98+
let count_equal = CountEqualVec::<2, NonEmptyStringRule>::new(value.clone())?;
99+
assert_eq!(count_equal.into_value(), value);
100+
Ok(())
101+
}
102+
}

0 commit comments

Comments
 (0)