6 releases (3 breaking)

0.4.1 Oct 8, 2022
0.4.0 Oct 5, 2022
0.3.0 Oct 4, 2022
0.2.0 Sep 29, 2022
0.1.1 Sep 26, 2022

#11 in #contain

MIT license

25KB
590 lines

Coproduct

Have you ever found yourself in a situation where you'd like to have two enums where only a few variants differ? Usually that involves a lot of duplication and boilerplate. Not any more! Coproducts allow you to describe them and convert between them effortlessly!

use coproduct::{Coproduct, MkUnion, Union};

#[derive(Debug)]
struct A;
#[derive(Debug)]
struct B;
#[derive(Debug)]
struct C;
#[derive(Debug)]
struct D;

type ABC = MkUnion!(A, B, C);

fn main() {
    let abc: Coproduct<ABC> = Coproduct::inject(A);
    let abcd: Coproduct<Union<D, ABC>> = abc.embed();
    println!("{:?}", abcd);
}

Find out more in the documentation.


lib.rs:

Rust enums are coproducts but the datastructure provided in this library allows writing functions that operate on generic coproducts.

For instance, the below function takes any coproduct that may contain a cat.

fn is_cat<C, I>(maybe_cat: C) -> bool
where
    C: coproduct::At<I, Cat>,
{
    maybe_cat.uninject().is_ok()
}

The coproducts take as much memory as the largest variant and 32 bits for the tag, which is pretty close to optimal. They do not benefit from Rust's enum layout optimizations, but the whole reason for this crate is that those optimizations aren't perfect. Implementing a coproduct as nested enums akin to a purely functional list results in extremely high memory use. (Tested in Rust 1.66)

Another benefit is that the implementation of some functions is a lot simpler when there is no need to pretend that a nested structure is traversed. The downside is that unlike the coproduct provided by frunk, this library uses unsafe.

No runtime deps