pub trait Transmogrifier<Target, TransmogrifyIndexIndices> {
    // Required method
    fn transmogrify(self) -> Target;
}
Expand description

Trait for transmogrifying a Source type into a Target type.

What is “transmogrifying”? In this context, it means to convert some data of type A into data of type B, in a typesafe, recursive way, as long as A and B are “similarly-shaped”. In other words, as long as B’s fields and their subfields are subsets of A’s fields and their respective subfields, then A can be turned into B.

Example

// required when using custom derives
use frunk::LabelledGeneric;
use frunk::labelled::Transmogrifier;
#[derive(LabelledGeneric)]
struct InternalPhoneNumber {
    emergency: Option<usize>,
    main: usize,
    secondary: Option<usize>,
}

#[derive(LabelledGeneric)]
struct InternalAddress<'a> {
    is_whitelisted: bool,
    name: &'a str,
    phone: InternalPhoneNumber,
}

#[derive(LabelledGeneric)]
struct InternalUser<'a> {
    name: &'a str,
    age: usize,
    address: InternalAddress<'a>,
    is_banned: bool,
}

#[derive(LabelledGeneric, PartialEq, Debug)]
struct ExternalPhoneNumber {
    main: usize,
}

#[derive(LabelledGeneric, PartialEq, Debug)]
struct ExternalAddress<'a> {
    name: &'a str,
    phone: ExternalPhoneNumber,
}

#[derive(LabelledGeneric, PartialEq, Debug)]
struct ExternalUser<'a> {
    age: usize,
    address: ExternalAddress<'a>,
    name: &'a str,
}

let internal_user = InternalUser {
    name: "John",
    age: 10,
    address: InternalAddress {
        is_whitelisted: true,
        name: "somewhere out there",
        phone: InternalPhoneNumber {
            main: 1234,
            secondary: None,
            emergency: Some(5678),
        },
    },
    is_banned: true,
};

/// Boilerplate-free conversion of a top-level InternalUser into an
/// ExternalUser, taking care of subfield conversions as well.
let external_user: ExternalUser = internal_user.transmogrify();

let expected_external_user = ExternalUser {
    name: "John",
    age: 10,
    address: ExternalAddress {
        name: "somewhere out there",
        phone: ExternalPhoneNumber {
            main: 1234,
        },
    }
};

assert_eq!(external_user, expected_external_user);
Run

Credit:

  1. Haskell “transmogrify” Github repo: https://github.com/ivan-m/transmogrify

Required Methods§

source

fn transmogrify(self) -> Target

Consume this current object and return an object of the Target type.

Although similar to sculpting, transmogrifying does its job recursively.

Implementors§

source§

impl Transmogrifier<HNil, HNil> for HNil

Implementation of Transmogrifier for when the Target is empty and the Source is empty.

source§

impl<Key, Source, Target, InnerIndices> Transmogrifier<Option<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, Option<Source>>where Source: Transmogrifier<Target, InnerIndices>,

Implementation of Transmogrifier that maps over an Option in a Field, transmogrifying the contained element on the way past if present.

source§

impl<Key, Source, Target, InnerIndices> Transmogrifier<Box<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, Box<Source>>where Source: Transmogrifier<Target, InnerIndices>,

Implementation of Transmogrifier that maps over an Box in a Field, transmogrifying the contained element on the way past.

source§

impl<Key, Source, Target, InnerIndices> Transmogrifier<LinkedList<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, LinkedList<Source>>where Source: Transmogrifier<Target, InnerIndices>,

Implementation of Transmogrifier that maps over a $container in a Field, transmogrifying the elements on the way past.

source§

impl<Key, Source, Target, InnerIndices> Transmogrifier<VecDeque<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, VecDeque<Source>>where Source: Transmogrifier<Target, InnerIndices>,

Implementation of Transmogrifier that maps over a $container in a Field, transmogrifying the elements on the way past.

source§

impl<Key, Source, Target, InnerIndices> Transmogrifier<Vec<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, Vec<Source>>where Source: Transmogrifier<Target, InnerIndices>,

Implementation of Transmogrifier that maps over a $container in a Field, transmogrifying the elements on the way past.

source§

impl<Key, SourceValue> Transmogrifier<SourceValue, IdentityTransMog> for Field<Key, SourceValue>

Implementation of Transmogrifier for identity plucked Field to Field Transforms.

source§

impl<Source, Target, TransmogIndices> Transmogrifier<Target, LabelledGenericTransmogIndicesWrapper<TransmogIndices>> for Sourcewhere Source: LabelledGeneric, Target: LabelledGeneric, <Source as LabelledGeneric>::Repr: Transmogrifier<<Target as LabelledGeneric>::Repr, TransmogIndices>,

source§

impl<Source, TargetName, TargetValue, TransmogIndices> Transmogrifier<TargetValue, PluckedLabelledGenericIndicesWrapper<TransmogIndices>> for Field<TargetName, Source>where Source: LabelledGeneric + Transmogrifier<TargetValue, TransmogIndices>, TargetValue: LabelledGeneric,

source§

impl<SourceHead, SourceTail> Transmogrifier<HNil, HNil> for HCons<SourceHead, SourceTail>

Implementation of Transmogrifier for when the Target is empty and the Source is non-empty.

source§

impl<SourceHead, SourceTail, TargetHeadName, TargetHeadValue, TargetTail, PluckSourceHeadNameIndex, TransMogSourceHeadValueIndices, TransMogTailIndices> Transmogrifier<HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail>, HCons<DoTransmog<PluckSourceHeadNameIndex, TransMogSourceHeadValueIndices>, TransMogTailIndices>> for HCons<SourceHead, SourceTail>where HCons<SourceHead, SourceTail>: ByNameFieldPlucker<TargetHeadName, PluckSourceHeadNameIndex>, Field<TargetHeadName, <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<TargetHeadName, PluckSourceHeadNameIndex>>::TargetValue>: Transmogrifier<TargetHeadValue, TransMogSourceHeadValueIndices>, <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<TargetHeadName, PluckSourceHeadNameIndex>>::Remainder: Transmogrifier<TargetTail, TransMogTailIndices>,

Non-trivial implementation of Transmogrifier where similarly-shaped Source and Target types are both Labelled HLists, but do not immediately transform into one another due to mis-matched fields, possibly recursively so.

source§

impl<SourceHead, SourceTail, TargetName, TargetHead, TargetTail, TransmogHeadIndex, TransmogTailIndices> Transmogrifier<HCons<TargetHead, TargetTail>, HCons<TransmogHeadIndex, TransmogTailIndices>> for Field<TargetName, HCons<SourceHead, SourceTail>>where HCons<SourceHead, SourceTail>: Transmogrifier<HCons<TargetHead, TargetTail>, HCons<TransmogHeadIndex, TransmogTailIndices>>,

Implementation of Transmogrifier for when the target is an HList, and the Source is a plucked HList.