wiwi/serialiser/binary/
int.rs1#![allow(
2 unused_variables,
3 reason = "wip"
4)]
5use crate::prelude::*;
6use crate::num::*;
7use super::{ Serialise, Serialiser, Deserialise, Input, Output };
8
9#[repr(transparent)]
10struct IntSerialiser<Num, const BYTES: usize>
11where
12 Num: BytesWithinBounds<BYTES>
13{
14 num: Num
15}
16
17impl<Num, const BYTES: usize> Serialiser<'_> for IntSerialiser<Num, BYTES>
18where
19 Num: BytesWithinBounds<BYTES>
20{
21 #[inline]
22 fn serialise<O>(&self, out: O)
23 where
24 O: Output
25 {
26 let bytes = self.num.clone().into_le_bytes();
27
28 let repr = if Num::SIGNED {
29 unsafe { get_repr_info_signed_le(bytes) }
31 } else {
32 unsafe { get_repr_info_unsigned_le(bytes) }
34 };
35
36 unsafe { serialise_repr_and_marker(out, bytes, repr) }
38 }
39}
40
41#[inline]
45unsafe fn serialise_repr_and_marker<O, const BYTES: usize>(out: O, bytes: [u8; BYTES], repr: IntReprInfo)
46where
47 O: Output
48{
49 unsafe { hint_bytes_valid::<BYTES>() }
51
52 match repr {
53 IntReprInfo::Inline => {}
54 IntReprInfo::I8 => {}
55 IntReprInfo::I16 if BYTES >= 2 => {}
56 IntReprInfo::I24 if BYTES >= 3 => {}
57 IntReprInfo::I32 if BYTES >= 4 => {}
58 IntReprInfo::I48 if BYTES >= 6 => {}
59 IntReprInfo::I64 if BYTES >= 8 => {}
60 IntReprInfo::I96 if BYTES >= 12 => {}
61 IntReprInfo::BigintUnsigned(_len) => {}
62 IntReprInfo::BigintSigned(_len) => {}
63 _ => {
64 unsafe { hint::unreachable_unchecked() }
67 }
68 }
69
70 todo!()
71}
72
73unsafe trait BytesWithinBounds<const BYTES: usize>
80where
81 Self: ArrayConversions<BYTES> + Clone + IntSignedness
82{}
83
84unsafe impl BytesWithinBounds<1> for u8 {}
86
87unsafe impl BytesWithinBounds<2> for u16 {}
89
90unsafe impl BytesWithinBounds<4> for u32 {}
92
93unsafe impl BytesWithinBounds<8> for u64 {}
95
96unsafe impl BytesWithinBounds<16> for u128 {}
98
99#[cfg(target_pointer_width = "16")]
100unsafe impl BytesWithinBounds<2> for usize {}
102
103#[cfg(target_pointer_width = "32")]
104unsafe impl BytesWithinBounds<4> for usize {}
106
107#[cfg(target_pointer_width = "64")]
108unsafe impl BytesWithinBounds<8> for usize {}
110
111unsafe impl BytesWithinBounds<1> for i8 {}
113
114unsafe impl BytesWithinBounds<2> for i16 {}
116
117unsafe impl BytesWithinBounds<4> for i32 {}
119
120unsafe impl BytesWithinBounds<8> for i64 {}
122
123unsafe impl BytesWithinBounds<16> for i128 {}
125
126#[cfg(target_pointer_width = "16")]
127unsafe impl BytesWithinBounds<2> for isize {}
129
130#[cfg(target_pointer_width = "32")]
131unsafe impl BytesWithinBounds<4> for isize {}
133
134#[cfg(target_pointer_width = "64")]
135unsafe impl BytesWithinBounds<8> for isize {}
137
138enum IntReprInfo {
139 Inline,
140 I8,
141 I16,
142 I24,
143 I32,
144 I48,
145 I64,
146 I96,
147 BigintUnsigned(u8),
148 BigintSigned(u8)
149}
150
151struct UnsignedByteCount {
152 count: u8,
153 highest_bit_set: bool
154}
155
156#[inline]
160unsafe fn get_repr_info_unsigned_le<const BYTES: usize>(bytes: [u8; BYTES]) -> IntReprInfo {
161 let byte_count = unsafe { get_byte_count_unsigned_le(bytes) };
163
164 match (byte_count.count, byte_count.highest_bit_set) {
165 (1, false) => { IntReprInfo::I8 }
166 (2, false) | (1, true) => { IntReprInfo::I16 }
167 (3, false) | (2, true) => { IntReprInfo::I24 }
168 (4, false) | (3, true) => { IntReprInfo::I32 }
169 (5..=6, false) | (4..=5, true) => { IntReprInfo::I48 }
170 (7..=8, false) | (6..=7, true) => { IntReprInfo::I64 }
171 (9..=12, false) | (8..=11, true) => { IntReprInfo::I96 }
172 (byte_count, _) => { IntReprInfo::BigintUnsigned(byte_count) }
173 }
174}
175
176#[inline]
180unsafe fn get_repr_info_signed_le<const BYTES: usize>(bytes: [u8; BYTES]) -> IntReprInfo {
181 let byte_count = unsafe { get_byte_count_signed_le(bytes) };
183
184 match byte_count {
185 1 => { IntReprInfo::I8 }
186 2 => { IntReprInfo::I16 }
187 3 => { IntReprInfo::I24 }
188 4 => { IntReprInfo::I32 }
189 5..=6 => { IntReprInfo::I48 }
190 7..=8 => { IntReprInfo::I64 }
191 9..=12 => { IntReprInfo::I96 }
192 byte_count => { IntReprInfo::BigintSigned(byte_count) }
193 }
194}
195
196#[inline]
200unsafe fn get_byte_count_unsigned_le<const BYTES: usize>(bytes: [u8; BYTES]) -> UnsignedByteCount {
201 unsafe { hint_bytes_valid::<BYTES>() }
203
204 for (i, byte) in bytes.into_iter().enumerate().rev() {
205 if byte != 0 {
211 let highest_bit_set = byte >> 7 != 0;
212 return UnsignedByteCount {
213 count: (i + 1).into_u8_lossy(),
216 highest_bit_set
217 }
218 }
219 }
220
221 UnsignedByteCount {
223 count: 1,
224 highest_bit_set: false
225 }
226}
227
228#[inline]
232unsafe fn get_byte_count_signed_le<const BYTES: usize>(bytes: [u8; BYTES]) -> u8 {
233 unsafe { hint_bytes_valid::<BYTES>() }
235
236 let sign_bit = {
237 let byte = unsafe { *bytes.get_unchecked(BYTES - 1) };
240
241 byte >> 7
242 };
243
244 let empty_byte = if sign_bit == 0 { 0 } else { u8::MAX };
247
248 for (i, byte) in bytes.into_iter().enumerate().rev() {
249 if byte == empty_byte {
254 } else if byte >> 7 == sign_bit {
257 return (i + 1).into_u8_lossy()
261 } else {
262 return (i + 2).into_u8_lossy()
268 }
269 }
270
271 1
273}
274
275#[expect(clippy::inline_always, reason = "in release this fn is no-op")]
283#[inline(always)]
284unsafe fn hint_bytes_valid<const BYTES: usize>() {
285 debug_assert!(BYTES > 0);
287 debug_assert!(BYTES <= 256);
289
290 unsafe { hint::assert_unchecked(BYTES > 0) }
292 unsafe { hint::assert_unchecked(BYTES <= 256) }
294}