Skip to content

Commit 03cea9c

Browse files
committed
add various logic type
1 parent c42c333 commit 03cea9c

File tree

7 files changed

+418
-0
lines changed

7 files changed

+418
-0
lines changed

src/rule.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::result::Error;
12
pub use collection::*;
23
pub use empty::*;
34
pub use length::*;
@@ -18,3 +19,27 @@ pub trait Rule {
1819
type Item;
1920
fn validate(target: Self::Item) -> crate::Result<Self::Item>;
2021
}
22+
23+
/// This is a `Rule` that always returns `Ok`
24+
pub struct Valid<T> {
25+
_phantom: std::marker::PhantomData<T>,
26+
}
27+
28+
impl<T> Rule for Valid<T> {
29+
type Item = T;
30+
fn validate(target: Self::Item) -> crate::Result<Self::Item> {
31+
Ok(target)
32+
}
33+
}
34+
35+
/// This is a `Rule` that always returns `Err`
36+
pub struct Invalid<T> {
37+
_phantom: std::marker::PhantomData<T>,
38+
}
39+
40+
impl<T> Rule for Invalid<T> {
41+
type Item = T;
42+
fn validate(target: Self::Item) -> crate::Result<Self::Item> {
43+
Err(Error::new(target, "Invalid"))
44+
}
45+
}

src/rule/composer.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
mod and;
2+
mod equiv;
3+
mod imply;
4+
mod nand;
5+
mod nor;
26
mod not;
37
mod or;
8+
mod xor;
49

510
pub use and::And;
11+
pub use equiv::Equiv;
12+
pub use imply::Imply;
13+
pub use nand::Nand;
14+
pub use nor::Nor;
615
pub use not::Not;
716
pub use or::Or;
17+
pub use xor::Xor;

src/rule/composer/equiv.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use crate::rule::composer::imply::Imply;
2+
use crate::And;
3+
4+
/// This is a type that represents logical equivalence in logic.
5+
///
6+
/// # Example
7+
/// ```rust
8+
/// use refined_type::rule::composer::Equiv;
9+
/// use refined_type::rule::{EvenRuleI8, GreaterEqualRuleI8, Rule};
10+
///
11+
/// type Target = Equiv<GreaterEqualRuleI8<10>, EvenRuleI8>;
12+
///
13+
/// for value in vec![1, 10] {
14+
/// assert!(Target::validate(value).is_ok());
15+
/// }
16+
///
17+
/// for value in vec![2, 4] {
18+
/// assert!(Target::validate(value).is_err());
19+
/// }
20+
/// ```
21+
pub type Equiv<RULE1, RULE2> = And![Imply<RULE1, RULE2>, Imply<RULE2, RULE1>];
22+
23+
#[cfg(test)]
24+
mod test {
25+
use crate::rule::composer::Equiv;
26+
use crate::rule::{EvenRuleI8, GreaterEqualRuleI8, Rule};
27+
28+
type Target = Equiv<GreaterEqualRuleI8<10>, EvenRuleI8>;
29+
30+
#[test]
31+
fn test_rule_binder_ok() {
32+
let table = vec![1, 10];
33+
34+
for value in table {
35+
assert!(Target::validate(value).is_ok());
36+
}
37+
}
38+
39+
#[test]
40+
fn test_rule_binder_err() {
41+
let table = vec![2, 4];
42+
43+
for value in table {
44+
assert!(Target::validate(value).is_err());
45+
}
46+
}
47+
}

