#![no_std]
#![forbid(unsafe_op_in_unsafe_fn, rust_2018_idioms)]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use core::any::Any;
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::panic::UnwindSafe;
pub use fields_iter_macros::FieldsInspect;
#[doc(hidden)]
pub trait FieldsInspectImpl {
fn struct_name() -> &'static str;
fn fields_count() -> u32;
fn field_name(n: u32) -> &'static str;
fn field(&self, n: u32) -> &dyn Any;
unsafe fn field_mut(this: *mut (), n: u32) -> &'static mut dyn Any;
}
impl<'a, T: ?Sized + FieldsInspectImpl + 'a> FieldsInspectImpl for &'a mut T {
fn struct_name() -> &'static str {
T::struct_name()
}
fn fields_count() -> u32 {
T::fields_count()
}
fn field_name(n: u32) -> &'static str {
T::field_name(n)
}
fn field(&self, n: u32) -> &dyn Any {
T::field(*self, n)
}
unsafe fn field_mut(this: *mut (), n: u32) -> &'static mut dyn Any {
unsafe { T::field_mut((*this.cast::<Self>()) as *mut T as *mut (), n) }
}
}
#[doc(hidden)]
pub struct FieldsIterMutVtable {
field_name: fn(u32) -> &'static str,
field_mut: unsafe fn(*mut (), n: u32) -> &'static mut dyn Any,
}
pub trait FieldsInspect {
fn struct_name(&self) -> &'static str;
fn fields_count(&self) -> u32;
fn field_name(&self, n: u32) -> &'static str;
fn field(&self, n: u32) -> &dyn Any;
fn field_mut(&mut self, n: u32) -> &mut dyn Any;
#[doc(hidden)]
fn __fields_mut_iter_vtable(&self) -> &'static FieldsIterMutVtable;
}
impl<T: ?Sized + FieldsInspectImpl> FieldsInspect for T {
fn struct_name(&self) -> &'static str {
<T as FieldsInspectImpl>::struct_name()
}
fn fields_count(&self) -> u32 {
<T as FieldsInspectImpl>::fields_count()
}
fn field_name(&self, n: u32) -> &'static str {
<T as FieldsInspectImpl>::field_name(n)
}
fn field(&self, n: u32) -> &dyn Any {
<T as FieldsInspectImpl>::field(self, n)
}
fn field_mut(&mut self, n: u32) -> &mut dyn Any {
unsafe { <T as FieldsInspectImpl>::field_mut(self as *mut Self as *mut (), n) }
}
#[doc(hidden)]
fn __fields_mut_iter_vtable(&self) -> &'static FieldsIterMutVtable {
&FieldsIterMutVtable {
field_name: <Self as FieldsInspectImpl>::field_name,
field_mut: <Self as FieldsInspectImpl>::field_mut,
}
}
}
pub struct FieldsIter<'a, T: ?Sized = dyn FieldsInspect> {
fields_count: u32,
next_field_idx: u32,
value: &'a T,
}
impl<'a, T: ?Sized + FieldsInspect> FieldsIter<'a, T> {
pub fn new(v: &'a T) -> Self {
Self { fields_count: v.fields_count(), next_field_idx: 0, value: v }
}
}
impl<'a, T: ?Sized + FieldsInspect> Iterator for FieldsIter<'a, T> {
type Item = (&'static str, &'a dyn Any);
fn next(&mut self) -> Option<Self::Item> {
if self.next_field_idx >= self.fields_count {
return None;
}
let name = self.value.field_name(self.next_field_idx);
let value = self.value.field(self.next_field_idx);
self.next_field_idx += 1;
Some((name, value))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let result = self.len();
(result, Some(result))
}
}
impl<'a, T: ?Sized + FieldsInspect> ExactSizeIterator for FieldsIter<'a, T> {
fn len(&self) -> usize {
(self.fields_count - self.next_field_idx) as usize
}
}
impl<'a, T: ?Sized + FieldsInspect> FusedIterator for FieldsIter<'a, T> {}
impl<'a, T: ?Sized + FieldsInspect> DoubleEndedIterator for FieldsIter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.fields_count == self.next_field_idx {
return None;
}
self.fields_count -= 1;
let name = self.value.field_name(self.fields_count);
let value = self.value.field(self.fields_count);
Some((name, value))
}
}
pub struct FieldsIterMut<'a, T: ?Sized = dyn FieldsInspect> {
fields_count: u32,
next_field_idx: u32,
value: *mut (),
vtable: &'static FieldsIterMutVtable,
_marker: PhantomData<&'a mut T>,
}
impl<'a, T: ?Sized + FieldsInspect> FieldsIterMut<'a, T> {
pub fn new(v: &'a mut T) -> Self {
Self {
fields_count: v.fields_count(),
next_field_idx: 0,
value: v as *mut T as *mut (),
vtable: v.__fields_mut_iter_vtable(),
_marker: PhantomData,
}
}
}
impl<'a, T: ?Sized + FieldsInspect> Iterator for FieldsIterMut<'a, T> {
type Item = (&'static str, &'a mut dyn Any);
fn next(&mut self) -> Option<Self::Item> {
if self.next_field_idx >= self.fields_count {
return None;
}
let name = (self.vtable.field_name)(self.next_field_idx);
let value = unsafe { (self.vtable.field_mut)(self.value, self.next_field_idx) };
self.next_field_idx += 1;
Some((name, value))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let result = self.len();
(result, Some(result))
}
}
impl<'a, T: ?Sized + FieldsInspect> ExactSizeIterator for FieldsIterMut<'a, T> {
fn len(&self) -> usize {
(self.fields_count - self.next_field_idx) as usize
}
}
impl<'a, T: ?Sized + FieldsInspect> FusedIterator for FieldsIterMut<'a, T> {}
impl<'a, T: ?Sized + FieldsInspect> DoubleEndedIterator for FieldsIterMut<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.fields_count == self.next_field_idx {
return None;
}
self.fields_count -= 1;
let name = (self.vtable.field_name)(self.fields_count);
let value = unsafe { (self.vtable.field_mut)(self.value, self.fields_count) };
Some((name, value))
}
}
unsafe impl<'a, T: ?Sized + FieldsInspect + Send> Send for FieldsIterMut<'a, T> {}
unsafe impl<'a, T: ?Sized + FieldsInspect + Sync> Sync for FieldsIterMut<'a, T> {}
impl<'a, T: ?Sized + FieldsInspect + UnwindSafe> UnwindSafe for FieldsIterMut<'a, T> {}
#[cold]
#[doc(hidden)]
#[track_caller]
pub fn field_out_of_bounds(struct_name: &str, field: u32) -> ! {
panic!("field index {field} is out of bounds for struct `{struct_name}`")
}
#[doc(hidden)]
pub use core::ptr::addr_of_mut;