Skip to content

Commit cfd9212

Browse files
committed
update README
1 parent 252b292 commit cfd9212

File tree

4 files changed

+231
-23
lines changed

4 files changed

+231
-23
lines changed

Cargo.toml

+6-6
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.1"
9+
version = "0.5.2"
1010
edition = "2021"
1111

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

1414
[dependencies]
15-
paste = "1.0.14"
16-
regex = "1.10.3"
17-
serde = { version = "1.0.197", features = ["derive"] }
15+
paste = "1.0.15"
16+
regex = "1.10.4"
17+
serde = { version = "1.0.203", features = ["derive"] }
1818

1919
[dev-dependencies]
20-
anyhow = "1.0.80"
21-
serde_json = "1.0.114"
20+
anyhow = "1.0.86"
21+
serde_json = "1.0.117"

README.md

+129-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ By using Rule Composer, composite rules can be easily created.
107107

108108
```rust
109109
struct ContainsHelloRule;
110+
110111
struct ContainsWorldRule;
111112

112113
impl Rule for ContainsHelloRule {
@@ -195,7 +196,9 @@ Therefore, it can be treated much like a composite function
195196

196197
```rust
197198
struct StartsWithHelloRule;
199+
198200
struct StartsWithByeRule;
201+
199202
struct EndsWithJohnRule;
200203