src/rule/composer/imply.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use crate::rule::composer::Not;
2+
use crate::Or;
3+
4+
/// This is a type that represents logical implication in logic.
5+
/// By applying it to programming, you can make it function similarly to an “If-Then” statement.
6+
/// # Example
7+
/// ```rust
8+
/// use refined_type::rule::composer::Imply;
9+
/// use refined_type::rule::{EvenRuleI8, GreaterEqualRuleI8, Rule};
10+
///
11+
/// type IfGreaterOrEqual10ThenEven = Imply<GreaterEqualRuleI8<10>, EvenRuleI8>;
12+
///
13+
/// for value in vec![8, 9, 10, 12] {
14+
/// assert!(IfGreaterOrEqual10ThenEven::validate(value).is_ok());
15+
/// }
16+
///
17+
/// for value in vec![11, 13] {
18+
/// assert!(IfGreaterOrEqual10ThenEven::validate(value).is_err());
19+
/// }
20+
pub type Imply<RULE1, RULE2> = Or![Not<RULE1>, RULE2];
21+
22+
#[cfg(test)]
23+
mod test {
24+
use crate::rule::composer::Imply;
25+
use crate::rule::{EvenRuleI8, GreaterEqualRuleI8, Rule};
26+
27+
type IfGreaterOrEqual10ThenEven = Imply<GreaterEqualRuleI8<10>, EvenRuleI8>;
28+
29+
#[test]
30+
fn test_rule_binder_ok() {
31+
let table = vec![8, 9, 10, 12];
32+
33+
for value in table {
34+
assert!(IfGreaterOrEqual10ThenEven::validate(value).is_ok());
35+
}
36+
}
37+
38+
#[test]
39+
fn test_rule_binder_err() {
40+
let table = vec![11, 13];
41+
42+
for value in table {
43+
assert!(IfGreaterOrEqual10ThenEven::validate(value).is_err());
44+
}
45+
}
46+
}

src/rule/composer/nand.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use crate::rule::composer::Not;
2+
use crate::And;
3+
4+
/// This is a type that represents logical NAND in logic.
5+
pub type Nand<RULE1, RULE2> = Not<And![RULE1, RULE2]>;
6+
7+
#[macro_export]
8+
macro_rules! Nand {
9+
($rule1:ty, $rule2:ty) => {
10+
$crate::rule::composer::Nand<$rule1, $rule2>
11+
};
12+
13+
($rule1:ty, $($rule2: ty), +) => {
14+
$crate::rule::composer::Nand<$rule1, $crate::And![$($rule2), +]>
15+
}
16+
}
17+
18+
#[cfg(test)]
19+
mod test_2 {
20+
use crate::rule::{Invalid, Rule, Valid};
21+
22+
type ValidI8 = Valid<i8>;
23+
type InvalidI8 = Invalid<i8>;
24+
25+
type Target1 = Nand![ValidI8, ValidI8]; // ERR
26+
type Target2 = Nand![ValidI8, InvalidI8]; // PASS
27+
type Target3 = Nand![InvalidI8, ValidI8]; // PASS
28+
type Target4 = Nand![InvalidI8, InvalidI8]; // PASS
29+
30+
#[test]
31+
fn test_rule_binder_ok() {
32+
assert!(Target2::validate(0).is_ok());
33+
assert!(Target3::validate(0).is_ok());
34+
assert!(Target4::validate(0).is_ok());
35+
}
36+
37+
#[test]
38+
fn test_rule_binder_err() {
39+
assert!(Target1::validate(0).is_err());
40+
}
41+
}
42+
43+
#[cfg(test)]
44+
mod test_3 {
45+
use crate::rule::{Invalid, Rule, Valid};
46+
47+
type ValidI8 = Valid<i8>;
48+
type InvalidI8 = Invalid<i8>;
49+
50+
type Target1 = Nand![ValidI8, ValidI8, ValidI8]; // ERR
51+
type Target2 = Nand![ValidI8, ValidI8, InvalidI8]; // PASS
52+
type Target3 = Nand![ValidI8, InvalidI8, ValidI8]; // PASS
53+
type Target4 = Nand![ValidI8, InvalidI8, InvalidI8]; // PASS
54+
type Target5 = Nand![InvalidI8, ValidI8, ValidI8]; // PASS
55+
type Target6 = Nand![InvalidI8, ValidI8, InvalidI8]; // PASS
56+
type Target7 = Nand![InvalidI8, InvalidI8, ValidI8]; // PASS
57+
type Target8 = Nand![InvalidI8, InvalidI8, InvalidI8]; // PASS
58+
59+
#[test]
60+
fn test_rule_binder_ok() {
61+
assert!(Target2::validate(0).is_ok());
62+
assert!(Target3::validate(0).is_ok());
63+
assert!(Target4::validate(0).is_ok());
64+
assert!(Target5::validate(0).is_ok());
65+
assert!(Target6::validate(0).is_ok());
66+
assert!(Target7::validate(0).is_ok());
67+
assert!(Target8::validate(0).is_ok());
68+
}
69+
70+
#[test]
71+
fn test_rule_binder_err() {
72+
assert!(Target1::validate(0).is_err());
73+
}
74+
}

