Skip to main content

Numeric

Struct Numeric 

Source
pub struct Numeric { /* private fields */ }
Expand description

A numeric (decimal) value with up to 38 digits of precision.

Hyper stores NUMERIC(precision, scale) as a fixed-point integer with implicit scale: the actual value is unscaled_value × 10^(-scale). The scale is determined by the column’s type modifier.

§Wire Format

Hyper uses two wire representations depending on declared precision:

Declared PrecisionWire SizeRust Storage
≤ 18 digits8 bytes (i64)Widened to i128 on read
19–38 digits16 bytes (i128)Stored directly

This distinction is transparent to callers — Numeric always stores an i128 internally. The 18-digit threshold corresponds to SMALL_NUMERIC_MAX_PRECISION.

The maximum precision of 38 digits (MAX_PRECISION) matches the limit of a signed 128-bit integer (which can represent up to ±1.7 × 10^38).

§No Arithmetic

Numeric does not implement arithmetic operators (Add, Sub, etc.) because scale handling during arithmetic is context-dependent and best done via SQL. Use to_f64 for approximate arithmetic in Rust, or perform calculations server-side.

Implementations§

Source§

impl Numeric

Source

pub const MAX_PRECISION: u8 = 38

Maximum precision (38 digits).

This is the single source of truth for Hyper’s NUMERIC precision limit. All validation elsewhere in the codebase should reference this constant.

Source

pub const SMALL_NUMERIC_MAX_PRECISION: u32 = 18

Maximum precision that fits in i64 storage (18 digits).

NUMERIC values with precision ≤ 18 are stored as 64-bit integers in HyperBinary format. Precision > 18 uses 128-bit storage.

Source

pub const fn new(value: i128, scale: u8) -> Numeric

Creates a Numeric from an unscaled value and scale.

Source

pub const fn from_i128(value: i128) -> Numeric

Creates a Numeric from an integer.

Source

pub const fn from_i64(value: i64) -> Numeric

Creates a Numeric from an i64.

Source

pub const fn from_i32(value: i32) -> Numeric

Creates a Numeric from an i32.

Source

pub const fn unscaled_value(&self) -> i128

Returns the unscaled value.

Source

pub const fn scale(&self) -> u8

Returns the scale.

Source

pub fn to_f64(&self) -> f64

Converts to f64 (may lose precision).

Source

pub fn from_f64(value: f64, scale: u8) -> Numeric

Creates from f64 with specified scale.

§Panics

Panics if value * 10^scale is not finite or exceeds the 38-digit precision limit of Hyper’s Numeric type. For a non-panicking variant, use try_from_f64.

Source

pub fn try_from_f64( value: f64, scale: u8, ) -> Result<Numeric, Box<dyn Error + Sync + Send>>

Creates from f64 with specified scale, returning an error if the value exceeds Hyper’s 38-digit precision limit.

§Errors

Returns an error if the scaled value exceeds ±(10^38 - 1) or if the intermediate result is not finite.

Source

pub fn encode(&self) -> [u8; 16]

Encodes the numeric as a 128-bit little-endian value, suitable for the HyperBinary BigNumeric wire format (precision > 18).

Source

pub fn encode_int64(&self) -> Result<[u8; 8], Box<dyn Error + Sync + Send>>

Encodes the numeric as a 64-bit little-endian value, suitable for the HyperBinary Numeric wire format (precision ≤ 18).

§Errors

Returns an Err if self.value is outside the i64 range. This happens exactly when the unscaled value exceeds what a 19+ digit precision can hold, i.e. the value belongs in the BigNumeric 16-byte wire form instead. The error names the specific out-of-range value so callers have something actionable in logs.

Returns Ok for every value that fits; callers who can statically prove their values are in range (e.g. building from a NUMERIC(p, s) schema with p ≤ 18) can .expect() the result without losing any safety.

For values that are always representable in 128 bits — i.e. anything Hyper can hold in any NUMERIC(p, s) with p ≤ 38 — use encode instead, which is infallible.

Source

pub fn decode(buf: &[u8; 16], scale: u8) -> Numeric

Decodes a numeric from the 128-bit HyperBinary BigNumeric wire form (precision > 18). See decode_int64 for the 8-byte Numeric form used when precision ≤ 18.

The scale parameter is not carried in the wire bytes — it must come from the column’s SqlType::Numeric { precision, scale } descriptor. See hyperdb_api::result::Rowset::schema() for how this flows end-to-end from a RowDescription message.

Source

pub fn decode_int64(buf: &[u8; 8], scale: u8) -> Numeric

