1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! This module holds the machinery behind Generic.
//!
//! It contains the Generic typeclass and some helper methods for using the Generic type class
//! without having to use universal function call syntax.
//!
//! # Examples
//!
//! ```rust
//! # #[allow(unused_imports)]
//! # #[macro_use] extern crate frunk_derives;
//! # #[macro_use] extern crate frunk_core;
//! # use frunk_core::hlist::*; fn main() {
//! # use frunk_core::hlist::*;
//! # use frunk_core::generic::*;
//! #[derive(Generic)]
//! struct ApiPerson<'a> {
//!     FirstName: &'a str,
//!     LastName: &'a str,
//!     Age: usize,
//! }
//!
//! #[derive(Generic)]
//! struct DomainPerson<'a> {
//!     first_name: &'a str,
//!     last_name: &'a str,
//!     age: usize,
//! }
//!
//! let a_person = ApiPerson {
//!     FirstName: "Joe",
//!     LastName: "Blow",
//!     Age: 30,
//! };
//! let d_person: DomainPerson = convert_from(a_person); // done
//! # }

/// A trait that converts from a type to a generic representation
///
/// For the most part, you should be using the derivation that is available through
/// frunk_derive to generate instances of this typeclass for your types.
///
/// # Examples
///
/// ```rust
/// # #[allow(unused_imports)]
/// # #[macro_use] extern crate frunk_derives;
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::hlist::*; fn main() {
/// use frunk_core::hlist::*;
/// use frunk_core::generic::*;
/// #[derive(Generic)]
/// struct ApiPerson<'a> {
///     FirstName: &'a str,
///     LastName: &'a str,
///     Age: usize,
/// }
///
/// #[derive(Generic)]
/// struct DomainPerson<'a> {
///     first_name: &'a str,
///     last_name: &'a str,
///     age: usize,
/// }
///
/// let a_person = ApiPerson {
///     FirstName: "Joe",
///     LastName: "Blow",
///     Age: 30,
/// };
/// let d_person: DomainPerson = convert_from(a_person); // done
/// # }
/// ```
pub trait Generic {
    /// The generic representation type
    type Repr;

    /// Go from something to Repr
    fn into(self) -> Self::Repr;

    /// Go from Repr to something
    fn from(r: Self::Repr) -> Self;

    /// From one type to another using a type with a compatible generic representation
    fn convert_from<A>(a: A) -> Self
    where
        A: Generic<Repr = Self::Repr>,
        Self: Sized,
    {
        let repr = <A as Generic>::into(a);
        <Self as Generic>::from(repr)
    }
}

/// Given a generic Representation of an A, returns A
pub fn from_generic<A, Repr>(gen: Repr) -> A
where
    A: Generic<Repr = Repr>,
{
    <A as Generic>::from(gen)
}

/// Given an A, returns its generic Representation
pub fn into_generic<A, Repr>(a: A) -> Repr
where
    A: Generic<Repr = Repr>,
{
    <A as Generic>::into(a)
}

/// Converts one type into another assuming they have the same generic Representation
pub fn convert_from<A, B, Repr>(a: A) -> B
where
    A: Generic<Repr = Repr>,
    B: Generic<Repr = Repr>,
{
    <B as Generic>::convert_from(a)
}