diff --git a/boa/src/builtins/object/internal_state.rs b/boa/src/builtins/object/internal_state.rs new file mode 100644 index 0000000000..06955258cc --- /dev/null +++ b/boa/src/builtins/object/internal_state.rs @@ -0,0 +1,64 @@ +//! Implementations for storing normal rust structs inside any object as internal state. + +use std::{ + any::Any, + fmt::{self, Debug}, + ops::{Deref, DerefMut}, + rc::Rc, +}; + +use gc::{unsafe_empty_trace, Finalize, Trace}; + +/// Wrapper around `Rc` to implement `Trace` and `Finalize`. +#[derive(Clone)] +pub struct InternalStateCell { + /// The internal state. + state: Rc, +} + +impl Finalize for InternalStateCell {} + +unsafe impl Trace for InternalStateCell { + unsafe_empty_trace!(); +} + +impl Deref for InternalStateCell { + type Target = dyn Any; + fn deref(&self) -> &Self::Target { + Deref::deref(&self.state) + } +} + +impl DerefMut for InternalStateCell { + fn deref_mut(&mut self) -> &mut Self::Target { + Rc::get_mut(&mut self.state).expect("failed to get mutable") + } +} + +/// The derived version would print 'InternalStateCell { state: ... }', this custom implementation +/// only prints the actual internal state. +impl Debug for InternalStateCell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.state, f) + } +} + +impl InternalStateCell { + /// Create new `InternalStateCell` from a value. + pub fn new(value: T) -> Self { + Self { + state: Rc::new(value), + } + } + /// Get a reference to the stored value and cast it to `T`. + pub fn downcast_ref(&self) -> Option<&T> { + self.deref().downcast_ref::() + } + /// Get a mutable reference to the stored value and cast it to `T`. + pub fn downcast_mut(&mut self) -> Option<&mut T> { + self.deref_mut().downcast_mut::() + } +} + +/// This trait must be implemented by all structs used for internal state. +pub trait InternalState: Debug {}