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 Precision | Wire Size | Rust Storage |
|---|---|---|
| ≤ 18 digits | 8 bytes (i64) | Widened to i128 on read |
| 19–38 digits | 16 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
impl Numeric
Sourcepub const MAX_PRECISION: u8 = 38
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.
Sourcepub const SMALL_NUMERIC_MAX_PRECISION: u32 = 18
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.
Sourcepub const fn new(value: i128, scale: u8) -> Numeric
pub const fn new(value: i128, scale: u8) -> Numeric
Creates a Numeric from an unscaled value and scale.
Sourcepub const fn unscaled_value(&self) -> i128
pub const fn unscaled_value(&self) -> i128
Returns the unscaled value.
Sourcepub fn from_f64(value: f64, scale: u8) -> Numeric
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.
Sourcepub fn try_from_f64(
value: f64,
scale: u8,
) -> Result<Numeric, Box<dyn Error + Sync + Send>>
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.
Sourcepub fn encode(&self) -> [u8; 16]
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).
Sourcepub fn encode_int64(&self) -> Result<[u8; 8], Box<dyn Error + Sync + Send>>
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.
Sourcepub fn decode(buf: &[u8; 16], scale: u8) -> Numeric
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.
Sourcepub fn decode_int64(buf: &[u8; 8], scale: u8) -> Numeric
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§impl Numeric
impl Numeric
Sourcepub fn from_binary_with_scale(
buf: &[u8],
scale: u8,
) -> Result<Numeric, Box<dyn Error + Sync + Send>>
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; seemaxPrecisionNumeric = 18inhyper/rts/type/Type.hpp). This is the form returned by aggregates likeAVG(INTEGER)which Hyper types asNumeric(16, 6)— seeAggregationLogic::dividingAggregateTypeinhyper/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-endianscale- 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 RowValue for Numeric
impl RowValue for Numeric
Source§fn from_row(row: &Row, idx: usize) -> Option<Self>
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
impl ToHyperBinary for Numeric
Source§fn to_hyper_binary(
&self,
buf: &mut BytesMut,
) -> Result<(), Box<dyn Error + Sync + Send>>
fn to_hyper_binary( &self, buf: &mut BytesMut, ) -> Result<(), Box<dyn Error + Sync + Send>>
Source§fn to_hyper_binary_not_null(
&self,
buf: &mut BytesMut,
) -> Result<(), Box<dyn Error + Sync + Send>>
fn to_hyper_binary_not_null( &self, buf: &mut BytesMut, ) -> Result<(), Box<dyn Error + Sync + Send>>
Source§fn hyper_binary_size(&self) -> usize
fn hyper_binary_size(&self) -> usize
Source§fn hyper_binary_size_not_null(&self) -> usize
fn hyper_binary_size_not_null(&self) -> usize
impl Copy for Numeric
impl Eq for Numeric
impl StructuralPartialEq for Numeric
Auto Trait Implementations§
impl Freeze for Numeric
impl RefUnwindSafe for Numeric
impl Send for Numeric
impl Sync for Numeric
impl Unpin for Numeric
impl UnsafeUnpin for Numeric
impl UnwindSafe for Numeric
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request