[][src]Enum frunk::coproduct::Coproduct

pub enum Coproduct<H, T> {
    Inl(H),
    Inr(T),
}

Enum type representing a Coproduct. Think of this as a Result, but capable of supporting any arbitrary number of types instead of just 2.

To construct a Coproduct, you would typically declare a type using the Coprod! type macro and then use the inject method.

Examples

type I32Bool = Coprod!(i32, bool);
let co1 = I32Bool::inject(3);
let get_from_1a: Option<&i32> = co1.get();
let get_from_1b: Option<&bool> = co1.get();
assert_eq!(get_from_1a, Some(&3));
assert_eq!(get_from_1b, None);Run

Variants

Inl(H)

Coproduct is either H or T, in this case, it is H

Inr(T)

Coproduct is either H or T, in this case, it is T

Methods

impl<Head, Tail> Coproduct<Head, Tail>[src]

pub fn inject<T, Index>(to_insert: T) -> Coproduct<Head, Tail> where
    Coproduct<Head, Tail>: CoprodInjector<T, Index>, 
[src]

Instantiate a coproduct from an element.

This is generally much nicer than nested usage of Coproduct::{Inl, Inr}. The method uses a trick with type inference to automatically build the correct variant according to the input type.

In standard usage, the Index type parameter can be ignored, as it will typically be solved for using type inference.

Rules

If the type does not appear in the coproduct, the conversion is forbidden.

If the type appears multiple times in the coproduct, type inference will fail.

Example

use frunk::Coproduct;

type I32F32 = Coprod!(i32, f32);

// Constructing coproducts using inject:
let co1_nice: I32F32 = Coproduct::inject(1i32);
let co2_nice: I32F32 = Coproduct::inject(42f32);

// Compare this to the "hard way":
let co1_ugly: I32F32 = Coproduct::Inl(1i32);
let co2_ugly: I32F32 = Coproduct::Inr(Coproduct::Inl(42f32));

assert_eq!(co1_nice, co1_ugly);
assert_eq!(co2_nice, co2_ugly);

// Feel free to use `inject` on a type alias, or even directly on the
// `Coprod!` macro. (the latter requires wrapping the type in `<>`)
let _ = I32F32::inject(42f32);
let _ = <Coprod!(i32, f32)>::inject(42f32);

// You can also use a turbofish to specify the type of the input when
// it is ambiguous (e.g. an empty `vec![]`).
// The Index parameter should be left as `_`.
type Vi32Vf32 = Coprod!(Vec<i32>, Vec<f32>);
let _: Vi32Vf32 = Coproduct::inject::<Vec<i32>, _>(vec![]);Run

pub fn get<S, Index>(&self) -> Option<&S> where
    Coproduct<Head, Tail>: CoproductSelector<S, Index>, 
[src]

Borrow an element from a coproduct by type.

Example

type I32F32 = Coprod!(i32, f32);

// You can let type inference find the desired type:
let co1 = I32F32::inject(42f32);
let co1_as_i32: Option<&i32> = co1.get();
let co1_as_f32: Option<&f32> = co1.get();
assert_eq!(co1_as_i32, None);
assert_eq!(co1_as_f32, Some(&42f32));

// You can also use turbofish syntax to specify the type.
// The Index parameter should be left as `_`.
let co2 = I32F32::inject(1i32);
assert_eq!(co2.get::<i32, _>(), Some(&1));
assert_eq!(co2.get::<f32, _>(), None);Run

pub fn take<T, Index>(self) -> Option<T> where
    Coproduct<Head, Tail>: CoproductTaker<T, Index>, 
[src]

Retrieve an element from a coproduct by type, ignoring all others.

Example

type I32F32 = Coprod!(i32, f32);

// You can let type inference find the desired type:
let co1 = I32F32::inject(42f32);
let co1_as_i32: Option<i32> = co1.take();
let co1_as_f32: Option<f32> = co1.take();
assert_eq!(co1_as_i32, None);
assert_eq!(co1_as_f32, Some(42f32));

