frunk_core/
generic.rs

1//! This module holds the machinery behind `Generic`.
2//!
3//! It contains the `Generic` trait and some helper methods for using the
4//! `Generic` trait without having to use universal function call syntax.
5//!
6//! # Examples
7//!
8//! ```rust
9//! use frunk::Generic;
10//!
11//! # fn main() {
12//! #[derive(Generic)]
13//! struct ApiPerson<'a> {
14//!     FirstName: &'a str,
15//!     LastName: &'a str,
16//!     Age: usize,
17//! }
18//!
19//! #[derive(Generic)]
20//! struct DomainPerson<'a> {
21//!     first_name: &'a str,
22//!     last_name: &'a str,
23//!     age: usize,
24//! }
25//!
26//! let a_person = ApiPerson {
27//!     FirstName: "Joe",
28//!     LastName: "Blow",
29//!     Age: 30,
30//! };
31//! let d_person: DomainPerson = frunk::convert_from(a_person); // done
32//! # }
33
34/// A trait that converts from a type to a generic representation.
35///
36/// For the most part, you should be using the derivation that is available
37/// through `frunk_derive` to generate instances of this trait for your types.
38///
39/// # Laws
40///
41/// Any implementation of `Generic` must satisfy the following two laws:
42///
43/// 1. `forall x : Self. x == Generic::from(Generic::into(x))`
44/// 2. `forall y : Repr. y == Generic::into(Generic::from(y))`
45///
46/// That is, `from` and `into` should make up an isomorphism between
47/// `Self` and the representation type `Repr`.
48///
49/// # Examples
50///
51/// ```rust
52/// use frunk::Generic;
53///
54/// # fn main() {
55/// #[derive(Generic)]
56/// struct ApiPerson<'a> {
57///     FirstName: &'a str,
58///     LastName: &'a str,
59///     Age: usize,
60/// }
61///
62/// #[derive(Generic)]
63/// struct DomainPerson<'a> {
64///     first_name: &'a str,
65///     last_name: &'a str,
66///     age: usize,
67/// }
68///
69/// let a_person = ApiPerson {
70///     FirstName: "Joe",
71///     LastName: "Blow",
72///     Age: 30,
73/// };
74/// let d_person: DomainPerson = frunk::convert_from(a_person); // done
75/// # }
76/// ```
77pub trait Generic {
78    /// The generic representation type.
79    type Repr;
80
81    /// Convert a value to its representation type `Repr`.
82    fn into(self) -> Self::Repr;
83
84    /// Convert a value's representation type `Repr` to the value's type.
85    fn from(repr: Self::Repr) -> Self;
86
87    /// Convert a value to another type provided that they have
88    /// the same representation type.
89    fn convert_from<Src>(src: Src) -> Self
90    where
91        Self: Sized,
92        Src: Generic<Repr = Self::Repr>,
93    {
94        let repr = <Src as Generic>::into(src);
95        <Self as Generic>::from(repr)
96    }
97
98    /// Maps the given value of type `Self` by first transforming it to
99    /// the representation type `Repr`, then applying a `mapper` function
100    /// on `Repr` and finally transforming it back to a value of type `Self`.
101    fn map_repr<Mapper>(self, mapper: Mapper) -> Self
102    where
103        Self: Sized,
104        Mapper: FnOnce(Self::Repr) -> Self::Repr,
105    {
106        Self::from(mapper(self.into()))
107    }
108
109    /// Maps the given value of type `Self` by first transforming it
110    /// a type `Inter` that has the same representation type as `Self`,
111    /// then applying a `mapper` function on `Inter` and finally transforming
112    /// it back to a value of type `Self`.
113    fn map_inter<Inter, Mapper>(self, mapper: Mapper) -> Self
114    where
115        Self: Sized,
116        Inter: Generic<Repr = Self::Repr>,
117        Mapper: FnOnce(Inter) -> Inter,
118    {
119        Self::convert_from(mapper(Inter::convert_from(self)))
120    }
121}
122
123/// Given a generic representation `Repr` of a `Dst`, returns `Dst`.
124pub fn from_generic<Dst, Repr>(repr: Repr) -> Dst
125where
126    Dst: Generic<Repr = Repr>,
127{
128    <Dst as Generic>::from(repr)
129}
130
131/// Given a value of type `Src`, returns its generic representation `Repr`.
132pub fn into_generic<Src, Repr>(src: Src) -> Repr
133where
134    Src: Generic<Repr = Repr>,
135{
136    <Src as Generic>::into(src)
137}
138
139/// Converts one type `Src` into another type `Dst` assuming they have the same
140/// representation type `Repr`.
141pub fn convert_from<Src, Dst, Repr>(src: Src) -> Dst
142where
143    Src: Generic<Repr = Repr>,
144    Dst: Generic<Repr = Repr>,
145{
146    <Dst as Generic>::convert_from(src)
147}
148
149/// Maps a value of a given type `Origin` using a function on
150/// the representation type `Repr` of `Origin`.
151pub fn map_repr<Origin, Mapper>(val: Origin, mapper: Mapper) -> Origin
152where
153    Origin: Generic,
154    Mapper: FnOnce(Origin::Repr) -> Origin::Repr,
155{
156    <Origin as Generic>::map_repr(val, mapper)
157}
158
159/// Maps a value of a given type `Origin` using a function on
160/// a type `Inter` which has the same representation type of `Origin`.
161///
162/// Note that the compiler will have a hard time inferring the type variable
163/// `Inter`. Thus, using `map_inter` is mostly effective if the type is
164/// constrained by the input function or by the body of a lambda.
165pub fn map_inter<Inter, Origin, Mapper>(val: Origin, mapper: Mapper) -> Origin
166where
167    Origin: Generic,
168    Inter: Generic<Repr = Origin::Repr>,
169    Mapper: FnOnce(Inter) -> Inter,
170{
171    <Origin as Generic>::map_inter(val, mapper)
172}