context_weaver/
lib.rs

1use core::processors::{PluginBridge, ScopedRegistry, WorldInfoRegistry};
2use std::{collections::{HashMap, HashSet}, fmt::Debug};
3
4use log::{debug, error, trace};
5use parser::{evaluate_nodes, parse_activation_condition, parse_entry_content, AstNode};
6
7pub mod core;
8pub mod errors;
9pub mod id;
10mod parser;
11mod tests;
12
13pub use errors::{ParserError, WorldInfoError};
14
15pub enum ContextNode {
16    TextChunk(String),
17    InsertionPoint(String),
18}
19
20pub struct Context(Vec<ContextNode>);
21
22impl Context {
23    pub fn new() -> Self {
24        Self(Vec::new())
25    }
26
27    pub fn push(&mut self, node: ContextNode) {
28        self.0.push(node);
29    }
30
31    pub fn text(&self) -> String {
32        let mut result = String::new();
33        for node in &self.0 {
34            if let ContextNode::TextChunk(text) = node {
35                result.push_str(text);
36            }
37        }
38        result
39    }
40}
41
42pub struct WorldInfoSettings {
43    /// List of allowed processors
44    pub permitted_processors: Vec<String>,
45    pub recursion_limit: u32,
46    pub id_length: usize,
47    pub seperate_context_nodes: bool
48}
49
50impl Default for WorldInfoSettings {
51    fn default() -> Self {
52        Self { 
53            permitted_processors: vec!["*".to_string()], 
54            recursion_limit: 10, 
55            id_length: 6, 
56            seperate_context_nodes: true
57        }
58    }
59}
60
61pub struct WorldInfo<P: PluginBridge + 'static> {
62    name: String,
63    entries: Vec<WorldInfoEntry>,
64    processor_registry: Box<WorldInfoRegistry<P>>,
65    error_stack: Vec<WorldInfoError>,
66    id_generator: id::IdGenerator,
67    settings: WorldInfoSettings,
68
69    // Stateful data
70    trigger_stack: HashSet<String>,
71    evaluated_entries: HashMap<String, String>
72}
73
74impl<P: PluginBridge> WorldInfo<P>{
75    pub fn evaluate(&mut self, context: Context) -> Result<String, &Vec<WorldInfoError>> {
76        self.reset();
77
78        // pre-parse entries
79        self.parse_entries();
80
81        if self.error_stack.len() > 0 {
82            return Err(&self.error_stack);
83        }
84
85        let mut failed = self.error_stack.len() > 0;
86        let activated_entries = self.filter_activated_entries(&context.text());
87
88        for entry in self.entries.iter_mut().filter(|e| activated_entries.contains(&e.id())) {
89            debug!("-- Evaluating entry {} --", entry.id());
90            let scopes = &entry.scopes.clone();
91            let id = entry.id();
92            let mut scoped_registry = self.processor_registry.scoped_registry(scopes, id.clone());
93        
94            
95            match entry.evaluate(&mut scoped_registry) {
96                Ok(content) => {
97                    if !self.evaluated_entries.contains_key(&id) {
98                        self.evaluated_entries.insert(id, content);
99                    }
100                },
101                Err(e) => {
102                    failed = true;
103                    self.error_stack.push(e);
104                },
105            }
106        }
107        
108        if failed {
109            Err(&self.error_stack)
110        } else {
111            self.trigger_stack = self.processor_registry.activation_stack();
112            self.evaluate_activation_stack(&mut 0);
113            Ok(self.format_output(context))
114        }
115    }
116
117    fn format_output(&self, context: Context) -> String {
118        let mut result = String::new();
119        for chunk in context.0 {
120            match chunk {
121                ContextNode::TextChunk(text) => result.push_str(&text),
122                ContextNode::InsertionPoint(id) => {
123                    for entry in self.entries_from_insertion(id).iter().map(|e| self.evaluated_entries.get(&e.id()).unwrap()) {
124                        if self.settings.seperate_context_nodes {
125                            result.push_str("\n");
126                        }
127                        result.push_str(&entry);
128                    }
129                }
130            }
131        }
132        result
133    }
134
135    fn entries_from_insertion(&self, insertion_id: String) -> Vec<&WorldInfoEntry> {
136        let mut result = self.entries
137            .iter()
138            .filter(|e| self.evaluated_entries.contains_key(&e.id()))
139            .filter(|e| e.insertion_point == Some(insertion_id.clone()))
140            .into_iter()
141            .collect::<Vec<_>>();
142
143        result.sort_by(|a, b| a.order.cmp(&b.order));
144
145        result
146    }
147
148    fn evaluate_activation_stack(&mut self, depth: &mut u32) {
149        debug!("Evaluating activation stack (depth: {})", depth);
150        let mut failed = false;
151        let mut activated = self.filter_activated_entries(&self.get_evaluated_context());
152        activated.retain(|id| !self.trigger_stack.contains(id) && !self.evaluated_entries.contains_key(id));
153        
154        let mut recurse_stack: HashSet<String> = self.trigger_stack.clone();
155        recurse_stack.extend(activated);
156
157        if recurse_stack.len() == 0 {
158            return;
159        }
160
161        trace!("Recursively evaluating {} entries", recurse_stack.len());
162        
163        for entry in self.entries.iter_mut().filter(|e| recurse_stack.contains(&e.id()))
164        {
165            let scopes = &entry.scopes.clone();
166            let id = entry.id();
167            let mut scoped_registry = self.processor_registry.scoped_registry(scopes, id.clone());
168            
169            if failed {
170                break;
171            }
172            
173            match entry.evaluate(&mut scoped_registry) {
174                Ok(content) => {
175                    trace!("Evaluated entry {} (depth: {}) -> {}", id, depth, content);
176                    if !self.evaluated_entries.contains_key(&id) {
177                        self.evaluated_entries.insert(id, content);
178                    }
179                },
180                Err(e) => {
181                    failed = true;
182                    error!("Failed to evaluate entry {} (depth: {}): {}", id, depth, e);
183                    self.error_stack.push(e);
184                },
185            }
186        }
187
188        self.trigger_stack = self.processor_registry.activation_stack();
189        
190        if failed {
191            return;
192        }
193        *depth += 1;
194        
195        if *depth < self.settings.recursion_limit && self.trigger_stack.len() > 0 {
196            self.evaluate_activation_stack(depth);
197        }
198    }
199
200    fn parse_entries(&mut self) {
201        debug!("-- Parsing entries --");
202        for entry in &mut self.entries {
203            trace!("-- Parsing entry {} --", entry.id());
204            match entry.parse::<P>() {
205                Ok(_) => (),
206                Err(e) => {
207                    self.error_stack.push(e); 
208                    break;
209                },
210            }
211        }
212    }
213
214    fn filter_activated_entries(&mut self, context: &String) -> Vec<String> {
215        let mut activated_entries: Vec<String> = Vec::new();
216        for entry in &mut self.entries {
217            let scopes = &entry.scopes.clone();
218            let mut scoped_registry = self.processor_registry.scoped_registry(scopes, entry.id());
219
220            match entry.determine_activation_status(&mut scoped_registry, context) {
221                Ok(active) => {
222                    if active {
223                        activated_entries.push(entry.id());
224                    }
225                },
226                Err(e) => self.error_stack.push(e),
227            }
228        }
229        activated_entries
230    }
231    
232    fn get_evaluated_context(&self) -> String {
233        let mut result = String::new();
234        for entry in &self.entries {
235            if self.evaluated_entries.contains_key(&entry.id()) {
236                result.push_str(&(self.evaluated_entries[&entry.id()].clone() + "\n"));
237            }
238        }
239        result
240    }
241
242    fn reset(&mut self) {
243        self.error_stack.clear();
244        self.trigger_stack.clear();
245        self.evaluated_entries.clear();
246    }
247}
248
249pub trait WorldInfoFactory<P: PluginBridge> {
250    /// Creates a new empty world info
251    fn new(registry: Box<WorldInfoRegistry<P>>) -> Self;
252    /// Sets the name of the world info
253    fn set_name(&mut self, name: &str) -> &mut Self;
254    /// Creates a new world info entry with a random id and inserts it
255    fn new_entry(&mut self, name: &str, order: u32) -> &mut WorldInfoEntry;
256    /// Inserts a world info entry
257    fn insert_entry(&mut self, entry: WorldInfoEntry) -> &mut Self;
258    /// Sets the list of permitted processors
259    fn set_permitted_processors(&mut self, processors: Vec<String>) -> &mut Self;
260    /// Builds the world info
261    fn build(&self) -> &Self;
262
263    /// Inserts a list of world info entries
264    fn insert_entries(&mut self, entries: Vec<WorldInfoEntry>) -> &mut Self {
265        for entry in entries {
266            self.insert_entry(entry);
267        }
268        self
269    }
270}
271
272impl<P: PluginBridge> WorldInfoFactory<P> for WorldInfo<P> {
273    fn new(registry: Box<WorldInfoRegistry<P>>) -> Self {
274        WorldInfo {
275            name: String::new(),
276            entries: Vec::new(),
277            settings: Default::default(),
278            processor_registry: registry,
279            error_stack: Vec::new(),
280            id_generator: id::IdGenerator::new(6),
281            trigger_stack: HashSet::new(),
282            evaluated_entries: HashMap::new()
283        }
284    }
285    fn set_name(&mut self, name: &str) -> &mut Self {
286        self.name = name.to_string();
287        self
288    }
289    fn insert_entry(&mut self, entry: WorldInfoEntry) -> &mut Self {
290        self.entries.push(entry);
291        self
292    }
293    fn set_permitted_processors(&mut self, processors: Vec<String>) -> &mut Self {
294        self.settings.permitted_processors = processors;
295        self
296    }
297    fn build(&self) -> &WorldInfo::<P> {
298        self
299    }
300    
301    fn new_entry(&mut self, name: &str, order: u32) -> &mut WorldInfoEntry {
302        let id = self.id_generator.generate_unique(&self.entries.iter().map(|e| e.id()).collect());
303        let entry = WorldInfoEntry::create(name, id.clone(), order);
304        self.insert_entry(entry);
305        
306        self.entries.last_mut().unwrap()
307    }
308}
309
310pub struct WorldInfoEntry {
311    name: String,
312    id: String,
313    order: u32,
314    scopes: Vec<String>,
315    activation_conditions: Vec<String>,
316    text: String,
317    enabled: bool,
318    constant: bool,
319    insertion_point: Option<String>,
320
321    // Stateful data
322    raw_nodes: Vec<AstNode>,
323    nodes: Vec<Box<dyn WorldInfoNode>>,
324    content_updated: bool
325}
326
327impl WorldInfoEntry {
328    pub fn new(name: String, id: String, order: u32) -> Self {
329        Self 
330        { 
331            name, 
332            id: id.clone(), 
333            order, 
334            nodes: Vec::new(), 
335            text: String::new(),
336            enabled: true,
337            constant: false,
338            insertion_point: None,
339            scopes: vec!["global".to_string(), id],
340            activation_conditions: Vec::new(),
341            content_updated: true,
342            raw_nodes: Vec::new()
343        }
344    }
345
346    pub fn name(&self) -> String {
347        self.name.clone()
348    }
349
350    pub fn id(&self) -> String {
351        self.id.clone()
352    }
353
354    pub fn order(&self) -> u32 {
355        self.order
356    }
357}
358
359pub trait EntryFactory {
360    fn create(name: &str, id: String, order: u32) -> WorldInfoEntry;
361    fn set_text(&mut self, text: &str) -> &mut WorldInfoEntry;
362    fn set_conditions(&mut self, conditions: Vec<String>) -> &mut WorldInfoEntry;
363    fn parse<P: PluginBridge>(&mut self) -> Result<&mut WorldInfoEntry, WorldInfoError>;
364    fn evaluate<P: PluginBridge>(&mut self, registry: &mut ScopedRegistry<P>) -> Result<String, WorldInfoError>;
365    fn determine_activation_status<P: PluginBridge>(&mut self, registry: &mut ScopedRegistry<P>, context: &String) -> Result<bool, WorldInfoError>;
366    fn set_enabled(&mut self, enabled: bool) -> &mut WorldInfoEntry;
367    fn set_constant(&mut self, constant: bool) -> &mut WorldInfoEntry;
368    fn set_insertion_point(&mut self, insertion_point: String) -> &mut WorldInfoEntry;
369}
370
371impl EntryFactory for WorldInfoEntry {
372    fn create(name: &str, id: String, order: u32) -> WorldInfoEntry {
373        WorldInfoEntry::new(name.to_string(), id, order)
374    }
375    fn parse<P: PluginBridge>(&mut self) -> Result<&mut WorldInfoEntry, WorldInfoError> {
376        log::debug!("Parsing node: {:?}", self.text);
377        // Re-parse if needed
378        if self.content_updated {
379            match parse_entry_content::<P>(&self.text) {
380                Ok(ast_nodes) => self.raw_nodes = ast_nodes,
381                Err(e) => return Err(WorldInfoError::ParserError(e)),
382            }
383        }
384        
385        self.content_updated = false;
386
387        Ok(self)
388    }
389    
390    fn set_text(&mut self, text: &str) -> &mut WorldInfoEntry {
391        self.text = text.to_string();
392        self.content_updated = true;
393        self
394    }
395    
396    fn evaluate<P: PluginBridge>(&mut self, registry: &mut ScopedRegistry<P>) -> Result<String, WorldInfoError> {
397        match evaluate_nodes(&self.raw_nodes, registry, &self.id, None) {
398            Ok(eval_nodes) => self.nodes = eval_nodes,
399            Err(e) => return Err(WorldInfoError::ParserError(e)),
400        };
401
402        let mut result = String::new();
403        for node in &self.nodes {
404            result.push_str(&node.content()?);
405        }
406        Ok(result)
407    }
408    
409    fn determine_activation_status<P: PluginBridge>(&mut self, registry: &mut ScopedRegistry<P>, context: &String) -> Result<bool, WorldInfoError> {
410        trace!("Activation conditions: {:?}, constant: {}", self.activation_conditions, self.constant);
411        match (self.enabled, self.constant, self.activation_conditions.len() > 0) {
412            (true, true, false) => return Ok(true), // Constant entries without additional conditions are active
413            (true, false, false) => return Ok(false), // Enabled entries without additional conditions are never active
414            (false, ..) => return Ok(false), // Disabled entries are never active
415            _ => (),
416        }
417
418        let mut results: Vec<bool> = Vec::new();
419        for condition in &self.activation_conditions {
420            if parse_activation_condition(condition, &context, registry, &self.id)
421                .map_err(|e| WorldInfoError::ParserError(e))? 
422            {
423                results.push(true);
424            }
425            else {
426                results.push(false);
427            }
428        }
429
430        Ok(results.iter().all(|b| *b) && self.enabled)
431    }
432    
433    fn set_conditions(&mut self, conditions: Vec<String>) -> &mut WorldInfoEntry {
434        self.activation_conditions = conditions;
435        self
436    }
437    
438    fn set_enabled(&mut self, enabled: bool) -> &mut WorldInfoEntry {
439        self.enabled = enabled;
440        self
441    }
442    
443    fn set_constant(&mut self, constant: bool) -> &mut WorldInfoEntry {
444        self.constant = constant;
445        self
446    }
447    
448    fn set_insertion_point(&mut self, insertion_point: String) -> &mut WorldInfoEntry {
449        self.insertion_point = Some(insertion_point);
450        self
451    }
452}
453
454pub trait WorldInfoNode: Debug {
455    fn content(&self) -> Result<String, crate::WorldInfoError>;
456    fn name(&self) -> String;
457    fn cloned(&self) -> Box<dyn WorldInfoNode + '_>;
458}
459
460pub trait WorldInfoProcessor: WorldInfoNode {
461    fn process(&self) -> Result<String, crate::WorldInfoError>;
462}