nulid_derive
Derive macros for types that wrap Nulid.
This crate provides procedural macros to automatically implement common traits for newtype wrappers around Nulid, eliminating boilerplate code.
Features
Core Traits
The Id derive macro automatically implements:
TryFrom<String>- Parse from owned StringTryFrom<&str>- Parse from string sliceFrom<Nulid>- Create wrapper from NulidFrom<WrapperType> for Nulid- Extract inner NulidAsRef<Nulid>- Borrow inner NulidDeref<Target = Nulid>- Direct access to all Nulid methodsDerefMut- Mutable access to inner Nulidstd::fmt::Display- Format as Base32 stringstd::fmt::Debug- Debug formattingstd::str::FromStr- Parse from string using.parse()Copy- Value semantics (automatically providesClone)PartialEqandEq- Equality comparison with other wrappersPartialEq<Nulid>- Direct equality comparison withNulidPartialOrdandOrd- Ordering comparison with other wrappersPartialOrd<Nulid>- Direct ordering comparison withNulidHash- Hashing support for collectionsDefault- Creates a default instance withNulid::ZERO
Constructor Methods
It also provides:
new()method - Creates a new instance with a freshly generatedNulidnow()method - Alias fornew()nil()method - Creates a nil/zero instancemin()method - Returns the minimum possible instancemax()method - Returns the maximum possible instancefrom_datetime(SystemTime)- Creates from specific timefrom_nanos(u128, u64)- Creates from timestamp and randomfrom_u128(u128)- Creates from raw u128from_bytes([u8; 16])- Creates from byte array
Feature-Gated Traits
When the corresponding features are enabled, additional trait implementations are automatically generated:
serde feature
Serialize- Serialization support for JSON, bincode, etc.Deserialize- Deserialization support
[]
# The 'serde' feature is automatically propagated to nulid_derive
= { = "0.5.7", = ["derive", "serde"] }
use Id;
use ;
// Automatically implements Serialize + Deserialize
;
uuid feature
From<uuid::Uuid>- Convert from UUIDInto<uuid::Uuid>- Convert to UUIDto_uuid()method - Convert to UUIDfrom_uuid(Uuid)method - Create from UUID
[]
# The 'uuid' feature is automatically propagated to nulid_derive
= { = "0.5.7", = ["derive", "uuid"] }
use Id;
use Uuid;
// Automatically implements UUID conversions
;
sqlx feature
Type<Postgres>- PostgreSQL type supportEncode<Postgres>- Encoding for PostgreSQLDecode<Postgres>- Decoding from PostgreSQLPgHasArrayType- Array type support
[]
# The 'sqlx' feature is automatically propagated to nulid_derive
= { = "0.5.7", = ["derive", "sqlx"] }
= { = "0.8", = ["postgres", "uuid"] }
use Id;
use PgPool;
// Automatically implements SQLx traits
;
async
postgres-types feature
FromSql- Deserialize from PostgreSQLToSql- Serialize to PostgreSQL
[]
# The 'postgres-types' feature is automatically propagated to nulid_derive
= { = "0.5.7", = ["derive", "postgres-types"] }
= "0.2"
use Id;
use ;
// Automatically implements ToSql + FromSql
;
// Can now be used with the postgres crate
// let row = client.query_one("SELECT id FROM users WHERE id = $1", &[&user_id])?;
rkyv feature
For rkyv zero-copy serialization support, you need to manually add the derive attributes to your wrapper type since proc macros cannot add attributes to the struct definition:
[]
= { = "0.5.7", = ["derive", "rkyv"] }
= "0.8"
use Id;
;
Feature Propagation
Important: When you enable the derive feature along with other features (like serde, uuid, sqlx, or postgres-types) on the nulid crate, those features are automatically propagated to nulid_derive. You don't need to enable them separately on both crates.
# ✓ Correct - features are automatically propagated to nulid_derive
[]
= { = "0.5.7", = ["derive", "serde", "uuid", "sqlx"] }
# ✗ Not necessary - you don't need to enable features on nulid_derive manually
[]
= { = "0.5.7", = ["derive", "serde"] }
= { = "0.5.7", = ["serde"] } # This is redundant
This automatic propagation works for all feature-gated traits:
serde→ enablesSerializeandDeserializeimplementationsuuid→ enables UUID conversion traitssqlx→ enables SQLx PostgreSQL traitspostgres-types→ enablesFromSqlandToSqltraits
Basic Usage
Add this to your Cargo.toml:
[]
= { = "0.5.7", = ["derive"] }
Then use the derive macro on your wrapper types:
use ;
;
;
Direct Access to Nulid Methods
With Deref and DerefMut traits, wrapper types can directly access all Nulid methods without needing to extract or dereference the inner value:
use Id;
;
Requirements
The derive macro requires:
- The type must be a tuple struct
- It must have exactly one field
- That field must be of type
Nulid
Valid examples:
; // ✓ Private field
; // ✓ Public field
Invalid examples:
; // ✗ Multiple fields
; // ✗ Wrong type
Type Safety
Using wrapper types provides type safety by preventing accidental mixing of different ID types:
use ;
;
;
let user_id = from;
let order_id = from;
process_user; // ✓ Correct type
// process_user(order_id); // ✗ Compile error: expected UserId, found OrderId
Error Handling
All parsing methods return Result<T, nulid::Error>, allowing proper error handling:
use ;
;
match try_from
Integration with Other Traits
The derive macro works well with other derive macros and automatically provides feature-gated trait implementations:
use ;
;
// Standard traits are automatically implemented:
// Debug, Copy (Clone), PartialEq, Eq, Hash, PartialOrd, Ord
// With features enabled, additional traits are automatically implemented:
// - serde feature: Serialize, Deserialize
// - uuid feature: From<Uuid>, Into<Uuid>
// - sqlx feature: Type<Postgres>, Encode, Decode
// - postgres-types feature: FromSql, ToSql
Combining Multiple Features
You can enable multiple features at once to get all the trait implementations you need:
[]
= { = "0.5.7", = ["derive", "serde", "uuid", "sqlx"] }
use Id;
;
// Now UserId automatically implements:
// - All core traits (Debug, Copy, PartialEq, etc.)
// - Serde traits (Serialize, Deserialize)
// - UUID conversions (From<Uuid>, Into<Uuid>)
// - SQLx traits (Type<Postgres>, Encode, Decode)
// Plus all the constructor methods (new, nil, min, max, etc.)
Examples
See the examples directory in the nulid repository for more usage examples.
License
This project is licensed under the MIT License - see the LICENSE file for details.