Skip to main content

Enumerable

Trait Enumerable 

Source
pub trait Enumerable<Enum> {
    // Required method
    fn into_enum(self) -> Enum;
}
Expand description

A type that can be turned into the enum of its sealed trait.

enumerate implements this for every permitted type, and makes Enumerable<AnyShape> a supertrait of the sealed trait. Naming the enum in the bound is what lets a caller reach it through the trait alone:

use closed_trait::{enumerate, sealed};

pub struct Square { pub side: i32 }
pub struct Circle { pub radius: i32 }

#[enumerate]
#[sealed(Square, Circle)]
pub trait Shape {}

impl Shape for Square {}
impl Shape for Circle {}

/// Generic over the trait, yet able to match exhaustively.
fn corners<S: Shape>(shape: S) -> u32 {
    match shape.into_enum() {
        AnyShape::Square(_) => 4,
        AnyShape::Circle(_) => 0,
    }
}

fn main() {
    assert_eq!(corners(Square { side: 1 }), 4);
    assert_eq!(corners(Circle { radius: 1 }), 0);
}

Note that Enumerable did not have to be imported above: the supertrait bound brings into_enum into scope through S: Shape. Calling it on a concrete type rather than a generic one does need the import.

The enum is a type parameter rather than an associated type so that one type can belong to several sealed traits at once, since an associated type could only be chosen once per implementor. The cost is that into_enum on a concrete type belonging to more than one needs the target spelled out, by annotation or turbofish. From sidesteps that, since the enum is named by the conversion itself.

From is implemented alongside it in the other direction, so AnyShape::from(square) and square.into() work too.

Required Methods§

Source

fn into_enum(self) -> Enum

Wraps self in the variant of Enum that holds this type.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§