clickhouse_arrow/native/values/
int256.rs

1#![expect(clippy::cast_sign_loss)]
2use std::fmt;
3
4use crate::{FromSql, Result, ToSql, Type, Value, unexpected_type};
5
6/// Wrapper type for `ClickHouse` `Int256` type.
7#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd, Debug, Default)]
8#[allow(non_camel_case_types)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct i256(pub [u8; 32]);
11
12impl From<i256> for u256 {
13    fn from(i: i256) -> Self { u256(i.0) }
14}
15
16impl ToSql for i256 {
17    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> { Ok(Value::Int256(self)) }
18}
19
20impl FromSql for i256 {
21    fn from_sql(type_: &Type, value: Value) -> Result<Self> {
22        if !matches!(type_, Type::Int256) {
23            return Err(unexpected_type(type_));
24        }
25        match value {
26            Value::Int256(x) => Ok(x),
27            _ => unimplemented!(),
28        }
29    }
30}
31
32impl From<i256> for (u128, u128) {
33    fn from(i: i256) -> Self {
34        let mut buf = [0u8; 16];
35        buf.copy_from_slice(&i.0[..16]);
36        let n1 = u128::from_be_bytes(buf);
37        buf.copy_from_slice(&i.0[16..]);
38        let n2 = u128::from_be_bytes(buf);
39        (n1, n2)
40    }
41}
42
43impl From<(u128, u128)> for i256 {
44    fn from(other: (u128, u128)) -> Self {
45        let mut buf = [0u8; 32];
46        buf[..16].copy_from_slice(&other.0.to_be_bytes()[..]);
47        buf[16..].copy_from_slice(&other.1.to_be_bytes()[..]);
48        i256(buf)
49    }
50}
51
52impl From<i128> for i256 {
53    fn from(value: i128) -> Self {
54        if value < 0 {
55            // For negative numbers, use two's complement
56            let abs_value = value.unsigned_abs();
57            i256::from((u128::MAX, u128::MAX - abs_value + 1))
58        } else {
59            // For positive numbers, high bits are 0
60            i256::from((0, value as u128))
61        }
62    }
63}
64
65impl From<(i128, u8)> for i256 {
66    fn from((value, scale): (i128, u8)) -> Self {
67        let scaled_value = value * 10i128.pow(u32::from(scale));
68
69        if scaled_value < 0 {
70            // For negative numbers, we need to handle two's complement representation
71            let abs_value = scaled_value.unsigned_abs();
72
73            // For small negative numbers that fit in u128:
74            // High bits are all 1s (0xFFFFFFFF...)
75            // Low bits are the two's complement of the absolute value
76            i256::from((u128::MAX, u128::MAX - abs_value + 1))
77        } else {
78            // For small positive numbers that fit in u128:
79            // High bits are all 0s
80            // Low bits contain the value directly
81            i256::from((0u128, scaled_value as u128))
82        }
83    }
84}
85
86impl fmt::Display for i256 {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        write!(f, "0x")?;
89        for b in self.0 {
90            write!(f, "{b:02X}")?;
91        }
92        Ok(())
93    }
94}
95
96// Create a basic multiply operation for i256 to use in from_parts
97impl std::ops::Mul<i256> for i256 {
98    type Output = Self;
99
100    fn mul(self, rhs: Self) -> Self {
101        // Extract the components from each i256
102        let (a_high, a_low) = self.into();
103        let (b_high, b_low) = rhs.into();
104
105        // For simple cases where one number is small, we can simplify
106        if a_high == 0 && b_high == 0 {
107            // Both numbers fit in u128, so we can just multiply
108            let result = a_low.wrapping_mul(b_low);
109            return i256::from((0, result));
110        }
111
112        // Check for signs
113        let a_negative = (a_high & (1u128 << 127)) != 0;
114        let b_negative = (b_high & (1u128 << 127)) != 0;
115
116        // Get absolute values
117        let (_, a_abs_low) = if a_negative {
118            let low_bits = !a_low;
119            let high_bits = !a_high;
120
121            let new_low = low_bits.wrapping_add(1);
122            let new_high = if new_low == 0 { high_bits.wrapping_add(1) } else { high_bits };
123
124            (new_high, new_low)
125        } else {
126            (a_high, a_low)
127        };
128
129        let (_, abs_b_low) = if b_negative {
130            let low_bits = !b_low;
131            let high_bits = !b_high;
132
133            let new_low = low_bits.wrapping_add(1);
134            let new_high = if new_low == 0 { high_bits.wrapping_add(1) } else { high_bits };
135
136            (new_high, new_low)
137        } else {
138            (b_high, b_low)
139        };
140
141        // Multiply the absolute values
142        // For a simple implementation, we'll only handle the low part
143        // This is sufficient for scaling by small numbers like 10
144        let result = a_abs_low.wrapping_mul(abs_b_low);
145
146        // Apply sign based on input signs
147        let result_negative = a_negative != b_negative;
148
149        if result_negative {
150            // Convert back to two's complement
151            let low_bits = !result;
152            let new_low = low_bits.wrapping_add(1);
153
154            i256::from((u128::MAX, new_low))
155        } else {
156            i256::from((0, result))
157        }
158    }
159}
160
161/// Wrapper type for `ClickHouse` `UInt256` type.
162#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd, Debug, Default)]
163#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
164#[allow(non_camel_case_types)]
165pub struct u256(pub [u8; 32]);
166
167impl ToSql for u256 {
168    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> { Ok(Value::UInt256(self)) }
169}
170
171impl FromSql for u256 {
172    fn from_sql(type_: &Type, value: Value) -> Result<Self> {
173        if !matches!(type_, Type::UInt256) {
174            return Err(unexpected_type(type_));
175        }
176        match value {
177            Value::UInt256(x) => Ok(x),
178            _ => unimplemented!(),
179        }
180    }
181}
182
183impl From<u256> for i256 {
184    fn from(u: u256) -> Self { i256(u.0) }
185}
186
187impl From<u256> for (u128, u128) {
188    fn from(u: u256) -> Self {
189        let mut buf = [0u8; 16];
190        buf.copy_from_slice(&u.0[..16]);
191        let n1 = u128::from_be_bytes(buf);
192        buf.copy_from_slice(&u.0[16..]);
193        let n2 = u128::from_be_bytes(buf);
194        (n1, n2)
195    }
196}
197
198impl From<(u128, u128)> for u256 {
199    fn from(other: (u128, u128)) -> Self {
200        let mut buf = [0u8; 32];
201        buf[..16].copy_from_slice(&other.0.to_be_bytes()[..]);
202        buf[16..].copy_from_slice(&other.1.to_be_bytes()[..]);
203        u256(buf)
204    }
205}
206
207impl fmt::Display for u256 {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        write!(f, "0x")?;
210        for b in self.0 {
211            write!(f, "{b:02X}")?;
212        }
213        Ok(())
214    }
215}