Skip to main content

frunk_core/
labelled.rs

1//! This module holds the machinery behind LabelledGeneric.
2//!
3//! A `LabelledGeneric` instance is pretty much exactly the same as a `Generic`
4//! instance, except that the generic representation should contain information
5//! about field names.
6//!
7//! Having a separate trait for `LabelledGeneric`s gives us the freedom to
8//! derive both labelled and non-labelled generic trait instances for our types.
9//!
10//! Aside from the main `LabelledGeneric` trait, this module holds helper
11//! methods that allow users to use `LabelledGeneric` without using universal
12//! function call syntax.
13//!
14//! In addition, this module holds macro-generated enums that map to letters
15//! in field names (identifiers).
16//!
17//! # Examples
18//!
19//! ```
20//! # fn main() {
21//! use frunk::labelled::chars::*;
22//! use frunk_core::field;
23//!
24//! // Optionally alias our tuple that represents our type-level string
25//! type name = (n, a, m, e);
26//! let labelled = field![name, "Lloyd"];
27//! assert_eq!(labelled.name, "name");
28//! assert_eq!(labelled.value, "Lloyd")
29//! # }
30//! ```
31//!
32//! A more common usage is to use `LabelledGeneric` to transform structs that
33//! have mismatched fields!
34//!
35//! ```
36//! // required when using custom derives
37//! use frunk::LabelledGeneric;
38//!
39//! # fn main() {
40//! #[derive(LabelledGeneric)]
41//! struct NewUser<'a> {
42//!     first_name: &'a str,
43//!     last_name: &'a str,
44//!     age: usize,
45//! }
46//!
47//! // Notice that the fields are mismatched in terms of ordering
48//! // *and* also in terms of the number of fields.
49//! #[derive(LabelledGeneric)]
50//! struct ShortUser<'a> {
51//!     last_name: &'a str,
52//!     first_name: &'a str,
53//! }
54//!
55//! let n_user = NewUser {
56//!     first_name: "Joe",
57//!     last_name: "Blow",
58//!     age: 30,
59//! };
60//!
61//! // transform_from automagically sculpts the labelled generic
62//! // representation of the source object to that of the target type
63//! let s_user: ShortUser = frunk::transform_from(n_user); // done
64//! # }
65//! ```
66//!
67//! If you have the need to transform types that are similarly-shaped recursively, then
68//! use the Transmogrifier trait.
69//!
70//! ```
71//! // required when using custom derives
72//! # fn main() {
73//! use frunk::labelled::Transmogrifier;
74//! use frunk::LabelledGeneric;
75//!
76//! #[derive(LabelledGeneric)]
77//! struct InternalPhoneNumber {
78//!     emergency: Option<usize>,
79//!     main: usize,
80//!     secondary: Option<usize>,
81//! }
82//!
83//! #[derive(LabelledGeneric)]
84//! struct InternalAddress<'a> {
85//!     is_whitelisted: bool,
86//!     name: &'a str,
87//!     phone: InternalPhoneNumber,
88//! }
89//!
90//! #[derive(LabelledGeneric)]
91//! struct InternalUser<'a> {
92//!     name: &'a str,
93//!     age: usize,
94//!     address: InternalAddress<'a>,
95//!     is_banned: bool,
96//! }
97//!
98//! #[derive(LabelledGeneric, PartialEq, Debug)]
99//! struct ExternalPhoneNumber {
100//!     main: usize,
101//! }
102//!
103//! #[derive(LabelledGeneric, PartialEq, Debug)]
104//! struct ExternalAddress<'a> {
105//!     name: &'a str,
106//!     phone: ExternalPhoneNumber,
107//! }
108//!
109//! #[derive(LabelledGeneric, PartialEq, Debug)]
110//! struct ExternalUser<'a> {
111//!     age: usize,
112//!     address: ExternalAddress<'a>,
113//!     name: &'a str,
114//! }
115//!
116//! let internal_user = InternalUser {
117//!     name: "John",
118//!     age: 10,
119//!     address: InternalAddress {
120//!         is_whitelisted: true,
121//!         name: "somewhere out there",
122//!         phone: InternalPhoneNumber {
123//!             main: 1234,
124//!             secondary: None,
125//!             emergency: Some(5678),
126//!         },
127//!     },
128//!     is_banned: true,
129//! };
130//!
131//! /// Boilerplate-free conversion of a top-level InternalUser into an
132//! /// ExternalUser, taking care of subfield conversions as well.
133//! let external_user: ExternalUser = internal_user.transmogrify();
134//!
135//! let expected_external_user = ExternalUser {
136//!     name: "John",
137//!     age: 10,
138//!     address: ExternalAddress {
139//!         name: "somewhere out there",
140//!         phone: ExternalPhoneNumber {
141//!             main: 1234,
142//!         },
143//!     }
144//! };
145//!
146//! assert_eq!(external_user, expected_external_user);
147//! # }
148//! ```
149
150use crate::coproduct::Coproduct;
151use crate::hlist::*;
152use crate::indices::*;
153use crate::traits::ToRef;
154use chars::*;
155#[cfg(feature = "serde")]
156use serde::{Deserialize, Serialize};
157
158use core::fmt;
159use core::marker::PhantomData;
160
161/// A trait that converts from a type to a labelled generic representation.
162///
163/// `LabelledGeneric`s allow us to have completely type-safe,
164/// boilerplate free conversions between different structs.
165///
166/// For the most part, you should be using the derivation that is available
167/// through `frunk_derive` to generate instances of this trait for your types.
168///
169/// # Examples
170///
171/// ```rust
172/// use frunk::LabelledGeneric;
173///
174/// # fn main() {
175/// #[derive(LabelledGeneric)]
176/// struct NewUser<'a> {
177///     first_name: &'a str,
178///     last_name: &'a str,
179///     age: usize,
180/// }
181///
182/// // Notice that the fields are mismatched in terms of ordering
183/// #[derive(LabelledGeneric)]
184/// struct SavedUser<'a> {
185///     last_name: &'a str,
186///     age: usize,
187///     first_name: &'a str,
188/// }
189///
190/// let n_user = NewUser {
191///     first_name: "Joe",
192///     last_name: "Blow",
193///     age: 30,
194/// };
195///
196/// // transform_from automagically sculpts the labelled generic
197/// // representation of the source object to that of the target type
198/// let s_user: SavedUser = frunk::transform_from(n_user); // done
199/// # }
200#[diagnostic::on_unimplemented(
201    message = "Cannot derive labelled generic representation for `{Self}`",
202    label = "LabelledGeneric not implemented",
203    note = "The type must have a LabelledGeneric instance to be used with transform_from or transmogrify.",
204    note = "Derive LabelledGeneric using #[derive(LabelledGeneric)] on your struct or enum."
205)]
206pub trait LabelledGeneric {
207    /// The labelled generic representation type.
208    type Repr;
209
210    /// Convert a value to its representation type `Repr`.
211    fn into(self) -> Self::Repr;
212
213    /// Convert a value's labelled representation type `Repr`
214    /// to the values's type.
215    fn from(repr: Self::Repr) -> Self;
216
217    /// Convert from one type to another using a type with the same
218    /// labelled generic representation
219    #[inline(always)]
220    fn convert_from<Src>(src: Src) -> Self
221    where
222        Src: LabelledGeneric<Repr = Self::Repr>,
223        Self: Sized,
224    {
225        let repr = <Src as LabelledGeneric>::into(src);
226        <Self as LabelledGeneric>::from(repr)
227    }
228
229    /// Converts from another type A into Self assuming that A and Self have
230    /// labelled generic representations that can be sculpted into each other.
231    ///
232    /// Note that this method tosses away the "remainder" of the sculpted representation. In other
233    /// words, anything that is not needed from A gets tossed out.
234    #[deprecated(note = "obsolete, transform_from instead")]
235    fn sculpted_convert_from<A, Indices>(a: A) -> Self
236    where
237        A: LabelledGeneric,
238        Self: Sized,
239        // The labelled representation of A must be sculpt-able into the labelled representation of Self
240        <A as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices>,
241    {
242        <Self as LabelledGeneric>::transform_from(a)
243    }
244
245    /// Converts from another type `Src` into `Self` assuming that `Src` and
246    /// `Self` have labelled generic representations that can be sculpted into
247    /// each other.
248    ///
249    /// Note that this method tosses away the "remainder" of the sculpted
250    /// representation. In other words, anything that is not needed from `Src`
251    /// gets tossed out.
252    #[inline(always)]
253    fn transform_from<Src, Indices>(src: Src) -> Self
254    where
255        Src: LabelledGeneric,
256        Self: Sized,
257        // The labelled representation of `Src` must be sculpt-able into the labelled representation of `Self`
258        <Src as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices>,
259    {
260        let src_gen = <Src as LabelledGeneric>::into(src);
261        // We toss away the remainder.
262        let (self_gen, _): (<Self as LabelledGeneric>::Repr, _) = src_gen.sculpt();
263        <Self as LabelledGeneric>::from(self_gen)
264    }
265}
266
267pub trait IntoLabelledGeneric {
268    /// The labelled generic representation type.
269    type Repr;
270
271    /// Convert a value to its representation type `Repr`.
272    fn into(self) -> Self::Repr;
273}
274
275impl<A> IntoLabelledGeneric for A
276where
277    A: LabelledGeneric,
278{
279    type Repr = <A as LabelledGeneric>::Repr;
280
281    #[inline(always)]
282    fn into(self) -> <Self as IntoLabelledGeneric>::Repr {
283        self.into()
284    }
285}
286
287type NoneLabel = (N, o, n, e);
288type SomeLabel = (S, o, m, e);
289type OkLabel = (O, k);
290type ErrLabel = (E, r, r);
291type FalseLabel = (f, a, l, s, e);
292type TrueLabel = (t, r, u, e);
293type TupleField0 = (__, _0);
294type UnitVariant<Name> = Field<Name, HNil>;
295type UnaryTupleVariant<Name, T> = Field<Name, crate::HList!(Field<TupleField0, T>)>;
296type LabelledOptionRepr<T> =
297    crate::Coprod!(UnitVariant<NoneLabel>, UnaryTupleVariant<SomeLabel, T>);
298type LabelledResultRepr<T, E> =
299    crate::Coprod!(UnaryTupleVariant<OkLabel, T>, UnaryTupleVariant<ErrLabel, E>);
300type LabelledBoolRepr = crate::Coprod!(UnitVariant<FalseLabel>, UnitVariant<TrueLabel>);
301
302#[inline(always)]
303fn labelled_tuple_field_0<T>(value: T) -> Field<TupleField0, T> {
304    crate::field!(TupleField0, value, "_0")
305}
306
307#[inline(always)]
308fn labelled_unit_variant<Name>(name: &'static str) -> UnitVariant<Name> {
309    crate::field!(Name, crate::hlist![], name)
310}
311
312#[inline(always)]
313fn labelled_unary_tuple_variant<Name, T>(
314    name: &'static str,
315    value: T,
316) -> UnaryTupleVariant<Name, T> {
317    crate::field!(Name, crate::hlist![labelled_tuple_field_0(value)], name)
318}
319
320impl<T> LabelledGeneric for Option<T> {
321    type Repr = LabelledOptionRepr<T>;
322
323    #[inline(always)]
324    fn into(self) -> Self::Repr {
325        match self {
326            None => Coproduct::Inl(labelled_unit_variant::<NoneLabel>("None")),
327            Some(value) => Coproduct::Inr(Coproduct::Inl(labelled_unary_tuple_variant::<
328                SomeLabel,
329                _,
330            >("Some", value))),
331        }
332    }
333
334    #[inline(always)]
335    fn from(repr: Self::Repr) -> Self {
336        match repr {
337            Coproduct::Inl(Field {
338                value: crate::hlist_pat![],
339                ..
340            }) => None,
341            Coproduct::Inr(Coproduct::Inl(Field {
342                value: crate::hlist_pat![Field { value, .. }],
343                ..
344            })) => Some(value),
345            Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
346        }
347    }
348}
349
350impl<T, E> LabelledGeneric for Result<T, E> {
351    type Repr = LabelledResultRepr<T, E>;
352
353    #[inline(always)]
354    fn into(self) -> Self::Repr {
355        match self {
356            Ok(value) => Coproduct::Inl(labelled_unary_tuple_variant::<OkLabel, _>("Ok", value)),
357            Err(value) => Coproduct::Inr(Coproduct::Inl(
358                labelled_unary_tuple_variant::<ErrLabel, _>("Err", value),
359            )),
360        }
361    }
362
363    #[inline(always)]
364    fn from(repr: Self::Repr) -> Self {
365        match repr {
366            Coproduct::Inl(Field {
367                value: crate::hlist_pat![Field { value, .. }],
368                ..
369            }) => Ok(value),
370            Coproduct::Inr(Coproduct::Inl(Field {
371                value: crate::hlist_pat![Field { value, .. }],
372                ..
373            })) => Err(value),
374            Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
375        }
376    }
377}
378
379impl LabelledGeneric for bool {
380    type Repr = LabelledBoolRepr;
381
382    #[inline(always)]
383    fn into(self) -> Self::Repr {
384        match self {
385            false => Coproduct::Inl(labelled_unit_variant::<FalseLabel>("false")),
386            true => Coproduct::Inr(Coproduct::Inl(labelled_unit_variant::<TrueLabel>("true"))),
387        }
388    }
389
390    #[inline(always)]
391    fn from(repr: Self::Repr) -> Self {
392        match repr {
393            Coproduct::Inl(Field {
394                value: crate::hlist_pat![],
395                ..
396            }) => false,
397            Coproduct::Inr(Coproduct::Inl(Field {
398                value: crate::hlist_pat![],
399                ..
400            })) => true,
401            Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
402        }
403    }
404}
405
406/// Given a labelled generic representation of a `Dst`, returns `Dst`
407pub fn from_labelled_generic<Dst, Repr>(repr: Repr) -> Dst
408where
409    Dst: LabelledGeneric<Repr = Repr>,
410{
411    <Dst as LabelledGeneric>::from(repr)
412}
413
414/// Given a `Src`, returns its labelled generic representation.
415pub fn into_labelled_generic<Src, Repr>(src: Src) -> Repr
416where
417    Src: LabelledGeneric<Repr = Repr>,
418{
419    <Src as LabelledGeneric>::into(src)
420}
421
422/// Converts one type into another assuming they have the same labelled generic
423/// representation.
424pub fn labelled_convert_from<Src, Dst, Repr>(src: Src) -> Dst
425where
426    Src: LabelledGeneric<Repr = Repr>,
427    Dst: LabelledGeneric<Repr = Repr>,
428{
429    <Dst as LabelledGeneric>::convert_from(src)
430}
431
432/// Converts from one type into another assuming that their labelled generic representations
433/// can be sculpted into each other.
434///
435/// The "Indices" type parameter allows the compiler to figure out that the two representations
436/// can indeed be morphed into each other.
437#[deprecated(note = "obsolete, transform_from instead")]
438pub fn sculpted_convert_from<A, B, Indices>(a: A) -> B
439where
440    A: LabelledGeneric,
441    B: LabelledGeneric,
442    // The labelled representation of A must be sculpt-able into the labelled representation of B
443    <A as LabelledGeneric>::Repr: Sculptor<<B as LabelledGeneric>::Repr, Indices>,
444{
445    <B as LabelledGeneric>::transform_from(a)
446}
447/// Converts from one type into another assuming that their labelled generic representations
448/// can be sculpted into each other.
449///
450/// The "Indices" type parameter allows the compiler to figure out that the two representations
451/// can indeed be morphed into each other.
452pub fn transform_from<Src, Dst, Indices>(src: Src) -> Dst
453where
454    Src: LabelledGeneric,
455    Dst: LabelledGeneric,
456    // The labelled representation of Src must be sculpt-able into the labelled representation of Dst
457    <Src as LabelledGeneric>::Repr: Sculptor<<Dst as LabelledGeneric>::Repr, Indices>,
458{
459    <Dst as LabelledGeneric>::transform_from(src)
460}
461
462pub mod chars {
463    //! Types for building type-level labels from character sequences.
464    //!
465    //! This is designed to be glob-imported:
466    //!
467    //! ```rust
468    //! # extern crate frunk;
469    //! # fn main() {
470    //! # #[allow(unused)]
471    //! use frunk::labelled::chars::*;
472    //! # }
473    //! ```
474
475    macro_rules! create_enums_for {
476        ($($i: ident)*) => {
477            $(
478                #[allow(non_snake_case, non_camel_case_types)]
479                #[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
480                pub enum $i {}
481            )*
482        }
483    }
484
485    // Add more as needed.
486    create_enums_for! {
487        // all valid identifier characters
488        a b c d e f g h i j k l m n o p q r s t u v w x y z
489        A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
490        _1 _2 _3 _4 _5 _6 _7 _8 _9 _0 __ _uc uc_
491    }
492
493    #[test]
494    fn simple_var_names_are_allowed() {
495        // Rust forbids variable bindings that shadow unit structs,
496        // so unit struct characters would cause a lot of trouble.
497        //
498        // Good thing I don't plan on adding reified labels. - Exp
499        let a = 3;
500        #[allow(clippy::match_single_binding)]
501        match a {
502            a => assert_eq!(a, 3),
503        }
504    }
505}
506
507/// A Label contains a type-level Name, a runtime value, and
508/// a reference to a `&'static str` name.
509///
510/// To construct one, use the `field!` macro.
511///
512/// # Examples
513///
514/// ```
515/// use frunk::labelled::chars::*;
516/// use frunk_core::field;
517/// # fn main() {
518/// let labelled = field![(n,a,m,e), "joe"];
519/// assert_eq!(labelled.name, "name");
520/// assert_eq!(labelled.value, "joe")
521/// # }
522/// ```
523#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
524#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
525pub struct Field<Name, Type> {
526    name_type_holder: PhantomData<Name>,
527    pub name: &'static str,
528    pub value: Type,
529}
530
531/// A version of Field that doesn't have a type-level label, just a
532/// value-level one
533#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
534#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
535pub struct ValueField<Type> {
536    pub name: &'static str,
537    pub value: Type,
538}
539
540impl<Name, Type> fmt::Debug for Field<Name, Type>
541where
542    Type: fmt::Debug,
543{
544    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
545        f.debug_struct("Field")
546            // show name without quotes
547            .field("name", &DebugAsDisplay(&self.name))
548            .field("value", &self.value)
549            .finish()
550    }
551}
552
553impl<Type> fmt::Debug for ValueField<Type>
554where
555    Type: fmt::Debug,
556{
557    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558        f.debug_struct("ValueField")
559            // show name without quotes
560            .field("name", &DebugAsDisplay(&self.name))
561            .field("value", &self.value)
562            .finish()
563    }
564}
565
566/// Utility type that implements Debug in terms of Display.
567struct DebugAsDisplay<T>(T);
568
569impl<T: fmt::Display> fmt::Debug for DebugAsDisplay<T> {
570    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571        fmt::Display::fmt(&self.0, f)
572    }
573}
574
575/// Returns a new Field for a given value and custom name.
576///
577/// If you don't want to provide a custom name and want to rely on the type you provide
578/// to build a name, then please use the field! macro.
579///
580/// # Examples
581///
582/// ```
583/// use frunk::labelled::chars::*;
584/// use frunk::labelled::field_with_name;
585///
586/// let l = field_with_name::<(n,a,m,e),_>("name", "joe");
587/// assert_eq!(l.value, "joe");
588/// assert_eq!(l.name, "name");
589/// ```
590pub fn field_with_name<Label, Value>(name: &'static str, value: Value) -> Field<Label, Value> {
591    Field {
592        name_type_holder: PhantomData,
593        name,
594        value,
595    }
596}
597
598/// Trait for turning a Field HList into an un-labelled HList
599pub trait IntoUnlabelled {
600    type Output;
601
602    /// Turns the current HList into an unlabelled one.
603    ///
604    /// Effectively extracts the values held inside the individual Field
605    ///
606    /// # Examples
607    ///
608    /// ```
609    /// # fn main() {
610    /// use frunk::labelled::chars::*;
611    /// use frunk::labelled::IntoUnlabelled;
612    /// use frunk_core::{field, hlist};
613    ///
614    /// let labelled_hlist = hlist![
615    ///     field!((n, a, m, e), "joe"),
616    ///     field!((a, g, e), 3)
617    /// ];
618    ///
619    /// let unlabelled = labelled_hlist.into_unlabelled();
620    ///
621    /// assert_eq!(unlabelled, hlist!["joe", 3])
622    /// # }
623    /// ```
624    fn into_unlabelled(self) -> Self::Output;
625}
626
627/// Implementation for HNil
628impl IntoUnlabelled for HNil {
629    type Output = HNil;
630    fn into_unlabelled(self) -> Self::Output {
631        self
632    }
633}
634
635/// Implementation when we have a non-empty HCons holding a label in its head
636impl<Label, Value, Tail> IntoUnlabelled for HCons<Field<Label, Value>, Tail>
637where
638    Tail: IntoUnlabelled,
639{
640    type Output = HCons<Value, <Tail as IntoUnlabelled>::Output>;
641
642    fn into_unlabelled(self) -> Self::Output {
643        HCons {
644            head: self.head.value,
645            tail: self.tail.into_unlabelled(),
646        }
647    }
648}
649
650/// A trait that strips type-level strings from the labels
651pub trait IntoValueLabelled {
652    type Output;
653
654    /// Turns the current HList into a value-labelled one.
655    ///
656    /// Effectively extracts the names and values held inside the individual Fields
657    /// and puts them into ValueFields, which do not have type-level names.
658    ///
659    /// # Examples
660    ///
661    /// ```
662    /// # fn main() {
663    /// use frunk::labelled::{ValueField, IntoValueLabelled};
664    /// use frunk::labelled::chars::*;
665    /// use frunk_core::{field, hlist, HList};
666    ///
667    /// let labelled_hlist = hlist![
668    ///     field!((n, a, m, e), "joe"),
669    ///     field!((a, g, e), 3)
670    /// ];
671    /// // Notice the lack of type-level names
672    /// let value_labelled: HList![ValueField<&str>, ValueField<isize>] = labelled_hlist.into_value_labelled();
673    ///
674    /// assert_eq!(
675    ///   value_labelled,
676    ///   hlist![
677    ///     ValueField {
678    ///       name: "name",
679    ///       value: "joe",
680    ///     },
681    ///     ValueField {
682    ///       name: "age",
683    ///       value: 3,
684    ///     },
685    /// ]);
686    /// # }
687    /// ```
688    fn into_value_labelled(self) -> Self::Output;
689}
690
691impl IntoValueLabelled for HNil {
692    type Output = HNil;
693    fn into_value_labelled(self) -> Self::Output {
694        self
695    }
696}
697
698impl<Label, Value, Tail> IntoValueLabelled for HCons<Field<Label, Value>, Tail>
699where
700    Tail: IntoValueLabelled,
701{
702    type Output = HCons<ValueField<Value>, <Tail as IntoValueLabelled>::Output>;
703
704    fn into_value_labelled(self) -> Self::Output {
705        HCons {
706            head: ValueField {
707                name: self.head.name,
708                value: self.head.value,
709            },
710            tail: self.tail.into_value_labelled(),
711        }
712    }
713}
714
715/// Trait for plucking out a `Field` from a type by type-level `TargetKey`.
716#[diagnostic::on_unimplemented(
717    message = "Cannot find field with key `{TargetKey}` in `{Self}`",
718    label = "Field not found",
719    note = "The source type does not contain a field with the target key.",
720    note = "Make sure the field name exists in the source struct and matches exactly."
721)]
722pub trait ByNameFieldPlucker<TargetKey, Index> {
723    type TargetValue;
724    type Remainder;
725
726    /// Returns a pair consisting of the value pointed to by the target key and the remainder.
727    fn pluck_by_name(self) -> (Field<TargetKey, Self::TargetValue>, Self::Remainder);
728}
729
730/// Implementation when the pluck target key is in the head.
731impl<K, V, Tail> ByNameFieldPlucker<K, Here> for HCons<Field<K, V>, Tail> {
732    type TargetValue = V;
733    type Remainder = Tail;
734
735    #[inline(always)]
736    fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
737        let field = field_with_name(self.head.name, self.head.value);
738        (field, self.tail)
739    }
740}
741
742/// Implementation when the pluck target key is in the tail.
743impl<Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for HCons<Head, Tail>
744where
745    Tail: ByNameFieldPlucker<K, TailIndex>,
746{
747    type TargetValue = <Tail as ByNameFieldPlucker<K, TailIndex>>::TargetValue;
748    type Remainder = HCons<Head, <Tail as ByNameFieldPlucker<K, TailIndex>>::Remainder>;
749
750    #[inline(always)]
751    fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
752        let (target, tail_remainder) =
753            <Tail as ByNameFieldPlucker<K, TailIndex>>::pluck_by_name(self.tail);
754        (
755            target,
756            HCons {
757                head: self.head,
758                tail: tail_remainder,
759            },
760        )
761    }
762}
763
764/// Implementation when target is reference and the pluck target key is in the head.
765impl<'a, K, V, Tail: ToRef<'a>> ByNameFieldPlucker<K, Here> for &'a HCons<Field<K, V>, Tail> {
766    type TargetValue = &'a V;
767    type Remainder = <Tail as ToRef<'a>>::Output;
768
769    #[inline(always)]
770    fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
771        let field = field_with_name(self.head.name, &self.head.value);
772        (field, self.tail.to_ref())
773    }
774}
775
776/// Implementation when target is reference and the pluck target key is in the tail.
777impl<'a, Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for &'a HCons<Head, Tail>
778where
779    &'a Tail: ByNameFieldPlucker<K, TailIndex>,
780{
781    type TargetValue = <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::TargetValue;
782    type Remainder = HCons<&'a Head, <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::Remainder>;
783
784    #[inline(always)]
785    fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
786        let (target, tail_remainder) =
787            <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::pluck_by_name(&self.tail);
788        (
789            target,
790            HCons {
791                head: &self.head,
792                tail: tail_remainder,
793            },
794        )
795    }
796}
797
798/// Trait for transmogrifying a `Source` type into a `Target` type.
799///
800/// What is "transmogrifying"? In this context, it means to convert some data of type `A`
801/// into data of type `B`, in a typesafe, recursive way, as long as `A` and `B` are "similarly-shaped".
802/// In other words, as long as `B`'s fields and their subfields are subsets of `A`'s fields and
803/// their respective subfields, then `A` can be turned into `B`.
804///
805/// # Example
806///
807/// ```
808/// // required when using custom derives
809/// # fn main() {
810/// use frunk::LabelledGeneric;
811/// use frunk::labelled::Transmogrifier;
812/// #[derive(LabelledGeneric)]
813/// struct InternalPhoneNumber {
814///     emergency: Option<usize>,
815///     main: usize,
816///     secondary: Option<usize>,
817/// }
818///
819/// #[derive(LabelledGeneric)]
820/// struct InternalAddress<'a> {
821///     is_whitelisted: bool,
822///     name: &'a str,
823///     phone: InternalPhoneNumber,
824/// }
825///
826/// #[derive(LabelledGeneric)]
827/// struct InternalUser<'a> {
828///     name: &'a str,
829///     age: usize,
830///     address: InternalAddress<'a>,
831///     is_banned: bool,
832/// }
833///
834/// #[derive(LabelledGeneric, PartialEq, Debug)]
835/// struct ExternalPhoneNumber {
836///     main: usize,
837/// }
838///
839/// #[derive(LabelledGeneric, PartialEq, Debug)]
840/// struct ExternalAddress<'a> {
841///     name: &'a str,
842///     phone: ExternalPhoneNumber,
843/// }
844///
845/// #[derive(LabelledGeneric, PartialEq, Debug)]
846/// struct ExternalUser<'a> {
847///     age: usize,
848///     address: ExternalAddress<'a>,
849///     name: &'a str,
850/// }
851///
852/// let internal_user = InternalUser {
853///     name: "John",
854///     age: 10,
855///     address: InternalAddress {
856///         is_whitelisted: true,
857///         name: "somewhere out there",
858///         phone: InternalPhoneNumber {
859///             main: 1234,
860///             secondary: None,
861///             emergency: Some(5678),
862///         },
863///     },
864///     is_banned: true,
865/// };
866///
867/// /// Boilerplate-free conversion of a top-level InternalUser into an
868/// /// ExternalUser, taking care of subfield conversions as well.
869/// let external_user: ExternalUser = internal_user.transmogrify();
870///
871/// let expected_external_user = ExternalUser {
872///     name: "John",
873///     age: 10,
874///     address: ExternalAddress {
875///         name: "somewhere out there",
876///         phone: ExternalPhoneNumber {
877///             main: 1234,
878///         },
879///     }
880/// };
881///
882/// assert_eq!(external_user, expected_external_user);
883/// # }
884/// ```
885///
886/// Credit:
887/// 1. Haskell "transmogrify" Github repo: <https://github.com/ivan-m/transmogrify>
888#[diagnostic::on_unimplemented(
889    message = "Cannot transmogrify `{Self}` into `{Target}`",
890    label = "Cannot convert this type into the target type",
891    note = "Transmogrify requires that the source and target types have compatible structures.",
892    note = "The source type must have all the fields needed for the target type, possibly in a different order or nested structure.",
893    note = "Check that field names match and types are compatible between the source and target."
894)]
895pub trait Transmogrifier<Target, TransmogrifyIndexIndices> {
896    /// Consume this current object and return an object of the Target type.
897    ///
898    /// Although similar to sculpting, transmogrifying does its job recursively.
899    fn transmogrify(self) -> Target;
900}
901
902/// Implementation of `Transmogrifier` for identity plucked `Field` to `Field` Transforms.
903impl<Key, SourceValue> Transmogrifier<SourceValue, IdentityTransMog> for Field<Key, SourceValue> {
904    #[inline(always)]
905    fn transmogrify(self) -> SourceValue {
906        self.value
907    }
908}
909
910/// Implementations of `Transmogrifier` that allow recursion through stdlib container types.
911#[cfg(feature = "alloc")]
912mod _alloc {
913    use super::MappingIndicesWrapper;
914    use super::{Field, Transmogrifier};
915    use alloc::boxed::Box;
916    use alloc::collections::{LinkedList, VecDeque};
917    use alloc::vec::Vec;
918
919    macro_rules! transmogrify_seq {
920        ($container:ident) => {
921            /// Implementation of `Transmogrifier` that maps over a `$container` in a `Field`, transmogrifying the
922            /// elements on the way past.
923            impl<Key, Source, Target, InnerIndices>
924                Transmogrifier<$container<Target>, MappingIndicesWrapper<InnerIndices>>
925                for Field<Key, $container<Source>>
926            where
927                Source: Transmogrifier<Target, InnerIndices>,
928            {
929                fn transmogrify(self) -> $container<Target> {
930                    self.value.into_iter().map(|e| e.transmogrify()).collect()
931                }
932            }
933        };
934    }
935
936    transmogrify_seq!(Vec);
937    transmogrify_seq!(LinkedList);
938    transmogrify_seq!(VecDeque);
939
940    /// Implementation of `Transmogrifier` that maps over an `Box` in a `Field`, transmogrifying the
941    /// contained element on the way past.
942    impl<Key, Source, Target, InnerIndices>
943        Transmogrifier<Box<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, Box<Source>>
944    where
945        Source: Transmogrifier<Target, InnerIndices>,
946    {
947        fn transmogrify(self) -> Box<Target> {
948            Box::new(self.value.transmogrify())
949        }
950    }
951}
952
953/// Implementation of `Transmogrifier` that maps over an `Option` in a `Field`, transmogrifying the
954/// contained element on the way past if present.
955impl<Key, Source, Target, InnerIndices>
956    Transmogrifier<Option<Target>, MappingIndicesWrapper<InnerIndices>>
957    for Field<Key, Option<Source>>
958where
959    Source: Transmogrifier<Target, InnerIndices>,
960{
961    fn transmogrify(self) -> Option<Target> {
962        self.value.map(|e| e.transmogrify())
963    }
964}
965
966/// Implementation of `Transmogrifier` for when the `Target` is empty and the `Source` is empty.
967impl Transmogrifier<HNil, HNil> for HNil {
968    #[inline(always)]
969    fn transmogrify(self) -> HNil {
970        HNil
971    }
972}
973
974/// Implementation of `Transmogrifier` for when the `Target` is empty and the `Source` is non-empty.
975impl<SourceHead, SourceTail> Transmogrifier<HNil, HNil> for HCons<SourceHead, SourceTail> {
976    #[inline(always)]
977    fn transmogrify(self) -> HNil {
978        HNil
979    }
980}
981
982/// Implementation of `Transmogrifier` for when the target is an `HList`, and the `Source` is a plucked
983/// `HList`.
984impl<
985        SourceHead,
986        SourceTail,
987        TargetName,
988        TargetHead,
989        TargetTail,
990        TransmogHeadIndex,
991        TransmogTailIndices,
992    > Transmogrifier<HCons<TargetHead, TargetTail>, HCons<TransmogHeadIndex, TransmogTailIndices>>
993    for Field<TargetName, HCons<SourceHead, SourceTail>>
994where
995    HCons<SourceHead, SourceTail>: Transmogrifier<
996        HCons<TargetHead, TargetTail>,
997        HCons<TransmogHeadIndex, TransmogTailIndices>,
998    >,
999{
1000    #[inline(always)]
1001    fn transmogrify(self) -> HCons<TargetHead, TargetTail> {
1002        self.value.transmogrify()
1003    }
1004}
1005
1006/// Non-trivial implementation of `Transmogrifier` where similarly-shaped `Source` and `Target` types are
1007/// both Labelled HLists, but do not immediately transform into one another due to mis-matched
1008/// fields, possibly recursively so.
1009impl<
1010        SourceHead,
1011        SourceTail,
1012        TargetHeadName,
1013        TargetHeadValue,
1014        TargetTail,
1015        PluckSourceHeadNameIndex,
1016        TransMogSourceHeadValueIndices,
1017        TransMogTailIndices,
1018    >
1019    Transmogrifier<
1020        HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail>,
1021        HCons<
1022            DoTransmog<PluckSourceHeadNameIndex, TransMogSourceHeadValueIndices>,
1023            TransMogTailIndices,
1024        >,
1025    > for HCons<SourceHead, SourceTail>
1026where
1027    // Pluck a value out of the Source by the Head Target Name
1028    HCons<SourceHead, SourceTail>: ByNameFieldPlucker<TargetHeadName, PluckSourceHeadNameIndex>,
1029    // The value we pluck out needs to be able to be transmogrified to the Head Target Value type
1030    Field<
1031        TargetHeadName,
1032        <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
1033            TargetHeadName,
1034            PluckSourceHeadNameIndex,
1035        >>::TargetValue,
1036    >: Transmogrifier<TargetHeadValue, TransMogSourceHeadValueIndices>,
1037    // The remainder from plucking out the Head Target Name must be able to be transmogrified to the
1038    // target tail, utilising the other remaining indices
1039    <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
1040        TargetHeadName,
1041        PluckSourceHeadNameIndex,
1042    >>::Remainder: Transmogrifier<TargetTail, TransMogTailIndices>,
1043{
1044    #[inline(always)]
1045    fn transmogrify(self) -> HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail> {
1046        let (source_field_for_head_target_name, remainder) = self.pluck_by_name();
1047        let name = source_field_for_head_target_name.name;
1048        let transmogrified_value: TargetHeadValue =
1049            source_field_for_head_target_name.transmogrify();
1050        let as_field: Field<TargetHeadName, TargetHeadValue> =
1051            field_with_name(name, transmogrified_value);
1052        HCons {
1053            head: as_field,
1054            tail: remainder.transmogrify(),
1055        }
1056    }
1057}
1058
1059impl<Source, Target, TransmogIndices>
1060    Transmogrifier<Target, LabelledGenericTransmogIndicesWrapper<TransmogIndices>> for Source
1061where
1062    Source: LabelledGeneric,
1063    Target: LabelledGeneric,
1064    <Source as LabelledGeneric>::Repr:
1065        Transmogrifier<<Target as LabelledGeneric>::Repr, TransmogIndices>,
1066{
1067    #[inline(always)]
1068    fn transmogrify(self) -> Target {
1069        let source_as_repr = self.into();
1070        let source_transmogged = source_as_repr.transmogrify();
1071        <Target as LabelledGeneric>::from(source_transmogged)
1072    }
1073}
1074
1075// Implementation for when the source value is plucked
1076impl<Source, TargetName, TargetValue, TransmogIndices>
1077    Transmogrifier<TargetValue, PluckedLabelledGenericIndicesWrapper<TransmogIndices>>
1078    for Field<TargetName, Source>
1079where
1080    Source: LabelledGeneric,
1081    TargetValue: LabelledGeneric,
1082    Source: Transmogrifier<TargetValue, TransmogIndices>,
1083{
1084    #[inline(always)]
1085    fn transmogrify(self) -> TargetValue {
1086        self.value.transmogrify()
1087    }
1088}
1089
1090#[cfg(test)]
1091mod tests {
1092    use super::*;
1093    use alloc::collections::{LinkedList, VecDeque};
1094    use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
1095
1096    // Set up some aliases
1097    #[allow(non_camel_case_types)]
1098    type abc = (a, b, c);
1099    #[allow(non_camel_case_types)]
1100    type name = (n, a, m, e);
1101    #[allow(non_camel_case_types)]
1102    type age = (a, g, e);
1103    #[allow(non_camel_case_types)]
1104    type is_admin = (i, s, __, a, d, m, i, n);
1105    #[allow(non_camel_case_types)]
1106    type inner = (i, n, n, e, r);
1107
1108    #[test]
1109    fn test_label_new_building() {
1110        let l1 = field!(abc, 3);
1111        assert_eq!(l1.value, 3);
1112        assert_eq!(l1.name, "abc");
1113        let l2 = field!((a, b, c), 3);
1114        assert_eq!(l2.value, 3);
1115        assert_eq!(l2.name, "abc");
1116
1117        // test named
1118        let l3 = field!(abc, 3, "nope");
1119        assert_eq!(l3.value, 3);
1120        assert_eq!(l3.name, "nope");
1121        let l4 = field!((a, b, c), 3, "nope");
1122        assert_eq!(l4.value, 3);
1123        assert_eq!(l4.name, "nope");
1124    }
1125
1126    #[test]
1127    fn test_field_construction() {
1128        let f1 = field!(age, 3);
1129        let f2 = field!((a, g, e), 3);
1130        assert_eq!(f1, f2)
1131    }
1132
1133    #[test]
1134    fn test_field_debug() {
1135        let field = field!(age, 3);
1136        let hlist_pat![value_field] = hlist![field].into_value_labelled();
1137
1138        // names don't have quotation marks
1139        assert!(format!("{:?}", field).contains("name: age"));
1140        assert!(format!("{:?}", value_field).contains("name: age"));
1141        // :#? works
1142        assert!(format!("{:#?}", field).contains('\n'));
1143        assert!(format!("{:#?}", value_field).contains('\n'));
1144    }
1145
1146    #[test]
1147    fn test_anonymous_record_usage() {
1148        let record = hlist![field!(name, "Joe"), field!((a, g, e), 30)];
1149        let (name, _): (Field<name, _>, _) = record.pluck();
1150        assert_eq!(name.value, "Joe")
1151    }
1152
1153    #[test]
1154    fn test_pluck_by_name() {
1155        let record = hlist![
1156            field!(is_admin, true),
1157            field!(name, "Joe".to_string()),
1158            field!((a, g, e), 30),
1159        ];
1160
1161        let (name, r): (Field<name, _>, _) = record.clone().pluck_by_name();
1162        assert_eq!(name.value, "Joe");
1163        assert_eq!(r, hlist![field!(is_admin, true), field!((a, g, e), 30),]);
1164    }
1165
1166    #[test]
1167    fn test_ref_pluck_by_name() {
1168        let record = &hlist![
1169            field!(is_admin, true),
1170            field!(name, "Joe".to_string()),
1171            field!((a, g, e), 30),
1172        ];
1173
1174        let (name, r): (Field<name, _>, _) = record.pluck_by_name();
1175        assert_eq!(name.value, "Joe");
1176        assert_eq!(r, hlist![&field!(is_admin, true), &field!((a, g, e), 30),]);
1177    }
1178
1179    #[test]
1180    fn test_unlabelling() {
1181        let labelled_hlist = hlist![field!(name, "joe"), field!((a, g, e), 3)];
1182        let unlabelled = labelled_hlist.into_unlabelled();
1183        assert_eq!(unlabelled, hlist!["joe", 3])
1184    }
1185
1186    #[test]
1187    fn test_value_labelling() {
1188        let labelled_hlist = hlist![field!(name, "joe"), field!((a, g, e), 3)];
1189        let value_labelled: HList![ValueField<&str>, ValueField<isize>] =
1190            labelled_hlist.into_value_labelled();
1191        let hlist_pat!(f1, f2) = value_labelled;
1192        assert_eq!(f1.name, "name");
1193        assert_eq!(f2.name, "age");
1194    }
1195
1196    #[test]
1197    fn test_name() {
1198        let labelled = field!(name, "joe");
1199        assert_eq!(labelled.name, "name")
1200    }
1201
1202    #[test]
1203    fn test_transmogrify_hnil_identity() {
1204        let hnil_again: HNil = HNil.transmogrify();
1205        assert_eq!(HNil, hnil_again);
1206    }
1207
1208    #[test]
1209    fn test_transmogrify_hcons_sculpting_super_simple() {
1210        type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1211        type Target = HList![Field<age, i32>];
1212        let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1213        let t_hcons: Target = hcons.transmogrify();
1214        assert_eq!(t_hcons, hlist!(field!(age, 3)));
1215    }
1216
1217    #[test]
1218    fn test_transmogrify_hcons_sculpting_somewhat_simple() {
1219        type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1220        type Target = HList![Field<is_admin, bool>, Field<name, &'static str>];
1221        let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1222        let t_hcons: Target = hcons.transmogrify();
1223        assert_eq!(t_hcons, hlist!(field!(is_admin, true), field!(name, "joe")));
1224    }
1225
1226    #[test]
1227    fn test_transmogrify_hcons_recursive_simple() {
1228        type Source = HList![
1229            Field<name,  HList![
1230                Field<inner, f32>,
1231                Field<is_admin, bool>,
1232            ]>,
1233            Field<age, i32>,
1234            Field<is_admin, bool>];
1235        type Target = HList![
1236            Field<is_admin, bool>,
1237            Field<name,  HList![
1238                Field<is_admin, bool>,
1239            ]>,
1240        ];
1241        let source: Source = hlist![
1242            field!(name, hlist![field!(inner, 42f32), field!(is_admin, true)]),
1243            field!(age, 32),
1244            field!(is_admin, true)
1245        ];
1246        let target: Target = source.transmogrify();
1247        assert_eq!(
1248            target,
1249            hlist![
1250                field!(is_admin, true),
1251                field!(name, hlist![field!(is_admin, true)]),
1252            ]
1253        )
1254    }
1255
1256    #[test]
1257    fn test_transmogrify_hcons_sculpting_required_simple() {
1258        type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1259        type Target = HList![Field<is_admin, bool>, Field<name, &'static str>, Field<age, i32>];
1260        let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1261        let t_hcons: Target = hcons.transmogrify();
1262        assert_eq!(
1263            t_hcons,
1264            hlist!(field!(is_admin, true), field!(name, "joe"), field!(age, 3))
1265        );
1266    }
1267
1268    #[test]
1269    fn test_transmogrify_identical_transform_labelled_fields() {
1270        type Source = HList![
1271            Field<name,  &'static str>,
1272            Field<age, i32>,
1273            Field<is_admin, bool>
1274        ];
1275        type Target = Source;
1276        let source: Source = hlist![field!(name, "joe"), field!(age, 32), field!(is_admin, true)];
1277        let target: Target = source.transmogrify();
1278        assert_eq!(
1279            target,
1280            hlist![field!(name, "joe"), field!(age, 32), field!(is_admin, true)]
1281        )
1282    }
1283
1284    #[test]
1285    fn test_transmogrify_through_containers() {
1286        type SourceOuter<T> = HList![
1287            Field<name, &'static str>,
1288            Field<inner, T>,
1289        ];
1290        type SourceInner = HList![
1291            Field<is_admin, bool>,
1292            Field<age, i32>,
1293        ];
1294        type TargetOuter<T> = HList![
1295            Field<name, &'static str>,
1296            Field<inner, T>,
1297        ];
1298        type TargetInner = HList![
1299            Field<age, i32>,
1300            Field<is_admin, bool>,
1301        ];
1302
1303        fn create_inner() -> (SourceInner, TargetInner) {
1304            let source_inner: SourceInner = hlist![field!(is_admin, true), field!(age, 14)];
1305            let target_inner: TargetInner = hlist![field!(age, 14), field!(is_admin, true)];
1306            (source_inner, target_inner)
1307        }
1308
1309        // Vec -> Vec
1310        let (source_inner, target_inner) = create_inner();
1311        let source: SourceOuter<Vec<SourceInner>> =
1312            hlist![field!(name, "Joe"), field!(inner, vec![source_inner])];
1313        let target: TargetOuter<Vec<TargetInner>> = source.transmogrify();
1314        assert_eq!(
1315            target,
1316            hlist![field!(name, "Joe"), field!(inner, vec![target_inner])]
1317        );
1318
1319        // LInkedList -> LinkedList
1320        let (source_inner, target_inner) = create_inner();
1321        let source_inner = {
1322            let mut list = LinkedList::new();
1323            list.push_front(source_inner);
1324            list
1325        };
1326        let target_inner = {
1327            let mut list = LinkedList::new();
1328            list.push_front(target_inner);
1329            list
1330        };
1331        let source: SourceOuter<LinkedList<SourceInner>> =
1332            hlist![field!(name, "Joe"), field!(inner, source_inner)];
1333        let target: TargetOuter<LinkedList<TargetInner>> = source.transmogrify();
1334        assert_eq!(
1335            target,
1336            hlist![field!(name, "Joe"), field!(inner, target_inner)]
1337        );
1338
1339        // VecDeque -> VecDeque
1340        let (source_inner, target_inner) = create_inner();
1341        let source_inner = {
1342            let mut list = VecDeque::new();
1343            list.push_front(source_inner);
1344            list
1345        };
1346        let target_inner = {
1347            let mut list = VecDeque::new();
1348            list.push_front(target_inner);
1349            list
1350        };
1351        let source: SourceOuter<VecDeque<SourceInner>> =
1352            hlist![field!(name, "Joe"), field!(inner, source_inner)];
1353        let target: TargetOuter<VecDeque<TargetInner>> = source.transmogrify();
1354        assert_eq!(
1355            target,
1356            hlist![field!(name, "Joe"), field!(inner, target_inner)]
1357        );
1358
1359        // Option -> Option
1360        let (source_inner, target_inner) = create_inner();
1361        let source_inner = Some(source_inner);
1362        let target_inner = Some(target_inner);
1363        let source: SourceOuter<Option<SourceInner>> =
1364            hlist![field!(name, "Joe"), field!(inner, source_inner)];
1365        let target: TargetOuter<Option<TargetInner>> = source.transmogrify();
1366        assert_eq!(
1367            target,
1368            hlist![field!(name, "Joe"), field!(inner, target_inner)]
1369        );
1370        let source: SourceOuter<Option<SourceInner>> =
1371            hlist![field!(name, "Joe"), field!(inner, None)];
1372        let target: TargetOuter<Option<TargetInner>> = source.transmogrify();
1373        assert_eq!(target, hlist![field!(name, "Joe"), field!(inner, None)]);
1374
1375        // Box -> Box
1376        let (source_inner, target_inner) = create_inner();
1377        let source_inner = Box::new(source_inner);
1378        let target_inner = Box::new(target_inner);
1379        let source: SourceOuter<Box<SourceInner>> =
1380            hlist![field!(name, "Joe"), field!(inner, source_inner)];
1381        let target: TargetOuter<Box<TargetInner>> = source.transmogrify();
1382        assert_eq!(
1383            target,
1384            hlist![field!(name, "Joe"), field!(inner, target_inner)]
1385        );
1386    }
1387
1388    //    #[test]
1389    //    fn test_transmogrify_identical_transform_nested_labelled_fields() {
1390    //        type Source = HList![
1391    //    Field<name,  HList![
1392    //        Field<inner, f32>,
1393    //        Field<is_admin, bool>,
1394    //    ]>,
1395    //    Field<age, i32>,
1396    //    Field<is_admin, bool>];
1397    //        type Target = Source;
1398    //        let source: Source = hlist![
1399    //            field!(name, hlist![field!(inner, 42f32), field!(is_admin, true)]),
1400    //            field!(age, 32),
1401    //            field!(is_admin, true)
1402    //        ];
1403    //        let target: Target = source.transmogrify();
1404    //        assert_eq!(
1405    //            target,
1406    //            hlist![
1407    //                field!(name, hlist![field!(inner, 42f32), field!(is_admin, true)]),
1408    //                field!(age, 32),
1409    //                field!(is_admin, true)
1410    //            ]
1411    //        )
1412    //    }
1413}