Skip to content

Commit

Permalink
implement try_from
Browse files Browse the repository at this point in the history
  • Loading branch information
tomoikey committed Nov 3, 2024
1 parent 49b926e commit e59227b
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 1 deletion.
148 changes: 147 additions & 1 deletion src/refined.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::result::Error;
use crate::rule::Rule;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::{HashMap, HashSet, VecDeque};
use std::fmt::{Debug, Display, Formatter};

/// Refined is a versatile type in ensuring that `T` satisfies the conditions of `RULE` (predicate type)
Expand Down Expand Up @@ -85,6 +86,64 @@ where
}
}

macro_rules! impl_try_from {
($t: ty) => {
impl<RULE: Rule<Item = $t>> TryFrom<$t> for Refined<RULE> {
type Error = Error<$t>;

fn try_from(value: $t) -> Result<Self, Self::Error> {
Refined::new(value)
}
}
};
($($ts: ty), +) => {
$(impl_try_from!($ts);)+
};
}

impl_try_from![u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64];
impl_try_from![String, char];

impl<'a, RULE: Rule<Item = String>> TryFrom<&'a str> for Refined<RULE> {
type Error = Error<String>;

fn try_from(value: &'a str) -> Result<Self, Self::Error> {
Refined::new(value.into())
}
}

impl<T, RULE: Rule<Item = Vec<T>>> TryFrom<Vec<T>> for Refined<RULE> {
type Error = Error<Vec<T>>;

fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
Refined::new(value)
}
}

impl<T, RULE: Rule<Item = VecDeque<T>>> TryFrom<VecDeque<T>> for Refined<RULE> {
type Error = Error<VecDeque<T>>;

fn try_from(value: VecDeque<T>) -> Result<Self, Self::Error> {
Refined::new(value)
}
}

impl<T, RULE: Rule<Item = HashSet<T>>> TryFrom<HashSet<T>> for Refined<RULE> {
type Error = Error<HashSet<T>>;

fn try_from(value: HashSet<T>) -> Result<Self, Self::Error> {
Refined::new(value)
}
}

impl<K, V, RULE: Rule<Item = HashMap<K, V>>> TryFrom<HashMap<K, V>> for Refined<RULE> {
type Error = Error<HashMap<K, V>>;

fn try_from(value: HashMap<K, V>) -> Result<Self, Self::Error> {
Refined::new(value)
}
}

impl<RULE, T> Display for Refined<RULE>
where
RULE: Rule<Item = T>,
Expand All @@ -99,10 +158,15 @@ where
mod test {
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::collections::{HashMap, HashSet, VecDeque};

use crate::refined::Refined;
use crate::result::Error;
use crate::rule::{NonEmptyString, NonEmptyStringRule, NonEmptyVec};
use crate::rule::{
EqualI128, EqualI16, EqualI32, EqualI64, EqualI8, EqualIsize, EqualU128, EqualU16,
EqualU32, EqualU64, EqualU8, EqualUsize, NonEmptyHashMap, NonEmptyHashSet, NonEmptyString,
NonEmptyStringRule, NonEmptyVec, NonEmptyVecDeque,
};

#[test]
fn test_unsafe_new_success() {
Expand Down Expand Up @@ -255,4 +319,86 @@ mod test {
assert!(result.is_err());
Ok(())
}

#[test]
fn test_try_from() -> anyhow::Result<()> {
let value = NonEmptyString::try_from("hello")?;
assert_eq!(value.into_value(), "hello");

let value = NonEmptyString::try_from("hello".to_string())?;
assert_eq!(value.into_value(), "hello");

let value = EqualU8::<8>::try_from(8)?;
assert_eq!(value.into_value(), 8);

let value = EqualU16::<16>::try_from(16)?;
assert_eq!(value.into_value(), 16);

let value = EqualU32::<32>::try_from(32)?;
assert_eq!(value.into_value(), 32);

let value = EqualU64::<64>::try_from(64)?;
assert_eq!(value.into_value(), 64);

let value = EqualU128::<128>::try_from(128)?;
assert_eq!(value.into_value(), 128);

let value = EqualUsize::<1>::try_from(1)?;
assert_eq!(value.into_value(), 1);

let value = EqualI8::<8>::try_from(8)?;
assert_eq!(value.into_value(), 8);

let value = EqualI16::<16>::try_from(16)?;
assert_eq!(value.into_value(), 16);

let value = EqualI32::<32>::try_from(32)?;
assert_eq!(value.into_value(), 32);

let value = EqualI64::<64>::try_from(64)?;
assert_eq!(value.into_value(), 64);

let value = EqualI128::<128>::try_from(128)?;
assert_eq!(value.into_value(), 128);

let value = EqualIsize::<1>::try_from(1)?;
assert_eq!(value.into_value(), 1);

let value = NonEmptyVec::try_from(vec!["hello".to_string()])?;
assert_eq!(value.into_value(), vec!["hello".to_string()]);

let value = NonEmptyVecDeque::try_from(
vec!["hello".to_string()]
.into_iter()
.collect::<VecDeque<_>>(),
)?;
assert_eq!(value.into_value(), vec!["hello".to_string()]);

let value = NonEmptyHashSet::try_from(
vec!["hello".to_string()]
.into_iter()
.collect::<HashSet<_>>(),
)?;
assert_eq!(
value.into_value(),
vec!["hello".to_string()].into_iter().collect()
);

let value = NonEmptyHashMap::try_from(
vec![("hello".to_string(), "world".to_string())]
.into_iter()
.collect::<HashMap<_, _>>(),
)?;
assert_eq!(
value.into_value(),
vec![("hello".to_string(), "world".to_string())]
.into_iter()
.collect()
);

let value: NonEmptyVec<NonEmptyString> =
NonEmptyVec::try_from(vec!["hello".to_string().try_into()?])?;
assert_eq!(value.into_value(), vec!["hello".to_string().try_into()?]);
Ok(())
}
}
6 changes: 6 additions & 0 deletions src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ impl<T> Error<T> {
}
}

impl<T: Debug> std::error::Error for Error<T> {
fn description(&self) -> &str {
&self.message
}
}

impl<T> Display for Error<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
Expand Down

0 comments on commit e59227b

Please sign in to comment.