use std::rc::Rc;
use super::val::Val;
use crate::check::model::{LocalId, UnitId};
use crate::check::types::TypeId;
#[derive(Debug, Clone, Default)]
pub(crate) struct Env(Option<Rc<Node>>);
const BITS: u32 = 4;
const WIDTH: usize = 1 << BITS;
#[derive(Debug)]
enum Node {
Branch {
shift: u32,
children: [Option<Rc<Node>>; WIDTH],
},
Leaf(Slot),
}
#[derive(Debug, Clone)]
pub(crate) enum Slot {
Ready(Val),
Late(Rc<LateLet>),
}
#[derive(Debug)]
pub(crate) struct LateLet {
pub(crate) unit: UnitId,
pub(crate) node: usize,
pub(crate) env: Env,
pub(crate) annotation: Option<TypeId>,
}
pub(crate) fn bind(env: &Env, id: LocalId, slot: Slot) -> Env {
let key = id.0;
let mut root = env.0.clone();
let mut shift = match root.as_deref() {
Some(Node::Branch { shift, .. }) => *shift,
_ => 0,
};
while key.checked_shr(shift + BITS).is_some_and(|rest| rest != 0) {
let mut children: [Option<Rc<Node>>; WIDTH] = Default::default();
children[0] = root.take();
shift += BITS;
root = Some(Rc::new(Node::Branch { shift, children }));
}
Env(Some(insert(root.as_ref(), shift, key, slot)))
}
fn insert(node: Option<&Rc<Node>>, shift: u32, key: u32, slot: Slot) -> Rc<Node> {
let mut children: [Option<Rc<Node>>; WIDTH] = match node.map(Rc::as_ref) {
Some(Node::Branch { children, .. }) => children.clone(),
_ => Default::default(),
};
let index = ((key >> shift) as usize) & (WIDTH - 1);
children[index] = Some(if shift == 0 {
Rc::new(Node::Leaf(slot))
} else {
insert(children[index].as_ref(), shift - BITS, key, slot)
});
Rc::new(Node::Branch { shift, children })
}
pub(crate) fn lookup(env: &Env, id: LocalId) -> Option<&Slot> {
let key = id.0;
let mut node = env.0.as_deref()?;
if let Node::Branch { shift, .. } = node
&& key.checked_shr(shift + BITS).is_some_and(|rest| rest != 0)
{
return None;
}
loop {
match node {
Node::Branch { shift, children } => {
node = children[((key >> shift) as usize) & (WIDTH - 1)].as_deref()?;
}
Node::Leaf(slot) => return Some(slot),
}
}
}
#[cfg(test)]
#[path = "env_tests.rs"]
mod tests;