// You can also use turbofish syntax to specify the type.
// The Index parameter should be left as `_`.
let co2 = I32F32::inject(1i32);
assert_eq!(co2.take::<i32, _>(), Some(1));
assert_eq!(co2.take::<f32, _>(), None);Run

pub fn uninject<T, Index>(
    self
) -> Result<T, <Coproduct<Head, Tail> as CoprodUninjector<T, Index>>::Remainder> where
    Coproduct<Head, Tail>: CoprodUninjector<T, Index>, 
[src]

Attempt to extract a value from a coproduct (or get the remaining possibilities).

By chaining calls to this, one can exhaustively match all variants of a coproduct.

Examples

Basic usage:

type I32F32 = Coprod!(i32, f32);
type I32 = Coprod!(i32); // remainder after uninjecting f32
type F32 = Coprod!(f32); // remainder after uninjecting i32

let co1 = I32F32::inject(42f32);

// You can let type inference find the desired type.
let co1 = I32F32::inject(42f32);
let co1_as_i32: Result<i32, F32> = co1.uninject();
let co1_as_f32: Result<f32, I32> = co1.uninject();
assert_eq!(co1_as_i32, Err(F32::inject(42f32)));
assert_eq!(co1_as_f32, Ok(42f32));

// It is not necessary to annotate the type of the remainder:
let res: Result<i32, _> = co1.uninject();
assert!(res.is_err());

// You can also use turbofish syntax to specify the type.
// The Index parameter should be left as `_`.
let co2 = I32F32::inject(1i32);
assert_eq!(co2.uninject::<i32, _>(), Ok(1));
assert_eq!(co2.uninject::<f32, _>(), Err(I32::inject(1)));Run

Chaining calls for an exhaustive match:

type I32F32 = Coprod!(i32, f32);

// Be aware that this particular example could be
// written far more succinctly using `fold`.
fn handle_i32_f32(co: I32F32) -> &'static str {
    // Remove i32 from the coproduct
    let co = match co.uninject::<i32, _>() {
        Ok(x) => return "integer!",
        Err(co) => co,
    };

    // Remove f32 from the coproduct
    let co = match co.uninject::<f32, _>() {
        Ok(x) => return "float!",
        Err(co) => co,
    };

    // Now co is empty
    match co { /* unreachable */ }
}

assert_eq!(handle_i32_f32(I32F32::inject(3)), "integer!");
assert_eq!(handle_i32_f32(I32F32::inject(3.0)), "float!");Run

pub fn subset<Targets, Indices>(
    self
) -> Result<Targets, <Coproduct<Head, Tail> as CoproductSubsetter<Targets, Indices>>::Remainder> where
    Coproduct<Head, Tail>: CoproductSubsetter<Targets, Indices>, 
[src]

Extract a subset of the possible types in a coproduct (or get the remaining possibilities)

This is basically uninject on steroids. It lets you remove a number of types from a coproduct at once, leaving behind the remainder in an Err. For instance, one can extract Coprod!(C, A) from Coprod!(A, B, C, D) to produce Result<Coprod!(C, A), Coprod!(B, D)>.

Each type in the extracted subset is required to be part of the input coproduct.

Example

Basic usage:

use ::frunk::Coproduct;

type I32BoolF32 = Coprod!(i32, bool, f32);
type I32F32 = Coprod!(i32, f32);

let co1 = I32BoolF32::inject(42_f32);
let co2 = I32BoolF32::inject(true);

let sub1: Result<Coprod!(i32, f32), _> = co1.subset();
let sub2: Result<Coprod!(i32, f32), _> = co2.subset();
assert!(sub1.is_ok());
assert!(sub2.is_err());

// Turbofish syntax for specifying the target subset is also supported.
// The Indices parameter should be left to type inference using `_`.
assert!(co1.subset::<Coprod!(i32, f32), _>().is_ok());
assert!(co2.subset::<Coprod!(i32, f32), _>().is_err());

