Skip to main content

typed_arrow/bridge/
decimals.rs

1//! Decimal128/Decimal256 bindings.
2
3#[cfg(feature = "views")]
4use arrow_array::Array;
5use arrow_array::{
6    Decimal128Array, Decimal256Array,
7    builder::{Decimal128Builder, Decimal256Builder},
8};
9use arrow_buffer::i256;
10use arrow_schema::DataType;
11
12use super::ArrowBinding;
13#[cfg(feature = "views")]
14use super::ArrowBindingView;
15
16/// Fixed-precision decimal stored in 128 bits.
17/// The value is represented as a scaled integer of type `i128`.
18#[derive(Debug, Clone, PartialEq)]
19pub struct Decimal128<const P: u8, const S: i8>(i128);
20impl<const P: u8, const S: i8> Decimal128<P, S> {
21    /// Construct a new `Decimal128<P,S>` from a scaled integer value.
22    #[inline]
23    #[must_use]
24    pub fn new(value: i128) -> Self {
25        Self(value)
26    }
27    /// Return the scaled integer value.
28    #[inline]
29    #[must_use]
30    pub fn value(&self) -> i128 {
31        self.0
32    }
33    /// Consume and return the scaled integer value.
34    #[inline]
35    #[must_use]
36    pub fn into_value(self) -> i128 {
37        self.0
38    }
39}
40
41// Serialize/Deserialize implementation forwards to that for i128.
42#[cfg(feature = "serde")]
43impl<'de, const P: u8, const S: i8> serde::de::Deserialize<'de> for Decimal128<P, S> {
44    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
45    where
46        D: serde::de::Deserializer<'de>,
47    {
48        Ok(Self(i128::deserialize(deserializer)?))
49    }
50}
51
52#[cfg(feature = "serde")]
53impl<const P: u8, const S: i8> serde::Serialize for Decimal128<P, S> {
54    fn serialize<S2: serde::Serializer>(&self, serializer: S2) -> Result<S2::Ok, S2::Error> {
55        self.0.serialize(serializer)
56    }
57}
58
59impl<const P: u8, const S: i8> ArrowBinding for Decimal128<P, S> {
60    type Builder = Decimal128Builder;
61    type Array = Decimal128Array;
62
63    fn data_type() -> DataType {
64        DataType::Decimal128(P, S)
65    }
66
67    fn new_builder(capacity: usize) -> Self::Builder {
68        Decimal128Builder::with_capacity(capacity).with_data_type(DataType::Decimal128(P, S))
69    }
70
71    fn append_value(b: &mut Self::Builder, v: &Self) {
72        b.append_value(v.0);
73    }
74
75    fn append_null(b: &mut Self::Builder) {
76        b.append_null();
77    }
78
79    fn finish(mut b: Self::Builder) -> Self::Array {
80        b.finish()
81    }
82}
83
84#[cfg(feature = "views")]
85impl<const P: u8, const S: i8> ArrowBindingView for Decimal128<P, S> {
86    type Array = Decimal128Array;
87    type View<'a> = Decimal128<P, S>;
88
89    fn get_view(
90        array: &Self::Array,
91        index: usize,
92    ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
93        if index >= array.len() {
94            return Err(crate::schema::ViewAccessError::OutOfBounds {
95                index,
96                len: array.len(),
97                field_name: None,
98            });
99        }
100        if array.is_null(index) {
101            return Err(crate::schema::ViewAccessError::UnexpectedNull {
102                index,
103                field_name: None,
104            });
105        }
106        Ok(Decimal128::new(array.value(index)))
107    }
108}
109
110/// Fixed-precision decimal stored in 256 bits.
111/// The value is represented as a scaled integer of type `i256`.
112pub struct Decimal256<const P: u8, const S: i8>(i256);
113impl<const P: u8, const S: i8> Decimal256<P, S> {
114    /// Construct a new `Decimal256<P,S>` from a scaled integer value.
115    #[inline]
116    #[must_use]
117    pub fn new(value: i256) -> Self {
118        Self(value)
119    }
120    /// Return the scaled integer value.
121    #[inline]
122    #[must_use]
123    pub fn value(&self) -> i256 {
124        self.0
125    }
126    /// Consume and return the scaled integer value.
127    #[inline]
128    #[must_use]
129    pub fn into_value(self) -> i256 {
130        self.0
131    }
132}
133
134impl<const P: u8, const S: i8> ArrowBinding for Decimal256<P, S> {
135    type Builder = Decimal256Builder;
136    type Array = Decimal256Array;
137
138    fn data_type() -> DataType {
139        DataType::Decimal256(P, S)
140    }
141
142    fn new_builder(capacity: usize) -> Self::Builder {
143        Decimal256Builder::with_capacity(capacity).with_data_type(DataType::Decimal256(P, S))
144    }
145
146    fn append_value(b: &mut Self::Builder, v: &Self) {
147        b.append_value(v.0);
148    }
149
150    fn append_null(b: &mut Self::Builder) {
151        b.append_null();
152    }
153
154    fn finish(mut b: Self::Builder) -> Self::Array {
155        b.finish()
156    }
157}
158
159#[cfg(feature = "views")]
160impl<const P: u8, const S: i8> ArrowBindingView for Decimal256<P, S> {
161    type Array = Decimal256Array;
162    type View<'a> = Decimal256<P, S>;
163
164    fn get_view(
165        array: &Self::Array,
166        index: usize,
167    ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
168        if index >= array.len() {
169            return Err(crate::schema::ViewAccessError::OutOfBounds {
170                index,
171                len: array.len(),
172                field_name: None,
173            });
174        }
175        if array.is_null(index) {
176            return Err(crate::schema::ViewAccessError::UnexpectedNull {
177                index,
178                field_name: None,
179            });
180        }
181        Ok(Decimal256::new(array.value(index)))
182    }
183}