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}