src/rule/composer/nor.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use crate::Or;
2+
use crate::rule::composer::Not;
3+
4+
/// This is a type that represents logical NOR in logic.
5+
pub type Nor<RULE1, RULE2> = Not<Or![RULE1, RULE2]>;
6+
7+
#[macro_export]
8+
macro_rules! Nor {
9+
($rule1:ty, $rule2:ty) => {
10+
$crate::rule::composer::Nor<$rule1, $rule2>
11+
};
12+
13+
($rule1:ty, $($rule2: ty), +) => {
14+
$crate::rule::composer::Nor<$rule1, $crate::Or![$($rule2), +]>
15+
}
16+
}
17+
18+
#[cfg(test)]
19+
mod test_2 {
20+
use crate::rule::{Invalid, Rule, Valid};
21+
22+
type ValidI8 = Valid<i8>;
23+
type InvalidI8 = Invalid<i8>;
24+
25+
type Target1 = Nor![ValidI8, ValidI8]; // 2: ERR
26+
type Target2 = Nor![ValidI8, InvalidI8]; // 1: ERR
27+
type Target3 = Nor![InvalidI8, ValidI8]; // 1: ERR
28+
type Target4 = Nor![InvalidI8, InvalidI8]; // 0: PASS
29+
30+
#[test]
31+
fn test_rule_binder_ok() {
32+
assert!(Target4::validate(0).is_ok());
33+
}
34+
35+
#[test]
36+
fn test_rule_binder_err() {
37+
assert!(Target1::validate(0).is_err());
38+
assert!(Target2::validate(0).is_err());
39+
assert!(Target3::validate(0).is_err());
40+
}
41+
}
42+
43+
#[cfg(test)]
44+
mod test_3 {
45+
use crate::rule::{Invalid, Rule, Valid};
46+
47+
type ValidI8 = Valid<i8>;
48+
type InvalidI8 = Invalid<i8>;
49+
50+
type Target1 = Nor![ValidI8, ValidI8, ValidI8]; // 3: ERR
51+
type Target2 = Nor![ValidI8, ValidI8, InvalidI8]; // 2: ERR
52+
type Target3 = Nor![ValidI8, InvalidI8, ValidI8]; // 2: ERR
53+
type Target4 = Nor![ValidI8, InvalidI8, InvalidI8]; // 1: ERR
54+
type Target5 = Nor![InvalidI8, ValidI8, ValidI8]; // 2: ERR
55+
type Target6 = Nor![InvalidI8, ValidI8, InvalidI8]; // 1: ERR
56+
type Target7 = Nor![InvalidI8, InvalidI8, ValidI8]; // 1: ERR
57+
type Target8 = Nor![InvalidI8, InvalidI8, InvalidI8]; // 0: PASS
58+
59+
#[test]
60+
fn test_rule_binder_ok() {
61+
assert!(Target8::validate(0).is_ok());
62+
}
63+
64+
#[test]
65+
fn test_rule_binder_err() {
66+
assert!(Target1::validate(0).is_err());
67+
assert!(Target2::validate(0).is_err());
68+
assert!(Target3::validate(0).is_err());
69+
assert!(Target4::validate(0).is_err());
70+
assert!(Target5::validate(0).is_err());
71+
assert!(Target6::validate(0).is_err());
72+
assert!(Target7::validate(0).is_err());
73+
}
74+
}

0 commit comments

Comments
 (0)