use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
macro_rules! wire_newtype {
($(#[$doc:meta])* $name:ident($inner:ty)) => {
$(#[$doc])*
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct $name(pub $inner);
impl Serialize for $name {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_newtype_struct(stringify!($name), &self.0)
}
}
impl<'de> Deserialize<'de> for $name {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
<$inner as Deserialize<'de>>::deserialize(d).map($name)
}
}
};
}
wire_newtype! {
DateDays(u16)
}
wire_newtype! {
Date32Days(i32)
}
wire_newtype! {
DateTimeSeconds(u32)
}
wire_newtype! {
DateTime64Secs(i64)
}
wire_newtype! {
DateTime64Millis(i64)
}
wire_newtype! {
DateTime64Micros(i64)
}
wire_newtype! {
DateTime64Nanos(i64)
}
wire_newtype! {
TimeSeconds(i32)
}
wire_newtype! {
Time64Secs(i64)
}
wire_newtype! {
Time64Millis(i64)
}
wire_newtype! {
Time64Micros(i64)
}
wire_newtype! {
Time64Nanos(i64)
}
macro_rules! decimal_newtype {
($(#[$doc:meta])* $name:ident($inner:ty), max_scale = $max:literal) => {
$(#[$doc])*
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct $name<const SCALE: u32>(pub $inner);
impl<const SCALE: u32> $name<SCALE> {
pub const SCALE: u32 = {
assert!(
SCALE <= $max,
concat!(
stringify!($name),
" scale exceeds the column type's maximum of ",
stringify!($max)
)
);
SCALE
};
}
impl<const SCALE: u32> Serialize for $name<SCALE> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let _ = Self::SCALE;
serializer.serialize_newtype_struct(stringify!($name), &self.0)
}
}
impl<'de, const SCALE: u32> Deserialize<'de> for $name<SCALE> {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let _ = Self::SCALE;
<$inner as Deserialize<'de>>::deserialize(d).map($name)
}
}
};
}
decimal_newtype! {
Decimal32(i32), max_scale = 9
}
decimal_newtype! {
Decimal64(i64), max_scale = 18
}
decimal_newtype! {
Decimal128(i128), max_scale = 38
}
#[cfg(feature = "rust_decimal")]
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum DecimalConvertError {
#[error("{value} cannot be rescaled to {scale} fractional digits")]
Rescale {
value: rust_decimal::Decimal,
scale: u32,
},
#[error("scaled mantissa of {value} overflows the column's integer width")]
Overflow {
value: rust_decimal::Decimal,
},
#[error("raw decimal {raw} at scale {scale} exceeds rust_decimal's range")]
Unrepresentable {
raw: i128,
scale: u32,
},
}
#[cfg(feature = "rust_decimal")]
mod rust_decimal_conv {
use super::{Decimal32, Decimal64, Decimal128, DecimalConvertError};
use rust_decimal::Decimal;
macro_rules! decimal_conversions {
($wrapper:ident, $int:ty) => {
impl<const SCALE: u32> TryFrom<Decimal> for $wrapper<SCALE> {
type Error = DecimalConvertError;
fn try_from(value: Decimal) -> Result<Self, Self::Error> {
let _ = Self::SCALE;
let mut scaled = value;
scaled.rescale(SCALE);
if scaled.scale() != SCALE {
return Err(DecimalConvertError::Rescale {
value,
scale: SCALE,
});
}
<$int>::try_from(scaled.mantissa())
.map($wrapper)
.map_err(|_| DecimalConvertError::Overflow { value })
}
}
impl<const SCALE: u32> TryFrom<$wrapper<SCALE>> for Decimal {
type Error = DecimalConvertError;
fn try_from(value: $wrapper<SCALE>) -> Result<Self, Self::Error> {
Decimal::try_from_i128_with_scale(i128::from(value.0), SCALE).map_err(|_| {
DecimalConvertError::Unrepresentable {
raw: i128::from(value.0),
scale: SCALE,
}
})
}
}
};
}
decimal_conversions!(Decimal32, i32);
decimal_conversions!(Decimal64, i64);
decimal_conversions!(Decimal128, i128);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Int256(pub [u8; 32]);
impl Int256 {
#[must_use]
pub const fn from_i128(v: i128) -> Self {
let mut bytes = [if v < 0 { 0xff } else { 0x00 }; 32];
let le = v.to_le_bytes();
let mut i = 0;
while i < 16 {
bytes[i] = le[i];
i += 1;
}
Int256(bytes)
}
#[must_use]
pub const fn from_le_bytes(bytes: [u8; 32]) -> Self {
Int256(bytes)
}
#[must_use]
pub const fn to_le_bytes(self) -> [u8; 32] {
self.0
}
}
impl Serialize for Int256 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_newtype_struct("Int256", &self.0)
}
}
impl<'de> Deserialize<'de> for Int256 {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
<[u8; 32]>::deserialize(d).map(Int256)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UInt256(pub [u8; 32]);
impl UInt256 {
#[must_use]
pub const fn from_u128(v: u128) -> Self {
let mut bytes = [0u8; 32];
let le = v.to_le_bytes();
let mut i = 0;
while i < 16 {
bytes[i] = le[i];
i += 1;
}
UInt256(bytes)
}
#[must_use]
pub const fn from_le_bytes(bytes: [u8; 32]) -> Self {
UInt256(bytes)
}
#[must_use]
pub const fn to_le_bytes(self) -> [u8; 32] {
self.0
}
}
impl Serialize for UInt256 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_newtype_struct("UInt256", &self.0)
}
}
impl<'de> Deserialize<'de> for UInt256 {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
<[u8; 32]>::deserialize(d).map(UInt256)
}
}
pub type Point = (f64, f64);
pub type Ring = Vec<Point>;
pub type LineString = Vec<Point>;
pub type Polygon = Vec<Ring>;
pub type MultiLineString = Vec<LineString>;
pub type MultiPolygon = Vec<Polygon>;
#[cfg(test)]
mod tests {
use super::*;
use crate::rowbinary::serialize_row;
use bytes::BytesMut;
fn enc<T: Serialize>(v: &T) -> Vec<u8> {
let mut buf = BytesMut::new();
serialize_row(v, &mut buf).expect("serialize");
buf.to_vec()
}
#[test]
fn date_and_time_newtypes_are_transparent_integers() {
assert_eq!(enc(&DateDays(1)), 1u16.to_le_bytes());
assert_eq!(enc(&Date32Days(-25567)), (-25567i32).to_le_bytes());
assert_eq!(enc(&DateTimeSeconds(42)), 42u32.to_le_bytes());
assert_eq!(enc(&DateTime64Secs(-1)), (-1i64).to_le_bytes());
assert_eq!(enc(&DateTime64Millis(1_000)), 1_000i64.to_le_bytes());
assert_eq!(enc(&DateTime64Micros(7)), 7i64.to_le_bytes());
assert_eq!(enc(&DateTime64Nanos(7)), 7i64.to_le_bytes());
assert_eq!(enc(&TimeSeconds(-3599)), (-3599i32).to_le_bytes());
assert_eq!(enc(&Time64Nanos(1)), 1i64.to_le_bytes());
}
#[test]
fn decimals_write_the_raw_scaled_integer() {
assert_eq!(enc(&Decimal32::<2>(999)), 999i32.to_le_bytes());
assert_eq!(enc(&Decimal64::<4>(-15_000)), (-15_000i64).to_le_bytes());
assert_eq!(enc(&Decimal128::<10>(1)), 1i128.to_le_bytes());
}
#[test]
fn int256_layouts() {
assert_eq!(Int256::from_i128(-1).0, [0xff; 32]);
let one = UInt256::from_u128(1);
let mut expected = [0u8; 32];
expected[0] = 1;
assert_eq!(one.0, expected);
let v = Int256::from_i128(i128::MIN);
assert_eq!(&v.0[..16], &i128::MIN.to_le_bytes());
assert_eq!(&v.0[16..], &[0xff; 16]);
assert_eq!(enc(&one), expected);
assert_eq!(enc(&Int256::from_i128(-1)), [0xff; 32]);
}
#[cfg(feature = "rust_decimal")]
#[test]
fn rust_decimal_conversions_are_checked_and_round_trip() {
use rust_decimal::Decimal;
let d = Decimal::new(1505, 3);
assert_eq!(Decimal64::<2>::try_from(d), Ok(Decimal64::<2>(151)));
let wrapped = Decimal64::<4>::try_from(Decimal::new(-15_000, 4)).unwrap();
assert_eq!(wrapped, Decimal64::<4>(-15_000));
assert_eq!(
Decimal::try_from(wrapped).unwrap(),
Decimal::new(-15_000, 4)
);
assert!(matches!(
Decimal32::<0>::try_from(Decimal::MAX),
Err(DecimalConvertError::Overflow { .. })
));
assert!(matches!(
Decimal128::<10>::try_from(Decimal::MAX),
Err(DecimalConvertError::Rescale { scale: 10, .. })
));
assert!(matches!(
Decimal::try_from(Decimal128::<2>(i128::MAX)),
Err(DecimalConvertError::Unrepresentable { .. })
));
}
#[test]
fn geo_shapes_encode_as_nested_arrays_of_points() {
let p: Point = (1.0, 2.0);
let mut expected = 1.0f64.to_le_bytes().to_vec();
expected.extend_from_slice(&2.0f64.to_le_bytes());
assert_eq!(enc(&p), expected);
let ring: Ring = vec![(1.0, 2.0), (3.0, 4.0)];
let bytes = enc(&ring);
assert_eq!(bytes[0], 2, "LEB128 point count");
assert_eq!(bytes.len(), 1 + 2 * 16);
let poly: Polygon = vec![ring.clone()];
let bytes = enc(&poly);
assert_eq!(bytes[0], 1, "one ring");
assert_eq!(bytes[1], 2, "two points");
let multi: MultiPolygon = vec![poly];
assert_eq!(enc(&multi)[0], 1);
}
}