From 114528764a028223744629a11ed6b7dee63f1d6e Mon Sep 17 00:00:00 2001 From: tomoikey <55743826+tomoikey@users.noreply.github.com> Date: Thu, 24 Oct 2024 07:17:33 +0900 Subject: [PATCH] refactoring length --- README.md | 134 ++++++++++++++++--------------------- src/rule/length.rs | 6 ++ src/rule/length/equal.rs | 74 +++++++------------- src/rule/length/grater.rs | 73 +++++++------------- src/rule/length/less.rs | 74 +++++++------------- src/rule/length/min_max.rs | 38 +++++++++++ tests/length.rs | 94 -------------------------- tests/read_me.rs | 110 ++++++++++++------------------ 8 files changed, 221 insertions(+), 382 deletions(-) create mode 100644 src/rule/length/min_max.rs delete mode 100644 tests/length.rs diff --git a/README.md b/README.md index 4879add..5d10317 100644 --- a/README.md +++ b/README.md @@ -657,113 +657,93 @@ fn example_22() -> anyhow::Result<()> { You can impose constraints on objects that have a length, such as `String` or `Vec`. -### String +## `LengthMinMax` +`LengthMinMax` is a type that signifies the target has a length between a certain number and another number. ```rust -fn example_23() -> Result<(), Error> { - length_greater_than!(5); - length_equal!(5, 10); - length_less_than!(10); +fn length_min_max_example() -> Result<(), Error> { + type Password = LengthMinMax<5, 10, String>; - type Password = Refined>; + let password = Password::new("123456".to_string())?; + assert_eq!(password.into_value(), "123456"); - type From5To10Rule = And![ - Or![LengthEqualRule5, LengthGreaterThanRule5], - Or![LengthLessThanRule10, LengthEqualRule10] - ]; - - // length is 8. so, this is valid - let raw_password = "password"; - let password = Password::new(raw_password.to_string())?; - assert_eq!(password.into_value(), "password"); + let password = Password::new("1234".to_string()); + assert!(password.is_err()); - // length is 4. so, this is invalid - let raw_password = "pswd"; - let password = Password::new(raw_password.to_string()); + let password = Password::new("12345678901".to_string()); assert!(password.is_err()); - // length is 17. so, this is invalid - let raw_password = "password password"; - let password = Password::new(raw_password.to_string()); + Ok(()) +} +``` + +## `LengthGreater` +`LengthGreater` is a type that signifies the target has a length greater than a certain number. + +```rust +fn length_greater_example() -> Result<(), Error> { + type Password = LengthGreater<5, String>; + + let password = Password::new("123456".to_string())?; + assert_eq!(password.into_value(), "123456"); + + let password = Password::new("1234".to_string()); assert!(password.is_err()); Ok(()) } ``` -### Vec +## `LengthLess` +`LengthLess` is a type that signifies the target has a length less than a certain number. ```rust -#[test] -fn example_24() -> anyhow::Result<()> { - length_greater_than!(5); - length_equal!(5, 10); - length_less_than!(10); +fn length_less_example() -> Result<(), Error> { + type Password = LengthLess<10, String>; - type Friends = Refined>>; + let password = Password::new("123456".to_string())?; + assert_eq!(password.into_value(), "123456"); - type From5To10Rule = And![ - Or![LengthEqualRule5, LengthGreaterThanRule5], - Or![LengthLessThanRule10, LengthEqualRule10], - ]; + let password = Password::new("12345678901".to_string()); + assert!(password.is_err()); - // length is 6. so, this is valid - let raw_friends = vec![ - "Tom".to_string(), - "Taro".to_string(), - "Jiro".to_string(), - "Hanako".to_string(), - "Sachiko".to_string(), - "Yoshiko".to_string(), - ]; - let friends = Friends::new(raw_friends.clone())?; - assert_eq!(friends.into_value(), raw_friends); - - // length is 2. so, this is invalid - let raw_friends = vec!["Tom".to_string(), "Taro".to_string()]; - let friends = Friends::new(raw_friends.clone()); - assert!(friends.is_err()); - - // length is 11. so, this is invalid - let raw_friends = vec![ - "Tom".to_string(), - "Taro".to_string(), - "Jiro".to_string(), - "Hanako".to_string(), - "Sachiko".to_string(), - "Yuiko".to_string(), - "Taiko".to_string(), - "John".to_string(), - "Jane".to_string(), - "Jack".to_string(), - "Jill".to_string(), - ]; - let friends = Friends::new(raw_friends.clone()); - assert!(friends.is_err()); + Ok(()) +} +``` + +## `LengthEqual` +`LengthEqual` is a type that signifies the target has a length equal to a certain number. + +```rust +fn length_equal_example() -> Result<(), Error> { + type Password = LengthEqual<5, String>; + + let password = Password::new("12345".to_string())?; + assert_eq!(password.into_value(), "12345"); + + let password = Password::new("1234".to_string()); + assert!(password.is_err()); Ok(()) } ``` -### Custom Length +## Custom Length You can define a length for any type. Therefore, if you want to implement a length that is not provided by `refined_type`, you can easily do so using `LengthDefinition`. ```rust -#[test] -fn example_25() -> anyhow::Result<()> { - length_equal!(5); - - #[derive(Debug, PartialEq)] - struct Hello; - impl LengthDefinition for Hello { - fn length(&self) -> usize { - 5 - } +#[derive(Debug, PartialEq)] +struct Hello; +impl LengthDefinition for Hello { + fn length(&self) -> usize { + 5 } +} - let hello = Refined::>::new(Hello)?; +fn custom_length_example() -> Result<(), Error> { + let hello = Refined::>::new(Hello)?; assert_eq!(hello.into_value(), Hello); Ok(()) } diff --git a/src/rule/length.rs b/src/rule/length.rs index e1b873e..cc00595 100644 --- a/src/rule/length.rs +++ b/src/rule/length.rs @@ -4,3 +4,9 @@ mod equal; mod grater; mod length_definition; mod less; +mod min_max; + +pub use equal::*; +pub use grater::*; +pub use less::*; +pub use min_max::*; diff --git a/src/rule/length/equal.rs b/src/rule/length/equal.rs index 6e1220d..2a616ac 100644 --- a/src/rule/length/equal.rs +++ b/src/rule/length/equal.rs @@ -1,60 +1,38 @@ -/// This macro generates a rule that checks if the length of the target is equal to `N` -/// # Example -/// ```rust -/// use refined_type::length_equal; -/// length_equal!(5); -/// -/// let target = "12345"; -/// let refined = LengthEqual5::new(target).unwrap(); -/// assert_eq!(refined.into_value(), "12345"); -/// -/// let target = "1234"; -/// let refined = LengthEqual5::new(target); -/// assert!(refined.is_err()); -/// ``` -#[macro_export] -macro_rules! length_equal { - ($length:literal) => { - $crate::paste::item! { - /// A type that holds a value satisfying the LengthEqualN rule. - #[allow(dead_code)] - pub type [] = $crate::Refined<[]>; +use crate::result::Error; +use crate::rule::{LengthDefinition, Rule}; +use crate::Refined; - /// Rule where the length of the input value is equal to N - #[allow(dead_code)] - #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] - pub struct [] { - _phantom: ::std::marker::PhantomData, - } +/// A type that holds a value satisfying the `LengthEqualRule` +pub type LengthEqual = Refined>; - impl $crate::rule::Rule for [] where ITEM: $crate::rule::LengthDefinition { - type Item = ITEM; - fn validate(target: Self::Item) -> Result> { - if target.length() == $length { - Ok(target) - } else { - Err($crate::result::Error::new(target, format!("target length is not equal to {}", $length))) - } - } - } +/// Rule where the input `ITEM` has a length equal to `LENGTH` +pub struct LengthEqualRule { + _phantom: std::marker::PhantomData, +} + +impl Rule for LengthEqualRule { + type Item = ITEM; + fn validate(target: Self::Item) -> Result> { + if target.length() == LENGTH { + Ok(target) + } else { + Err(Error::new( + target, + format!("target length is not equal to {}", LENGTH), + )) } - }; - ($length:literal, $($lengths:literal),+) => { - length_equal!($length); - length_equal!($($lengths),+); - }; + } } #[cfg(test)] mod tests { use crate::result::Error; - - length_equal!(5, 10); + use crate::rule::length::equal::LengthEqual; #[test] fn test_length_equal_5() -> Result<(), Error<&'static str>> { let target = "12345"; - let refined = LengthEqual5::new(target)?; + let refined = LengthEqual::<5, _>::new(target)?; assert_eq!(refined.into_value(), "12345"); Ok(()) } @@ -62,14 +40,14 @@ mod tests { #[test] fn test_length_equal_5_fail() { let target = "1234"; - let refined = LengthEqual5::new(target); + let refined = LengthEqual::<5, _>::new(target); assert!(refined.is_err()); } #[test] fn test_length_equal_10() -> Result<(), Error<&'static str>> { let target = "1234567890"; - let refined = LengthEqual10::new(target)?; + let refined = LengthEqual::<10, _>::new(target)?; assert_eq!(refined.into_value(), "1234567890"); Ok(()) } @@ -77,7 +55,7 @@ mod tests { #[test] fn test_length_equal_10_fail() { let target = "123456789"; - let refined = LengthEqual10::new(target); + let refined = LengthEqual::<10, _>::new(target); assert!(refined.is_err()); } } diff --git a/src/rule/length/grater.rs b/src/rule/length/grater.rs index 4af120a..eaa8cb8 100644 --- a/src/rule/length/grater.rs +++ b/src/rule/length/grater.rs @@ -1,59 +1,38 @@ -/// This macro generates a rule that checks if the length of the target is greater than `N` -/// # Example -/// ```rust -/// use refined_type::length_greater_than; -/// length_greater_than!(5); -/// -/// let target = "123456"; -/// let refined = LengthGreaterThan5::new(target).unwrap(); -/// assert_eq!(refined.into_value(), "123456"); -/// -/// let target = "12345"; -/// let refined = LengthGreaterThan5::new(target); -/// assert!(refined.is_err()); -#[macro_export] -macro_rules! length_greater_than { - ($length:literal) => { - $crate::paste::item! { - /// A type that holds a value satisfying the LengthGreaterThanN rule. - #[allow(dead_code)] - pub type [] = $crate::Refined<[]>; +use crate::result::Error; +use crate::rule::{LengthDefinition, Rule}; +use crate::Refined; - /// Rule where the length of the input value is greater than N - #[allow(dead_code)] - #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] - pub struct [] { - _phantom: ::std::marker::PhantomData, - } +/// A type that holds a value satisfying the `LengthGreaterRule` +pub type LengthGreater = Refined>; - impl $crate::rule::Rule for [] where ITEM: $crate::rule::LengthDefinition { - type Item = ITEM; - fn validate(target: Self::Item) -> Result> { - if target.length() > $length { - Ok(target) - } else { - Err($crate::result::Error::new(target, format!("target length is not greater than {}", $length))) - } - } - } +/// Rule where the input `ITEM` has a length greater than `THAN` +pub struct LengthGreaterRule { + _phantom: std::marker::PhantomData, +} + +impl Rule for LengthGreaterRule { + type Item = ITEM; + fn validate(target: Self::Item) -> Result> { + if target.length() > THAN { + Ok(target) + } else { + Err(Error::new( + target, + format!("target length is not greater than {}", THAN), + )) } - }; - ($length:literal, $($lengths:literal),+) => { - length_greater_than!($length); - length_greater_than!($($lengths),+); - }; + } } #[cfg(test)] mod tests { use crate::result::Error; - - length_greater_than!(5, 10); + use crate::rule::length::grater::LengthGreater; #[test] fn test_length_greater_than_5() -> Result<(), Error<&'static str>> { let target = "123456"; - let refined = LengthGreaterThan5::new(target)?; + let refined = LengthGreater::<5, _>::new(target)?; assert_eq!(refined.into_value(), "123456"); Ok(()) } @@ -61,14 +40,14 @@ mod tests { #[test] fn test_length_greater_than_5_fail() { let target = "1234"; - let refined = LengthGreaterThan5::new(target); + let refined = LengthGreater::<5, _>::new(target); assert!(refined.is_err()); } #[test] fn test_length_greater_than_10() -> Result<(), Error<&'static str>> { let target = "12345678901"; - let refined = LengthGreaterThan10::new(target)?; + let refined = LengthGreater::<10, _>::new(target)?; assert_eq!(refined.into_value(), "12345678901"); Ok(()) } @@ -76,7 +55,7 @@ mod tests { #[test] fn test_length_greater_than_10_fail() { let target = "123456789"; - let refined = LengthGreaterThan10::new(target); + let refined = LengthGreater::<10, _>::new(target); assert!(refined.is_err()); } } diff --git a/src/rule/length/less.rs b/src/rule/length/less.rs index 133d3e4..93d681a 100644 --- a/src/rule/length/less.rs +++ b/src/rule/length/less.rs @@ -1,60 +1,38 @@ -/// This macro generates a rule that checks if the length of the target is less than `N` -/// # Example -/// ```rust -/// use refined_type::length_less_than; -/// length_less_than!(5); -/// -/// let target = "1234"; -/// let refined = LengthLessThan5::new(target).unwrap(); -/// assert_eq!(refined.into_value(), "1234"); -/// -/// let target = "12345"; -/// let refined = LengthLessThan5::new(target); -/// assert!(refined.is_err()); -/// ``` -#[macro_export] -macro_rules! length_less_than { - ($length:literal) => { - $crate::paste::item! { - /// A type that holds a value satisfying the LengthLessThanN rule. - #[allow(dead_code)] - pub type [] = $crate::Refined<[]>; +use crate::result::Error; +use crate::rule::{LengthDefinition, Rule}; +use crate::Refined; - /// Rule where the length of the input value is less than N - #[allow(dead_code)] - #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] - pub struct [] { - _phantom: ::std::marker::PhantomData, - } +/// A type that holds a value satisfying the `LengthLessRule` +pub type LengthLess = Refined>; - impl $crate::rule::Rule for [] where ITEM: $crate::rule::LengthDefinition { - type Item = ITEM; - fn validate(target: Self::Item) -> Result> { - if target.length() < $length { - Ok(target) - } else { - Err($crate::result::Error::new(target, format!("target length is not less than {}", $length))) - } - } - } +/// Rule where the input `ITEM` has a length less than `THAN` +pub struct LengthLessRule { + _phantom: std::marker::PhantomData, +} + +impl Rule for LengthLessRule { + type Item = ITEM; + fn validate(target: Self::Item) -> Result> { + if target.length() < THAN { + Ok(target) + } else { + Err(Error::new( + target, + format!("target length is not less than {}", THAN), + )) } - }; - ($length:literal, $($lengths:literal),+) => { - length_less_than!($length); - length_less_than!($($lengths),+); - }; + } } #[cfg(test)] mod tests { use crate::result::Error; - - length_less_than!(5, 10); + use crate::rule::LengthLess; #[test] fn test_length_less_than_5() -> Result<(), Error<&'static str>> { let target = "1234"; - let refined = LengthLessThan5::new(target)?; + let refined = LengthLess::<5, _>::new(target)?; assert_eq!(refined.into_value(), "1234"); Ok(()) } @@ -62,14 +40,14 @@ mod tests { #[test] fn test_length_less_than_5_fail() { let target = "12345"; - let refined = LengthLessThan5::new(target); + let refined = LengthLess::<5, _>::new(target); assert!(refined.is_err()); } #[test] fn test_length_less_than_10() -> Result<(), Error<&'static str>> { let target = "123456789"; - let refined = LengthLessThan10::new(target)?; + let refined = LengthLess::<10, _>::new(target)?; assert_eq!(refined.into_value(), "123456789"); Ok(()) } @@ -77,7 +55,7 @@ mod tests { #[test] fn test_length_less_than_10_fail() { let target = "1234567890"; - let refined = LengthLessThan10::new(target); + let refined = LengthLess::<10, _>::new(target); assert!(refined.is_err()); } } diff --git a/src/rule/length/min_max.rs b/src/rule/length/min_max.rs new file mode 100644 index 0000000..7d5fb47 --- /dev/null +++ b/src/rule/length/min_max.rs @@ -0,0 +1,38 @@ +use crate::rule::{LengthEqualRule, LengthGreaterRule, LengthLessRule}; +use crate::{And, Or, Refined}; + +pub type LengthMinMax = + Refined>; + +pub type LengthMinMaxRule = And![ + Or![LengthEqualRule, LengthGreaterRule], + Or![LengthEqualRule, LengthLessRule] +]; + +#[cfg(test)] +mod tests { + use crate::result::Error; + use crate::rule::length::min_max::LengthMinMax; + + #[test] + fn test_length_min_max_5_10() -> Result<(), Error<&'static str>> { + let target = "123456"; + let refined = LengthMinMax::<5, 10, _>::new(target)?; + assert_eq!(refined.into_value(), "123456"); + Ok(()) + } + + #[test] + fn test_length_min_max_5_10_fail() { + let target = "1234"; + let refined = LengthMinMax::<5, 10, _>::new(target); + assert!(refined.is_err()); + } + + #[test] + fn test_length_min_max_5_10_fail_2() { + let target = "12345678901"; + let refined = LengthMinMax::<5, 10, _>::new(target); + assert!(refined.is_err()); + } +} diff --git a/tests/length.rs b/tests/length.rs deleted file mode 100644 index ad2edbc..0000000 --- a/tests/length.rs +++ /dev/null @@ -1,94 +0,0 @@ -use refined_type::rule::composer::{And, Or}; -use refined_type::{length_equal, length_greater_than, length_less_than, Refined}; - -length_greater_than!(5); -length_equal!(5, 10); -length_less_than!(10); - -#[test] -fn test_length() -> Result<(), refined_type::result::Error> { - type Password = Refined>; - - type From5To10Rule = And< - Or, LengthGreaterThanRule5>, - Or, LengthEqualRule10>, - >; - - let raw_password = "password"; - let password = Password::new(raw_password.to_string())?; - assert_eq!(password.into_value(), "password"); - Ok(()) -} - -#[test] -fn test_length_fail() { - type Password = Refined< - And< - And, LengthGreaterThanRule5>, - And, LengthEqualRule10>, - >, - >; - let raw_password = "password password"; - let password = Password::new(raw_password.to_string()); - assert!(password.is_err()); -} - -#[test] -fn test_length_greater_than_5() -> Result<(), refined_type::result::Error<&'static str>> { - let target = "123456"; - let refined = LengthGreaterThan5::new(target)?; - assert_eq!(refined.into_value(), "123456"); - Ok(()) -} - -#[test] -fn test_length_greater_than_5_fail() { - let target = "1234"; - let refined = LengthGreaterThan5::new(target); - assert!(refined.is_err()); -} - -#[test] -fn test_length_equal_5() -> Result<(), refined_type::result::Error<&'static str>> { - let target = "12345"; - let refined = LengthEqual5::new(target)?; - assert_eq!(refined.into_value(), "12345"); - Ok(()) -} - -#[test] -fn test_length_equal_5_fail() { - let target = "1234"; - let refined = LengthEqual5::new(target); - assert!(refined.is_err()); -} - -#[test] -fn test_length_equal_10() -> Result<(), refined_type::result::Error<&'static str>> { - let target = "1234567890"; - let refined = LengthEqual10::new(target)?; - assert_eq!(refined.into_value(), "1234567890"); - Ok(()) -} - -#[test] -fn test_length_equal_10_fail() { - let target = "123456789"; - let refined = LengthEqual10::new(target); - assert!(refined.is_err()); -} - -#[test] -fn test_length_less_than_10() -> Result<(), refined_type::result::Error<&'static str>> { - let target = "123456789"; - let refined = LengthLessThan10::new(target)?; - assert_eq!(refined.into_value(), "123456789"); - Ok(()) -} - -#[test] -fn test_length_less_than_10_fail() { - let target = "1234567890"; - let refined = LengthLessThan10::new(target); - assert!(refined.is_err()); -} diff --git a/tests/read_me.rs b/tests/read_me.rs index c254120..d0ebc83 100644 --- a/tests/read_me.rs +++ b/tests/read_me.rs @@ -5,10 +5,11 @@ 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, NonEmptyString, NonEmptyStringRule, NonEmptyVec, - NonEmptyVecDeque, Reverse, Rule, SkipFirst, SkipVec, TailVec, + LengthDefinition, LengthEqual, LengthEqualRule, LengthGreater, LengthLess, LengthMinMax, + LessU8, MinMaxU8, 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::{And, Or, Refined}; // define a struct for converting from JSON. #[derive(Debug, Deserialize)] @@ -540,82 +541,56 @@ fn example_22() -> Result<(), Error>> { } #[test] -fn example_23() -> Result<(), Error> { - length_greater_than!(5); - length_equal!(5, 10); - length_less_than!(10); +fn length_min_max_example() -> Result<(), Error> { + type Password = LengthMinMax<5, 10, String>; - type Password = Refined>; + let password = Password::new("123456".to_string())?; + assert_eq!(password.into_value(), "123456"); - type From5To10Rule = And![ - Or![LengthEqualRule5, LengthGreaterThanRule5], - Or![LengthLessThanRule10, LengthEqualRule10] - ]; - - // length is 8. so, this is valid - let raw_password = "password"; - let password = Password::new(raw_password.to_string())?; - assert_eq!(password.into_value(), "password"); + let password = Password::new("1234".to_string()); + assert!(password.is_err()); - // length is 4. so, this is invalid - let raw_password = "pswd"; - let password = Password::new(raw_password.to_string()); + let password = Password::new("12345678901".to_string()); assert!(password.is_err()); - // length is 17. so, this is invalid - let raw_password = "password password"; - let password = Password::new(raw_password.to_string()); + Ok(()) +} + +#[test] +fn length_greater_example() -> Result<(), Error> { + type Password = LengthGreater<5, String>; + + let password = Password::new("123456".to_string())?; + assert_eq!(password.into_value(), "123456"); + + let password = Password::new("1234".to_string()); assert!(password.is_err()); Ok(()) } #[test] -fn example_24() -> Result<(), Error>> { - length_greater_than!(5); - length_equal!(5, 10); - length_less_than!(10); +fn length_less_example() -> Result<(), Error> { + type Password = LengthLess<10, String>; - type Friends = Refined>>; + let password = Password::new("123456".to_string())?; + assert_eq!(password.into_value(), "123456"); - type From5To10Rule = And![ - Or![LengthEqualRule5, LengthGreaterThanRule5], - Or![LengthLessThanRule10, LengthEqualRule10] - ]; + let password = Password::new("12345678901".to_string()); + assert!(password.is_err()); - // length is 6. so, this is valid - let raw_friends = vec![ - "Tom".to_string(), - "Taro".to_string(), - "Jiro".to_string(), - "Hanako".to_string(), - "Sachiko".to_string(), - "Yoshiko".to_string(), - ]; - let friends = Friends::new(raw_friends.clone())?; - assert_eq!(friends.into_value(), raw_friends); - - // length is 2. so, this is invalid - let raw_friends = vec!["Tom".to_string(), "Taro".to_string()]; - let friends = Friends::new(raw_friends.clone()); - assert!(friends.is_err()); - - // length is 11. so, this is invalid - let raw_friends = vec![ - "Tom".to_string(), - "Taro".to_string(), - "Jiro".to_string(), - "Hanako".to_string(), - "Sachiko".to_string(), - "Yuiko".to_string(), - "Taiko".to_string(), - "John".to_string(), - "Jane".to_string(), - "Jack".to_string(), - "Jill".to_string(), - ]; - let friends = Friends::new(raw_friends.clone()); - assert!(friends.is_err()); + Ok(()) +} + +#[test] +fn length_equal_example() -> Result<(), Error> { + type Password = LengthEqual<5, String>; + + let password = Password::new("12345".to_string())?; + assert_eq!(password.into_value(), "12345"); + + let password = Password::new("1234".to_string()); + assert!(password.is_err()); Ok(()) } @@ -629,9 +604,8 @@ impl LengthDefinition for Hello { } #[test] -fn example_25() -> Result<(), Error> { - length_equal!(5); - let hello = Refined::>::new(Hello)?; +fn custom_length_example() -> Result<(), Error> { + let hello = Refined::>::new(Hello)?; assert_eq!(hello.into_value(), Hello); Ok(()) }