Skip to content

Commit b8a5042

Browse files
authored
Merge pull request #11 from tomoikey/impl_add_trait
Impl add trait
2 parents 0e70545 + 786d34d commit b8a5042

File tree

8 files changed

+148
-31
lines changed

8 files changed

+148
-31
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ repository = "https://github.com/tomoikey/refined-type"
66
readme = "README.md"
77
categories = ["development-tools"]
88
license = "MIT"
9-
version = "0.3.7"
9+
version = "0.4.0"
1010
edition = "2021"
1111

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

README.md

+40-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ struct Human {
224224
age: u8,
225225
}
226226

227-
fn test_refined_deserialize_json_ok_struct() -> anyhow::Result<()> {
227+
fn main() -> anyhow::Result<()> {
228228
let json = json! {{
229229
"name": "john",
230230
"age": 8
@@ -242,6 +242,45 @@ fn test_refined_deserialize_json_ok_struct() -> anyhow::Result<()> {
242242
}
243243
```
244244

245+
# Add Trait
246+
I have implemented the `Add` trait for a part of the `Refined` that I provided. Therefore, operations can be performed without downgrading the type level.
247+
### NonEmptyString
248+
```rust
249+
fn main() -> anyhow::Result<()> {
250+
let non_empty_string_1 = NonEmptyString::new("Hello".to_string())?;
251+
let non_empty_string_2 = NonEmptyString::new("World".to_string())?;
252+
let non_empty_string = non_empty_string_1 + non_empty_string_2; // This is also `NonEmptyString` type
253+
254+
assert_eq!(non_empty_string.into_value(), "HelloWorld");
255+
Ok(())
256+
}
257+
```
258+
259+
### NonEmptyVec
260+
```rust
261+
#[test]
262+
fn test_add_vec() -> anyhow::Result<()> {
263+
let ne_vec_1 = NonEmptyVec::new(vec![1, 2, 3])?;
264+
let ne_vec_2 = NonEmptyVec::new(vec![4, 5, 6])?;
265+
let ne_vec = ne_vec_1 + ne_vec_2; // This is also `NonEmptyVec` type
266+
267+
assert_eq!(ne_vec.into_value(), vec![1, 2, 3, 4, 5, 6]);
268+
Ok(())
269+
}
270+
```
271+
272+
### Empty
273+
```rust
274+
fn test_add_empty() -> anyhow::Result<()> {
275+
let empty_1 = Empty::new(0)?;
276+
let empty_2 = Empty::new(0)?;
277+
let empty = empty_1 + empty_2; // This is also `Empty` type
278+
279+
assert_eq!(empty.into_value(), 0);
280+
Ok(())
281+
}
282+
```
283+
245284
# Tips
246285
Directly writing `And`, `Or`, `Not` or `Refined` can often lead to a decrease in readability.
247286
Therefore, using **type aliases** can help make your code clearer.

src/rule/composer/not.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use std::marker::PhantomData;
66
/// # Example
77
/// ```rust
88
/// use refined_type::rule::composer::Not;
9-
/// use refined_type::rule::{Empty, Rule};
9+
/// use refined_type::rule::{EmptyRule, Rule};
1010
///
11-
/// type NonEmptyString = Not<Empty<String>>;
11+
/// type NonEmptyString = Not<EmptyRule<String>>;
1212
///
1313
/// assert!(NonEmptyString::validate("non empty".to_string()).is_ok());
1414
/// assert!(NonEmptyString::validate("".to_string()).is_err());

src/rule/composer/or.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use std::marker::PhantomData;
66
/// # Example
77
/// ```rust
88
/// use refined_type::rule::composer::Or;
9-
/// use refined_type::rule::{AlphabetRule, Empty, Rule};
9+
/// use refined_type::rule::{AlphabetRule, EmptyRule, Rule};
1010
///
11-
/// type EmptyOrAlphabetString = Or<Empty<String>, AlphabetRule>;
11+
/// type EmptyOrAlphabetString = Or<EmptyRule<String>, AlphabetRule>;
1212
///
1313
/// assert!(EmptyOrAlphabetString::validate("".to_string()).is_ok());
1414
/// assert!(EmptyOrAlphabetString::validate("alphabet".to_string()).is_ok());

src/rule/empty.rs

+40-10
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,42 @@
11
use crate::result::Error;
22
use crate::rule::Rule;
3+
use crate::Refined;
4+
35
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
6+
use std::fmt::Debug;
47
use std::marker::PhantomData;
8+
use std::ops::Add;
9+
10+
pub type Empty<T> = Refined<EmptyRule<T>>;
11+
12+
impl<T> Add for Empty<T>
13+
where
14+
T: EmptyDefinition,
15+
{
16+
type Output = Self;
17+
18+
fn add(self, _rhs: Self) -> Self::Output {
19+
self
20+
}
21+
}
522

623
/// Rule where the data is empty
724
/// ```rust
8-
/// use refined_type::rule::{Empty, Rule};
25+
/// use refined_type::rule::{EmptyRule, Rule};
926
///
10-
/// assert!(Empty::<String>::validate("".to_string()).is_ok());
11-
/// assert!(Empty::<String>::validate("non empty".to_string()).is_err());
27+
/// assert!(EmptyRule::<String>::validate("".to_string()).is_ok());
28+
/// assert!(EmptyRule::<String>::validate("non empty".to_string()).is_err());
1229
///
13-
/// assert!(Empty::<Vec<u8>>::validate(Vec::<u8>::new()).is_ok());
14-
/// assert!(Empty::<Vec<u8>>::validate(vec![1, 2, 3]).is_err());
30+
/// assert!(EmptyRule::<Vec<u8>>::validate(Vec::<u8>::new()).is_ok());
31+
/// assert!(EmptyRule::<Vec<u8>>::validate(vec![1, 2, 3]).is_err());
1532
///
16-
/// assert!(Empty::<u8>::validate(0).is_ok());
17-
/// assert!(Empty::<u8>::validate(1).is_err());
33+
/// assert!(EmptyRule::<u8>::validate(0).is_ok());
34+
/// assert!(EmptyRule::<u8>::validate(1).is_err());
1835
/// ```
1936
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
20-
pub struct Empty<T> {
37+
pub struct EmptyRule<T> {
2138
_phantom_data: PhantomData<T>,
2239
}
23-
2440
pub trait EmptyDefinition {
2541
fn empty(&self) -> bool;
2642
}
@@ -151,7 +167,7 @@ impl EmptyDefinition for f64 {
151167
}
152168
}
153169

154-
impl<T> Rule for Empty<T>
170+
impl<T> Rule for EmptyRule<T>
155171
where
156172
T: EmptyDefinition,
157173
{
@@ -165,3 +181,17 @@ where
165181
}
166182
}
167183
}
184+
185+
#[cfg(test)]
186+
mod test {
187+
use crate::rule::Empty;
188+
189+
#[test]
190+
fn test_add_empty() -> anyhow::Result<()> {
191+
let empty_1 = Empty::new(0)?;
192+
let empty_2 = Empty::new(0)?;
193+
let empty = empty_1 + empty_2;
194+
assert_eq!(empty.into_value(), 0);
195+
Ok(())
196+
}
197+
}

src/rule/non_empty.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,24 @@ mod non_empty_string;
22
mod non_empty_vec;
33

44
use crate::rule::composer::Not;
5-
use crate::rule::Empty;
5+
use crate::rule::EmptyRule;
6+
use crate::Refined;
7+
68
pub use non_empty_string::*;
79
pub use non_empty_vec::*;
810

11+
pub type NonEmpty<T> = Refined<NonEmptyRule<T>>;
12+
913
/// Rule where the data is non-empty
1014
/// ```rust
11-
/// use refined_type::rule::{NonEmpty, Rule};
12-
/// assert!(NonEmpty::<String>::validate("non empty".to_string()).is_ok());
13-
/// assert!(NonEmpty::<String>::validate("".to_string()).is_err());
15+
/// use refined_type::rule::{NonEmptyRule, Rule};
16+
/// assert!(NonEmptyRule::<String>::validate("non empty".to_string()).is_ok());
17+
/// assert!(NonEmptyRule::<String>::validate("".to_string()).is_err());
1418
///
15-
/// assert!(NonEmpty::<Vec<u8>>::validate(vec![1, 2, 3]).is_ok());
16-
/// assert!(NonEmpty::<Vec<u8>>::validate(Vec::new()).is_err());
19+
/// assert!(NonEmptyRule::<Vec<u8>>::validate(vec![1, 2, 3]).is_ok());
20+
/// assert!(NonEmptyRule::<Vec<u8>>::validate(Vec::new()).is_err());
1721
///
18-
/// assert!(NonEmpty::<u8>::validate(1).is_ok());
19-
/// assert!(NonEmpty::<u8>::validate(0).is_err());
22+
/// assert!(NonEmptyRule::<u8>::validate(1).is_ok());
23+
/// assert!(NonEmptyRule::<u8>::validate(0).is_err());
2024
/// ```
21-
pub type NonEmpty<T> = Not<Empty<T>>;
25+
pub type NonEmptyRule<T> = Not<EmptyRule<T>>;
+23-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,38 @@
11
use crate::refined::Refined;
2-
use crate::rule::NonEmpty;
2+
use crate::rule::NonEmptyRule;
3+
use std::ops::Add;
34

45
/// This is a predicate type representing a non-empty string
56
pub type NonEmptyString = Refined<NonEmptyStringRule>;
67

7-
pub type NonEmptyStringRule = NonEmpty<String>;
8+
impl Add for NonEmptyString {
9+
type Output = Self;
10+
11+
fn add(self, rhs: Self) -> Self::Output {
12+
Refined::new(format!("{}{}", self.into_value(), rhs.into_value()))
13+
.expect("This error is always unreachable")
14+
}
15+
}
16+
17+
pub type NonEmptyStringRule = NonEmptyRule<String>;
818

919
#[cfg(test)]
1020
mod test {
11-
use crate::rule::{NonEmptyStringRule, Rule};
21+
use crate::rule::{NonEmptyString, NonEmptyStringRule, Rule};
1222

1323
#[test]
1424
fn test_non_empty_string() {
1525
assert!(NonEmptyStringRule::validate("hello".to_string()).is_ok());
1626
assert!(NonEmptyStringRule::validate("".to_string()).is_err());
1727
}
28+
29+
#[test]
30+
fn test_add_string() -> anyhow::Result<()> {
31+
let non_empty_string_1 = NonEmptyString::new("Hello".to_string())?;
32+
let non_empty_string_2 = NonEmptyString::new("World".to_string())?;
33+
let non_empty_string = non_empty_string_1 + non_empty_string_2;
34+
35+
assert_eq!(non_empty_string.into_value(), "HelloWorld");
36+
Ok(())
37+
}
1838
}

src/rule/non_empty/non_empty_vec.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,41 @@
1-
use crate::rule::NonEmpty;
1+
use crate::rule::NonEmptyRule;
22
use crate::Refined;
33

4+
use std::ops::Add;
5+
46
pub type NonEmptyVec<T> = Refined<NonEmptyVecRule<T>>;
5-
pub type NonEmptyVecRule<T> = NonEmpty<Vec<T>>;
7+
8+
impl<T> Add for NonEmptyVec<T> {
9+
type Output = Self;
10+
11+
fn add(self, rhs: Self) -> Self::Output {
12+
let mut result = self.into_value();
13+
result.append(&mut rhs.into_value());
14+
Refined::new(result)
15+
.ok()
16+
.expect("This error is always unreachable")
17+
}
18+
}
19+
20+
pub type NonEmptyVecRule<T> = NonEmptyRule<Vec<T>>;
621

722
#[cfg(test)]
823
mod test {
924
use crate::rule::non_empty::NonEmptyVecRule;
10-
use crate::rule::Rule;
25+
use crate::rule::{NonEmptyVec, Rule};
1126

1227
#[test]
1328
fn test_non_empty_vec() {
1429
assert!(NonEmptyVecRule::validate(vec![1, 2, 3]).is_ok());
1530
assert!(NonEmptyVecRule::<u8>::validate(vec![]).is_err());
1631
}
32+
33+
#[test]
34+
fn test_add_vec() -> anyhow::Result<()> {
35+
let ne_vec_1 = NonEmptyVec::new(vec![1, 2, 3])?;
36+
let ne_vec_2 = NonEmptyVec::new(vec![4, 5, 6])?;
37+
let ne_vec = ne_vec_1 + ne_vec_2;
38+
assert_eq!(ne_vec.into_value(), vec![1, 2, 3, 4, 5, 6]);
39+
Ok(())
40+
}
1741
}

0 commit comments

Comments
 (0)