Skip to main content

sim_lib_dispatch/
metaobject.rs

1use sim_kernel::{Cx, Result, Symbol, Value};
2
3/// Language-neutral slot lookup for values with metadata-driven behavior.
4///
5/// Implementations provide raw indexed access plus a named meta-slot lookup.
6/// The slot names are supplied by language crates or other callers, so this
7/// protocol can model metatables, prototype parents, method dictionaries, and
8/// similar object layers without baking any one language's names into dispatch.
9pub trait MetaObjectProtocol: Send + Sync {
10    /// Returns a raw indexed value before consulting any metaobject fallback.
11    fn raw_get(&self, cx: &mut Cx, value: &Value, key: &Value) -> Result<Option<Value>>;
12
13    /// Returns the meta value installed under `slot` for `value`, if present.
14    fn get_meta(&self, cx: &mut Cx, value: &Value, slot: &Symbol) -> Result<Option<Value>>;
15
16    /// Applies a meta value to the original indexed read.
17    ///
18    /// The default treats the meta value as another indexable object and looks
19    /// up `key` on it. Prototype languages can override this to recurse through
20    /// parent objects, while function-backed systems can override it to invoke
21    /// or otherwise interpret a callable meta value.
22    fn apply_meta(
23        &self,
24        cx: &mut Cx,
25        _receiver: &Value,
26        key: &Value,
27        _index_slot: &Symbol,
28        meta_value: &Value,
29    ) -> Result<Option<Value>> {
30        self.raw_get(cx, meta_value, key)
31    }
32}
33
34/// Performs an indexed read with a caller-selected metaobject fallback slot.
35///
36/// Raw values win. If raw access misses, the protocol looks up `index_slot` on
37/// `receiver` and applies that meta value through
38/// [`MetaObjectProtocol::apply_meta`].
39pub fn meta_index(
40    cx: &mut Cx,
41    proto: &dyn MetaObjectProtocol,
42    receiver: &Value,
43    key: &Value,
44    index_slot: &Symbol,
45) -> Result<Option<Value>> {
46    if let Some(value) = proto.raw_get(cx, receiver, key)? {
47        return Ok(Some(value));
48    }
49    let Some(meta_value) = proto.get_meta(cx, receiver, index_slot)? else {
50        return Ok(None);
51    };
52    proto.apply_meta(cx, receiver, key, index_slot, &meta_value)
53}