Github
Github Download Tests crates.io docs.rs

penum is a procedural macro that is used to make an enum conform to a given pattern that can include generics with trait bounds, which then allows for static dispatching. It's a tool for asserting how enums should look and behave through simple expressive rust grammar.

Allowing developers to assert how an enum should look and behave.

Installation

This crate is available on crates.io and can be used by adding the following to your project's Cargo.toml: toml [dependencies] penum = "0.1.14" Or run this command in your cargo project: sh $ cargo add penum

Overview

enum Foo { V1(Struct), V2(Struct), } ```

Boilerplate code for aboves examples rust struct Struct; trait Trait { fn method(&self, text: &str); } impl Trait for Struct {}

Examples

It's also possible to make an enum conform to multiple shapes by seperating a shape with | symbol, for example:

```rust

[penum( (T) | (T, T) | { num: T } where T: Copy )]

enum Foo { Bar(String), ^^^^^^ // ERROR: String doesn't implement Copy Bor(i32), Ber(u32, i32), Bur { num: f32 } } ..or if a variant doesn't match the specified `shape`: rust

[penum( (T) | (T, T) | { num: T } where T: Copy )]

enum Foo { Bar(u32), Bor(i32), Ber(u32, i32, i32), ^^^^^^^^^^^^^ // Found: Ber(u32, i32, i32) // Expected: (T) | (T, T) | { num: T } Bwr(String), ^^^^^^ // ERROR: String doesn't implement Copy Bur { num: f32 } } ```

Sometime we don't care about specifying a where clause and just want our enum to follow a specific shape. This is done by specifing _: ```rust

[penum( () | (, _) | { num: _ } )]

enum Foo { Bar(u32), Bor(i32, f32), Ber(u32, i32), Bur { num: f32 } } ```

Other times we only care about the first varaint field implementing a trait: ```rust

[penum( (T, ..) | { num: T, .. } where T: Copy )]

enum Foo { Bar(u32), Bor(i32, f32), Ber(u32, i32), Bur { num: f32 } } ```

..or you could just use impl expressions instead. ```rust

[penum( (impl Copy, ..) | { num: f32 } )]

enum Foo { Bar(u32), Bor(i32, f32), Ber(u32, i32), Bur { num: f32 } } ```

Under development

Demo

```rust use penum::shape;

trait Trait {} impl Trait for f32 {} impl Trait for i32 {}

trait Advanced {} impl Advanced for usize {}

// (T, FOO, BAR) are valid generic parameters, but (t, Foo, BaR) are not, // they are considered as concrete types.

[penum( (T, T, U) | (T, U) | { name: T } where T: Trait, U: Advanced )]

enum Vector3 { Integer(i32, f32, usize), Float(f32, i32, usize), }

[penum( { name: _, age: usize } where usize: Advanced )]

enum Strategy<'a> { V1 { name: String, age: usize }, V2 { name: usize, age: usize }, V3 { name: &'a str, age: usize }, }

[penum( { name: &'a str, age: usize } )]

enum Concrete<'a> { Static { name: &'a str, age: usize }, } ```

```rust

[penum( tuple(_) )]

enum Must<'a> { Static { name: &'a str, age: usize } ^^^^^^^^^^^^^^^^^^^^^^^^^^^ // Found: Static { name : & 'a str, age : usize } // Expected: tuple(_) } // Note that this shape has a name (tuple). Right now // it doesn't do anything,but there is an idea of using // regexp to be able to validate on Variant names too.

// Also, there is thoughts about using these Idents to // specify other rules, like if penum should auto implement // a static dispatch for a certain pattern. But this could // also be done by other rules.

[penum( tuple(T) where T: Trait )]

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait boundusize: Traitis not satisfied enum Must { Static (usize) } ```

| Traits | Supported | | ---------- | ------------- | |Any| :heavycheckmark: supported | |Borrow| :heavycheckmark: supported | |BorrowMut| :heavycheckmark: supported | |Eq| :heavycheckmark: supported | |AsMut| :heavycheckmark: supported | |AsRef| :heavycheckmark: supported | |From| :heavycheckmark: supported | |Into| :heavycheckmark: supported | |TryFrom| :heavycheckmark: supported | |TryInto| :heavycheckmark: supported | |Default| :heavycheckmark: supported | |Binary| :heavycheckmark: supported | |Debug| :heavycheckmark: supported | |Display| :heavycheckmark: supported | |LowerExp| :heavycheckmark: supported | |LowerHex| :heavycheckmark: supported | |Octal| :heavycheckmark: supported | |Pointer| :heavycheckmark: supported | |UpperExp| :heavycheckmark: supported | |UpperHex| :heavycheckmark: supported | |Future| :heavycheckmark: supported | |IntoFuture| :heavycheckmark: supported | |FromIterator| :heavycheckmark: supported | |FusedIterator| :heavycheckmark: supported | |IntoIterator| :heavycheckmark: supported | |Product| :heavycheckmark: supported | |Sum| :heavycheckmark: supported | |Copy| :heavycheckmark: supported | |Sized| :heavycheckmark: supported | |ToSocketAddrs| :heavycheckmark: supported | |Add| :heavycheckmark: supported | |AddAssign| :heavycheckmark: supported | |BitAnd| :heavycheckmark: supported | |BitAndAssign| :heavycheckmark: supported | |BitOr| :heavycheckmark: supported | |BitOrAssign| :heavycheckmark: supported | |BitXor| :heavycheckmark: supported | |BitXorAssign| :heavycheckmark: supported | |Deref| :heavycheckmark: supported | |DerefMut| :heavycheckmark: supported | |Div| :heavycheckmark: supported | |DivAssign| :heavycheckmark: supported | |Drop| :heavycheckmark: supported | |Fn| :heavycheckmark: supported | |FnMut| :heavycheckmark: supported | |FnOnce| :heavycheckmark: supported | |Index| :heavycheckmark: supported | |IndexMut| :heavycheckmark: supported | |Mul| :heavycheckmark: supported | |MulAssign| :heavycheckmark: supported | |MultiMethod| :heavycheckmark: supported | |Neg| :heavycheckmark: supported | |Not| :heavycheckmark: supported | |Rem| :heavycheckmark: supported | |RemAssign| :heavycheckmark: supported | |Shl| :heavycheckmark: supported | |ShlAssign| :heavycheckmark: supported | |Shr| :heavycheckmark: supported | |ShrAssign| :heavycheckmark: supported | |Sub| :heavycheckmark: supported | |SubAssign| :heavycheckmark: supported | |Termination| :heavycheckmark: supported | |SliceIndex| :heavycheckmark: supported | |FromStr| :heavycheckmark: supported | |ToString| :heavycheckmark: supported |

Unsupported