Files
endorphin-tessera-gui/src/protocols.rs
T

91 lines
3.3 KiB
Rust

//! Host capability definitions over Aster's explicit managed trait relations.
use endor_core::{
AnnotationType, CallArity, CallEffect, CallSignature, ObjectRef, TypedMethodRequirement, Value,
Vm, VmError,
};
pub fn install(
vm: &mut Vm,
roots: &mut Vec<ObjectRef>,
desktop: ObjectRef,
ui: ObjectRef,
) -> Result<(), VmError> {
let Value::Object(trait_type) = vm.get_attr(ui, "Trait")? else {
return Err(VmError::InvalidArgument("missing Trait type"));
};
let Value::Object(types) = vm.get_attr(desktop, "types")? else {
return Err(VmError::InvalidArgument("missing type registry"));
};
for (name, methods, owner) in [
(
"Visual",
vec![("measure", 2), ("arrange", 2), ("paint", 2), ("hitTest", 2)],
Some("Block"),
),
(
"EventTarget",
vec![("on", 3), ("dispatch", 2), ("onEvent", 1)],
Some("Block"),
),
(
"Children",
vec![
("append", 1),
("insert", 2),
("remove", 1),
("replace", 2),
("move", 2),
("children", 0),
],
Some("ContainerBlock"),
),
("Presentable", vec![("present", 1)], None),
] {
let owner_definition = if let Some(owner) = owner {
let Value::Object(definition) = vm.get_attr(ui, owner)? else {
return Err(VmError::InvalidArgument("missing protocol owner"));
};
Some(definition)
} else {
None
};
let mut requirements = Vec::new();
for (method, parameters) in methods {
let mut signature = if let Some(owner) = owner_definition {
let function = vm
.object_store()
.lookup_method(owner, method)?
.ok_or(VmError::InvalidArgument("missing protocol method"))?;
vm.object_store()
.native_signature(function)?
.ok_or(VmError::InvalidArgument(
"protocol method lacks native types",
))?
} else {
let window = crate::ui_bridge::desktop_type(vm.object_store(), "Window", desktop)?;
let block = crate::ui_bridge::desktop_type(vm.object_store(), "Block", desktop)?;
CallSignature::exact(
vec![AnnotationType::Any, AnnotationType::Nominal(window)],
AnnotationType::Nominal(block),
CallEffect::External,
)
};
signature.arity = CallArity::exact(parameters + 1);
signature.parameters[0] = AnnotationType::Any.into();
requirements.push(TypedMethodRequirement {
name: method.into(),
signature,
});
}
let capability = vm.new_typed_trait(name, requirements)?;
roots.push(capability);
vm.attach_type(capability, trait_type)?;
vm.set_attr(ui, name, Value::Object(capability))?;
vm.dict_set(types, Value::Text(name.into()), Value::Object(capability))?;
if let Some(owner) = owner_definition {
vm.implement_trait(owner, capability)?;
}
}
Ok(())
}