pub trait Base32SnowExt: SnowflakeId{
// Provided methods
fn buf() -> <<Self as Id>::Ty as BeBytes>::Base32Array { ... }
fn encode(&self) -> Base32SnowFormatter<Self> { ... }
fn encode_to_buf<'buf>(
&self,
buf: &'buf mut <<Self as Id>::Ty as BeBytes>::Base32Array,
) -> Base32SnowFormatterRef<'buf, Self> { ... }
fn decode(s: impl AsRef<str>) -> Result<Self, Error<Self>> { ... }
}base32 and snowflake 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§
Sourcefn buf() -> <<Self as Id>::Ty as BeBytes>::Base32Array
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 Base32SnowExt::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: Base32SnowExt::encode_to_buf for usage.
Sourcefn encode(&self) -> Base32SnowFormatter<Self>
fn encode(&self) -> Base32SnowFormatter<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::{Base32SnowExt, SnowflakeTwitterId};
use std::fmt::Write;
let id = SnowflakeTwitterId::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, "23953MG16DJDJ");Sourcefn encode_to_buf<'buf>(
&self,
buf: &'buf mut <<Self as Id>::Ty as BeBytes>::Base32Array,
) -> Base32SnowFormatterRef<'buf, Self>
fn encode_to_buf<'buf>( &self, buf: &'buf mut <<Self as Id>::Ty as BeBytes>::Base32Array, ) -> Base32SnowFormatterRef<'buf, Self>
Encodes this ID into the provided buffer without heap allocation and
returns a formatter view over the buffer similar to
Base32SnowExt::encode.
The buffer must be exactly BeBytes::BASE32_SIZE bytes long, which is
guaranteed at compile time when using Base32SnowExt::buf.
§Example
use ferroid::{Base32SnowExt, BeBytes, Id, SnowflakeTwitterId};
let id = SnowflakeTwitterId::from_raw(2_424_242_424_242_424_242);
// Stack-allocated buffer of the correct size.
let mut buf = SnowflakeTwitterId::buf();
// Formatter is a view over the external buffer
let formatter = id.encode_to_buf(&mut buf);
assert_eq!(formatter, "23953MG16DJDJ");
// Or access the raw bytes directly:
let as_str = unsafe { core::str::from_utf8_unchecked(buf.as_ref()) };
assert_eq!(as_str, "23953MG16DJDJ");See also: Base32SnowExt::encode for a version that manages its own
buffer.
Sourcefn decode(s: impl AsRef<str>) -> Result<Self, Error<Self>>
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 Snowflake ID, regardless of whether the input is
a canonical Snowflake ID.
- If the input string’s Crockford encoding is larger than the Snowflake’s maximum (i.e. “FZZZZZZZZZZZZ” for 64-bit integers), the excess bit is automatically ignored (i.e., the top 1 bit of the decoded value is discarded), so no overflow or error occurs.
- As a result, base32 strings that are technically invalid (i.e., lexicographically greater than the max Snowflake 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. 13 chars for u64, 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, Base32SnowExt, Error, Id, SnowflakeId, SnowflakeTwitterId};
// Crockford Base32 encodes values in 5-bit chunks, so encoding a u64
// (64 bits)
// requires 13 characters (13 × 5 = 65 bits). Since u64 can only hold 64
// bits, the highest (leftmost) bit is discarded during decoding.
//
// This means *any* 13-character Base32 string will decode into a u64, even
// if it represents a value that exceeds the canonical range of a specific
// ID type.
//
// Many ID formats (such as Twitter Snowflake IDs) 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 `SnowflakeTwitterId`, "7ZZZZZZZZZZZZ" represents the
// largest lexicographically valid encoding that fills all non-reserved bits
// with ones. Lexicographically larger values like "QZZZZZZZZZZZZ" decode to
// the *same* ID because their first character differs only in the highest
// (65th) bit, which is discarded:
// - '7' = 0b00111 → top bit 0, reserved bit 0, rest = 111...
// - 'Q' = 0b10111 → top bit 1, reserved bit 0, rest = 111...
// ↑↑↑↑ identical after discarding MSB
let id1 = SnowflakeTwitterId::decode("7ZZZZZZZZZZZZ").unwrap();
let id2 = SnowflakeTwitterId::decode("QZZZZZZZZZZZZ").unwrap();
assert_eq!(id1, id2);
// In contrast, "PZZZZZZZZZZZZ" differs in more significant bits and decodes
// to a distinct value:
// - 'P' = 0b10110 → top bit 1, reserved bit 0, rest = 110...
// ↑ alters bits within the ID layout beyond the reserved region
let id3 = SnowflakeTwitterId::decode("PZZZZZZZZZZZZ").unwrap();
assert_ne!(id1, id3);
// If the reserved bits are set (e.g., 'F' = 0b01111 or 'Z' = 0b11111),
// decoding fails and the invalid ID is returned:
// - 'F' = 0b01111 → top bit 0, reserved bit 1, rest = 111...
// ↑ reserved bit is set - ID is invalid
let id = SnowflakeTwitterId::decode("FZZZZZZZZZZZZ")
.or_else(|err| {
match err {
Error::Base32Error(Base32Error::DecodeOverflow { id }) => {
debug_assert!(!id.is_valid());
// clears reserved bits
let valid = id.into_valid();
debug_assert!(valid.is_valid());
Ok(valid)
}
other => Err(other),
}
})
.expect("should produce a valid ID");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.