use std::collections::BTreeSet;
use sim_kernel::{
Cx, Error, Expr, Object, ObjectEncode, ObjectEncoding, Result, Symbol, Table, Value,
id::CORE_TABLE_CLASS_ID, object::ClassRef,
};
#[derive(Clone)]
pub struct OverrideTable {
layers: Vec<Value>,
}
impl OverrideTable {
pub fn new(layers: Vec<Value>) -> Result<Self> {
if layers.is_empty() {
return Err(Error::Eval(
"table/override: expected at least one table layer".to_owned(),
));
}
for layer in &layers {
if layer.object().as_table_impl().is_none() {
return Err(Error::Eval(
"table/override: every layer must be a table".to_owned(),
));
}
}
Ok(Self { layers })
}
pub fn layers(&self) -> &[Value] {
&self.layers
}
fn front(&self) -> &Value {
&self.layers[0]
}
}
impl Object for OverrideTable {
fn display(&self, _cx: &mut Cx) -> Result<String> {
Ok(format!("table/override[layers={}]", self.layers.len()))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl sim_kernel::ObjectCompat for OverrideTable {
fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
let symbol = Symbol::qualified("core", "Table");
if let Some(value) = cx.registry().class_by_symbol(&symbol) {
return Ok(value.clone());
}
cx.factory().class_stub(CORE_TABLE_CLASS_ID, symbol)
}
fn as_expr(&self, cx: &mut Cx) -> Result<Expr> {
self.as_table_expr(cx)
}
fn truth(&self, cx: &mut Cx) -> Result<bool> {
Ok(!self.is_empty(cx)?)
}
fn as_table_impl(&self) -> Option<&dyn Table> {
Some(self)
}
fn as_object_encoder(&self) -> Option<&dyn ObjectEncode> {
Some(self)
}
}
impl ObjectEncode for OverrideTable {
fn object_encoding(&self, cx: &mut Cx) -> Result<ObjectEncoding> {
let args = self
.layers
.iter()
.map(|layer| layer.object().as_expr(cx))
.collect::<Result<Vec<_>>>()?;
Ok(ObjectEncoding::Constructor {
class: Symbol::new("OverrideTable"),
args,
})
}
}
impl sim_citizen::Citizen for OverrideTable {
fn citizen_symbol() -> Symbol {
Symbol::new("OverrideTable")
}
fn citizen_version() -> u32 {
0
}
fn citizen_arity() -> usize {
1
}
fn citizen_fields() -> &'static [&'static str] {
&["layer"]
}
}
impl Table for OverrideTable {
fn backend_symbol(&self) -> Symbol {
Symbol::qualified("table", "override")
}
fn get(&self, cx: &mut Cx, key: Symbol) -> Result<Value> {
for layer in &self.layers {
let table = layer
.object()
.as_table_impl()
.expect("validated table layer");
if table.has(cx, key.clone())? {
return table.get(cx, key);
}
}
cx.factory().nil()
}
fn set(&self, cx: &mut Cx, key: Symbol, value: Value) -> Result<()> {
self.front()
.object()
.as_table_impl()
.expect("validated table layer")
.set(cx, key, value)
}
fn has(&self, cx: &mut Cx, key: Symbol) -> Result<bool> {
for layer in &self.layers {
if layer
.object()
.as_table_impl()
.expect("validated table layer")
.has(cx, key.clone())?
{
return Ok(true);
}
}
Ok(false)
}
fn del(&self, cx: &mut Cx, key: Symbol) -> Result<Value> {
self.front()
.object()
.as_table_impl()
.expect("validated table layer")
.del(cx, key)
}
fn keys(&self, cx: &mut Cx) -> Result<Vec<Symbol>> {
let mut seen = BTreeSet::new();
let mut out = Vec::new();
for layer in &self.layers {
for key in layer
.object()
.as_table_impl()
.expect("validated table layer")
.keys(cx)?
{
if seen.insert(key.clone()) {
out.push(key);
}
}
}
Ok(out)
}
fn entries(&self, cx: &mut Cx) -> Result<Vec<(Symbol, Value)>> {
let mut seen = BTreeSet::new();
let mut out = Vec::new();
for layer in &self.layers {
for (key, value) in layer
.object()
.as_table_impl()
.expect("validated table layer")
.entries(cx)?
{
if seen.insert(key.clone()) {
out.push((key, value));
}
}
}
Ok(out)
}
fn len(&self, cx: &mut Cx) -> Result<usize> {
Ok(self.keys(cx)?.len())
}
fn clear(&self, cx: &mut Cx) -> Result<()> {
self.front()
.object()
.as_table_impl()
.expect("validated table layer")
.clear(cx)
}
}