mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 15:50:18 +00:00
initial actions, entries, generators mechanism!
This commit is contained in:
146
src/context.rs
Normal file
146
src/context.rs
Normal 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 ¤t_values {
|
||||
let (changed, result) = Self::stamp_values(¤t_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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user