TypeFn

Trait TypeFn 

Source
pub trait TypeFn<T>
where T: ?Sized,
{ type Output: ?Sized; }
Expand description

A trait that defines a mapping between an input type and an output type.

This trait is used to map specialization types to other wrapped or associated specialization types. If generic types T1 and T2 are proven to be equivalent, then types <Mapper as TypeFn<T1>>::Output and <Mapper as TypeFn<T2>>::Output are also equivalent.

This trait can also be used to specialize generics of the third-party library types that do not implement LifetimeFree.

§Examples

Custom data encoders and decoders with customizable per-type encoding and decoding errors and optimized byte array encoding and decoding. Full example code is available at examples/encode.rs.

// ...

impl<T> Encode for [T]
where
    T: Encode,
{
    type EncodeError = T::EncodeError;

    #[inline]
    fn encode_to<W>(&self, writer: &mut W) -> Result<(), Self::EncodeError>
    where
        W: ?Sized + Write,
    {
        if let Some(spec) = Specialization::<[T], [u8]>::try_new() {
            // Specialize self from `[T; N]` to `[u32; N]`
            let bytes: &[u8] = spec.specialize_ref(self);
            // Map type specialization to its associated error specialization.
            let spec_err = spec.rev().map::<MapToEncodeError>();
            writer
                .write_all(bytes)
                // Specialize error from `io::Error` to `Self::EncodeError`.
                .map_err(|err| spec_err.specialize(err))?;
        } else {
            for item in self {
                item.encode_to(writer)?;
            }
        }
        Ok(())
    }
}

// ...

We can’t use reader.read_exact(&mut array)?; in the example above because its error variant is io::Error while the function error variant is T::Error. But we can use the same specialization, but reversed and mapped:

  • [T; N] => [u8; N],
  • with .rev(): [u8; N] => [T; N],
  • with .map::<MapError>(): <[u8; N] as Decode>::Error => <[T; N] as Decode>::Error,
  • and for the compiler <[u8; N] as Decode>::Error and io::Error are equal types, so we can specialize the error as well: io::Error => <[T; N] as Decode>::Error.

Truncated synthetic example with multiple generics specialization for a third-party type:

use try_specialize::{Specialization, TypeFn};

fn some_generic_fn<K, V>(value: hashbrown::HashMap<K, V>) -> &'static str {
    struct MapIntoHashMap;
    impl<K, V> TypeFn<(K, V)> for MapIntoHashMap {
        type Output = hashbrown::HashMap<K, V>;
    }

    if let Some(spec) = Specialization::<(K, V), (u32, char)>::try_new() {
        let spec = spec.map::<MapIntoHashMap>();
        let value = spec.specialize(value);
        specialized_impl(value)
    } else {
        default_impl(value)
    }
}

fn default_impl<K, V>(value: hashbrown::HashMap<K, V>) -> &'static str {
    // ...
}

fn specialized_impl(value: hashbrown::HashMap<u32, char>) -> &'static str {
    // ...
}

Required Associated Types§

Source

type Output: ?Sized

The returned type.

Implementors§