diskplan_traversal/
stack.rs1use std::{
2 collections::HashMap,
3 fmt::{Debug, Display},
4};
5
6use crate::eval::Value;
7use diskplan_config::Config;
8use diskplan_filesystem::Mode;
9use diskplan_schema::{DirectorySchema, Identifier, SchemaNode};
10
11pub struct StackFrame<'g, 'p, 'l>
33where
34 'g: 'p, 'p: 'l, {
37 parent: Option<&'p StackFrame<'g, 'p, 'p>>,
38
39 pub config: &'g Config<'g>,
41
42 variables: VariableSource<'g>,
44
45 owner: &'l str,
47 group: &'l str,
49 mode: Mode,
51}
52
53impl<'g, 'p, 'l> StackFrame<'g, 'p, 'l> {
54 pub fn stack(
56 config: &'g Config<'g>,
57 variables: VariableSource<'g>,
58 owner: &'l str,
59 group: &'l str,
60 mode: Mode,
61 ) -> Self {
62 StackFrame {
63 parent: None,
64 config,
65 variables,
66 owner,
67 group,
68 mode,
69 }
70 }
71
72 pub fn push<'s, 'r>(&'s self, variables: VariableSource<'g>) -> StackFrame<'g, 'r, 'r>
74 where
75 'g: 'r,
76 's: 'r,
77 {
78 StackFrame {
79 parent: Some(self),
80 variables,
81 owner: self.owner,
82 group: self.group,
83 mode: self.mode,
84 config: self.config,
85 }
86 }
87
88 pub fn put_owner(&mut self, owner: &'l str) {
90 self.owner = owner;
91 }
92
93 pub fn put_group(&mut self, group: &'l str) {
95 self.group = group;
96 }
97
98 pub fn owner(&self) -> &'l str {
100 self.owner
101 }
102
103 pub fn group(&self) -> &'l str {
105 self.group
106 }
107
108 pub fn mode(&self) -> Mode {
110 self.mode
111 }
112
113 pub fn variables(&self) -> &VariableSource<'l> {
115 &self.variables
116 }
117
118 pub fn lookup<'a>(&'a self, var: &Identifier<'a>) -> Option<Value<'a>> {
120 match &self.variables {
121 VariableSource::Empty => None,
122 VariableSource::Directory(directory) => directory.get_var(var).map(Value::Expression),
123 VariableSource::Binding(bind, ref value) => {
124 if *bind == var {
125 Some(Value::String(value))
126 } else {
127 None
128 }
129 }
130 VariableSource::Map(map) => map.get(var.value()).map(|s| Value::String(s.as_str())),
131 }
132 .or_else(|| self.parent.and_then(|parent| parent.lookup(var)))
133 }
134
135 pub fn find_definition<'a>(&self, var: &Identifier<'a>) -> Option<&'a SchemaNode<'g>> {
137 match self.variables {
138 VariableSource::Directory(directory) => directory.get_def(var),
139 _ => None,
140 }
141 .or_else(|| self.parent.and_then(|parent| parent.find_definition(var)))
142 }
143}
144
145#[derive(Debug)]
147pub enum VariableSource<'a> {
148 Empty,
150 Directory(&'a DirectorySchema<'a>),
152 Binding(&'a Identifier<'a>, String),
154 Map(HashMap<String, String>),
156}
157
158impl Default for VariableSource<'_> {
159 fn default() -> Self {
160 VariableSource::Empty
161 }
162}
163
164impl From<HashMap<String, String>> for VariableSource<'_> {
165 fn from(map: HashMap<String, String>) -> Self {
166 VariableSource::Map(map)
167 }
168}
169
170impl<'a> VariableSource<'a> {
171 pub fn as_binding(&self) -> Option<(&Identifier<'a>, &String)> {
173 match self {
174 VariableSource::Binding(id, value) => Some((id, value)),
175 _ => None,
176 }
177 }
178}
179
180impl Display for StackFrame<'_, '_, '_> {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 match &self.variables {
183 VariableSource::Empty => {}
184 VariableSource::Directory(directory_schema) => {
185 write!(f, "Directory variables:",)?;
186 let mut no_vars = true;
187 for (ident, expr) in directory_schema.vars() {
188 no_vars = false;
189 write!(f, "\n ${ident} = \"{expr}\"")?;
190 }
191 if no_vars {
192 write!(f, "\n (no variables)",)?;
193 }
194 }
195 VariableSource::Binding(ident, value) => {
196 write!(f, "Schema binding:")?;
197 write!(f, "\n ${ident} = \"{value}\"",)?;
198 }
199 VariableSource::Map(map) => {
200 write!(f, "Variable map:")?;
201 for (key, value) in map.iter() {
202 write!(f, "\n ${key} = \"{value}\"")?;
203 }
204 }
205 }
206 Ok(())
207 }
208}