use facet_core::{Facet, FieldError, StructType};
use facet_path::Path;
use crate::{ReflectError, ReflectErrorKind};
use super::Poke;
pub struct PokeStruct<'mem, 'facet> {
pub(crate) value: Poke<'mem, 'facet>,
pub(crate) ty: StructType,
}
impl core::fmt::Debug for PokeStruct<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PokeStruct").finish_non_exhaustive()
}
}
impl<'mem, 'facet> PokeStruct<'mem, 'facet> {
fn err(&self, kind: ReflectErrorKind) -> ReflectError {
ReflectError::new(kind, Path::new(self.value.shape))
}
#[inline(always)]
pub const fn ty(&self) -> &StructType {
&self.ty
}
#[inline(always)]
pub const fn field_count(&self) -> usize {
self.ty.fields.len()
}
pub fn field(&mut self, index: usize) -> Result<Poke<'_, 'facet>, ReflectError> {
let field = self.ty.fields.get(index).ok_or_else(|| {
self.err(ReflectErrorKind::FieldError {
shape: self.value.shape,
field_error: FieldError::IndexOutOfBounds {
index,
bound: self.ty.fields.len(),
},
})
})?;
let field_data = unsafe { self.value.data.field(field.offset) };
let field_shape = field.shape();
Ok(unsafe { Poke::from_raw_parts(field_data, field_shape) })
}
pub fn field_by_name(&mut self, name: &str) -> Result<Poke<'_, 'facet>, ReflectError> {
for (i, field) in self.ty.fields.iter().enumerate() {
if field.name == name {
return self.field(i);
}
}
Err(self.err(ReflectErrorKind::FieldError {
shape: self.value.shape,
field_error: FieldError::NoSuchField,
}))
}
pub fn set_field<T: Facet<'facet>>(
&mut self,
index: usize,
value: T,
) -> Result<(), ReflectError> {
if !self.value.shape.is_pod() {
return Err(self.err(ReflectErrorKind::NotPod {
shape: self.value.shape,
}));
}
let field = self.ty.fields.get(index).ok_or_else(|| {
self.err(ReflectErrorKind::FieldError {
shape: self.value.shape,
field_error: FieldError::IndexOutOfBounds {
index,
bound: self.ty.fields.len(),
},
})
})?;
let field_shape = field.shape();
if field_shape != T::SHAPE {
return Err(self.err(ReflectErrorKind::WrongShape {
expected: field_shape,
actual: T::SHAPE,
}));
}
unsafe {
let field_ptr = self.value.data.field(field.offset);
field_shape.call_drop_in_place(field_ptr);
core::ptr::write(field_ptr.as_mut_byte_ptr() as *mut T, value);
}
Ok(())
}
pub fn set_field_by_name<T: Facet<'facet>>(
&mut self,
name: &str,
value: T,
) -> Result<(), ReflectError> {
for (i, field) in self.ty.fields.iter().enumerate() {
if field.name == name {
return self.set_field(i, value);
}
}
Err(self.err(ReflectErrorKind::FieldError {
shape: self.value.shape,
field_error: FieldError::NoSuchField,
}))
}
pub fn peek_field(&self, index: usize) -> Result<crate::Peek<'_, 'facet>, FieldError> {
let field = self
.ty
.fields
.get(index)
.ok_or(FieldError::IndexOutOfBounds {
index,
bound: self.ty.fields.len(),
})?;
let field_data = unsafe { self.value.data.as_const().field(field.offset) };
Ok(unsafe { crate::Peek::unchecked_new(field_data, field.shape()) })
}
pub fn peek_field_by_name(&self, name: &str) -> Result<crate::Peek<'_, 'facet>, FieldError> {
for (i, field) in self.ty.fields.iter().enumerate() {
if field.name == name {
return self.peek_field(i);
}
}
Err(FieldError::NoSuchField)
}
#[inline]
pub const fn into_inner(self) -> Poke<'mem, 'facet> {
self.value
}
#[inline]
pub fn as_peek_struct(&self) -> crate::PeekStruct<'_, 'facet> {
crate::PeekStruct {
value: self.value.as_peek(),
ty: self.ty,
}
}
}