// Order doesn't matter.
assert!(co1.subset::<Coprod!(f32, i32), _>().is_ok());Run

Like uninject, subset can be used for exhaustive matching, with the advantage that it can remove more than one type at a time:

use frunk::Coproduct;

fn handle_stringly_things(co: Coprod!(&'static str, String)) -> String {
    co.fold(hlist![
        |s| format!("&str {}", s),
        |s| format!("String {}", s),
    ])
}

fn handle_countly_things(co: Coprod!(u32)) -> String {
    co.fold(hlist![
        |n| vec!["."; n as usize].concat(),
    ])
}

fn handle_all(co: Coprod!(String, u32, &'static str)) -> String {
    // co is currently Coprod!(String, u32, &'static str)
    let co = match co.subset().map(handle_stringly_things) {
        Ok(s) => return s,
        Err(co) => co,
    };

    // Now co is Coprod!(u32).
    let co = match co.subset().map(handle_countly_things) {
        Ok(s) => return s,
        Err(co) => co,
    };

    // Now co is empty.
    match co { /* unreachable */ }
}

assert_eq!(handle_all(Coproduct::inject("hello")), "&str hello");
assert_eq!(handle_all(Coproduct::inject(String::from("World!"))), "String World!");
assert_eq!(handle_all(Coproduct::inject(4)), "....");Run

pub fn embed<Targets, Indices>(self) -> Targets where
    Coproduct<Head, Tail>: CoproductEmbedder<Targets, Indices>, 
[src]

Convert a coproduct into another that can hold its variants.

This converts a coproduct into another one which is capable of holding each of its types. The most well-supported use-cases (i.e. those where type inference is capable of solving for the indices) are:

  • Reordering variants: Coprod!(C, A, B) -> Coprod!(A, B, C)
  • Embedding into a superset: Coprod!(B, D) -> Coprod!(A, B, C, D, E)
  • Coalescing duplicate inputs: Coprod!(B, B, B, B) -> Coprod!(A, B, C)

and of course any combination thereof.

Rules

If any type in the input does not appear in the output, the conversion is forbidden.

If any type in the input appears multiple times in the output, type inference will fail.

All of these rules fall naturally out of its fairly simple definition, which is equivalent to:

coprod.fold(hlist![
    |x| Coproduct::inject(x),
    |x| Coproduct::inject(x),
            ...
    |x| Coproduct::inject(x),
])

Example

type I32BoolF32 = Coprod!(i32, bool, f32);
type BoolI32 = Coprod!(bool, i32);

let co = BoolI32::inject(true);
let embedded: I32BoolF32 = co.embed();
assert_eq!(embedded, I32BoolF32::inject(true));

// Turbofish syntax for specifying the output type is also supported.
// The Indices parameter should be left to type inference using `_`.
let embedded = co.embed::<I32BoolF32, _>();
assert_eq!(embedded, I32BoolF32::inject(true));Run

pub fn to_ref<'a>(&'a self) -> <Coproduct<Head, Tail> as ToRef<'a>>::Output where
    Coproduct<Head, Tail>: ToRef<'a>, 
[src]

Borrow each variant of the Coproduct.

Example

Composing with subset to match a subset of variants without consuming the coproduct:

use frunk::Coproduct;

let co: Coprod!(i32, bool, String) = Coproduct::inject(true);

assert!(co.to_ref().subset::<Coprod!(&bool, &String), _>().is_ok());Run

pub fn to_mut<'a>(&'a mut self) -> <Coproduct<Head, Tail> as ToMut<'a>>::Output where
    Coproduct<Head, Tail>: ToMut<'a>, 
[src]

Borrow each variant of the Coproduct mutably.

Example

Composing with subset to match a subset of variants without consuming the coproduct:

use frunk::Coproduct;

let mut co: Coprod!(i32, bool, String) = Coproduct::inject(true);

assert!(co.to_mut().subset::<Coprod!(&mut bool, &mut String), _>().is_ok());Run

