use crate::data::BindingExpressionBase;
use crate::{FerroObject, FerroProperty, Ref};
use std::rc::Rc;
pub trait BindingBase {
fn create_instance(
&self,
target: &FerroObject,
target_property: Option<&'static FerroProperty>,
anchor: Option<&Ref<FerroObject>>,
) -> Rc<dyn BindingExpressionBase>;
fn as_any(&self) -> Option<&dyn std::any::Any> {
None
}
#[doc(hidden)]
fn reference_id(&self) -> *const () {
self as *const Self as *const ()
}
}
impl PartialEq for dyn BindingBase {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.reference_id() == other.reference_id()
}
}
impl<T: BindingBase + ?Sized> BindingBase for Rc<T> {
fn create_instance(
&self,
target: &FerroObject,
target_property: Option<&'static FerroProperty>,
anchor: Option<&Ref<FerroObject>>,
) -> Rc<dyn BindingExpressionBase> {
(**self).create_instance(target, target_property, anchor)
}
fn as_any(&self) -> Option<&dyn std::any::Any> {
(**self).as_any()
}
fn reference_id(&self) -> *const () {
(**self).reference_id()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::data::{CompiledBinding, CompiledBindingPath, ReflectionBinding};
#[test]
fn a_binding_is_cast_to_its_concrete_class_through_any_handle() {
let reflection = ReflectionBinding::new("Name");
let contract: Rc<dyn BindingBase> = reflection.clone();
assert!(contract.as_any().is_some_and(|any| any.is::<ReflectionBinding>()));
let handle: &dyn BindingBase = &reflection;
let concrete = handle.as_any().and_then(|any| any.downcast_ref::<ReflectionBinding>());
assert!(concrete.is_some_and(|binding| std::ptr::eq(binding, &*reflection)));
let handle: &dyn BindingBase = &contract;
assert!(handle.as_any().is_some_and(|any| any.is::<ReflectionBinding>()));
let compiled: Rc<dyn BindingBase> = CompiledBinding::new(CompiledBindingPath::new());
assert!(compiled.as_any().is_some_and(|any| any.is::<CompiledBinding>()));
assert!(!compiled.as_any().is_some_and(|any| any.is::<ReflectionBinding>()));
}
}