refined_type/
refined.rs

1use crate::result::Error;
2use crate::rule::Rule;
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use std::collections::{HashMap, HashSet, VecDeque};
5use std::fmt::{Debug, Display, Formatter};
6
7/// Refined is a versatile type in ensuring that `T` satisfies the conditions of `RULE` (predicate type)
8/// # Example
9/// ```rust
10/// use refined_type::rule::{NonEmptyString, NonEmptyStringRule};
11/// use refined_type::Refined;
12///
13/// let non_empty_string_result = Refined::<NonEmptyStringRule>::new("Hello World".to_string());
14/// assert_eq!(non_empty_string_result.unwrap().into_value(), "Hello World");
15///
16/// let empty_string_result = Refined::<NonEmptyStringRule>::new("".to_string());
17/// assert!(empty_string_result.is_err())
18/// ```
19#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
20pub struct Refined<RULE>
21where
22    RULE: Rule,
23{
24    value: RULE::Item,
25}
26
27impl<RULE, T> Serialize for Refined<RULE>
28where
29    RULE: Rule<Item = T>,
30    T: Serialize,
31{
32    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
33    where
34        S: Serializer,
35    {
36        self.value.serialize(serializer)
37    }
38}
39
40impl<'de, RULE, T> Deserialize<'de> for Refined<RULE>
41where
42    RULE: Rule<Item = T>,
43    T: Deserialize<'de>,
44{
45    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
46    where
47        D: Deserializer<'de>,
48    {
49        use serde::de::Error;
50        let item: T = Deserialize::deserialize(deserializer)?;
51        let refined = Refined::new(item).map_err(|e| Error::custom(e.to_string()))?;
52        Ok(refined)
53    }
54}
55
56impl<RULE, T> Refined<RULE>
57where
58    RULE: Rule<Item = T>,
59{
60    /// Creates a new `Refined` instance if the provided value satisfies the rule.
61    ///
62    /// # Arguments
63    ///
64    /// * `value` - The value to be refined.
65    ///
66    /// # Returns
67    ///
68    /// * `Result<Self, Error<T>>` - A `Refined` instance if the value satisfies the rule, otherwise an error.
69    ///
70    /// # Example
71    ///
72    /// ```rust
73    /// use refined_type::rule::NonEmptyStringRule;
74    /// use refined_type::Refined;
75    ///
76    /// let non_empty_string = Refined::<NonEmptyStringRule>::new("Hello".to_string());
77    /// assert!(non_empty_string.is_ok());
78    ///
79    /// let empty_string = Refined::<NonEmptyStringRule>::new("".to_string());
80    /// assert!(empty_string.is_err());
81    /// ```
82    pub fn new(value: T) -> Result<Self, Error<T>> {
83        let value = RULE::validate(value).map_err(|e| {
84            let message = e.to_string();
85            Error::new(e.into_value(), message)
86        })?;
87        Ok(Self { value })
88    }
89
90    /// Creates a new `Refined` instance if the provided value satisfies the rule.
91    ///
92    /// # Arguments
93    ///
94    /// * `value` - The value to be refined.
95    ///
96    /// # Panics
97    ///
98    /// This function will panic if the value does not satisfy the rule.
99    ///
100    /// # Example
101    ///
102    /// ```rust
103    /// use refined_type::rule::NonEmptyStringRule;
104    /// use refined_type::Refined;
105    ///
106    /// let non_empty_string = Refined::<NonEmptyStringRule>::unsafe_new("Hello".to_string());
107    /// assert_eq!(non_empty_string.into_value(), "Hello");
108    ///
109    /// // This will panic
110    /// // let empty_string = Refined::<NonEmptyStringRule>::unsafe_new("".to_string());
111    /// ```
112    pub fn unsafe_new(value: T) -> Self
113    where
114        T: Debug,
115    {
116        let value = RULE::validate(value).expect("initialization by `unsafe_new` failed");
117        Self { value }
118    }
119
120    pub(crate) fn new_unchecked(value: T) -> Self {
121        Self { value }
122    }
123
124    /// Mutates the value inside the `Refined` type using the provided function.
125    ///
126    /// This method takes ownership of the current `Refined` instance, applies the
127    /// provided function to its inner value, and attempts to create a new `Refined`
128    /// instance with the mutated value. If the mutated value does not satisfy the
129    /// rule, an error is returned.
130    ///
131    /// # Arguments
132    ///
133    /// * `f` - A function that takes the inner value and returns a new value.
134    ///
135    /// # Returns
136    ///
137    /// * `Result<Self, Error<T>>` - A new `Refined` instance with the mutated value
138    ///   if the value satisfies the rule, otherwise an error.
139    ///
140    /// # Example
141    ///
142    /// ```rust
143    /// use refined_type::rule::NonEmptyString;
144    /// use refined_type::Refined;
145    ///
146    /// let value = NonEmptyString::new("h".to_string())
147    ///     .unwrap()
148    ///     .mutate(|n| n + "e")
149    ///     .unwrap()
150    ///     .mutate(|n| n + "l")
151    ///     .unwrap()
152    ///     .mutate(|n| n + "l")
153    ///     .unwrap()
154    ///     .mutate(|n| n + "o")
155    ///     .unwrap();
156    /// assert_eq!(value.into_value(), "hello");
157    /// ```
158    pub fn mutate<F>(self, f: F) -> Result<Self, Error<T>>
159    where
160        F: FnOnce(T) -> T,
161    {
162        Refined::new(f(self.into_value()))
163    }
164
165    /// Returns a reference to the value inside the `Refined` type.
166    ///
167    /// # Returns
168    ///
169    /// * `&RULE::Item` - A reference to the value inside the `Refined` type.
170    ///
171    /// # Example
172    ///
173    /// ```rust
174    /// use refined_type::rule::NonEmptyStringRule;
175    /// use refined_type::Refined;
176    ///
177    /// let non_empty_string = Refined::<NonEmptyStringRule>::new("Hello".to_string()).unwrap();
178    /// assert_eq!(non_empty_string.value(), "Hello");
179    /// ```
180    pub fn value(&self) -> &RULE::Item {
181        &self.value
182    }
183
184    /// Consumes the `Refined` instance and returns the inner value.
185    ///
186    /// # Returns
187    ///
188    /// * `RULE::Item` - The value inside the `Refined` type.
189    ///
190    /// # Example
191    ///
192    /// ```rust
193    /// use refined_type::rule::NonEmptyStringRule;
194    /// use refined_type::Refined;
195    ///
196    /// let non_empty_string = Refined::<NonEmptyStringRule>::new("Hello".to_string()).unwrap();
197    /// assert_eq!(non_empty_string.into_value(), "Hello");
198    /// ```
199    pub fn into_value(self) -> RULE::Item {
200        self.value
201    }
202}
203
204macro_rules! impl_try_from {
205    ($t: ty) => {
206        impl<RULE: Rule<Item = $t>> TryFrom<$t> for Refined<RULE> {
207            type Error = Error<$t>;
208
209            fn try_from(value: $t) -> Result<Self, Self::Error> {
210                Refined::new(value)
211            }
212        }
213    };
214    ($($ts: ty), +) => {
215        $(impl_try_from!($ts);)+
216    };
217}
218
219impl_try_from![u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64];
220impl_try_from![String, char];
221
222impl<'a, RULE: Rule<Item = String>> TryFrom<&'a str> for Refined<RULE> {
223    type Error = Error<String>;
224
225    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
226        Refined::new(value.into())
227    }
228}
229
230impl<T, RULE: Rule<Item = Vec<T>>> TryFrom<Vec<T>> for Refined<RULE> {
231    type Error = Error<Vec<T>>;
232
233    fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
234        Refined::new(value)
235    }
236}
237
238impl<T, RULE: Rule<Item = VecDeque<T>>> TryFrom<VecDeque<T>> for Refined<RULE> {
239    type Error = Error<VecDeque<T>>;
240
241    fn try_from(value: VecDeque<T>) -> Result<Self, Self::Error> {
242        Refined::new(value)
243    }
244}
245
246impl<T, RULE: Rule<Item = HashSet<T>>> TryFrom<HashSet<T>> for Refined<RULE> {
247    type Error = Error<HashSet<T>>;
248
249    fn try_from(value: HashSet<T>) -> Result<Self, Self::Error> {
250        Refined::new(value)
251    }
252}
253
254impl<K, V, RULE: Rule<Item = HashMap<K, V>>> TryFrom<HashMap<K, V>> for Refined<RULE> {
255    type Error = Error<HashMap<K, V>>;
256
257    fn try_from(value: HashMap<K, V>) -> Result<Self, Self::Error> {
258        Refined::new(value)
259    }
260}
261
262impl<RULE, T> Display for Refined<RULE>
263where
264    RULE: Rule<Item = T>,
265    T: Display,
266{
267    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
268        write!(f, "{}", self.value)
269    }
270}
271
272#[cfg(test)]
273mod test {
274    use serde::{Deserialize, Serialize};
275    use serde_json::json;
276    use std::collections::{HashMap, HashSet, VecDeque};
277
278    use crate::refined::Refined;
279    use crate::result::Error;
280    use crate::rule::{
281        EqualI128, EqualI16, EqualI32, EqualI64, EqualI8, EqualIsize, EqualU128, EqualU16,
282        EqualU32, EqualU64, EqualU8, EqualUsize, NonEmptyHashMap, NonEmptyHashSet, NonEmptyString,
283        NonEmptyStringRule, NonEmptyVec, NonEmptyVecDeque,
284    };
285
286    #[test]
287    fn test_unsafe_new_success() {
288        let non_empty_string = Refined::<NonEmptyStringRule>::unsafe_new("Hello".to_string());
289        assert_eq!(non_empty_string.value, "Hello");
290    }
291
292    #[test]
293    #[should_panic(expected = "initialization by `unsafe_new` failed")]
294    fn test_unsafe_new_panic() {
295        let non_empty_string = Refined::<NonEmptyStringRule>::unsafe_new("".to_string());
296        assert_eq!(non_empty_string.value, ""); // unreachable
297    }
298
299    #[test]
300    fn test_refined_non_empty_string_ok() -> Result<(), Error<String>> {
301        let non_empty_string = Refined::<NonEmptyStringRule>::new("Hello".to_string())?;
302        assert_eq!(non_empty_string.value, "Hello");
303        Ok(())
304    }
305
306    #[test]
307    fn test_refined_non_empty_string_err() -> Result<(), String> {
308        let non_empty_string = Refined::<NonEmptyStringRule>::new("".to_string());
309        assert!(non_empty_string.is_err());
310        Ok(())
311    }
312
313    #[test]
314    fn test_refined_display() -> Result<(), Error<String>> {
315        let non_empty_string = Refined::<NonEmptyStringRule>::new("Hello".to_string())?;
316        assert_eq!(format!("{}", non_empty_string), "Hello");
317        Ok(())
318    }
319
320    #[test]
321    fn test_refined_serialize_json_string() -> Result<(), Error<String>> {
322        let non_empty_string = Refined::<NonEmptyStringRule>::new("hello".to_string())?;
323
324        let actual = json!(non_empty_string);
325        let expected = json!("hello");
326        assert_eq!(actual, expected);
327        Ok(())
328    }
329
330    #[test]
331    fn test_refined_serialize_json_struct() -> Result<(), Error<String>> {
332        type NonEmptyString = Refined<NonEmptyStringRule>;
333        #[derive(Serialize)]
334        struct Human {
335            name: NonEmptyString,
336            age: u8,
337        }
338
339        let john = Human {
340            name: NonEmptyString::new("john".to_string())?,
341            age: 8,
342        };
343
344        let actual = json!(john);
345        let expected = json! {{
346            "name": "john",
347            "age": 8
348        }};
349        assert_eq!(actual, expected);
350        Ok(())
351    }
352
353    #[test]
354    fn test_refined_deserialize_json_ok_string() -> anyhow::Result<()> {
355        let json = json!("hello").to_string();
356        let non_empty_string: Refined<NonEmptyStringRule> = serde_json::from_str(&json)?;
357
358        let actual = non_empty_string.into_value();
359        let expected = "hello";
360        assert_eq!(actual, expected);
361        Ok(())
362    }
363
364    #[test]
365    fn test_refined_deserialize_json_ok_1() -> anyhow::Result<()> {
366        #[derive(Debug, Eq, PartialEq, Deserialize)]
367        struct Human {
368            name: NonEmptyString,
369            friends: NonEmptyVec<String>,
370            age: u8,
371        }
372        let json = json! {{
373            "name": "john",
374            "friends": ["tom", "taro"],
375            "age": 8
376        }}
377        .to_string();
378
379        let actual = serde_json::from_str::<Human>(&json)?;
380
381        let expected = Human {
382            name: NonEmptyString::unsafe_new("john".to_string()),
383            friends: NonEmptyVec::unsafe_new(vec!["tom".to_string(), "taro".to_string()]),
384            age: 8,
385        };
386        assert_eq!(actual, expected);
387        Ok(())
388    }
389
390    #[test]
391    fn test_refined_deserialize_json_err_1() -> anyhow::Result<()> {
392        #[derive(Debug, Eq, PartialEq, Deserialize)]
393        struct Human {
394            name: NonEmptyString,
395            friends: NonEmptyVec<String>,
396            age: u8,
397        }
398        let json = json! {{
399            "name": "john",
400            "friends": [],
401            "age": 8
402        }}
403        .to_string();
404
405        // because `friends` is empty vec
406        assert!(serde_json::from_str::<Human>(&json).is_err());
407        Ok(())
408    }
409
410    #[test]
411    fn test_refined_deserialize_json_err_2() -> anyhow::Result<()> {
412        #[derive(Debug, Eq, PartialEq, Deserialize)]
413        struct Human {
414            name: NonEmptyString,
415            friends: NonEmptyVec<String>,
416            age: u8,
417        }
418        let json = json! {{
419            "name": "",
420            "friends": ["tom", "taro"],
421            "age": 8
422        }}
423        .to_string();
424
425        // because `name` is empty string
426        assert!(serde_json::from_str::<Human>(&json).is_err());
427        Ok(())
428    }
429
430    #[test]
431    fn test_refined_deserialize_json_err_3() -> anyhow::Result<()> {
432        let json = json!("").to_string();
433        let result = serde_json::from_str::<Refined<NonEmptyStringRule>>(&json);
434        assert!(result.is_err());
435        Ok(())
436    }
437
438    #[test]
439    fn test_try_from() -> anyhow::Result<()> {
440        let value = NonEmptyString::try_from("hello")?;
441        assert_eq!(value.into_value(), "hello");
442
443        let value = NonEmptyString::try_from("hello".to_string())?;
444        assert_eq!(value.into_value(), "hello");
445
446        let value = EqualU8::<8>::try_from(8)?;
447        assert_eq!(value.into_value(), 8);
448
449        let value = EqualU16::<16>::try_from(16)?;
450        assert_eq!(value.into_value(), 16);
451
452        let value = EqualU32::<32>::try_from(32)?;
453        assert_eq!(value.into_value(), 32);
454
455        let value = EqualU64::<64>::try_from(64)?;
456        assert_eq!(value.into_value(), 64);
457
458        let value = EqualU128::<128>::try_from(128)?;
459        assert_eq!(value.into_value(), 128);
460
461        let value = EqualUsize::<1>::try_from(1)?;
462        assert_eq!(value.into_value(), 1);
463
464        let value = EqualI8::<8>::try_from(8)?;
465        assert_eq!(value.into_value(), 8);
466
467        let value = EqualI16::<16>::try_from(16)?;
468        assert_eq!(value.into_value(), 16);
469
470        let value = EqualI32::<32>::try_from(32)?;
471        assert_eq!(value.into_value(), 32);
472
473        let value = EqualI64::<64>::try_from(64)?;
474        assert_eq!(value.into_value(), 64);
475
476        let value = EqualI128::<128>::try_from(128)?;
477        assert_eq!(value.into_value(), 128);
478
479        let value = EqualIsize::<1>::try_from(1)?;
480        assert_eq!(value.into_value(), 1);
481
482        let value = NonEmptyVec::try_from(vec!["hello".to_string()])?;
483        assert_eq!(value.into_value(), vec!["hello".to_string()]);
484
485        let value = NonEmptyVecDeque::try_from(
486            vec!["hello".to_string()]
487                .into_iter()
488                .collect::<VecDeque<_>>(),
489        )?;
490        assert_eq!(value.into_value(), vec!["hello".to_string()]);
491
492        let value = NonEmptyHashSet::try_from(
493            vec!["hello".to_string()]
494                .into_iter()
495                .collect::<HashSet<_>>(),
496        )?;
497        assert_eq!(
498            value.into_value(),
499            vec!["hello".to_string()].into_iter().collect()
500        );
501
502        let value = NonEmptyHashMap::try_from(
503            vec![("hello".to_string(), "world".to_string())]
504                .into_iter()
505                .collect::<HashMap<_, _>>(),
506        )?;
507        assert_eq!(
508            value.into_value(),
509            vec![("hello".to_string(), "world".to_string())]
510                .into_iter()
511                .collect()
512        );
513
514        let value: NonEmptyVec<NonEmptyString> =
515            NonEmptyVec::try_from(vec!["hello".to_string().try_into()?])?;
516        assert_eq!(value.into_value(), vec!["hello".to_string().try_into()?]);
517        Ok(())
518    }
519
520    #[test]
521    fn test_mutate() -> anyhow::Result<()> {
522        let value = NonEmptyString::try_from("h")?
523            .mutate(|n| n + "e")?
524            .mutate(|n| n + "l")?
525            .mutate(|n| n + "l")?
526            .mutate(|n| n + "o")?;
527        assert_eq!(value.into_value(), "hello");
528        Ok(())
529    }
530}