initial actions, entries, generators mechanism!

This commit is contained in:
2025-10-04 23:12:01 -07:00
parent b995ea0625
commit 24a9e2c727
10 changed files with 373 additions and 32 deletions

146
src/context.rs Normal file
View File

@@ -0,0 +1,146 @@
use crate::config::{ActionDeclaration, EntryDeclaration};
use std::collections::{BTreeMap, BTreeSet};
use std::rc::Rc;
#[derive(Default)]
pub struct RootContext {
actions: BTreeMap<String, ActionDeclaration>,
entries: BTreeMap<String, (Rc<Context>, EntryDeclaration)>,
}
impl RootContext {
pub fn new() -> Self {
Default::default()
}
pub fn actions(&self) -> &BTreeMap<String, ActionDeclaration> {
&self.actions
}
pub fn actions_mut(&mut self) -> &mut BTreeMap<String, ActionDeclaration> {
&mut self.actions
}
pub fn entries(&self) -> &BTreeMap<String, (Rc<Context>, EntryDeclaration)> {
&self.entries
}
pub fn entries_mut(&mut self) -> &mut BTreeMap<String, (Rc<Context>, EntryDeclaration)> {
&mut self.entries
}
}
pub struct Context {
root: Rc<RootContext>,
parent: Option<Rc<Context>>,
values: BTreeMap<String, String>,
}
impl Context {
pub fn new(root: RootContext) -> Self {
Self {
root: Rc::new(root),
parent: None,
values: BTreeMap::new(),
}
}
pub fn root(&self) -> &RootContext {
self.root.as_ref()
}
pub fn get(&self, key: impl AsRef<str>) -> Option<&String> {
self.values.get(key.as_ref()).or_else(|| {
self.parent
.as_ref()
.and_then(|parent| parent.get(key.as_ref()))
})
}
pub fn all_keys(&self) -> Vec<String> {
let mut keys = BTreeSet::new();
for key in self.values.keys() {
keys.insert(key.clone());
}
if let Some(parent) = &self.parent {
keys.extend(parent.all_keys());
}
keys.into_iter().collect()
}
pub fn all_values(&self) -> BTreeMap<String, String> {
let mut values = BTreeMap::new();
for key in self.all_keys() {
values.insert(key.clone(), self.get(key).cloned().unwrap_or_default());
}
values
}
pub fn set(&mut self, key: impl AsRef<str>, value: impl ToString) {
self.values
.insert(key.as_ref().to_string(), value.to_string());
}
pub fn insert(&mut self, values: &BTreeMap<String, String>) {
for (key, value) in values {
self.values.insert(key.clone(), value.clone());
}
}
pub fn fork(self: &Rc<Context>) -> Self {
Self {
root: self.root.clone(),
parent: Some(self.clone()),
values: BTreeMap::new(),
}
}
pub fn freeze(self) -> Rc<Context> {
Rc::new(self)
}
pub fn finalize(&self) -> Context {
let mut current_values = self.all_values();
loop {
let mut did_change = false;
let mut values = BTreeMap::new();
for (key, value) in &current_values {
let (changed, result) = Self::stamp_values(&current_values, value);
if changed {
did_change = true;
}
values.insert(key.clone(), result);
}
current_values = values;
if !did_change {
break;
}
}
Self {
root: self.root.clone(),
parent: None,
values: current_values,
}
}
fn stamp_values(values: &BTreeMap<String, String>, text: impl AsRef<str>) -> (bool, String) {
let mut result = text.as_ref().to_string();
let mut did_change = false;
for (key, value) in values {
let next_result = result.replace(&format!("${key}"), value);
if result != next_result {
did_change = true;
}
result = next_result;
}
(did_change, result)
}
pub fn stamp(&self, text: impl AsRef<str>) -> String {
Self::stamp_values(&self.all_values(), text.as_ref()).1
}
}