Base32UlidExt

Trait Base32UlidExt 

Source
pub trait Base32UlidExt: UlidId
where Self::Ty: BeBytes,
{ // Provided methods fn buf() -> <<Self as Id>::Ty as BeBytes>::Base32Array { ... } fn encode(&self) -> Base32UlidFormatter<Self> { ... } fn encode_to_buf<'buf>( &self, buf: &'buf mut <<Self as Id>::Ty as BeBytes>::Base32Array, ) -> Base32UlidFormatterRef<'buf, Self> { ... } fn decode(s: impl AsRef<str>) -> Result<Self, Error<Self>> { ... } }
Available on crate features base32 and ulid only.
Expand description

Extension trait for Crockford Base32 encoding and decoding of ID types.

This trait enables converting IDs backed by integer types into fixed-length, lexicographically sortable Base32 representation using the Crockford Base32 alphabet.

Provided Methods§

Source

fn buf() -> <<Self as Id>::Ty as BeBytes>::Base32Array

Returns a stack-allocated, zero-initialized buffer for Base32 encoding.

This is a convenience method that returns a BeBytes::Base32Array suitable for use with Base32UlidExt::encode_to_buf. The returned buffer is stack-allocated, has a fixed size known at compile time, and is guaranteed to match the Crockford Base32 output size for the backing integer type.

See also: Base32UlidExt::encode_to_buf for usage.

Source

fn encode(&self) -> Base32UlidFormatter<Self>

Returns a formatter containing the Crockford Base32 representation of the ID.

The formatter is a lightweight, zero-allocation view over that internal buffer that implements core::fmt::Display and AsRef<str>.

§Example
use ferroid::{Base32UlidExt, ULID};
use std::fmt::Write;

let id = ULID::from_raw(2_424_242_424_242_424_242);

// Formatter is a view over the internal encoded buffer
let formatter = id.encode();

assert_eq!(formatter, "000000000000023953MG16DJDJ");
Source

fn encode_to_buf<'buf>( &self, buf: &'buf mut <<Self as Id>::Ty as BeBytes>::Base32Array, ) -> Base32UlidFormatterRef<'buf, Self>

Encodes this ID into the provided buffer without heap allocation and returns a formatter view over the buffer similar to Base32UlidExt::encode.

The buffer must be exactly BeBytes::BASE32_SIZE bytes long, which is guaranteed at compile time when using Base32UlidExt::buf.

§Example
use ferroid::{Base32UlidExt, BeBytes, Id, ULID};

let id = ULID::from_raw(2_424_242_424_242_424_242);

// Stack-allocated buffer of the correct size.
let mut buf = ULID::buf();

// Formatter is a view over the external buffer
let formatter = id.encode_to_buf(&mut buf);

assert_eq!(formatter, "000000000000023953MG16DJDJ");

// Or access the raw bytes directly:
let as_str = unsafe { core::str::from_utf8_unchecked(buf.as_ref()) };
assert_eq!(as_str, "000000000000023953MG16DJDJ");

See also: Base32UlidExt::encode for a version that manages its own buffer.

Source

fn decode(s: impl AsRef<str>) -> Result<Self, Error<Self>>

Decodes a Base32-encoded string back into an ID.

⚠️ Note:
This method structurally decodes a Crockford base32 string into an integer representing a ULID, regardless of whether the input is a canonical ULID.

  • If the input string’s Crockford encoding is larger than the ULID spec’s maximum (i.e. “7ZZZZZZZZZZZZZZZZZZZZZZZZZ” for 128-bit integers), the excess bits are automatically ignored (i.e., the top 2 bits of the decoded value are discarded), so no overflow or error occurs.
  • As a result, base32 strings that are technically invalid per the ULID spec (i.e., lexicographically greater than the max ULID string) will still successfully decode.
  • However, if your ID type reserves bits (e.g., reserved or unused bits in your layout), decoding a string with excess bits may set these reserved bits to 1, causing .is_valid() to fail, and decode to return an error.
§Errors

Returns an error if the input string:

  • is not the expected fixed length of the backing integer representation (i.e. 26 chars for u128)
  • contains invalid ASCII characters (i.e., not in the Crockford Base32 alphabet)
  • sets reserved bits that make the decoded value invalid for this ID type
§Example
use ferroid::{Base32Error, Base32UlidExt, Error, Id, ULID, UlidId};

// Crockford Base32 encodes values in 5-bit chunks, so encoding a u128 (128
// bits) requires 26 characters (26 × 5 = 130 bits). Since u128 can only hold
// 128 bits, the highest 2 bits are discarded during decoding.
//
// This means *any* 26-character Base32 string will decode into a u128, even
// if it represents a value that exceeds the canonical range of a specific
// ID type.
//
// Other ID formats may reserve one or more high bits for future use. These
// reserved bits **must remain unset** for the decoded value to be
// considered valid.
//
// For example, in a `ULID`, "7ZZZZZZZZZZZZZZZZZZZZZZZZZ" represents the
// largest lexicographically valid encoding that fills all 128 bits with
// ones. Lexicographically larger values like "ZZZZZZZZZZZZZZZZZZZZZZZZZZ"
// decode to the *same* ID because their first character differs only in the
// highest bits (129th & 130th), which are discarded:
// - '7' = 0b00111 → top bits 00, rest = 111...
// - 'Z' = 0b11111 → top bits 11, rest = 111...
//             ↑↑↑ identical after discarding MSBs
let id1 = ULID::decode("7ZZZZZZZZZZZZZZZZZZZZZZZZZ").unwrap();
let id2 = ULID::decode("ZZZZZZZZZZZZZZZZZZZZZZZZZZ").unwrap();
assert_eq!(id1, id2);

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl<ID> Base32UlidExt for ID
where ID: UlidId, ID::Ty: BeBytes,