use crate::visitor::{
error::VisitError,
field::{Field, FieldKind},
Visit, VisitResult, Visitor,
};
const POD_TYPES: &[&str] = &[
"u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64",
];
fn type_id_to_str(type_id: u8) -> &'static str {
POD_TYPES
.get(type_id as usize)
.copied()
.unwrap_or("Invalid Type")
}
pub trait Pod: Copy {
fn type_id() -> u8;
}
impl Pod for u8 {
fn type_id() -> u8 {
0
}
}
impl Pod for i8 {
fn type_id() -> u8 {
1
}
}
impl Pod for u16 {
fn type_id() -> u8 {
2
}
}
impl Pod for i16 {
fn type_id() -> u8 {
3
}
}
impl Pod for u32 {
fn type_id() -> u8 {
4
}
}
impl Pod for i32 {
fn type_id() -> u8 {
5
}
}
impl Pod for u64 {
fn type_id() -> u8 {
6
}
}
impl Pod for i64 {
fn type_id() -> u8 {
7
}
}
impl Pod for f32 {
fn type_id() -> u8 {
8
}
}
impl Pod for f64 {
fn type_id() -> u8 {
9
}
}
pub struct PodVecView<'a, T: Pod> {
type_id: u8,
vec: &'a mut Vec<T>,
}
impl<'a, T: Pod> PodVecView<'a, T> {
pub fn from_pod_vec(vec: &'a mut Vec<T>) -> Self {
Self {
type_id: T::type_id(),
vec,
}
}
}
impl<T: Pod> Visit for PodVecView<'_, T> {
#[allow(clippy::uninit_vec)]
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
if visitor.reading {
if let Some(field) = visitor.find_field(name) {
match &field.kind {
FieldKind::PodArray {
type_id,
element_size,
bytes,
} => {
if *type_id == self.type_id {
let len = bytes.len() / *element_size as usize;
let mut data = Vec::<T>::with_capacity(len);
unsafe {
data.set_len(len);
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
data.as_mut_ptr() as *mut u8,
bytes.len(),
);
}
*self.vec = data;
Ok(())
} else {
Err(VisitError::TypeMismatch {
expected: type_id_to_str(self.type_id),
actual: type_id_to_str(*type_id),
})
}
}
_ => Err(VisitError::FieldTypeDoesNotMatch {
expected: stringify!(FieldKind::PodArray),
actual: format!("{:?}", field.kind),
}),
}
} else {
Err(VisitError::field_does_not_exist(name, visitor))
}
} else if visitor.find_field(name).is_some() {
Err(VisitError::FieldAlreadyExists(name.to_owned()))
} else {
let node = visitor.current_node();
node.fields.push(Field::new(
name,
FieldKind::PodArray {
type_id: T::type_id(),
element_size: std::mem::size_of::<T>() as u32,
bytes: unsafe {
let mut data = self.vec.clone();
let bytes = Vec::from_raw_parts(
data.as_mut_ptr() as *mut u8,
data.len() * std::mem::size_of::<T>(),
data.capacity() * std::mem::size_of::<T>(),
);
std::mem::forget(data);
bytes
},
},
));
Ok(())
}
}
}
#[cfg(test)]
mod test {
use crate::visitor::pod::PodVecView;
#[test]
fn pod_vec_view_from_pod_vec() {
let mut v = Vec::<u8>::new();
let mut v2 = v.clone();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 0_u8);
assert_eq!(p.vec, &mut v2);
let mut v = Vec::<i8>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 1_u8);
let mut v = Vec::<u16>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 2_u8);
let mut v = Vec::<i16>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 3_u8);
let mut v = Vec::<u32>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 4_u8);
let mut v = Vec::<i32>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 5_u8);
let mut v = Vec::<u64>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 6_u8);
let mut v = Vec::<i64>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 7_u8);
let mut v = Vec::<f32>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 8_u8);
let mut v = Vec::<f64>::new();
let p = PodVecView::from_pod_vec(&mut v);
assert_eq!(p.type_id, 9_u8);
}
}