pub fn fold<Output, Folder>(self, folder: Folder) -> Output where
    Coproduct<Head, Tail>: CoproductFoldable<Folder, Output>, 
[src]

Use functions to transform a Coproduct into a single value.

A variety of types are supported for the Folder argument:

  • An hlist![] of closures (one for each type, in order).
  • A single closure (for a Coproduct that is homogenous).
  • A single Poly.

Example

type I32F32StrBool = Coprod!(i32, f32, bool);

let co1 = I32F32StrBool::inject(3);
let co2 = I32F32StrBool::inject(true);
let co3 = I32F32StrBool::inject(42f32);

let folder = hlist![|&i| format!("int {}", i),
                    |&f| format!("float {}", f),
                    |&b| (if b { "t" } else { "f" }).to_string()];

assert_eq!(co1.to_ref().fold(folder), "int 3".to_string());Run

Using a polymorphic function type has the advantage of not forcing you to care about the order in which you declare handlers for the types in your Coproduct.

use frunk::{Poly, Func};

type I32F32StrBool = Coprod!(i32, f32, bool);

impl Func<i32> for P {
    type Output = bool;
    fn call(args: i32) -> Self::Output {
        args > 100
    }
}
impl Func<bool> for P {
    type Output = bool;
    fn call(args: bool) -> Self::Output {
        args
    }
}
impl Func<f32> for P {
    type Output = bool;
    fn call(args: f32) -> Self::Output {
        args > 9000f32
    }
}
struct P;

let co1 = I32F32StrBool::inject(3);
let folded = co1.fold(Poly(P));Run

Trait Implementations

impl<H, T> Clone for Coproduct<H, T> where
    H: Clone,
    T: Clone
[src]

impl<I, Tail> CoprodInjector<I, Here> for Coproduct<I, Tail>[src]

impl<Head, I, Tail, TailIndex> CoprodInjector<I, There<TailIndex>> for Coproduct<Head, Tail> where
    Tail: CoprodInjector<I, TailIndex>, 
[src]

impl<Hd, Tl> CoprodUninjector<Hd, Here> for Coproduct<Hd, Tl>[src]

type Remainder = Tl

impl<Hd, Tl, T, N> CoprodUninjector<T, There<N>> for Coproduct<Hd, Tl> where
    Tl: CoprodUninjector<T, N>, 
[src]

type Remainder = Coproduct<Hd, <Tl as CoprodUninjector<T, N>>::Remainder>

impl<Head, Tail> CoproductEmbedder<Coproduct<Head, Tail>, HNil> for CNil where
    CNil: CoproductEmbedder<Tail, HNil>, 
[src]

impl<Head, Tail, Out, NHead, NTail> CoproductEmbedder<Out, HCons<NHead, NTail>> for Coproduct<Head, Tail> where
    Out: CoprodInjector<Head, NHead>,
    Tail: CoproductEmbedder<Out, NTail>, 
[src]

impl<F, R, FTail, CH, CTail> CoproductFoldable<HCons<F, FTail>, R> for Coproduct<CH, CTail> where
    CTail: CoproductFoldable<FTail, R>,
    F: FnOnce(CH) -> R, 
[src]

impl<P, R, CH, CTail> CoproductFoldable<Poly<P>, R> for Coproduct<CH, CTail> where
    CTail: CoproductFoldable<Poly<P>, R>,
    P: Func<CH, Output = R>, 
[src]

impl<Head, FromTail, Tail, TailIndex> CoproductSelector<FromTail, There<TailIndex>> for Coproduct<Head, Tail> where
    Tail: CoproductSelector<FromTail, TailIndex>, 
[src]

impl<Head, Tail> CoproductSelector<Head, Here> for Coproduct<Head, Tail>[src]

impl<Choices, THead, TTail, NHead, NTail, Rem> CoproductSubsetter<Coproduct<THead, TTail>, HCons<NHead, NTail>> for Choices where
    Choices: CoprodUninjector<THead, NHead, Remainder = Rem>,
    Rem: CoproductSubsetter<TTail, NTail>, 
