#any #adt #either #left-right #both

no-std any_of

A general optional sum of product type which can be Neither, Left, Right or Both

17 releases (10 stable)

new 2.1.0 Feb 11, 2025
2.0.0 Feb 9, 2025
1.3.4 Feb 9, 2025
0.11.0 Feb 6, 2025
0.9.2 Feb 6, 2025

#186 in Rust patterns

Download history 1914/week @ 2025-02-04

1,914 downloads per month

MIT license

310KB
1K SLoC

AnyOf : a versatile type for Rust

Rust

This project implements a flexible Algebraic Data Type : AnyOf.

AnyOf is an optional sum of product of two types,
which enables clear and safe data representations in functional and type-driven programming.

Overview

At the core of the project is the AnyOf enum, a general-purpose algebraic type, alongside additional types as EitherOf and BothOf.

These abstractions allow to express dynamic states, optional values, and branching logic in a natural and explicit manner.

Key Types

  1. AnyOf<L, R>

    • A flexible type that represents four possible states:
      • Neither: No value is present.
      • Either:
        • Left: Only the left value is present.
        • Right: Only the right value is present.
      • Both: Both values are present.
    • It combines variants in the following way:
      AnyOf<L, R> = Neither | EitherOf<L, R> | BothOf<L, R>
      
    • Its cases are:
      AnyOf(L, R) = Neither | Left(L) | Right(R) | BothOf{left: L, right: R}
      
    • This type can also be viewed as a product of two optional types:
      AnyOf<L, R>::any() -> (Option<L>, Option<R>)
      
      Cases :
      • Neither.any() returns (None, None)
      • Left(L).any() returns (Some(L), None)
      • Right(R).any() returns (None, Some(R))
      • Both(L, R).any() returns (Some(L), Some(R))
  2. EitherOf<L, R>

    • A simple sum type representing one of two values.
    • Variants:
      • Left(L)
      • Right(R)
    • Ideal for binary decision-making.
    • Implements any() too :
      • Left(L).any() returns (Some(L), None)
      • Right(R).any() returns (None, Some(R))
    • It is the type :
      EitherOf<L, R> = Left(L) | Right(R)
      
  3. BothOf<L, R>

    • A product type that pairs two values, left and right, of potentially different types.
    • Implements any() too :
      • BothOf{ left: L, right: R }.any() returns (Some(L), Some(R))
    • It is the type:
      BothOf<L, R> = {left: L, right: R}
      
    • It can be transformed into a tuple with:
      into_couple(self) -> Couple<L, R>,
    • And can be transformed from a tuple with:
      from_couple(Couple<L, R>) -> Self,
  4. Enhanced Type Composition

    • A Couple<T, U> is a (T, U),
    • A Pair<T> is a Couple<T, T>,
    • An Any<T, U> is a Couple<Option<T>, Option<U>>,
    • Complex types like AnyOf4, AnyOf8, and AnyOf16 are implemented for handling larger, structured combinations via nested AnyOf structures.
    • The LeftOrRight trait :
      • Provides the methods is_right(), is_left(), any(), left() and right().
      • Implemented by AnyOf, EitherOf and BothOf,
      • Can be implemented by a custom type.
    • Other useful traits : Unwrap<L, R>, Swap<L, R> and Map<L, R>.

Features and Utilities

  • Methods inspired by Rust's Option and Result types:

    • Creation utilities: new, new_left, new_both, etc.
    • State checks: is_neither, is_left, is_both, etc.
    • Transformations: map_left, map_right, swap, etc.
    • Unwrapping: unwrap_left, unwrap_right, unwrap_both.
  • Flexible combinations:

    • Operators :
      • + to combine AnyOf values, or,
      • - to filter AnyOf values, or,
      • ! to swap AnyOf, EitherOf and BothOf values,
      • >> to map AnyOf, EitherOf and BothOf values,
    • Default value handling and state manipulation methods.

Type diagram PNG

Download the type diagram.

Use Cases

AnyOf and its related types simplify dynamic state management and are well-suited for:

  • Branching logic in functional programming.
  • Handling optional or partial data.
  • Implementing explicit and exhaustive handling of all potential states.
  • Minimizing boilerplate for complex decision-making.

Motivation

The project aims to enrich Rust's type system with expressive and flexible types for representing data combinations and states.
It is inspired by the Haskel's Either type.

  • Unlike the Rust's Result type, the types AnyOf, EitherOf or LeftOrRight have not an "error" semantic, they are general purpose,
  • LeftOrRight<L, R>::any() can be represented by a (Option<L>, Option<R>) which is a product of two optional types, but the two types has not the same composition conciseness :
    AnyOf<AnyOf<LL, LR>, AnyOf<RL, RR>>
    vs
    (Option<(Option<LL>, Option<LR>)>, Option<(Option<RL>, Option<RR>)>)
    
    AnyOf<AnyOf<AnyOf<LLL, LLR>, AnyOf<LRL, LRR>>, AnyOf<AnyOf<RLL, RLR>, AnyOf<RRL, RRR>>>
    vs
    (Option<(Option<(Option<LLL>, Option<LLR>)>, Option<(Option<LRL>, Option<LRR>)>)>, Option<(Option<(Option<RLL>, Option<RLR>)>, Option<(Option<RRL>, Option<RRR>)>)>)
    

Status

The library may evolve following semantic versioning, so the API will be stable in a given major version.

Feedback is welcome!

License

© 2025 Sébastien Geldreich
Distributed under the MIT License.

No runtime deps