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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::tup_struct::{TupDefault, Unused, Used};

named_tup_derive::sealed_trait_builder!();

/// A copy of the [`Into`] trait from the standard library. The [`Into`] trait could unfortunately
/// not be used due to it's type reflexivity which clashed with the Tup implementation.
///
/// This trait is sealed as it should only ever be implemented on the Tup type.
///
/// A Tup can be transformed to another type if for all arguments it falls
/// in one of the following categories:
///
/// ```rust
/// # use named_tup::{TupInto, tup, Tup, tup_default};
/// #[tup_default]
/// pub fn main() {
///     let unused_to_unused: Tup!(bar: () = ()) = tup!().into_tup();
///     assert_eq!(unused_to_unused, tup!());
///
///     let used_to_used: Tup!(foo: i32) = tup!(foo: 3).into_tup();
///     assert_eq!(used_to_used, tup!(foo: 3));
///
///     let used_to_default: Tup!(foo: &'static str = "hi") = tup!(foo: "yum").into_tup();
///     assert_eq!(used_to_default, tup!(foo: "yum"));
///
///     let unused_to_default: Tup!(foo: f64 = 1.3) = tup!().into_tup();
///     assert_eq!(unused_to_default, tup!(foo: 1.3));
///
///     let default_to_used: Tup!(foo: f64) = unused_to_default.into_tup();
///     assert_eq!(default_to_used, tup!(foo: 1.3));
/// }
/// ```
///
/// <br>
///
/// Since each rule acts individually on the tup's arguments we can combine them together.
///
/// ```rust
/// # use named_tup::{TupInto, Tup, tup, tup_default};
/// let colour = tup!(red: 65, green: 105, blue: 225);
/// let pixel = tup!(x: 5.0, y: 6.4, height: 4.7);
///
/// paint(pixel.into_tup(), colour.into_tup());
///
/// #[tup_default]
/// fn paint(pixel: Tup!(x: f64, y: f64, height: f64 = 1.0, width: f64 = 1.0),
///          colour: Tup!(red: i32, green: i32, blue: i32, opacity: f64 = 1.0))
/// {
///     let pixel_colour = pixel + colour;
///     // Paint    
/// }
/// ```
///
pub trait TupInto<T>: private::Sealed {
    /// Performs the conversion.
    #[must_use]
    fn into_tup(self) -> T;
}

/// A copy of the [`From`] trait from the standard library. The [`From`] trait could unfortunately
/// not be used due to it's type reflexivity which clashed with the Tup implementation.
///
/// This trait is sealed as it should only ever be implemented on the Tup type.
///
/// For more information please look at the [`TupInto`] trait.
/// ```rust
/// # use named_tup::{TupFrom, tup, Tup, tup_default};
/// #[tup_default]
/// pub fn main() {
///     let rick = tup!(funny: true);
///     let rick = <Tup!(funny: bool, lyrics: &'static str = "Never Gonna Give You Up...")>::from_tup(rick);
///     assert_eq!(rick, tup!(funny: true, lyrics: "Never Gonna Give You Up..."))
/// }
/// ```
pub trait TupFrom<T>: private::Sealed {
    /// Performs the conversion
    #[must_use]
    fn from_tup(_: T) -> Self;
}

impl<T, U> TupInto<U> for T
where
    U: TupFrom<T>,
    T: private::Sealed,
{
    fn into_tup(self) -> U {
        U::from_tup(self)
    }
}

/// A helper trait to figure out if a tup field can transformed.
pub trait CanInto<OLD, NEW> {
    type Output;
    fn into(self) -> Self::Output;
}

impl CanInto<Unused, Unused> for () {
    type Output = ();
    fn into(self) {}
}

impl<T> CanInto<Used, Used> for T {
    type Output = T;
    fn into(self) -> T {
        self
    }
}

impl<D: TupDefault> CanInto<Unused, D> for () {
    type Output = D::Output;
    fn into(self) -> D::Output {
        D::default()
    }
}

impl<T, D> CanInto<Used, D> for T
where
    D: TupDefault<Output = T>,
{
    type Output = T;
    fn into(self) -> T {
        self
    }
}

impl<T, D> CanInto<D, Used> for T
where
    D: TupDefault<Output = T>,
{
    type Output = T;
    fn into(self) -> T {
        self
    }
}