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>::Errorandio::Errorare 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 {
// ...
}