use super::*;
pub(super) fn recall_part<T: Clone>(
register: &[Reg],
r: &RegRef,
part: impl Fn(&Reg) -> &T,
none: T,
list: impl Fn(Vec<T>) -> T,
record: impl Fn(Vec<(String, T)>) -> T,
) -> T {
match r {
RegRef::Top => register.last().map(|r| part(r).clone()).unwrap_or(none),
RegRef::Index(n) => register
.get(n.saturating_sub(1))
.map(|r| part(r).clone())
.unwrap_or(none),
RegRef::Named(name) => register
.iter()
.rev()
.find(|r| r.name.as_deref() == Some(name.as_str()))
.map(|r| part(r).clone())
.unwrap_or(none),
RegRef::Whole => list(register.iter().map(|r| part(r).clone()).collect()),
RegRef::Record => record(named_register(register, part)),
RegRef::FullRecord => {
let mut fields: Vec<(String, T)> = Vec::new();
for (i, reg) in register.iter().enumerate() {
match ®.name {
Some(name) => match fields.iter_mut().find(|(n, _)| n == name) {
Some((_, v)) => *v = part(reg).clone(),
None => fields.push((name.clone(), part(reg).clone())),
},
None => fields.push((format!(".{}", i + 1), part(reg).clone())),
}
}
record(fields)
}
}
}
pub(super) fn recall(register: &[Reg], r: &RegRef) -> Value {
recall_part(
register,
r,
|r| &r.value,
Value::Null,
Value::list,
Value::Record,
)
}
pub(super) fn recall_prov(register: &[Reg], r: &RegRef) -> Prov {
recall_part(
register,
r,
|r| &r.prov,
Prov::default(),
Prov::list,
Prov::record,
)
}
pub(super) fn named_register<T: Clone>(
register: &[Reg],
part: impl Fn(&Reg) -> &T,
) -> Vec<(String, T)> {
let mut fields: Vec<(String, T)> = Vec::new();
for reg in register {
if let Some(name) = ®.name {
match fields.iter_mut().find(|(n, _)| n == name) {
Some((_, v)) => *v = part(reg).clone(),
None => fields.push((name.clone(), part(reg).clone())),
}
}
}
fields
}
pub(super) fn named_register_parts(register: &[Reg]) -> Vec<(String, Prov)> {
named_register(register, |r| &r.prov)
}
pub(super) fn named_register_fields(register: &[Reg]) -> Vec<(String, Value)> {
named_register(register, |r| &r.value)
}
pub(super) type RegKey = Vec<(Option<String>, String)>;
pub(super) type RoundState = (NodeId, Option<Value>, Vec<(String, Value)>);
pub(super) fn reg_key(register: &[Reg]) -> RegKey {
register
.iter()
.map(|r| (r.name.clone(), r.value.to_string()))
.collect()
}