use std::sync::Arc;
use crate::op::SlotId;
use super::ValueId;
#[derive(Debug, Clone)]
pub(crate) struct SlotStore<Data> {
payloads: Vec<Data>,
nodes: Vec<ValueId>,
}
impl<Data> SlotStore<Data> {
pub(crate) fn new() -> Self {
Self {
payloads: Vec::new(),
nodes: Vec::new(),
}
}
pub(crate) fn len(&self) -> usize {
self.payloads.len()
}
pub(crate) fn payloads(&self) -> &[Data] {
&self.payloads
}
pub(crate) fn install(
&mut self,
data: Data,
record: impl FnOnce(SlotId) -> ValueId,
) -> ValueId {
debug_assert_eq!(self.payloads.len(), self.nodes.len());
let slot = SlotId::new(self.payloads.len());
self.payloads.push(data);
let node = record(slot);
self.nodes.push(node);
node
}
pub(crate) fn from_rows(rows: impl IntoIterator<Item = (ValueId, Data)>) -> Self {
let mut payloads = Vec::new();
let mut nodes: Vec<ValueId> = Vec::new();
for (node, payload) in rows {
debug_assert!(
nodes.last().is_none_or(|last| last.index() < node.index()),
"slot rows must arrive in recording order"
);
nodes.push(node);
payloads.push(payload);
}
Self { payloads, nodes }
}
pub(crate) fn set(&mut self, slot: SlotId, data: Data) {
self.payloads[slot.index()] = data;
}
pub(crate) fn last_node(&self) -> Option<ValueId> {
self.nodes.last().copied()
}
pub(crate) fn slot_of(&self, node: ValueId) -> Option<SlotId> {
self.nodes
.binary_search_by_key(&node.index(), |linked| linked.index())
.ok()
.map(SlotId::new)
}
pub(crate) fn with_payloads(&self, payloads: Vec<Data>) -> Self {
assert_eq!(
payloads.len(),
self.nodes.len(),
"payload count must match the store's slots"
);
Self {
payloads,
nodes: self.nodes.clone(),
}
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (ValueId, &Data)> {
debug_assert_eq!(self.payloads.len(), self.nodes.len());
self.nodes.iter().copied().zip(self.payloads.iter())
}
}
impl<T: Clone> SlotStore<T> {
pub(crate) fn overlaid(defaults: &Arc<Self>, bindings: Vec<(SlotId, T)>) -> Arc<Self> {
if bindings.is_empty() {
return Arc::clone(defaults);
}
let mut overlaid = defaults.as_ref().clone();
for (slot, payload) in bindings {
overlaid.set(slot, payload);
}
Arc::new(overlaid)
}
}