Skip to content

Commit

Permalink
update readme and fix derive macro for numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
tomoikey committed Oct 23, 2024
1 parent c6562a8 commit 8398c32
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 58 deletions.
40 changes: 18 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,47 @@
**refined_type** is a library developed for Rust. It enhances your types, making them more robust and expanding the
range of guarantees your applications can statically ensure.

# Installation

```shell
cargo add refined_type
```

# Overview

You can create various rules for a certain type, such as phone numbers, addresses, times, and so on.
Once you have established the rules, you can easily combine them.
Specifically, if you create rules for 'non-empty strings' and 'strings composed only of alphabets,' you do not need to
redefine a new rule for 'non-empty strings composed only of alphabets'.
All rules can be arbitrarily combined and extended as long as the target type matches. Enjoy a wonderful type life!

# Example Usage
# Installation

```shell
cargo add refined_type
```

# Get Started

As an example, let's convert from JSON to a struct.

```rust
// define the constraints you expect by combining 'Refined' and 'Rule'.
type MyNonEmptyString = Refined<NonEmptyRule<String>>;
type MyNonEmptyVec<T> = Refined<NonEmptyRule<Vec<T>>>;

// define a struct for converting from JSON.
#[derive(Debug, Eq, PartialEq, Deserialize)]
#[derive(Debug, Deserialize)]
struct Human {
name: MyNonEmptyString,
friends: MyNonEmptyVec<String>,
name: NonEmptyString,
age: MinMaxU8<18, 80>,
friends: NonEmptyVec<String>,
}

fn example_1() -> anyhow::Result<()> {
let json = json! {{
"name": "john",
"age": 20,
"friends": ["tom", "taro"]
}}
.to_string();

let actual = serde_json::from_str::<Human>(&json)?;
let expected = Human {
name: MyNonEmptyString::new("john".to_string())?,
friends: MyNonEmptyVec::new(vec!["tom".to_string(), "taro".to_string()])?,
};
assert_eq!(actual, expected);
let human = serde_json::from_str::<Human>(&json)?;

assert_eq!(human.name.into_value(), "john");
assert_eq!(human.age.into_value(), 20);
assert_eq!(human.friends.into_value(), vec!["tom", "taro"]);
Ok(())
}
```

