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}
216
217#[cfg(test)]
218mod tests {
219    use super::*;
220    use crate::{Type, Value};
221
222    #[test]
223    fn test_i256_to_u128_tuple() {
224        // Test zero conversion
225        let zero = i256([0u8; 32]);
226        let (high, low) = zero.into();
227        assert_eq!(high, 0u128);
228        assert_eq!(low, 0u128);
229
230        // Test max value conversion
231        let max = i256([0xFFu8; 32]);
232        let (high, low) = max.into();
233        assert_eq!(high, u128::MAX);
234        assert_eq!(low, u128::MAX);
235
236        // Test mixed value
237        let mut bytes = [0u8; 32];
238        bytes[15] = 0x12; // Last byte of first u128
239        bytes[31] = 0x34; // Last byte of second u128
240        let mixed = i256(bytes);
241        let (high, low) = mixed.into();
242        assert_eq!(high, 0x12);
243        assert_eq!(low, 0x34);
244    }
245
246    #[test]
247    fn test_i256_from_i128_scale() {
248        // Test positive small scale
249        let result = i256::from((123i128, 2u8));
250        let expected = i256::from((0u128, 12300u128));
251        assert_eq!(result, expected);
252
253        // Test negative small scale
254        let result = i256::from((-456i128, 3u8));
255        let scaled_value = -456_000i128;
256        let abs_value = scaled_value.unsigned_abs();
257        let expected = i256::from((u128::MAX, u128::MAX - abs_value + 1));
258        assert_eq!(result, expected);
259
260        // Test zero with scale
261        let result = i256::from((0i128, 5u8));
262        let expected = i256::from((0u128, 0u128));
263        assert_eq!(result, expected);
264
265        // Test larger scale
266        let result = i256::from((42i128, 10u8));
267        let expected = i256::from((0u128, 420_000_000_000u128));
268        assert_eq!(result, expected);
269    }
270
271    #[test]
272    fn test_i256_multiplication_simple_cases() {
273        // Test simple multiplication within u128 range
274        let a = i256::from((0u128, 100u128));
275        let b = i256::from((0u128, 200u128));
276        let result = a * b;
277        let expected = i256::from((0u128, 20000u128));
278        assert_eq!(result, expected);
279
280        // Test multiplication by zero
281        let a = i256::from((0u128, 12345u128));
282        let b = i256::from((0u128, 0u128));
283        let result = a * b;
284        let expected = i256::from((0u128, 0u128));
285        assert_eq!(result, expected);
286
287        // Test multiplication by one
288        let a = i256::from((0u128, 9876u128));
289        let b = i256::from((0u128, 1u128));
290        let result = a * b;
291        assert_eq!(result, a);
292    }
293
294    #[test]
295    fn test_i256_multiplication_negative_numbers() {
296        // Test negative * positive
297        let a = i256::from((u128::MAX, u128::MAX - 100 + 1)); // -100
298        let b = i256::from((0u128, 50u128)); // 50
299        let result = a * b;
300
301        // Result should be negative (u128::MAX in high bits)
302        let (high, _) = result.into();
303        assert_eq!(high, u128::MAX);
304
305        // Test positive * negative
306        let a = i256::from((0u128, 75u128)); // 75
307        let b = i256::from((u128::MAX, u128::MAX - 25 + 1)); // -25
308        let result = a * b;
309
310        // Result should be negative
311        let (high, _) = result.into();
312        assert_eq!(high, u128::MAX);
313
314        // Test negative * negative should be positive
315        let a = i256::from((u128::MAX, u128::MAX - 10 + 1)); // -10
316        let b = i256::from((u128::MAX, u128::MAX - 20 + 1)); // -20
317        let result = a * b;
318
319        // Result should be positive
320        let (high, low) = result.into();
321        assert_eq!(high, 0u128);
322        assert_eq!(low, 200u128);
323    }
324
325    #[test]
326    fn test_i256_multiplication_complex_cases() {
327        // Test multiplication where high bits are involved
328        let a = i256::from((1u128, 100u128));
329        let b = i256::from((2u128, 200u128));
330        let result = a * b;
331
332        // This should trigger the complex multiplication path
333        // The exact result depends on the implementation details
334        // but we can verify it doesn't panic and produces some result
335        let _: (u128, u128) = result.into();
336    }
337
338    #[test]
339    fn test_u256_to_i256_conversion() {
340        let u = u256([0x12u8; 32]);
341        let i: i256 = u.into();
342        assert_eq!(i.0, [0x12u8; 32]);
343    }
344
345    #[test]
346    fn test_u256_to_u128_tuple() {
347        // Test zero conversion
348        let zero = u256([0u8; 32]);
349        let (high, low) = zero.into();
350        assert_eq!(high, 0u128);
351        assert_eq!(low, 0u128);
352
353        // Test max value conversion
354        let max = u256([0xFFu8; 32]);
355        let (high, low) = max.into();
356        assert_eq!(high, u128::MAX);
357        assert_eq!(low, u128::MAX);
358
359        // Test mixed value
360        let mut bytes = [0u8; 32];
361        bytes[15] = 0xAB; // Last byte of first u128
362        bytes[31] = 0xCD; // Last byte of second u128
363        let mixed = u256(bytes);
364        let (high, low) = mixed.into();
365        assert_eq!(high, 0xAB);
366        assert_eq!(low, 0xCD);
367    }
368
369    #[test]
370    fn test_from_sql_error_handling() {
371        // Test i256 with wrong type - i256 should fail with UInt256 type
372        let result = i256::from_sql(&Type::UInt256, Value::Int256(i256([0u8; 32])));
373        assert!(result.is_err(), "i256::from_sql should fail with UInt256 type");
374
375        // Test u256 with wrong type - u256 should fail with Int256 type
376        let result = u256::from_sql(&Type::Int256, Value::UInt256(u256([0u8; 32])));
377        assert!(result.is_err(), "u256::from_sql should fail with Int256 type");
378
379        // Test correct types for comparison
380        let result = i256::from_sql(&Type::Int256, Value::Int256(i256([0u8; 32])));
381        assert!(result.is_ok(), "i256::from_sql should succeed with Int256 type");
382
383        let result = u256::from_sql(&Type::UInt256, Value::UInt256(u256([0u8; 32])));
384        assert!(result.is_ok(), "u256::from_sql should succeed with UInt256 type");
385    }
386
387    #[test]
388    fn test_from_sql_unimplemented_values() {
389        // Test i256 with unsupported Value variant
390        let result = std::panic::catch_unwind(|| i256::from_sql(&Type::Int256, Value::Int32(42)));
391        assert!(result.is_err()); // Should panic with unimplemented!()
392
393        // Test u256 with unsupported Value variant
394        let result = std::panic::catch_unwind(|| u256::from_sql(&Type::UInt256, Value::UInt32(42)));
395        assert!(result.is_err()); // Should panic with unimplemented!()
396    }
397
398    #[test]
399    fn test_display_formatting() {
400        // Test i256 display
401        let i = i256([
402            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
403            0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
404            0x1C, 0x1D, 0x1E, 0x1F,
405        ]);
406        let formatted = format!("{i}");
407        assert_eq!(formatted, "0x000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
408
409        // Test u256 display
410        let u = u256([0xFF; 32]);
411        let formatted = format!("{u}");
412        assert_eq!(formatted, "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
413    }
414
415    #[test]
416    fn test_conversion_roundtrips() {
417        // Test i256 -> (u128, u128) -> i256 roundtrip
418        let original = i256([
419            0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
420            0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x12, 0x34, 0x56, 0x78,
421            0x9A, 0xBC, 0xDE, 0xF0,
422        ]);
423        let tuple: (u128, u128) = original.into();
424        let reconstructed = i256::from(tuple);
425        assert_eq!(original, reconstructed);
426
427        // Test u256 -> (u128, u128) -> u256 roundtrip
428        let original = u256([
429            0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33,
430            0x22, 0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0xF0, 0xDE, 0xBC, 0x9A,
431            0x78, 0x56, 0x34, 0x12,
432        ]);
433        let tuple: (u128, u128) = original.into();
434        let reconstructed = u256::from(tuple);
435        assert_eq!(original, reconstructed);
436    }
437
438    #[test]
439    fn test_edge_cases() {
440        // Test scaling with large u8 scale value (but not max to avoid overflow)
441        let result = i256::from((1i128, 20u8));
442        // This shouldn't panic
443        let _: (u128, u128) = result.into();
444
445        // Test i128 min/max values
446        let min_result = i256::from(i128::MIN);
447        let max_result = i256::from(i128::MAX);
448
449        // Verify these don't panic and produce some result
450        let _: (u128, u128) = min_result.into();
451        let _: (u128, u128) = max_result.into();
452    }
453}