diff --git a/mission_rust/src/fsrc/introspection.rs b/mission_rust/src/fsrc/introspection.rs new file mode 100644 index 0000000..38e155d --- /dev/null +++ b/mission_rust/src/fsrc/introspection.rs @@ -0,0 +1,63 @@ +/// A trait to allow objects to be queried for some of their inner attributes at runtime. +/// +pub trait Introspection { + /// Executes a function/closure on all members of the implementing struct. + /// + /// The parameters for the closure a reference to the member as well as the name of the member. + /// + /// To keep the trait object safe, we need to pass the closure as a reference. Otherwise, + /// the trait can not be used as a `dyn` reference, because the function becomes generic. + /// (Either using `impl FnMut` not `where F: FnMut` will be treated as generic making the + /// trait not object safe). + /// Additionally, the closure is typed as `FnMut`, to allow the closure to capture mutably. + /// + /// + /// # Examples + /// + /// ```rust + /// use fsrc::introspection::Introspection; + /// + /// struct Empty {} + /// + /// impl Empty { + /// fn getRandomNumber(&self) -> u8 { + /// return 4 // chosen by fair dice roll. + /// // guaranteed to be random. + /// } + /// } + /// + /// fn parsing_something(something: &dyn Introspection) { + /// let mut a = 0; + /// something.for_each_member(&mut |x, _| { + /// if let Some( empty) = x.downcast_ref::() { + /// a = empty.getRandomNumber(); + /// } + /// }); + /// } + /// ```` + /// + fn for_each_member(&self, f: &mut dyn FnMut(&dyn core::any::Any, &str) -> ()); + + /// Same as [for_each_member](Introspection::for_each_member), only with a return value for the closure. + /// + /// # Examples + /// + /// The return value allows using `x.downcast_ref()?` or similar constructs in the closure like in: + /// + /// ```rust + /// use fsrc::introspection::Introspection; + /// + /// struct Empty {} + /// + /// fn do_something(_: &Empty) {} + /// + /// fn parsing_something(something: &dyn Introspection) { + /// something.for_each_member_return(&mut |x, _| { + /// do_something(x.downcast_ref()?); + /// None + /// }); + /// } + /// ``` + /// + fn for_each_member_return(&self, f: &mut dyn FnMut(&dyn core::any::Any, &str) -> Option<()>); +} \ No newline at end of file