Skip to main content

DecimalLexEncoder

Struct DecimalLexEncoder 

Source
pub struct DecimalLexEncoder;
Expand description

Variable-length lexicographic encoding for D128 values that preserves sort order.

This encoder converts D128 values into byte sequences that maintain the same lexicographic ordering as the original decimal values. This is crucial for database indexing where byte-level comparison must match numeric comparison.

§Encoding Format

The encoding uses a variable-length format optimized for lexicographic ordering:

§Zero Values

  • Zero is encoded as a single byte: 0x80
  • This ensures zero sorts between negative and positive numbers

§Non-Zero Values

The format consists of:

  1. Class/marker byte (1 byte):

    • 0x80 Zero
    • 0x40 Finite negative
    • 0xA0 Finite positive
    • 0x20 Negative infinity
    • 0xC0 Positive infinity
    • 0xFF NaN
  2. Biased scale (2 bytes, big-endian):

    • We bias the “scale” (not the raw exponent). Scale is defined as: scale = exponent + (digit_count - 1), i.e., the position of the most-significant digit in a scientific-notation sense.
    • Stored as: biased = scale + EXP_BIAS (unsigned 16-bit)
    • For negative numbers: stored as 0xFFFF - biased (one’s complement) to reverse order
    • EXP_BIAS = 6144. With D128, exponent ∈ [-6143, +6144] and digit_count ∈ [1, 34], so scale ∈ [-6143, 6177], which maps into [1, 12321] after biasing, well within u16.
  3. Packed digit representation (variable length):

    • Digits are taken from the absolute value’s base-10 representation
    • Each pair of digits is packed into one byte (4 bits per digit)
    • For positive numbers: stored as-is
    • For negative numbers: all bytes are bitwise complemented to reverse ordering
    • Termination: encoding stops when a nibble equals 0x0. This naturally handles both odd and even digit counts: • odd count: the last byte has a low nibble of 0 • even count: an extra full terminator byte is appended (0x00 for positives, 0xFF for negatives)

Because a terminator is always present within (or immediately after) the mantissa, any trailing type-marker byte appended by higher layers will never be consumed by the mantissa decoder.

§Properties

  • Preserves lexicographic ordering: if a < b then encode(a) < encode(b)
  • Variable length encoding (3+ bytes typical: 1 sign + 2 scale + packed digits)
  • Handles full D128 range including extreme values
  • Uses packed digit encoding for efficient storage (2 digits per byte)

Implementations§

Source§

impl DecimalLexEncoder

Source

pub fn encode(dec: D128) -> Vec<u8> ⓘ

Encodes a D128 value into a lexicographically ordered byte sequence.

The encoding preserves sort order: if a < b then encode(a) < encode(b). This is essential for database indexing where byte-level comparison must match numeric comparison.

Source

pub fn decode(bytes: &[u8]) -> Result<D128>

Decodes a lexicographically encoded byte sequence back to a D128 value.

This reverses the encoding process, reconstructing the original D128 from its byte representation while handling all the encoding transformations.

Source

pub fn to_d128(dec: Decimal) -> D128

Converts a rust_decimal::Decimal to a fastnum::D128.

This conversion extracts the mantissa, scale, and sign from the Decimal and reconstructs them as a D128 value.

Source

pub fn to_decimal(d128: D128) -> Result<Decimal>

Converts a fastnum::D128 to a rust_decimal::Decimal.

This conversion uses string representation as an intermediate format to ensure precision is maintained during the conversion.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<U> As for U

Source§

fn as_<T>(self) -> T
where T: CastFrom<U>, U: Sized,

Casts self to type T. The semantics of numeric casting with the as operator are followed, so <T as As>::as_::<U> can be used in the same way as T as U for numeric conversions. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<G1, G2> Within<G2> for G1
where G2: Contains<G1>,

Source§

fn is_within(&self, b: &G2) -> bool