[src]

type Remainder = <Rem as CoproductSubsetter<TTail, NTail>>::Remainder

fn subset(
    self
) -> Result<Coproduct<THead, TTail>, <Choices as CoproductSubsetter<Coproduct<THead, TTail>, HCons<NHead, NTail>>>::Remainder>
[src]

Attempt to extract a value from a subset of the types.

impl<Head, FromTail, Tail, TailIndex> CoproductTaker<FromTail, There<TailIndex>> for Coproduct<Head, Tail> where
    Tail: CoproductTaker<FromTail, TailIndex>, 
[src]

impl<Head, Tail> CoproductTaker<Head, Here> for Coproduct<Head, Tail>[src]

impl<H, T> Copy for Coproduct<H, T> where
    H: Copy,
    T: Copy
[src]

impl<H, T> Debug for Coproduct<H, T> where
    H: Debug,
    T: Debug
[src]

impl<H, T> Eq for Coproduct<H, T> where
    H: Eq,
    T: Eq
[src]

impl<H, T> Hash for Coproduct<H, T> where
    H: Hash,
    T: Hash
[src]

impl<H, T> Ord for Coproduct<H, T> where
    H: Ord,
    T: Ord
[src]

impl<H, T> PartialEq<Coproduct<H, T>> for Coproduct<H, T> where
    H: PartialEq<H>,
    T: PartialEq<T>, 
[src]

impl<H, T> PartialOrd<Coproduct<H, T>> for Coproduct<H, T> where
    H: PartialOrd<H>,
    T: PartialOrd<T>, 
[src]

impl<H, T> StructuralEq for Coproduct<H, T>[src]

impl<H, T> StructuralPartialEq for Coproduct<H, T>[src]

impl<'a, CH, CTail> ToMut<'a> for Coproduct<CH, CTail> where
    CH: 'a,
    CTail: ToMut<'a>, 
[src]

type Output = Coproduct<&'a mut CH, <CTail as ToMut<'a>>::Output>

impl<'a, CH, CTail> ToRef<'a> for Coproduct<CH, CTail> where
    CH: 'a,
    CTail: ToRef<'a>, 
[src]

type Output = Coproduct<&'a CH, <CTail as ToRef<'a>>::Output>

Auto Trait Implementations

impl<H, T> RefUnwindSafe for Coproduct<H, T> where
    H: RefUnwindSafe,
    T: RefUnwindSafe

impl<H, T> Send for Coproduct<H, T> where
    H: Send,
    T: Send

impl<H, T> Sync for Coproduct<H, T> where
    H: Sync,
    T: Sync

impl<H, T> Unpin for Coproduct<H, T> where
    H: Unpin,
    T: Unpin

impl<H, T> UnwindSafe for Coproduct<H, T> where
    H: UnwindSafe,
    T: UnwindSafe

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Choices> CoproductSubsetter<CNil, HNil> for Choices[src]

type Remainder = Choices

impl<Choices, THead, TTail, NHead, NTail, Rem> CoproductSubsetter<Coproduct<THead, TTail>, HCons<NHead, NTail>> for Choices where
    Choices: CoprodUninjector<THead, NHead, Remainder = Rem>,
    Rem: CoproductSubsetter<TTail, NTail>, 
[src]

type Remainder = <Rem as CoproductSubsetter<TTail, NTail>>::Remainder

fn subset(
    self
) -> Result<Coproduct<THead, TTail>, <Choices as CoproductSubsetter<Coproduct<THead, TTail>, HCons<NHead, NTail>>>::Remainder>
[src]

Attempt to extract a value from a subset of the types.

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U, I> LiftInto<U, I> for T where
    U: LiftFrom<T, I>, 
[src]

impl<Source> Sculptor<HNil, HNil> for Source[src]

type Remainder = Source

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.