Decodes a numeric from the 64-bit HyperBinary Numeric wire form (used by Hyper when precision ≤ 18 — see Type::maxPrecisionNumeric = 18 in the Hyper DB source at hyper/rts/type/Type.hpp). The 64-bit form is what AVG(SmallInt | Integer) returns (as Numeric(11, 6) or Numeric(16, 6) respectively — see AggregationLogic:: dividingAggregateType in hyper/cts/algebra/operator/AggregationLogic.cpp).

Like decode, scale is not carried in the bytes and must come from the column’s SqlType::Numeric descriptor.

Source

pub fn to_packed(&self) -> [u8; 16]

Returns the packed 128-bit representation for insertion.

This is an alias for encode() for API consistency.

Source§

impl Numeric

Source

pub fn from_binary_with_scale( buf: &[u8], scale: u8, ) -> Result<Numeric, Box<dyn Error + Sync + Send>>

Creates a Numeric from binary data with explicit scale.

This is the preferred method for decoding Numeric values from binary data, as the scale must be obtained from the column’s type metadata.

Dispatches on buffer size to handle both of Hyper’s NUMERIC wire forms:

  • 8 bytes (i64): used when the column’s precision is ≤ 18 (Hyper’s Type::Numeric; see maxPrecisionNumeric = 18 in hyper/rts/type/Type.hpp). This is the form returned by aggregates like AVG(INTEGER) which Hyper types as Numeric(16, 6) — see AggregationLogic::dividingAggregateType in hyper/cts/algebra/operator/AggregationLogic.cpp.
  • 16 bytes (i128): used when the column’s precision is

    18 (Hyper’s Type::BigNumeric, up to 38 digits).

Any other buffer size is rejected with an error — callers that reach this function with, say, a 4-byte truncated read should surface the bug rather than silently decoding garbage.

§Arguments
  • buf - An 8-byte or 16-byte buffer containing the unscaled value in little-endian
  • scale - The number of digits after the decimal point, from type metadata (SqlType::Numeric { scale, .. })
§Examples
use hyperdb_api_core::types::Numeric;

// 16-byte form: NUMERIC(25, 2) value = 100
let bytes16 = [100u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let numeric = Numeric::from_binary_with_scale(&bytes16, 2).unwrap();
assert_eq!(numeric.to_f64(), 1.00);

// 8-byte form: NUMERIC(16, 6) = 2.0 (as returned by AVG(INTEGER))
let bytes8: [u8; 8] = 2_000_000i64.to_le_bytes();
let numeric = Numeric::from_binary_with_scale(&bytes8, 6).unwrap();
assert_eq!(numeric.to_f64(), 2.0);
§Errors

Returns an error if buf.len() is anything other than 8 or 16 bytes. Hyper encodes NUMERIC(precision, scale) values in exactly one of those two widths, so any other size indicates a truncated read or protocol violation upstream.

§Panics

Does not panic in practice: the buf.len() == 8 and buf.len() == 16 branches each use try_into().expect(...) whose invariant is proven by the enclosing match arm.

Trait Implementations§

Source§

impl Clone for Numeric

Source§

fn clone(&self) -> Numeric

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Numeric

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for Numeric

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Hash for Numeric

Source§

fn hash<__H>(&self, state: &mut __H)
where __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl IntoValue for &Numeric

Source§

fn add_to_inserter(&self, inserter: &mut Inserter<'_>) -> Result<()>

Adds this value to the inserter. Read more
Source§

impl IntoValue for Numeric

Source§

fn add_to_inserter(&self, inserter: &mut Inserter<'_>) -> Result<()>

Adds this value to the inserter. Read more
Source§

impl PartialEq for Numeric

Source§

fn eq(&self, other: &Numeric) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl RowValue for Numeric

Source§

fn from_row(row: &Row, idx: usize) -> Option<Self>

Unlike every other RowValue impl, Numeric decode requires per-column metadata (scale + wire-form width) that lives on the row’s attached ResultSchema. Row::get_numeric does the lookup; this impl delegates there so generic row.get::<Numeric>() / row.try_get::<Numeric>(idx, "name") call sites work the same as every other type.

Source§

impl ToHyperBinary for Numeric

Source§

fn to_hyper_binary( &self, buf: &mut BytesMut, ) -> Result<(), Box<dyn Error + Sync + Send>>

Serializes the value to HyperBinary format for a nullable column. Read more
Source§

fn to_hyper_binary_not_null( &self, buf: &mut BytesMut, ) -> Result<(), Box<dyn Error + Sync + Send>>

Serializes the value to HyperBinary format for a NOT NULL column. Read more
Source§

fn hyper_binary_size(&self) -> usize

Returns the size in bytes this value will occupy when serialized (nullable).
Source§

fn hyper_binary_size_not_null(&self) -> usize

Returns the size in bytes this value will occupy when serialized (not nullable).
Source§

impl Copy for Numeric

Source§

impl Eq for Numeric

Source§

impl StructuralPartialEq for Numeric

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<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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
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> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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<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<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,