named_tup/
convert.rs

1use crate::tup_struct::{TupDefault, Unused, Used};
2
3named_tup_derive::sealed_trait_builder!();
4
5/// A copy of the [`Into`] trait from the standard library. The [`Into`] trait could unfortunately
6/// not be used due to it's type reflexivity which clashed with the Tup implementation.
7///
8/// This trait is sealed as it should only ever be implemented on the Tup type.
9///
10/// A Tup can be transformed to another type if for all arguments it falls
11/// in one of the following categories:
12///
13/// ```rust
14/// # use named_tup::{TupInto, tup, Tup, tup_default};
15/// #[tup_default]
16/// pub fn main() {
17///     let unused_to_unused: Tup!(bar: () = ()) = tup!().into_tup();
18///     assert_eq!(unused_to_unused, tup!());
19///
20///     let used_to_used: Tup!(foo: i32) = tup!(foo: 3).into_tup();
21///     assert_eq!(used_to_used, tup!(foo: 3));
22///
23///     let used_to_default: Tup!(foo: &'static str = "hi") = tup!(foo: "yum").into_tup();
24///     assert_eq!(used_to_default, tup!(foo: "yum"));
25///
26///     let unused_to_default: Tup!(foo: f64 = 1.3) = tup!().into_tup();
27///     assert_eq!(unused_to_default, tup!(foo: 1.3));
28///
29///     let default_to_used: Tup!(foo: f64) = unused_to_default.into_tup();
30///     assert_eq!(default_to_used, tup!(foo: 1.3));
31/// }
32/// ```
33///
34/// <br>
35///
36/// Since each rule acts individually on the tup's arguments we can combine them together.
37///
38/// ```rust
39/// # use named_tup::{TupInto, Tup, tup, tup_default};
40/// let colour = tup!(red: 65, green: 105, blue: 225);
41/// let pixel = tup!(x: 5.0, y: 6.4, height: 4.7);
42///
43/// paint(pixel.into_tup(), colour.into_tup());
44///
45/// #[tup_default]
46/// fn paint(pixel: Tup!(x: f64, y: f64, height: f64 = 1.0, width: f64 = 1.0),
47///          colour: Tup!(red: i32, green: i32, blue: i32, opacity: f64 = 1.0))
48/// {
49///     let pixel_colour = pixel + colour;
50///     // Paint    
51/// }
52/// ```
53///
54pub trait TupInto<T>: private::Sealed {
55    /// Performs the conversion.
56    #[must_use]
57    fn into_tup(self) -> T;
58}
59
60/// A copy of the [`From`] trait from the standard library. The [`From`] trait could unfortunately
61/// not be used due to it's type reflexivity which clashed with the Tup implementation.
62///
63/// This trait is sealed as it should only ever be implemented on the Tup type.
64///
65/// For more information please look at the [`TupInto`] trait.
66/// ```rust
67/// # use named_tup::{TupFrom, tup, Tup, tup_default};
68/// #[tup_default]
69/// pub fn main() {
70///     let rick = tup!(funny: true);
71///     let rick = <Tup!(funny: bool, lyrics: &'static str = "Never Gonna Give You Up...")>::from_tup(rick);
72///     assert_eq!(rick, tup!(funny: true, lyrics: "Never Gonna Give You Up..."))
73/// }
74/// ```
75pub trait TupFrom<T>: private::Sealed {
76    /// Performs the conversion
77    #[must_use]
78    fn from_tup(_: T) -> Self;
79}
80
81impl<T, U> TupInto<U> for T
82where
83    U: TupFrom<T>,
84    T: private::Sealed,
85{
86    fn into_tup(self) -> U {
87        U::from_tup(self)
88    }
89}
90
91/// A helper trait to figure out if a tup field can transformed.
92pub trait CanInto<OLD, NEW> {
93    type Output;
94    fn into(self) -> Self::Output;
95}
96
97impl CanInto<Unused, Unused> for () {
98    type Output = ();
99    fn into(self) {}
100}
101
102impl<T> CanInto<Used, Used> for T {
103    type Output = T;
104    fn into(self) -> T {
105        self
106    }
107}
108
109impl<D: TupDefault> CanInto<Unused, D> for () {
110    type Output = D::Output;
111    fn into(self) -> D::Output {
112        D::default()
113    }
114}
115
116impl<T, D> CanInto<Used, D> for T
117where
118    D: TupDefault<Output = T>,
119{
120    type Output = T;
121    fn into(self) -> T {
122        self
123    }
124}
125
126impl<T, D> CanInto<D, Used> for T
127where
128    D: TupDefault<Output = T>,
129{
130    type Output = T;
131    fn into(self) -> T {
132        self
133    }
134}