Skip to content

Commit

Permalink
Merge pull request #33 from tomoikey/v0.5.18
Browse files Browse the repository at this point in the history
Release V0.5.18
  • Loading branch information
tomoikey authored Nov 10, 2024
2 parents d8733c7 + 635849f commit ef1fe16
Show file tree
Hide file tree
Showing 14 changed files with 667 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ repository = "https://github.com/tomoikey/refined_type"
readme = "README.md"
categories = ["accessibility", "development-tools", "rust-patterns"]
license = "MIT"
version = "0.5.17"
version = "0.5.18"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,58 @@ fn not_example() -> Result<(), Error<u8>> {
}
```

### 4: `If` Rule Composer

`If` Rule Composer is a rule that applies a specific rule only when a certain condition is met.

```rust
type Target = Refined<If<GreaterEqualRuleI8<10>, EvenRuleI8>>;

fn if_example() -> Result<(), Error<i8>> {
let target = Target::new(8)?;
assert_eq!(target.into_value(), 8);

let target = Target::new(9)?;
assert_eq!(target.into_value(), 9);

let target = Target::new(10)?;
assert_eq!(target.into_value(), 10);

let target = Target::new(11);
assert!(target.is_err());

Ok(())
}
```

### 5: `IfElse` Rule Composer

`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.

```rust
type Target = Refined<IfElse<GreaterEqualRuleI8<10>, EvenRuleI8, OddRuleI8>>;

fn if_else_example() -> Result<(), Error<i8>> {
let target = Target::new(8);
assert!(target.is_err());

let target = Target::new(9)?;
assert_eq!(target.into_value(), 9);

let target = Target::new(10)?;
assert_eq!(target.into_value(), 10);

let target = Target::new(11);
assert!(target.is_err());

Ok(())
}
```

### 6: Other Rule Composer

`Equiv`, `Nand`, `Nor` and `Xor` are also available.

# Number

## `MinMax`
Expand Down
25 changes: 25 additions & 0 deletions src/rule.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::result::Error;
pub use collection::*;
pub use empty::*;
pub use length::*;
Expand All @@ -18,3 +19,27 @@ pub trait Rule {
type Item;
fn validate(target: Self::Item) -> crate::Result<Self::Item>;
}

/// This is a `Rule` that always returns `Ok`
pub struct Valid<T> {
_phantom: std::marker::PhantomData<T>,
}

impl<T> Rule for Valid<T> {
type Item = T;
fn validate(target: Self::Item) -> crate::Result<Self::Item> {
Ok(target)
}
}

/// This is a `Rule` that always returns `Err`
pub struct Invalid<T> {
_phantom: std::marker::PhantomData<T>,
}

impl<T> Rule for Invalid<T> {
type Item = T;
fn validate(target: Self::Item) -> crate::Result<Self::Item> {
Err(Error::new(target, "Invalid"))
}
}
2 changes: 2 additions & 0 deletions src/rule/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod index;
mod init;
mod iterable;
mod last;
mod nothing;
mod reverse;
mod skip;
mod tail;
Expand All @@ -16,6 +17,7 @@ pub use index::*;
pub use init::*;
pub use iterable::*;
pub use last::*;
pub use nothing::*;
pub use reverse::*;
pub use skip::*;
pub use tail::*;
12 changes: 10 additions & 2 deletions src/rule/collection/exists.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet, VecDeque};

use crate::rule::composer::Not;
use crate::rule::{ForAllRule, Rule};
use crate::rule::{NothingRule, Rule};
use crate::Refined;

/// A type that holds a value satisfying the `ExistsRule`
Expand All @@ -23,7 +23,7 @@ pub type ExistsHashMap<K, RULE> = Refined<ExistsHashMapRule<K, RULE>>;
pub type ExistsString<RULE> = Refined<ExistsStringRule<RULE>>;

/// Rule where at least one data in the collection satisfies the condition
pub type ExistsRule<RULE, ITERABLE> = Not<ForAllRule<Not<RULE>, ITERABLE>>;
pub type ExistsRule<RULE, ITERABLE> = Not<NothingRule<RULE, ITERABLE>>;

/// Rule where at least one data in the `Vec` satisfies the condition
pub type ExistsVecRule<RULE> = ExistsRule<RULE, Vec<<RULE as Rule>::Item>>;
Expand Down Expand Up @@ -60,4 +60,12 @@ mod tests {
assert!(exists_result.is_err());
Ok(())
}

#[test]
fn exists_3() -> anyhow::Result<()> {
let value = vec![];
let exists_result = Exists::<NonEmptyStringRule, Vec<_>>::new(value.clone());
assert!(exists_result.is_err());
Ok(())
}
}
73 changes: 73 additions & 0 deletions src/rule/collection/nothing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::rule::composer::Not;
use crate::rule::{ForAllRule, Rule};
use crate::Refined;
use std::collections::{HashMap, HashSet, VecDeque};

/// A type that holds a value satisfying the `NothingRule`
pub type Nothing<RULE, ITERABLE> = Refined<NothingRule<RULE, ITERABLE>>;

/// A type that holds a `Vec` value satisfying the `NothingRule`
pub type NothingVec<RULE> = Refined<NothingVecRule<RULE>>;

/// A type that holds a `VecDeque` value satisfying the `NothingRule`
pub type NothingVecDeque<RULE> = Refined<NothingVecDequeRule<RULE>>;

/// A type that holds a `HashSet` value satisfying the `NothingRule`
pub type NothingHashSet<RULE> = Refined<NothingHashSetRule<RULE>>;

