nulid_derive 0.5.2

Derive macros for nulid wrapper types
Documentation
# 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

The `Id` derive macro automatically implements:

- `TryFrom<String>` - Parse from owned String
- `TryFrom<&str>` - Parse from string slice
- `From<Nulid>` - Create wrapper from Nulid
- `From<WrapperType> for Nulid` - Extract inner Nulid
- `AsRef<Nulid>` - Borrow inner Nulid
- `std::fmt::Display` - Format as Base32 string
- `std::fmt::Debug` - Debug formatting
- `std::str::FromStr` - Parse from string using `.parse()`
- `Copy` - Value semantics (automatically provides `Clone`)
- `PartialEq` and `Eq` - Equality comparison with other wrappers
- `PartialEq<Nulid>` - Direct equality comparison with `Nulid`
- `PartialOrd` and `Ord` - Ordering comparison with other wrappers
- `PartialOrd<Nulid>` - Direct ordering comparison with `Nulid`
- `Hash` - Hashing support for collections

## Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
nulid = { version = "0.5", features = ["derive"] }
```

Then use the derive macro on your wrapper types:

```rust
use nulid::{Nulid, Id};

#[derive(Id)]
pub struct UserId(Nulid);

#[derive(Id)]
pub struct OrderId(pub Nulid);

fn main() -> nulid::Result<()> {
    // Parse from &str
    let user_id = UserId::try_from("01H0JQ4VEFSBV974PRXXWEK5ZW")?;

    // Parse from String
    let user_id2 = UserId::try_from("01H0JQ4VEFSBV974PRXXWEK5ZW".to_string())?;

    // Parse using FromStr
    let user_id3: UserId = "01H0JQ4VEFSBV974PRXXWEK5ZW".parse()?;

    // Create from Nulid
    let nulid = Nulid::new()?;
    let order_id = OrderId::from(nulid);

    // Extract inner Nulid
    let back_to_nulid: Nulid = order_id.into();

    // Borrow inner Nulid
    let nulid_ref: &Nulid = order_id.as_ref();

    // Display as string
    println!("User ID: {}", user_id);

    // Direct comparison with Nulid
    assert_eq!(order_id, nulid);
    assert!(order_id <= nulid);

    Ok(())
}
```

## Requirements

The derive macro requires:

1. The type must be a tuple struct
2. It must have exactly one field
3. That field must be of type `Nulid`

Valid examples:

```rust
#[derive(Id)]
pub struct UserId(Nulid);           // ✓ Private field

#[derive(Id)]
pub struct OrderId(pub Nulid);      // ✓ Public field
```

Invalid examples:

```rust
#[derive(Id)]
pub struct UserId {                 // ✗ Not a tuple struct
    nulid: Nulid,
}

#[derive(Id)]
pub struct UserId(Nulid, String);   // ✗ Multiple fields

#[derive(Id)]
pub struct UserId(String);          // ✗ Wrong type
```

## Type Safety

Using wrapper types provides type safety by preventing accidental mixing of different ID types:

```rust
use nulid::{Nulid, Id};

#[derive(Id)]
pub struct UserId(Nulid);

#[derive(Id)]
pub struct OrderId(Nulid);

fn process_user(id: UserId) { /* ... */ }
fn process_order(id: OrderId) { /* ... */ }

let user_id = UserId::from(Nulid::new()?);
let order_id = OrderId::from(Nulid::new()?);

process_user(user_id);   // ✓ 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:

```rust
use nulid::{Error, Id};

#[derive(Id)]
pub struct UserId(nulid::Nulid);

match UserId::try_from("invalid-string") {
    Ok(id) => println!("Parsed: {}", id),
    Err(Error::InvalidLength { expected, found }) => {
        eprintln!("Wrong length: expected {}, got {}", expected, found);
    }
    Err(Error::InvalidChar(ch, pos)) => {
        eprintln!("Invalid character '{}' at position {}", ch, pos);
    }
    Err(e) => eprintln!("Parse error: {}", e),
}
```

## Integration with Other Traits

The derive macro works well with other derive macros:

```rust
use nulid::{Nulid, Id};

#[derive(Id)]
pub struct UserId(Nulid);

// Standard traits are automatically implemented!
// UserId now has: Debug, Copy (Clone), PartialEq, Eq, Hash, PartialOrd, Ord

// You can also add serde support if the serde feature is enabled in nulid
#[cfg(feature = "serde")]
#[derive(Id, serde::Serialize, serde::Deserialize)]
pub struct OrderId(Nulid);
```

## Examples

See the [examples directory](https://github.com/kakilangit/nulid/tree/main/examples) in the nulid repository for more usage examples.

## License

This project is licensed under the MIT License - see the LICENSE file for details.