#[cfg(any(
feature = "split",
feature = "split-by-struct",
feature = "tokenize",
feature = "dispatch"
))]
use alloc::vec::Vec;
#[cfg(any(feature = "split", feature = "dispatch", feature = "parse-int"))]
use core::any::Any;
#[cfg(any(feature = "split", feature = "dispatch", feature = "parse-int"))]
use crate::compressor::core::exec::NodeCx;
#[cfg(any(feature = "split", feature = "dispatch", feature = "parse-int"))]
pub(crate) enum Param<'p> {
Object(&'p (dyn Any + Send + Sync)),
Bytes(&'p [u8]),
}
#[cfg(any(feature = "split", feature = "dispatch", feature = "parse-int"))]
pub(crate) fn local_param<'p>(cx: &'p NodeCx<'_, '_>, id: i32) -> Option<Param<'p>> {
if let Some(object) = cx.ref_param(id) {
return Some(Param::Object(object));
}
cx.copy_param(id).map(Param::Bytes)
}
#[cfg(any(feature = "split", feature = "tokenize"))]
pub(crate) fn read_le(bytes: &[u8]) -> u64 {
let mut word = [0u8; 8];
word[..bytes.len()].copy_from_slice(bytes);
u64::from_le_bytes(word)
}
#[cfg(any(feature = "tokenize", feature = "dispatch"))]
pub(crate) fn push_le(out: &mut Vec<u8>, value: u64, width: usize) {
out.extend_from_slice(&value.to_le_bytes()[..width]);
}
#[cfg(feature = "dispatch")]
pub(crate) const fn width_for(max_value: u64) -> usize {
if max_value < 256 {
1
} else if max_value < 65_536 {
2
} else if max_value <= u32::MAX as u64 {
4
} else {
8
}
}
#[cfg(any(feature = "split", feature = "split-by-struct"))]
pub(crate) fn usize_words(bytes: &[u8]) -> Vec<usize> {
bytes
.as_chunks::<{ core::mem::size_of::<usize>() }>()
.0
.iter()
.map(|chunk| usize::from_ne_bytes(*chunk))
.collect()
}
#[cfg(feature = "split")]
pub(crate) fn usize_array(param: &Param<'_>) -> Option<Vec<usize>> {
match param {
Param::Object(object) => object.downcast_ref::<Vec<usize>>().cloned(),
Param::Bytes(bytes) => Some(usize_words(bytes)),
}
}
#[cfg(all(
test,
feature = "split",
feature = "split-by-struct",
feature = "tokenize",
feature = "dispatch",
feature = "parse-int"
))]
mod tests {
use super::*;
#[test]
fn little_endian_helpers_round_trip() {
let mut out = Vec::new();
push_le(&mut out, 0x0102_0304, 3);
assert_eq!(out, [4, 3, 2]);
assert_eq!(read_le(&out), 0x0002_0304);
assert_eq!(read_le(&[]), 0);
}
#[test]
fn widths_follow_the_value_ranges() {
assert_eq!(
[0, 255, 256, 65_535, 65_536, u64::from(u32::MAX), 1 << 32].map(width_for),
[1, 1, 2, 2, 4, 4, 8]
);
}
#[test]
fn size_arrays_come_from_objects_or_bytes() {
let object: Vec<usize> = alloc::vec![3, 5];
let found = usize_array(&Param::Object(&object)).unwrap();
assert_eq!(found, [3, 5]);
let wrong = 7u8;
assert!(usize_array(&Param::Object(&wrong)).is_none());
let mut bytes = Vec::new();
bytes.extend_from_slice(&9usize.to_ne_bytes());
bytes.extend_from_slice(&[1, 2, 3]);
assert_eq!(usize_array(&Param::Bytes(&bytes)).unwrap(), [9]);
}
}