use core::fmt::{Display, Debug};
use crate::ptr::{OpaqueConst, OpaqueMut};
use crate::types::{self, StructType, TypeKind};
use crate::{Model, Reflect};
pub struct Inspect<'ins, 'data, 'model> {
ptr: OpaqueConst<'data>,
model: &'ins Model<'model>,
}
impl<'ins, 'data, 'model> Display for Inspect<'ins, 'data, 'model> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.model.vtable.display {
Some(display) => {
unsafe { display(self.ptr, f) }
}
None => {
write!(f, "Model ( {:?} )", self.model.ty)
}
}
}
}
impl<'ins, 'data, 'model> Debug for Inspect<'ins, 'data, 'model> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.model.vtable.debug {
Some(debug) => {
unsafe { debug(self.ptr, f) }
}
None => {
write!(f, "Model ( {:?} )", self.model.ty)
}
}
}
}
impl<'ins, 'data, 'model> Inspect<'ins, 'data, 'model> {
pub fn new<R: Reflect + ?Sized>(r: &'data R) -> Self {
Self {
ptr: OpaqueConst::new(r),
model: R::MODEL,
}
}
pub fn from_parts(model: &'model Model<'model>, ptr: OpaqueConst<'data>) -> Self {
Self { ptr, model }
}
pub fn fields(&'ins self) -> Option<InspectFields<'data, 'model>> {
let TypeKind::Struct(sty) = &self.model.ty.kind else { return None };
Some(InspectFields::new(sty, self.ptr))
}
}
pub struct InspectFields<'data, 'model> {
ptr: OpaqueConst<'data>,
sty: &'model StructType<'model>,
}
impl<'data, 'model> InspectFields<'data, 'model> {
pub fn new(sty: &'model StructType<'model>, ptr: OpaqueConst<'data>) -> Self {
Self { ptr, sty }
}
pub fn get_by_name<T: 'static>(&self, name: &str) -> Option<&T> {
for field in self.sty.fields {
if field.name == name {
let exp_id = core::any::TypeId::of::<T>();
if field.model.ty.id.get() != exp_id {
return None
}
unsafe {
let r = self.ptr
.as_byte_ptr()
.byte_add(field.offset)
.cast::<T>()
.as_ref()
.unwrap();
return Some(r)
}
}
}
None
}
pub fn get_at<T: 'static>(&self, index: usize) -> Option<&T> {
unsafe {
self.ptr
.as_byte_ptr()
.add( self.sty.fields[index].offset )
.cast::<T>()
.as_ref()
}
}
pub const fn len(&self) -> usize {
self.sty.fields.len()
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'data, 'model> IntoIterator for InspectFields<'data, 'model> {
type Item = Field<'data, 'model>;
type IntoIter = FieldsIter<'data, 'model>;
fn into_iter(self) -> Self::IntoIter {
FieldsIter {
fields: self.sty.fields,
offset: 0,
ptr: self.ptr,
}
}
}
pub struct Field<'data, 'model> {
pub f: &'model types::Field<'model>,
pub ptr: OpaqueConst<'data>,
}
pub struct FieldsIter<'data, 'model> {
offset: usize,
fields: &'model [types::Field<'model>],
ptr: OpaqueConst<'data>
}
impl<'data, 'model> Iterator for FieldsIter<'data, 'model> {
type Item = Field<'data, 'model>;
fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.fields.len() {
return None
}
let f = &self.fields[self.offset];
let ptr = self.ptr.byte_add(f.offset);
let f = Field { f, ptr };
self.offset += 1;
Some(f)
}
}
pub struct InspectMut<'ins, 'data, 'model> {
ptr: OpaqueMut<'data>,
model: &'ins Model<'model>,
}
impl<'ins, 'data, 'model> Display for InspectMut<'ins, 'data, 'model> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.model.vtable.display {
Some(display) => {
unsafe { display(self.ptr.as_const(), f) }
}
None => {
write!(f, "Model ( {:?} )", self.model.ty)
}
}
}
}
impl<'ins, 'data, 'model> Debug for InspectMut<'ins, 'data, 'model> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.model.vtable.debug {
Some(debug) => {
unsafe { debug(self.ptr.as_const(), f) }
}
None => {
write!(f, "Model ( {:?} )", self.model.ty)
}
}
}
}
impl<'ins, 'data, 'model> InspectMut<'ins, 'data, 'model> {
pub fn new<R: Reflect + ?Sized>(r: &'data mut R) -> Self {
Self {
ptr: OpaqueMut::new(r),
model: R::MODEL,
}
}
pub fn fields<'d>(&'d self) -> Option<InspectFields<'d, 'model>> {
let TypeKind::Struct(sty) = &self.model.ty.kind else { return None };
Some(InspectFields::new(sty, self.ptr.as_const()))
}
pub fn fields_mut(&mut self) -> Option<InspectFieldsMut<'data, 'model>> {
let TypeKind::Struct(sty) = &self.model.ty.kind else { return None };
Some(InspectFieldsMut::new(sty, self.ptr))
}
}
pub struct InspectFieldsMut<'data, 'model> {
ptr: OpaqueMut<'data>,
sty: &'model StructType<'model>,
}
impl<'data, 'model> InspectFieldsMut<'data, 'model> {
pub fn new(sty: &'model StructType<'model>, ptr: OpaqueMut<'data>) -> Self {
Self { ptr, sty }
}
fn _get_raw_by_name<T: 'static>(&self, name: &str, ptr: *mut u8) -> Option<*mut T> {
for field in self.sty.fields {
if field.name == name {
let exp_id = core::any::TypeId::of::<T>();
if field.model.ty.id.get() != exp_id {
return None
}
unsafe {
let r = ptr.byte_add(field.offset)
.cast::<T>();
return Some(r)
}
}
}
None
}
pub fn get_by_name<T: 'static>(&self, name: &str) -> Option<&T> {
self._get_raw_by_name(name, self.ptr.as_byte_ptr() as *mut _)
.and_then(|p: *mut T| unsafe { p.as_ref() })
}
pub fn get_by_name_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T> {
let p = self.ptr.as_mut_byte_ptr();
self._get_raw_by_name(name, p)
.and_then(|p: *mut T| unsafe { p.as_mut() })
}
pub fn set_by_name<T: 'static>(&mut self, name: &str, val: T) -> Result<(), T> {
match self.get_by_name_mut::<T>(name) {
Some(e) => {
*e = val;
Ok(())
}
None => Err(val)
}
}
pub fn get_at<T: 'static>(&self, index: usize) -> Option<&T> {
unsafe {
self.ptr
.as_byte_ptr()
.add( self.sty.fields[index].offset )
.cast::<T>()
.as_ref()
}
}
pub fn get_at_mut<T: 'static>(&mut self, index: usize) -> Option<&mut T> {
unsafe {
self.ptr
.as_mut_byte_ptr()
.add( self.sty.fields[index].offset )
.cast::<T>()
.as_mut()
}
}
pub fn set_at<T: 'static>(&mut self, index: usize, val: T) -> Result<(), T> {
match self.get_at_mut::<T>(index) {
Some(r) => {
*r = val;
Ok(())
}
None => Err(val)
}
}
}