16 releases (1 stable)

1.0.0 Sep 9, 2024
0.5.1 Jun 10, 2024
0.5.0 Jan 8, 2024
0.4.1 Dec 26, 2023
0.1.3 Feb 22, 2023

#319 in Web programming

48 downloads per month

MIT license

43KB
751 lines

pxid

Prefixed Globally Unique Identifier

Crates.io Documentation Build Clippy Formatter

Motivation

Extend the rs/xid implementation by adding capability to have a prefix and at the same time have a u16 type support by fitting prefix bits.

This library is inspired in Stripe IDs which have a friendly notation and are very short IDs. These IDs are prefixed with a maximum of 4 bytes belonging to the entity behind them.

Usage

use pxid::Pxid;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Given that some of the dependencies to build
    // an instance of the Pxid may fail.
    // - Getting current timestamp
    // - Getting machine id
    // - Getting process id
    //
    // A `Result<Pxid, Error>` is returned.
    let id = Pxid::new("acct".as_bytes())?;

    println!("{}", id); // acct_9m4e2mr0ui3e8a215n4g
}

To improve memory usage (reduce allocations), and reuse dependencies required, the Factory struct can also be used to build Pxid instances.

This is the recommended way to build Pxid instances, given that resources are initialized once, and then reused.

use pxid::Factory;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let factory = Factory::new_without_prefix()?;
    let id = factory.with_prefix("acct");

    println!("{}", id); // acct_9m4e2mr0ui3e8a215n4g

    let factory_with_prefix = Factory::new("acct")?;
    let id = factory_with_prefix.generate();

    println!("{}", id); // acct_9m4e2mr0ui3e8a215n4g
}

GraphQL Support

You can use Pxid on GraphQL via the async-graphql crate. Make sure the graphql feature is enabled and import Pxid for GraphQL.

use async_graphql::{Context, InputObject, Result, SimpleObject};
use pxid::graphql::Pxid;

// -- snip --

#[derive(Debug, InputObject)]
pub struct PostCreateInput {
    pub title: String,
    pub content: String,
    pub parent_id: Option<Pxid>,
}

impl PostCreate {
    pub async fn exec(ctx: &Context<'_>, input: PostCreateInput) -> Result<Self> {
// -- snip --

Check out the full example here.

Layout

A prefixed XID fits nicely on a 16 bytes slice thanks to its packed data format.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Prefix Timestamp Machine ID Process ID Counter

For a total of 16 bytes.

The prefix allows up to 4 UTF-8 Characters, this allows the ID to provide some context about its scope.

acct_9m4e2mr0ui3e8a215n4g
ordr_9m4e2mr0ui3e8a215n4g
usr_9m4e2mr0ui3e8a215n4g

This way IDs are not only even harder to collide, but they also provides a bit of context on record association.

License

This project is licensed under the MIT License

Dependencies

~0.6–12MB
~155K SLoC