/// A type that holds a `HashMap` value satisfying the `NothingRule`
pub type NothingHashMap<K, RULE> = Refined<NothingHashMapRule<K, RULE>>;

/// A type that holds a `String` value satisfying the `NothingRule`
pub type NothingString<RULE> = Refined<NothingStringRule<RULE>>;

/// Rule where no data in the collection satisfies the condition
pub type NothingRule<RULE, ITERABLE> = ForAllRule<Not<RULE>, ITERABLE>;

/// Rule where no data in the `Vec` satisfies the condition
pub type NothingVecRule<RULE> = NothingRule<RULE, Vec<<RULE as Rule>::Item>>;

/// Rule where no data in the `VecDeque` satisfies the condition
pub type NothingVecDequeRule<RULE> = NothingRule<RULE, VecDeque<<RULE as Rule>::Item>>;

/// Rule where no data in the `HashSet` satisfies the condition
pub type NothingHashSetRule<RULE> = NothingRule<RULE, HashSet<<RULE as Rule>::Item>>;

/// Rule where no data in the `HashMap` satisfies the condition
pub type NothingHashMapRule<K, RULE> = NothingRule<RULE, HashMap<K, <RULE as Rule>::Item>>;

/// Rule where no data in the `String` satisfies the condition
pub type NothingStringRule<RULE> = NothingRule<RULE, String>;

#[cfg(test)]
mod tests {
use crate::result::Error;
use crate::rule::{NonEmptyStringRule, NothingVec};

#[test]
fn nothing_valid() -> Result<(), Error<Vec<String>>> {
let table = vec![vec![], vec!["".to_string()]];

for value in table {
let nothing = NothingVec::<NonEmptyStringRule>::new(value.clone())?;
assert_eq!(nothing.into_value(), value);
}

Ok(())
}

#[test]
fn nothing_invalid() -> anyhow::Result<()> {
let table = vec![
vec!["good morning".to_string(), "hello".to_string()],
vec!["good morning".to_string()],
];

for value in table {
let nothing_result = NothingVec::<NonEmptyStringRule>::new(value.clone());
assert!(nothing_result.is_err());
}

Ok(())
}
}
12 changes: 12 additions & 0 deletions src/rule/composer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
mod and;
mod equiv;
mod if_else;
mod imply;
mod nand;
mod nor;
mod not;
mod or;
mod xor;

pub use and::And;
pub use equiv::Equiv;
pub use if_else::IfElse;
pub use imply::{If, Imply};
pub use nand::Nand;
pub use nor::Nor;
pub use not::Not;
pub use or::Or;
pub use xor::Xor;
47 changes: 47 additions & 0 deletions src/rule/composer/equiv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::rule::composer::imply::Imply;
use crate::And;

/// This is a type that represents logical equivalence in logic.
///
/// # Example
/// ```rust
/// use refined_type::rule::composer::Equiv;
/// use refined_type::rule::{EvenRuleI8, GreaterEqualRuleI8, Rule};
///
/// type Target = Equiv<GreaterEqualRuleI8<10>, EvenRuleI8>;
///
/// for value in vec![1, 10] {
/// assert!(Target::validate(value).is_ok());
/// }
///
/// for value in vec![2, 4] {
/// assert!(Target::validate(value).is_err());
/// }
/// ```
pub type Equiv<RULE1, RULE2> = And![Imply<RULE1, RULE2>, Imply<RULE2, RULE1>];

#[cfg(test)]
mod test {
use crate::rule::composer::Equiv;
use crate::rule::{EvenRuleI8, GreaterEqualRuleI8, Rule};

type Target = Equiv<GreaterEqualRuleI8<10>, EvenRuleI8>;

#[test]
fn test_rule_binder_ok() {
let table = vec![1, 10];

for value in table {
assert!(Target::validate(value).is_ok());
}
}

#[test]
fn test_rule_binder_err() {
let table = vec![2, 4];

for value in table {
assert!(Target::validate(value).is_err());
}
}
}
47 changes: 47 additions & 0 deletions src/rule/composer/if_else.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::rule::composer::Not;
use crate::{And, Or};

/// This is a type that represents logical if-else in logic.
/// # Example
/// ```rust
/// use refined_type::rule::composer::IfElse;
///
/// use refined_type::rule::{EvenRuleI8, GreaterEqualRuleI8, OddRuleI8, Rule};
///
/// type Target = IfElse<GreaterEqualRuleI8<10>, EvenRuleI8, OddRuleI8>;
///
/// for value in vec![1, 10] {
/// assert!(Target::validate(value).is_ok());
/// }
///
/// for value in vec![2, 11] {
/// assert!(Target::validate(value).is_err());
/// }
/// ```
pub type IfElse<CONDITION, THEN, ELSE> = Or![And![CONDITION, THEN], And![Not<CONDITION>, ELSE]];

#[cfg(test)]
mod test {
use crate::rule::composer::IfElse;
use crate::rule::{EvenRuleI8, GreaterEqualRuleI8, OddRuleI8, Rule};

type Target = IfElse<GreaterEqualRuleI8<10>, EvenRuleI8, OddRuleI8>;

#[test]
fn test_rule_binder_ok() {
let table = vec![1, 10];

for value in table {
assert!(Target::validate(value).is_ok());
}
}

#[test]
fn test_rule_binder_err() {
let table = vec![2, 11];

for value in table {
assert!(Target::validate(value).is_err());
}
}
}
Loading

0 comments on commit ef1fe16

Please sign in to comment.