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>> { ... } }
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
#[cfg(all(feature = "base32", feature = "ulid"))]
{
    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
#[cfg(all(feature = "base32", feature = "ulid"))]
{
    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
#[cfg(all(feature = "base32", feature = "ulid"))]
{
   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,