smallint/
convert.rs

1use crate::smallint::{SmallIntType, SmallUintType};
2use crate::SmallInt;
3use crate::SmallIntError;
4use crate::SmallUint;
5use core::mem::ManuallyDrop;
6
7macro_rules! int_impl {
8    ($itype:ty, $rt:tt, $rtt:tt, $n:tt) => {
9        impl From<$itype> for $rt {
10            fn from(a: $itype) -> Self {
11                Self(<$rtt>::Inline($n::from(a)))
12            }
13        }
14
15        impl TryFrom<$rt> for $itype {
16            type Error = SmallIntError;
17
18            fn try_from(s: $rt) -> Result<Self, Self::Error> {
19                match s.0 {
20                    $rtt::Inline(i) => {
21                        <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError)
22                    }
23                    $rtt::Heap((_, _)) => Err(SmallIntError::ConversionError),
24                }
25            }
26        }
27    };
28}
29
30int_impl!(u8, SmallInt, SmallIntType, i128);
31int_impl!(u16, SmallInt, SmallIntType, i128);
32int_impl!(u32, SmallInt, SmallIntType, i128);
33int_impl!(u64, SmallInt, SmallIntType, i128);
34int_impl!(i8, SmallInt, SmallIntType, i128);
35int_impl!(i16, SmallInt, SmallIntType, i128);
36int_impl!(i32, SmallInt, SmallIntType, i128);
37int_impl!(i64, SmallInt, SmallIntType, i128);
38int_impl!(i128, SmallInt, SmallIntType, i128);
39
40int_impl!(u8, SmallUint, SmallUintType, u128);
41int_impl!(u16, SmallUint, SmallUintType, u128);
42int_impl!(u32, SmallUint, SmallUintType, u128);
43int_impl!(u64, SmallUint, SmallUintType, u128);
44int_impl!(u128, SmallUint, SmallUintType, u128);
45
46macro_rules! try_from_itou {
47    ($itype:ty) => {
48        impl TryFrom<$itype> for SmallUint {
49            type Error = SmallIntError;
50
51            fn try_from(a: $itype) -> Result<Self, Self::Error> {
52                Ok(Self(SmallUintType::Inline(
53                    u128::try_from(a).map_err(|_| SmallIntError::ConversionError)?,
54                )))
55            }
56        }
57
58        impl TryFrom<SmallUint> for $itype {
59            type Error = SmallIntError;
60
61            fn try_from(s: SmallUint) -> Result<Self, Self::Error> {
62                match s.0 {
63                    SmallUintType::Inline(i) => {
64                        <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError)
65                    }
66                    SmallUintType::Heap((_, _)) => Err(SmallIntError::ConversionError),
67                }
68            }
69        }
70    };
71}
72
73try_from_itou!(i8);
74try_from_itou!(i16);
75try_from_itou!(i32);
76try_from_itou!(i64);
77try_from_itou!(i128);
78
79impl From<u128> for SmallInt {
80    fn from(a: u128) -> Self {
81        match i128::try_from(a) {
82            Ok(i) => Self(SmallIntType::Inline(i)),
83            Err(_) => {
84                let mut v = a;
85                let mut vec = Vec::with_capacity(4);
86                while v != 0 {
87                    vec.push(v as u32);
88
89                    v >>= 32;
90                }
91                let mut slice = ManuallyDrop::new(vec.into_boxed_slice());
92                Self(SmallIntType::Heap((
93                    slice.as_mut_ptr(),
94                    isize::try_from(slice.len()).unwrap(),
95                )))
96            }
97        }
98    }
99}
100
101impl TryFrom<SmallInt> for u128 {
102    type Error = SmallIntError;
103
104    fn try_from(s: SmallInt) -> Result<Self, Self::Error> {
105        match s.0 {
106            SmallIntType::Inline(i) => {
107                u128::try_from(i).map_err(|_| SmallIntError::ConversionError)
108            }
109            SmallIntType::Heap((r, s)) => {
110                let mut ret: u128 = 0;
111                let mut bits = 0;
112                let size = usize::try_from(s.abs()).unwrap();
113                let slice = unsafe { core::slice::from_raw_parts(r, size) };
114                for i in slice {
115                    if bits >= 128 {
116                        return Err(SmallIntError::ConversionError);
117                    }
118                    ret |= u128::from(*i) << bits;
119                    bits += 32;
120                }
121
122                Ok(ret)
123            }
124        }
125    }
126}
127
128impl From<SmallUint> for SmallInt {
129    fn from(s: SmallUint) -> Self {
130        match s.0 {
131            SmallUintType::Inline(i) => SmallInt::from(i),
132            SmallUintType::Heap((r, s)) => {
133                let slice = unsafe { core::slice::from_raw_parts(r, s) };
134                let mut ret = vec![0; s];
135                ret.clone_from_slice(slice);
136                let mut val = ManuallyDrop::new(ret.into_boxed_slice());
137                SmallInt(SmallIntType::Heap((
138                    val.as_mut_ptr(),
139                    isize::try_from(s).unwrap(),
140                )))
141            }
142        }
143    }
144}
145
146impl TryFrom<SmallInt> for SmallUint {
147    type Error = SmallIntError;
148
149    fn try_from(value: SmallInt) -> Result<Self, Self::Error> {
150        match value.0 {
151            SmallIntType::Inline(i) => Self::try_from(i),
152            SmallIntType::Heap((r, s)) => {
153                let size = usize::try_from(s).map_err(|_| SmallIntError::ConversionError)?;
154                if size > 4 {
155                    let slice = unsafe { core::slice::from_raw_parts(r, size) };
156                    let mut ret = vec![0; size];
157                    ret.clone_from_slice(slice);
158                    let mut val = ManuallyDrop::new(ret.into_boxed_slice());
159                    Ok(Self(SmallUintType::Heap((val.as_mut_ptr(), size))))
160                } else {
161                    Ok(Self(SmallUintType::Inline(u128::try_from(value)?)))
162                }
163            }
164        }
165    }
166}
167
168impl SmallUint {
169    /// Converts a `SmallInt` into a `SmallUint` and drops the sign instead of throwing an error.
170    pub fn from_smallint_unsigned(value: SmallInt) -> Self {
171        match value.0 {
172            SmallIntType::Inline(i) => Self::try_from(i.abs()).unwrap(),
173            SmallIntType::Heap((r, s)) => {
174                let size = usize::try_from(s.abs()).unwrap();
175                if size > 4 {
176                    let slice = unsafe { core::slice::from_raw_parts(r, size) };
177                    let mut ret = vec![0; size];
178                    ret.clone_from_slice(slice);
179                    let mut val = ManuallyDrop::new(ret.into_boxed_slice());
180                    Self(SmallUintType::Heap((val.as_mut_ptr(), size)))
181                } else if s >= 0 {
182                    Self(SmallUintType::Inline(u128::try_from(value).unwrap()))
183                } else {
184                    Self(SmallUintType::Inline(u128::try_from(-value).unwrap()))
185                }
186            }
187        }
188    }
189}