Crate subtype_macro

Crate subtype_macro 

Source
Expand description

§#[subtype] procedural macro

This crate provides a single attribute macro, #[subtype], that eliminates boilerplate for integer-backed tuple newtypes (a.k.a. “subtypes”) and C-like enums.

§Struct mode (tuple newtypes over primitive integers)

Attach #[subtype(min = <expr>, max = <expr>)] to a tuple struct with one primitive integer field (e.g. u32, i64, usize, …). The macro generates:

  • const MIN / const MAX using your expressions,
  • constructor new(value) -> Result<Self, E> (with range checks),
  • TryFrom<Inner> (calls new),
  • From<Self> for Inner, Deref<Target=Inner>, AsRef<Inner>, Borrow<Inner>,
  • Display (delegates to the inner value).

Optionally specify a custom error type via error = "my::Error" or error(my::Error). Your error must implement From<SubtypeError<Inner>>.

§Enum mode (C-like enums with explicit #[repr(<int>)])

Attach #[subtype] to a C-like enum that has an explicit integer repr (e.g. #[repr(u8)]). The macro generates:

  • Display as the numeric representation,
  • From<Enum> for repr and to_repr(),
  • TryFrom<repr> with two paths:
    • Contiguous, literal discriminants: defines MIN/MAX and uses a bounds check + transmute (see safety note below).
    • Otherwise: matches explicitly on known discriminants.

You may provide a custom error type via error = "my::Error" / error(my::Error). Otherwise, a small enum-specific error type is generated.

§Safety note (enum fast-path)

When all discriminants are integer literals forming a contiguous range, the macro uses unsafe transmute::<repr, Enum>(x) after verifying x is within [MIN, MAX]. This is sound because every integer in the checked range maps to a valid variant.

§Examples

§1) Integer subtype

use subtype_rs::subtype;

#[subtype(min = 0u16, max = 100u16)]
pub struct Percent(u16);

let p = Percent::new(42).unwrap();
assert_eq!(*p, 42);
assert!(Percent::new(200).is_err());

With a custom error:

use subtype_rs::{subtype, SubtypeError};

#[derive(Debug)]
enum MyErr { TooSmall(u8), TooLarge(u8) }
impl From<SubtypeError<u8>> for MyErr {
    fn from(e: SubtypeError<u8>) -> Self {
        match e {
            SubtypeError::BelowMinimum(v) => MyErr::TooSmall(v),
            SubtypeError::AboveMaximum(v) => MyErr::TooLarge(v),
        }
    }
}

#[subtype(min = 10u8, max = 20u8, error = "MyErr")]
pub struct Tiny(u8);

§2) C-like enum

use subtype_rs::subtype;

#[repr(u8)]
#[subtype]
enum Code { A = 1, B = 2, C = 3 }

assert_eq!(u8::from(Code::B), 2);
assert_eq!(Code::B.to_repr(), 2);
assert_eq!(format!("{}", Code::B), "2");

Attribute Macros§

subtype
Attribute macro entry point for both struct mode and enum mode.