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>
(callsnew
),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
andto_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.
- Contiguous, literal discriminants: defines
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.