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}