use crate::ns::*;
pub struct InterfaceImplementations<'a>(pub &'a SemanticHost);
impl<'a> InterfaceImplementations<'a> {
pub fn verify(&self, implementor: &Thingy, interface: &Thingy) -> Result<Vec<InterfaceImplementationLog>, DeferError> {
let mut interfaces = interface.all_ascending_types(self.0);
interfaces.push(interface.clone());
let mut log: Vec<InterfaceImplementationLog> = vec![];
for interface in interfaces {
interface.defer()?;
let implementor_prototype = implementor.prototype(self.0);
for (name, item) in interface.prototype(self.0).borrow().iter() {
let local_name = name.local_name();
let implementor_item = implementor_prototype.get_in_any_public_ns(&local_name).ok().unwrap_or(None);
if implementor_item.is_none() {
if item.is::<VirtualSlot>() {
if item.getter(self.0).is_some() {
log.push(InterfaceImplementationLog::GetterNotImplemented { name: local_name.clone() });
}
if item.setter(self.0).is_some() {
log.push(InterfaceImplementationLog::SetterNotImplemented { name: local_name.clone() });
}
} else {
log.push(InterfaceImplementationLog::MethodNotImplemented { name: local_name.clone() });
}
} else if item.is::<VirtualSlot>() {
let implementor_item = implementor_item.unwrap();
if !implementor_item.is::<VirtualSlot>() {
log.push(InterfaceImplementationLog::PropertyMustBeVirtual { name: local_name.clone() });
} else {
if implementor_item.getter(self.0).is_none() {
if item.getter(self.0).is_some() {
log.push(InterfaceImplementationLog::GetterNotImplemented { name: local_name.clone() });
}
} else if item.getter(self.0).is_some() && item.getter(self.0).unwrap().signature(self.0) != implementor_item.getter(self.0).unwrap().signature(self.0) {
let expected_signature = item.getter(self.0).unwrap().signature(self.0);
expected_signature.defer()?;
let actual_signature = implementor_item.getter(self.0).unwrap().signature(self.0);
actual_signature.defer()?;
log.push(InterfaceImplementationLog::IncompatibleGetterSignature {
name: local_name.clone(), expected_signature,
});
}
if implementor_item.setter(self.0).is_none() {
if item.setter(self.0).is_some() {
log.push(InterfaceImplementationLog::SetterNotImplemented { name: local_name.clone() });
}
} else if item.setter(self.0).is_some() && item.setter(self.0).unwrap().signature(self.0) != implementor_item.setter(self.0).unwrap().signature(self.0) {
let expected_signature = item.setter(self.0).unwrap().signature(self.0);
expected_signature.defer()?;
let actual_signature = implementor_item.setter(self.0).unwrap().signature(self.0);
actual_signature.defer()?;
log.push(InterfaceImplementationLog::IncompatibleSetterSignature {
name: local_name.clone(), expected_signature,
});
}
}
} else {
let implementor_item = implementor_item.unwrap();
if !implementor_item.is::<MethodSlot>() {
log.push(InterfaceImplementationLog::PropertyMustBeMethod { name: local_name.clone() });
}
let expected_signature = item.signature(self.0);
expected_signature.defer()?;
let actual_signature = implementor_item.signature(self.0);
actual_signature.defer()?;
if expected_signature != actual_signature {
log.push(InterfaceImplementationLog::IncompatibleMethodSignature {
name: local_name.clone(), expected_signature,
});
}
}
}
}
Ok(log)
}
}
pub enum InterfaceImplementationLog {
MethodNotImplemented { name: String },
GetterNotImplemented { name: String },
SetterNotImplemented { name: String },
PropertyMustBeMethod { name: String },
PropertyMustBeVirtual { name: String },
IncompatibleMethodSignature { name: String, expected_signature: Thingy },
IncompatibleGetterSignature { name: String, expected_signature: Thingy },
IncompatibleSetterSignature { name: String, expected_signature: Thingy },
}