1use crate::ext::Complex;
2use crate::header::*;
3use crate::size::write_size;
4use core::ptr;
5use half::{bf16, f16};
6
7#[inline]
9fn write_typed_array_header_numeric(out: &mut Vec<u8>, class: u8, byte_code: u8, len: usize) {
10 let header = ((byte_code & 0b111) << 5) | ((class & 0b11) << 3) | (TYPE_TYPED_ARRAY & 0b111);
11 out.push(header);
12 write_size(len as u64, out);
13}
14
15#[inline]
17fn write_typed_array_header_bool(out: &mut Vec<u8>, len: usize) {
18 let header = ((ARRAY_BOOL_OR_STRING & 0b11) << 3) | (TYPE_TYPED_ARRAY & 0b111);
19 out.push(header);
20 write_size(len as u64, out);
21}
22
23#[inline]
25fn write_typed_array_header_string(out: &mut Vec<u8>, len: usize) {
26 let header = ((1u8) << 5) | ((ARRAY_BOOL_OR_STRING & 0b11) << 3) | (TYPE_TYPED_ARRAY & 0b111);
28 out.push(header);
29 write_size(len as u64, out);
30}
31
32pub trait BeveTypedSlice: Sized {
34 const CLASS: u8;
36 const BYTE_CODE: u8;
38 const ELEM_SIZE: usize;
40 fn write_one_le(v: &Self, out: &mut Vec<u8>);
42}
43
44macro_rules! impl_beve_typed_int {
45 ($t:ty, $class:expr, $code:expr) => {
46 impl BeveTypedSlice for $t {
47 const CLASS: u8 = $class;
48 const BYTE_CODE: u8 = $code;
49 const ELEM_SIZE: usize = core::mem::size_of::<$t>();
50 #[inline]
51 fn write_one_le(v: &Self, out: &mut Vec<u8>) {
52 out.extend_from_slice(&v.to_le_bytes());
53 }
54 }
55 };
56}
57
58impl_beve_typed_int!(i8, ARRAY_SIGNED, 0);
59impl_beve_typed_int!(i16, ARRAY_SIGNED, 1);
60impl_beve_typed_int!(i32, ARRAY_SIGNED, 2);
61impl_beve_typed_int!(i64, ARRAY_SIGNED, 3);
62impl_beve_typed_int!(i128, ARRAY_SIGNED, 4);
63
64impl_beve_typed_int!(u8, ARRAY_UNSIGNED, 0);
65impl_beve_typed_int!(u16, ARRAY_UNSIGNED, 1);
66impl_beve_typed_int!(u32, ARRAY_UNSIGNED, 2);
67impl_beve_typed_int!(u64, ARRAY_UNSIGNED, 3);
68impl_beve_typed_int!(u128, ARRAY_UNSIGNED, 4);
69
70impl BeveTypedSlice for f32 {
71 const CLASS: u8 = ARRAY_FLOAT;
72 const BYTE_CODE: u8 = 2; const ELEM_SIZE: usize = core::mem::size_of::<f32>();
74 #[inline]
75 fn write_one_le(v: &Self, out: &mut Vec<u8>) {
76 out.extend_from_slice(&v.to_le_bytes());
77 }
78}
79impl BeveTypedSlice for f64 {
80 const CLASS: u8 = ARRAY_FLOAT;
81 const BYTE_CODE: u8 = 3; const ELEM_SIZE: usize = core::mem::size_of::<f64>();
83 #[inline]
84 fn write_one_le(v: &Self, out: &mut Vec<u8>) {
85 out.extend_from_slice(&v.to_le_bytes());
86 }
87}
88impl BeveTypedSlice for bf16 {
89 const CLASS: u8 = ARRAY_FLOAT;
90 const BYTE_CODE: u8 = 0; const ELEM_SIZE: usize = core::mem::size_of::<bf16>();
92 #[inline]
93 fn write_one_le(v: &Self, out: &mut Vec<u8>) {
94 out.extend_from_slice(&v.to_le_bytes());
95 }
96}
97impl BeveTypedSlice for f16 {
98 const CLASS: u8 = ARRAY_FLOAT;
99 const BYTE_CODE: u8 = 1; const ELEM_SIZE: usize = core::mem::size_of::<f16>();
101 #[inline]
102 fn write_one_le(v: &Self, out: &mut Vec<u8>) {
103 out.extend_from_slice(&v.to_le_bytes());
104 }
105}
106
107pub fn write_typed_slice<T: BeveTypedSlice>(out: &mut Vec<u8>, slice: &[T]) {
109 let payload = core::mem::size_of_val(slice);
110 out.reserve(1 + 8 + payload);
112 write_typed_array_header_numeric(out, T::CLASS, T::BYTE_CODE, slice.len());
113 if slice.is_empty() {
114 return;
115 }
116 #[cfg(target_endian = "little")]
117 {
118 let start = out.len();
119 unsafe {
120 let dst = out.as_mut_ptr().add(start);
121 ptr::copy_nonoverlapping(slice.as_ptr() as *const u8, dst, payload);
122 out.set_len(start + payload);
123 }
124 }
125 #[cfg(not(target_endian = "little"))]
126 {
127 for v in slice {
128 T::write_one_le(v, out);
129 }
130 }
131}
132
133pub fn to_vec_typed_slice<T: BeveTypedSlice>(slice: &[T]) -> Vec<u8> {
135 let payload = slice.len() * T::ELEM_SIZE;
136 let mut out = Vec::with_capacity(1 + 8 + payload);
137 write_typed_slice(&mut out, slice);
138 out
139}
140
141pub fn write_bool_slice(out: &mut Vec<u8>, slice: &[bool]) {
143 write_typed_array_header_bool(out, slice.len());
144 let mut acc: u8 = 0;
146 let mut idx: u8 = 0; for &b in slice {
148 if b {
149 acc |= 1 << (7 - idx);
150 }
151 idx += 1;
152 if idx == 8 {
153 out.push(acc);
154 acc = 0;
155 idx = 0;
156 }
157 }
158 if idx != 0 {
159 out.push(acc);
160 }
161}
162
163pub fn to_vec_bool_slice(slice: &[bool]) -> Vec<u8> {
165 let mut out = Vec::new();
166 write_bool_slice(&mut out, slice);
167 out
168}
169
170pub fn write_str_slice(out: &mut Vec<u8>, slice: &[&str]) {
172 write_typed_array_header_string(out, slice.len());
173 for s in slice {
174 write_size(s.len() as u64, out);
175 out.extend_from_slice(s.as_bytes());
176 }
177}
178
179pub fn to_vec_str_slice(slice: &[&str]) -> Vec<u8> {
181 let mut out = Vec::new();
182 write_str_slice(&mut out, slice);
183 out
184}
185
186pub fn write_string_slice(out: &mut Vec<u8>, slice: &[String]) {
188 write_typed_array_header_string(out, slice.len());
189 for s in slice {
190 write_size(s.len() as u64, out);
191 out.extend_from_slice(s.as_bytes());
192 }
193}
194
195pub fn to_vec_string_slice(slice: &[String]) -> Vec<u8> {
197 let mut out = Vec::new();
198 write_string_slice(&mut out, slice);
199 out
200}
201
202#[inline]
205fn write_complex_header(out: &mut Vec<u8>, is_array: bool, byte_code: u8) {
206 out.push(((EXT_COMPLEX & 0x1f) << 3) | (TYPE_EXTENSION & 0b111));
208 let h = ((byte_code & 0b111) << 5) | ((NUM_FLOAT & 0b11) << 3) | (if is_array { 1 } else { 0 });
209 out.push(h);
210}
211
212pub fn to_vec_complex64(re: f64, im: f64) -> Vec<u8> {
213 let mut out = Vec::new();
214 write_complex_header(&mut out, false, 3);
215 out.extend_from_slice(&re.to_le_bytes());
216 out.extend_from_slice(&im.to_le_bytes());
217 out
218}
219
220pub fn to_vec_complex32(re: f32, im: f32) -> Vec<u8> {
221 let mut out = Vec::new();
222 write_complex_header(&mut out, false, 2);
223 out.extend_from_slice(&re.to_le_bytes());
224 out.extend_from_slice(&im.to_le_bytes());
225 out
226}
227
228pub fn to_vec_complex64_slice(slice: &[Complex<f64>]) -> Vec<u8> {
229 let payload = core::mem::size_of_val(slice);
230 let mut out = Vec::with_capacity(2 + 8 + payload);
231 write_complex_header(&mut out, true, 3);
232 write_size(slice.len() as u64, &mut out);
233 if !slice.is_empty() {
234 #[cfg(target_endian = "little")]
235 {
236 let start = out.len();
237 unsafe {
238 let dst = out.as_mut_ptr().add(start);
239 ptr::copy_nonoverlapping(slice.as_ptr() as *const u8, dst, payload);
240 out.set_len(start + payload);
241 }
242 }
243 #[cfg(not(target_endian = "little"))]
244 {
245 out.reserve(payload);
246 for c in slice {
247 out.extend_from_slice(&c.re.to_le_bytes());
248 out.extend_from_slice(&c.im.to_le_bytes());
249 }
250 }
251 }
252 out
253}
254
255pub fn to_vec_complex32_slice(slice: &[Complex<f32>]) -> Vec<u8> {
256 let payload = core::mem::size_of_val(slice);
257 let mut out = Vec::with_capacity(2 + 8 + payload);
258 write_complex_header(&mut out, true, 2);
259 write_size(slice.len() as u64, &mut out);
260 if !slice.is_empty() {
261 #[cfg(target_endian = "little")]
262 {
263 let start = out.len();
264 unsafe {
265 let dst = out.as_mut_ptr().add(start);
266 ptr::copy_nonoverlapping(slice.as_ptr() as *const u8, dst, payload);
267 out.set_len(start + payload);
268 }
269 }
270 #[cfg(not(target_endian = "little"))]
271 {
272 out.reserve(payload);
273 for c in slice {
274 out.extend_from_slice(&c.re.to_le_bytes());
275 out.extend_from_slice(&c.im.to_le_bytes());
276 }
277 }
278 }
279 out
280}
281
282#[derive(Clone, Copy, Debug, PartialEq, Eq)]
285pub enum MatrixLayoutFast {
286 Right,
287 Left,
288}
289
290pub fn to_vec_matrix_f64(layout: MatrixLayoutFast, extents: &[u64], data: &[f64]) -> Vec<u8> {
291 let mut out = Vec::new();
292 out.push(((EXT_MATRICES & 0x1f) << 3) | (TYPE_EXTENSION & 0b111));
294 let mh = match layout {
296 MatrixLayoutFast::Right => 0u8,
297 MatrixLayoutFast::Left => 1u8,
298 };
299 out.push(mh);
300 write_typed_array_header_numeric(&mut out, ARRAY_UNSIGNED, 3, extents.len());
302 for &e in extents {
303 out.extend_from_slice(&e.to_le_bytes());
304 }
305 write_typed_array_header_numeric(&mut out, ARRAY_FLOAT, 3, data.len());
307 for &v in data {
308 out.extend_from_slice(&v.to_le_bytes());
309 }
310 out
311}