// In the second example, while `friends` meets the rule, `name` does not, causing the conversion from JSON to fail
fn example_2() -> anyhow::Result<()> {
Expand Down
8 changes: 4 additions & 4 deletions src/rule/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ mod equal;
mod even;
mod greater;
mod less;
mod odd;
mod min_max;
mod odd;

pub use even::*;
pub use odd::*;
pub use equal::*;
pub use even::*;
pub use greater::*;
pub use less::*;
pub use min_max::*;
pub use min_max::*;
pub use odd::*;
2 changes: 1 addition & 1 deletion src/rule/number/equal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ macro_rules! define_equal_rule {
$crate::paste::item! {
pub type [<Equal $t:camel>]<const EQUAL: $t> = $crate::Refined<[<EqualRule $t:camel>]<EQUAL>>;

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct [<EqualRule $t:camel>]<const EQUAL: $t>;

impl<const EQUAL: $t> $crate::rule::Rule for [<EqualRule $t:camel>]<EQUAL> {
Expand Down
2 changes: 1 addition & 1 deletion src/rule/number/greater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ macro_rules! define_greater_rule {
$crate::paste::item! {
pub type [<Greater $t:camel>]<const THAN: $t> = $crate::Refined<[<GreaterRule $t:camel>]<THAN>>;

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct [<GreaterRule $t:camel>]<const THAN: $t>;

impl<const THAN: $t> $crate::rule::Rule for [<GreaterRule $t:camel>]<THAN> {
Expand Down
2 changes: 1 addition & 1 deletion src/rule/number/less.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ macro_rules! define_less_rule {
$crate::paste::item! {
pub type [<Less $t:camel>]<const THAN: $t> = $crate::Refined<[<LessRule $t:camel>]<THAN>>;

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct [<LessRule $t:camel>]<const THAN: $t>;

impl<const THAN: $t> $crate::rule::Rule for [<LessRule $t:camel>]<THAN> {
Expand Down
2 changes: 1 addition & 1 deletion src/rule/number/min_max.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ mod test {
let min_max_result = MinMaxI8::<1, 10>::new(100);
assert!(min_max_result.is_err());
}
}
}
54 changes: 26 additions & 28 deletions tests/read_me.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,35 @@ use serde_json::json;

use refined_type::result::Error;
use refined_type::rule::composer::Not;
use refined_type::rule::{EqualU8, ExistsVec, ForAllVec, GreaterU8, HeadVec, Index0VecRule, Index1Vec, InitVec, LastVec, LengthDefinition, LessU8, MinMaxU8, NonEmptyRule, NonEmptyString, NonEmptyStringRule, NonEmptyVec, NonEmptyVecDeque, Reverse, Rule, SkipFirst, SkipVec, TailVec};
use refined_type::{
length_equal, length_greater_than, length_less_than, And,
Or, Refined,
use refined_type::rule::{
EqualU8, ExistsVec, ForAllVec, GreaterU8, HeadVec, Index0VecRule, Index1Vec, InitVec, LastVec,
LengthDefinition, LessU8, MinMaxU8, NonEmptyString, NonEmptyStringRule, NonEmptyVec,
NonEmptyVecDeque, Reverse, Rule, SkipFirst, SkipVec, TailVec,
};

// define the constraints you expect by combining 'Refined' and 'Rule'.
type MyNonEmptyString = Refined<NonEmptyRule<String>>;
type MyNonEmptyVec<T> = Refined<NonEmptyRule<Vec<T>>>;
use refined_type::{length_equal, length_greater_than, length_less_than, And, Or, Refined};

// define a struct for converting from JSON.
#[derive(Debug, Eq, PartialEq, Deserialize)]
#[derive(Debug, Deserialize)]
struct Human {
name: MyNonEmptyString,
friends: MyNonEmptyVec<String>,
name: NonEmptyString,
age: MinMaxU8<18, 80>,
friends: NonEmptyVec<String>,
}

#[test]
fn example_1() -> anyhow::Result<()> {
let json = json! {{
"name": "john",
"age": 20,
"friends": ["tom", "taro"]
}}
.to_string();
.to_string();

let actual = serde_json::from_str::<Human>(&json)?;
let expected = Human {
name: MyNonEmptyString::unsafe_new("john".to_string()),
friends: MyNonEmptyVec::unsafe_new(vec!["tom".to_string(), "taro".to_string()]),
};
assert_eq!(actual, expected);
let human = serde_json::from_str::<Human>(&json)?;

assert_eq!(human.name.into_value(), "john");
assert_eq!(human.age.into_value(), 20);
assert_eq!(human.friends.into_value(), vec!["tom", "taro"]);
Ok(())
}

Expand All @@ -44,7 +42,7 @@ fn example_2() -> anyhow::Result<()> {
"name": "",
"friends": ["tom", "taro"]
}}
.to_string();
.to_string();

// because `name` is empty
assert!(serde_json::from_str::<Human>(&json).is_err());
Expand All @@ -58,7 +56,7 @@ fn example_3() -> anyhow::Result<()> {
"name": "john",
"friends": []
}}
.to_string();
.to_string();

// because `friends` is empty
assert!(serde_json::from_str::<Human>(&json).is_err());
Expand Down Expand Up @@ -228,7 +226,7 @@ fn example_10() -> anyhow::Result<()> {
"name": "john",
"age": 8
}}
.to_string();
.to_string();

let actual = serde_json::from_str::<Human2>(&json)?;

Expand Down Expand Up @@ -261,23 +259,23 @@ fn min_max_example() -> Result<(), Error<u8>> {
#[test]
fn less_example() -> Result<(), Error<u8>> {
type Age = LessU8<80>;

let age = Age::new(79)?;
assert_eq!(age.into_value(), 79);

let age = Age::new(80);
assert!(age.is_err());

Ok(())
}

#[test]
fn greater_example() -> Result<(), Error<u8>> {
type Age = GreaterU8<18>;

let age = Age::new(19)?;
assert_eq!(age.into_value(), 19);

let age = Age::new(18);
assert!(age.is_err());

Expand All @@ -287,10 +285,10 @@ fn greater_example() -> Result<(), Error<u8>> {
#[test]
fn equal_example() -> Result<(), Error<u8>> {
type Age = EqualU8<18>;

let age = Age::new(18)?;
assert_eq!(age.into_value(), 18);

let age = Age::new(19);
assert!(age.is_err());

Expand Down

0 comments on commit 8398c32

Please sign in to comment.