A Rust procedural macro that enforces strict typing on struct fields, enum variants, function signatures, trait definitions, and impl blocks. It prevents the use of bare primitive types, encouraging newtype wrappers for clarity and safety.
Rust is all about correctness in my humble opinion. And I want it to stay that way in my personal experience. I think this is how Rust should have been made. This should be a compiler built-in.
Bare primitives like u32 or bool compile fine but carry no domain meaning. A u32 could be a user ID, a pixel count, or a port number — the type system won't stop you from mixing them up. Newtype wrappers (struct UserId(u32)) make intent explicit and catch misuse at compile time.
In my projects, I always create the transparent newtypes that precisely define what they carry. If I ever need to, I also create only the correct versions of conversions between such and other types.
Originally wrote for my own projects, I decided to share it with others. Enjoy.
#[strict_types] turns this from a convention into a compiler-enforced rule.
P.S. I decided to name the project strict-typing initially with the intention to
extend its functionality.
Add the dependency:
[dependencies]
strict-typing = "0.1"use strict_typing::strict_types;
struct Percentage(u8);
struct Label(String);
#[strict_types]
struct Config {
ratio: Percentage, // OK — newtype wrapper
name: Label, // OK
// count: u32, // compile error: disallowed type `u32`
}use strict_typing::strict_types;
struct Velocity(f64);
#[strict_types]
enum Event {
Click { x: Velocity, y: Velocity },
Disconnect,
// Resize(u32, u32), // compile error
}use strict_typing::strict_types;
struct Distance(f64);
struct Speed(f64);
struct Duration(f64);
#[strict_types]
fn compute_speed(d: Distance, t: Duration) -> Speed {
Speed(d.0 / t.0)
}By default, all numeric primitives plus bool and char are disallowed. Add more with disallow(...):
use strict_typing::strict_types;
/// # Strictness
///
/// - [String] disallowed because domain names should use a newtype.
#[strict_types(disallow(String))]
struct Name {
// value: String, // compile error
}Remove types from the default disallow list with allow(...):
use strict_typing::strict_types;
/// # Strictness
///
/// - [bool] allowed here because a simple flag is sufficient.
#[strict_types(allow(bool))]
struct Flags {
enabled: bool, // OK
}When using allow(...) or disallow(...), you must document each override in a /// # Strictness doc section. This forces authors to justify every exception, keeping the decision visible in code review.
u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64 bool char
MIT