201204
impl Rule for StartsWithHelloRule {
@@ -320,15 +323,19 @@ type TargetAgeRule = And<TargetAge18OrMore, TargetAge80OrLess>;
320323
```
321324

322325
# Iterator
326+
323327
I have also prepared several useful refined types for Iterators.
328+
324329
## `ForAll`
330+
325331
`ForAll` is a rule that applies a specific rule to all elements in the Iterator.
332+
326333
```rust
327334
fn example_11() -> anyhow::Result<()> {
328335
let vec = vec!["Hello".to_string(), "World".to_string()];
329336
let for_all_ok = ForAll::<NonEmptyStringRule, _>::new(vec.clone())?;
330337
assert_eq!(vec, for_all_ok.into_value());
331-
338+
332339
let vec = vec!["Hello".to_string(), "".to_string()];
333340
let for_all_err = ForAll::<NonEmptyStringRule, _>::new(vec.clone());
334341
assert!(for_all_err.is_err());
@@ -337,7 +344,9 @@ fn example_11() -> anyhow::Result<()> {
337344
```
338345

339346
## `Exists`
347+
340348
`Exists` is a rule that applies a specific rule to at least one element in the Iterator.
349+
341350
```rust
342351
fn example_12() -> anyhow::Result<()> {
343352
let vec = vec!["Hello".to_string(), "".to_string()];
@@ -350,8 +359,11 @@ fn example_12() -> anyhow::Result<()> {
350359
Ok(())
351360
}
352361
```
362+
353363
---
364+
354365
## `into_iter()` and `iter()`
366+
355367
The Iterator I’ve prepared has `into_iter` and `iter` implemented.
356368
Therefore, you can easily map or convert it to a different Iterator using `collect`.
357369
Feel free to explore the capabilities of the Iterator you’ve been given!
@@ -420,6 +432,122 @@ fn example_15() -> anyhow::Result<()> {
420432
}
421433
```
422434

435+
# Length
436+
437+
You can impose constraints on objects that have a length, such as `String` or `Vec`.
438+
439+
### String
440+
441+
```rust
442+
fn example_16() -> Result<(), Error> {
443+
length_greater_than!(5);
444+
length_equal!(5, 10);
445+
length_less_than!(10);
446+
447+
type Password = Refined<From5To10Rule<String>>;
448+
449+
type From5To10Rule<T> = And<
450+
Or<LengthEqualRule5<T>, LengthGreaterThanRule5<T>>,
451+
Or<LengthLessThanRule10<T>, LengthEqualRule10<T>>,
452+
>;
453+
454+
// length is 8. so, this is valid
455+
let raw_password = "password";
456+
let password = Password::new(raw_password.to_string())?;
457+
assert_eq!(password.into_value(), "password");
458+
459+
// length is 4. so, this is invalid
460+
let raw_password = "pswd";
461+
let password = Password::new(raw_password.to_string());
462+
assert!(password.is_err());
463+
464+
// length is 17. so, this is invalid
465+
let raw_password = "password password";
466+
let password = Password::new(raw_password.to_string());
467+
assert!(password.is_err());
468+
469+
Ok(())
470+
}
471+
```
472+
473+
### Vec
474+
475+
```rust
476+
#[test]
477+
fn example_17() -> anyhow::Result<()> {
478+
length_greater_than!(5);
479+
length_equal!(5, 10);
480+
length_less_than!(10);
481+
482+
type Friends = Refined<From5To10Rule<Vec<String>>>;
483+
484+
type From5To10Rule<T> = And<
485+
Or<LengthEqualRule5<T>, LengthGreaterThanRule5<T>>,
486+
Or<LengthLessThanRule10<T>, LengthEqualRule10<T>>,
487+
>;
488+
489+
// length is 6. so, this is valid
490+
let raw_friends = vec![
491+
"Tom".to_string(),
492+
"Taro".to_string(),
493+
"Jiro".to_string(),
494+
"Hanako".to_string(),
495+
"Sachiko".to_string(),
496+
"Yoshiko".to_string(),
497+
];
498+
let friends = Friends::new(raw_friends.clone())?;
499+
assert_eq!(friends.into_value(), raw_friends);
500+
501+
// length is 2. so, this is invalid
502+
let raw_friends = vec!["Tom".to_string(), "Taro".to_string()];
503+
let friends = Friends::new(raw_friends.clone());
504+
assert!(friends.is_err());
505+
506+
// length is 11. so, this is invalid
507+
let raw_friends = vec![
508+
"Tom".to_string(),
509+
"Taro".to_string(),
510+
"Jiro".to_string(),
511+
"Hanako".to_string(),
512+
"Sachiko".to_string(),
513+
"Yuiko".to_string(),
514+
"Taiko".to_string(),
515+
"John".to_string(),
516+
"Jane".to_string(),
517+
"Jack".to_string(),
518+
"Jill".to_string(),
519+
];
520+
let friends = Friends::new(raw_friends.clone());
521+
assert!(friends.is_err());
522+
523+
Ok(())
524+
}
525+
```
526+
527+
### Custom Length
528+
529+
You can define a length for any type. Therefore, if you want to implement a length that is not provided
530+
by `refined_type`, you can easily do so using `LengthDefinition`.
531+
532+
```rust
533+
#[test]
534+
fn example_18() -> anyhow::Result<()> {
535+
length_equal!(5);
536+
537+
#[derive(Debug, PartialEq)]
538+
struct Hello;
539+
impl LengthDefinition for Hello {
540+
fn length(&self) -> usize {
541+
5
542+
}
543+
}
544+
545+
let hello = Refined::<LengthEqualRule5<Hello>>::new(Hello)?;
546+
assert_eq!(hello.into_value(), Hello);
547+
Ok(())
548+
}
549+
```
550+
423551
# Tips
424552

425553
Directly writing `And`, `Or`, `Not` or `Refined` can often lead to a decrease in readability.

src/rule/length/length_definition.rs

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ impl<T> LengthDefinition for Vec<T> {
3333
}
3434
}
3535

36-
// Implementions of Iteration
3736
impl<T> LengthDefinition for [T] {
3837
fn length(&self) -> usize {
3938
self.len()

tests/read_me.rs

+96-15
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
use serde::{Deserialize, Serialize};
2+
use serde_json::json;
3+
4+
use refined_type::{
5+
equal_rule, greater_rule, length_equal, length_greater_than, length_less_than, less_rule,
6+
Refined,
7+
};
18
use refined_type::result::Error;
2-
use refined_type::rule::composer::{And, Not, Or};
39
use refined_type::rule::{
4-
Exists, ForAll, NonEmptyRule, NonEmptyString, NonEmptyStringRule, NonEmptyVec,
5-
NonEmptyVecDeque, Rule,
10+
Exists, ForAll, LengthDefinition, NonEmptyRule, NonEmptyString, NonEmptyStringRule,
11+
NonEmptyVec, NonEmptyVecDeque, Rule,
612
};
7-
use refined_type::{equal_rule, greater_rule, less_rule, Refined};
8-
use serde::{Deserialize, Serialize};
9-
use serde_json::json;
13+
use refined_type::rule::composer::{And, Not, Or};
1014

1115
// define the constraints you expect by combining 'Refined' and 'Rule'.
1216
type MyNonEmptyString = Refined<NonEmptyRule<String>>;
@@ -298,22 +302,99 @@ fn example_15() -> anyhow::Result<()> {
298302
}
299303

300304
#[test]
301-
fn example_16() -> anyhow::Result<()> {
302-
let non_empty_string_1 = NonEmptyString::new("Hello".to_string())?;
303-
let non_empty_string_2 = NonEmptyString::new("World".to_string())?;
304-
let non_empty_string = non_empty_string_1 + non_empty_string_2; // This is also `NonEmptyString` type
305+
fn example_16() -> Result<(), Error> {
306+
length_greater_than!(5);
307+
length_equal!(5, 10);
308+
length_less_than!(10);
309+
310+
type Password = Refined<From5To10Rule<String>>;
311+
312+
type From5To10Rule<T> = And<
313+
Or<LengthEqualRule5<T>, LengthGreaterThanRule5<T>>,
314+
Or<LengthLessThanRule10<T>, LengthEqualRule10<T>>,
315+
>;
316+
317+
// length is 8. so, this is valid
318+
let raw_password = "password";
319+
let password = Password::new(raw_password.to_string())?;
320+
assert_eq!(password.into_value(), "password");
321+
322+
// length is 4. so, this is invalid
323+
let raw_password = "pswd";
324+
let password = Password::new(raw_password.to_string());
325+
assert!(password.is_err());
326+
327+
// length is 17. so, this is invalid
328+
let raw_password = "password password";
329+
let password = Password::new(raw_password.to_string());
330+
assert!(password.is_err());
305331

306-
assert_eq!(non_empty_string.into_value(), "HelloWorld");
307332
Ok(())
308333
}
309334

310335
#[test]
311336
fn example_17() -> anyhow::Result<()> {
312-
let ne_vec_1 = NonEmptyVec::new(vec![1, 2, 3])?;
313-
let ne_vec_2 = NonEmptyVec::new(vec![4, 5, 6])?;
314-
let ne_vec = ne_vec_1 + ne_vec_2; // This is also `NonEmptyVec` type
337+
length_greater_than!(5);
338+
length_equal!(5, 10);
339+
length_less_than!(10);
340+
341+
type Friends = Refined<From5To10Rule<Vec<String>>>;
342+
343+
type From5To10Rule<T> = And<
344+
Or<LengthEqualRule5<T>, LengthGreaterThanRule5<T>>,
345+
Or<LengthLessThanRule10<T>, LengthEqualRule10<T>>,
346+
>;
347+
348+
// length is 6. so, this is valid
349+
let raw_friends = vec![
350+
"Tom".to_string(),
351+
"Taro".to_string(),
352+
"Jiro".to_string(),
353+
"Hanako".to_string(),
354+
"Sachiko".to_string(),
355+
"Yoshiko".to_string(),
356+
];
357+
let friends = Friends::new(raw_friends.clone())?;
358+
assert_eq!(friends.into_value(), raw_friends);
359+
360+
// length is 2. so, this is invalid
361+
let raw_friends = vec!["Tom".to_string(), "Taro".to_string()];
362+
let friends = Friends::new(raw_friends.clone());
363+
assert!(friends.is_err());
364+
365+
// length is 11. so, this is invalid
366+
let raw_friends = vec![
367+
"Tom".to_string(),
368+
"Taro".to_string(),
369+
"Jiro".to_string(),
370+
"Hanako".to_string(),
371+
"Sachiko".to_string(),
372+
"Yuiko".to_string(),
373+
"Taiko".to_string(),
374+
"John".to_string(),
375+
"Jane".to_string(),
376+
"Jack".to_string(),
377+
"Jill".to_string(),
378+
];
379+
let friends = Friends::new(raw_friends.clone());
380+
assert!(friends.is_err());
381+
382+
Ok(())
383+
}
384+
385+
#[test]
386+
fn example_18() -> anyhow::Result<()> {
387+
#[derive(Debug, PartialEq)]
388+
struct Hello;
389+
impl LengthDefinition for Hello {
390+
fn length(&self) -> usize {
391+
5
392+
}
393+
}
315394

316-
assert_eq!(ne_vec.into_value(), vec![1, 2, 3, 4, 5, 6]);
395+
length_equal!(5);
396+
let hello = Refined::<LengthEqualRule5<Hello>>::new(Hello)?;
397+
assert_eq!(hello.into_value(), Hello);
317398
Ok(())
318399
}
319400

0 commit comments

Comments
 (0)