Skip to main content

oxilean_kernel/export/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::declaration::ConstantInfo;
6use crate::{
7    BinderInfo, Declaration, Environment, Expr, FVarId, Level, LevelMVarId, Literal, Name,
8};
9use std::collections::HashMap;
10
11use super::functions::import_module;
12
13/// A pair of `StatSummary` values tracking before/after a transformation.
14#[allow(dead_code)]
15pub struct TransformStat {
16    before: StatSummary,
17    after: StatSummary,
18}
19#[allow(dead_code)]
20impl TransformStat {
21    /// Creates a new transform stat recorder.
22    pub fn new() -> Self {
23        Self {
24            before: StatSummary::new(),
25            after: StatSummary::new(),
26        }
27    }
28    /// Records a before value.
29    pub fn record_before(&mut self, v: f64) {
30        self.before.record(v);
31    }
32    /// Records an after value.
33    pub fn record_after(&mut self, v: f64) {
34        self.after.record(v);
35    }
36    /// Returns the mean reduction ratio (after/before).
37    pub fn mean_ratio(&self) -> Option<f64> {
38        let b = self.before.mean()?;
39        let a = self.after.mean()?;
40        if b.abs() < f64::EPSILON {
41            return None;
42        }
43        Some(a / b)
44    }
45}
46/// Result of a module integrity check.
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub enum IntegrityCheckResult {
49    /// All checks passed.
50    Ok,
51    /// The module is empty.
52    EmptyModule,
53    /// The module has duplicate declaration names.
54    DuplicateNames(Vec<Name>),
55    /// The magic number in the binary header is wrong.
56    BadMagicNumber,
57    /// The version is unsupported.
58    UnsupportedVersion(u32),
59}
60/// A label set for a graph node.
61#[allow(dead_code)]
62pub struct LabelSet {
63    labels: Vec<String>,
64}
65#[allow(dead_code)]
66impl LabelSet {
67    /// Creates a new empty label set.
68    pub fn new() -> Self {
69        Self { labels: Vec::new() }
70    }
71    /// Adds a label (deduplicates).
72    pub fn add(&mut self, label: impl Into<String>) {
73        let s = label.into();
74        if !self.labels.contains(&s) {
75            self.labels.push(s);
76        }
77    }
78    /// Returns `true` if `label` is present.
79    pub fn has(&self, label: &str) -> bool {
80        self.labels.iter().any(|l| l == label)
81    }
82    /// Returns the count of labels.
83    pub fn count(&self) -> usize {
84        self.labels.len()
85    }
86    /// Returns all labels.
87    pub fn all(&self) -> &[String] {
88        &self.labels
89    }
90}
91/// A hierarchical configuration tree.
92#[allow(dead_code)]
93pub struct ConfigNode {
94    key: String,
95    value: Option<String>,
96    children: Vec<ConfigNode>,
97}
98#[allow(dead_code)]
99impl ConfigNode {
100    /// Creates a leaf config node with a value.
101    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
102        Self {
103            key: key.into(),
104            value: Some(value.into()),
105            children: Vec::new(),
106        }
107    }
108    /// Creates a section node with children.
109    pub fn section(key: impl Into<String>) -> Self {
110        Self {
111            key: key.into(),
112            value: None,
113            children: Vec::new(),
114        }
115    }
116    /// Adds a child node.
117    pub fn add_child(&mut self, child: ConfigNode) {
118        self.children.push(child);
119    }
120    /// Returns the key.
121    pub fn key(&self) -> &str {
122        &self.key
123    }
124    /// Returns the value, or `None` for section nodes.
125    pub fn value(&self) -> Option<&str> {
126        self.value.as_deref()
127    }
128    /// Returns the number of children.
129    pub fn num_children(&self) -> usize {
130        self.children.len()
131    }
132    /// Looks up a dot-separated path.
133    pub fn lookup(&self, path: &str) -> Option<&str> {
134        let mut parts = path.splitn(2, '.');
135        let head = parts.next()?;
136        let tail = parts.next();
137        if head != self.key {
138            return None;
139        }
140        match tail {
141            None => self.value.as_deref(),
142            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
143        }
144    }
145    fn lookup_relative(&self, path: &str) -> Option<&str> {
146        let mut parts = path.splitn(2, '.');
147        let head = parts.next()?;
148        let tail = parts.next();
149        if head != self.key {
150            return None;
151        }
152        match tail {
153            None => self.value.as_deref(),
154            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
155        }
156    }
157}
158/// A dependency graph between modules.
159///
160/// Allows topological ordering for deterministic import order.
161#[derive(Debug, Default)]
162pub struct ModuleDependencyGraph {
163    /// Adjacency list: module → list of modules it depends on.
164    edges: HashMap<String, Vec<String>>,
165}
166impl ModuleDependencyGraph {
167    /// Create an empty dependency graph.
168    pub fn new() -> Self {
169        Self::default()
170    }
171    /// Add a module to the graph.
172    pub fn add_module(&mut self, name: String) {
173        self.edges.entry(name).or_default();
174    }
175    /// Add a dependency edge: `from` depends on `to`.
176    pub fn add_dep(&mut self, from: String, to: String) {
177        self.edges.entry(from).or_default().push(to);
178    }
179    /// Build a dependency graph from a module cache.
180    pub fn from_cache(cache: &ModuleCache) -> Self {
181        let mut g = Self::new();
182        for name in cache.all_modules() {
183            g.add_module(name.to_string());
184            if let Some(module) = cache.get(name) {
185                for dep in &module.dependencies {
186                    g.add_dep(name.to_string(), dep.clone());
187                }
188            }
189        }
190        g
191    }
192    /// Compute a topological ordering of modules (Kahn's algorithm).
193    ///
194    /// Returns `Err` if there is a cycle.
195    pub fn topological_order(&self) -> Result<Vec<String>, String> {
196        use std::collections::VecDeque;
197        let mut in_degree: HashMap<String, usize> = HashMap::new();
198        for (node, deps) in &self.edges {
199            in_degree.entry(node.clone()).or_insert(0);
200            for dep in deps {
201                in_degree.entry(dep.clone()).or_insert(0);
202            }
203        }
204        for deps in self.edges.values() {
205            for dep in deps {
206                *in_degree.entry(dep.clone()).or_insert(0) += 0;
207            }
208        }
209        let mut in_degree: HashMap<String, usize> = HashMap::new();
210        for node in self.edges.keys() {
211            let deps = self.edges.get(node).map(|v| v.len()).unwrap_or(0);
212            in_degree.insert(node.clone(), deps);
213        }
214        let mut queue: VecDeque<String> = in_degree
215            .iter()
216            .filter(|(_, d)| **d == 0)
217            .map(|(k, _)| k.clone())
218            .collect();
219        let mut order = Vec::new();
220        while let Some(node) = queue.pop_front() {
221            order.push(node.clone());
222            for (other, deps) in &self.edges {
223                if deps.contains(&node) {
224                    let deg = in_degree
225                        .get_mut(other)
226                        .expect("node must exist in in_degree map");
227                    *deg = deg.saturating_sub(1);
228                    if *deg == 0 {
229                        queue.push_back(other.clone());
230                    }
231                }
232            }
233        }
234        if order.len() != self.edges.len() {
235            Err("Cycle detected in module dependency graph".to_string())
236        } else {
237            Ok(order)
238        }
239    }
240    /// Check if module `a` depends (transitively) on module `b`.
241    pub fn depends_on(&self, a: &str, b: &str) -> bool {
242        if let Some(deps) = self.edges.get(a) {
243            if deps.iter().any(|d| d == b) {
244                return true;
245            }
246            deps.iter().any(|d| self.depends_on(d, b))
247        } else {
248            false
249        }
250    }
251    /// Number of modules in the graph.
252    pub fn num_modules(&self) -> usize {
253        self.edges.len()
254    }
255}
256/// A versioned record that stores a history of values.
257#[allow(dead_code)]
258pub struct VersionedRecord<T: Clone> {
259    history: Vec<T>,
260}
261#[allow(dead_code)]
262impl<T: Clone> VersionedRecord<T> {
263    /// Creates a new record with an initial value.
264    pub fn new(initial: T) -> Self {
265        Self {
266            history: vec![initial],
267        }
268    }
269    /// Updates the record with a new version.
270    pub fn update(&mut self, val: T) {
271        self.history.push(val);
272    }
273    /// Returns the current (latest) value.
274    pub fn current(&self) -> &T {
275        self.history
276            .last()
277            .expect("VersionedRecord history is always non-empty after construction")
278    }
279    /// Returns the value at version `n` (0-indexed), or `None`.
280    pub fn at_version(&self, n: usize) -> Option<&T> {
281        self.history.get(n)
282    }
283    /// Returns the version number of the current value.
284    pub fn version(&self) -> usize {
285        self.history.len() - 1
286    }
287    /// Returns `true` if more than one version exists.
288    pub fn has_history(&self) -> bool {
289        self.history.len() > 1
290    }
291}
292/// A non-empty list (at least one element guaranteed).
293#[allow(dead_code)]
294pub struct NonEmptyVec<T> {
295    head: T,
296    tail: Vec<T>,
297}
298#[allow(dead_code)]
299impl<T> NonEmptyVec<T> {
300    /// Creates a non-empty vec with a single element.
301    pub fn singleton(val: T) -> Self {
302        Self {
303            head: val,
304            tail: Vec::new(),
305        }
306    }
307    /// Pushes an element.
308    pub fn push(&mut self, val: T) {
309        self.tail.push(val);
310    }
311    /// Returns a reference to the first element.
312    pub fn first(&self) -> &T {
313        &self.head
314    }
315    /// Returns a reference to the last element.
316    pub fn last(&self) -> &T {
317        self.tail.last().unwrap_or(&self.head)
318    }
319    /// Returns the number of elements.
320    pub fn len(&self) -> usize {
321        1 + self.tail.len()
322    }
323    /// Returns whether the collection is empty.
324    pub fn is_empty(&self) -> bool {
325        self.len() == 0
326    }
327    /// Returns all elements as a Vec.
328    pub fn to_vec(&self) -> Vec<&T> {
329        let mut v = vec![&self.head];
330        v.extend(self.tail.iter());
331        v
332    }
333}
334/// A registry that tracks which declarations come from which module.
335///
336/// Used during compilation to produce better error messages and to support
337/// incremental builds.
338#[derive(Debug, Default)]
339pub struct ModuleRegistry {
340    /// Maps declaration name to the module it was imported from.
341    decl_to_module: HashMap<Name, String>,
342    /// Maps module name to the set of declarations it provides.
343    module_to_decls: HashMap<String, Vec<Name>>,
344}
345impl ModuleRegistry {
346    /// Create a new registry.
347    pub fn new() -> Self {
348        Self::default()
349    }
350    /// Register a declaration as coming from a module.
351    pub fn register(&mut self, decl_name: Name, module_name: String) {
352        self.decl_to_module
353            .insert(decl_name.clone(), module_name.clone());
354        self.module_to_decls
355            .entry(module_name)
356            .or_default()
357            .push(decl_name);
358    }
359    /// Register all declarations from a module.
360    pub fn register_module(&mut self, module: &ExportedModule) {
361        for name in module.declaration_names() {
362            self.register(name.clone(), module.name.clone());
363        }
364    }
365    /// Look up which module a declaration came from.
366    pub fn module_for(&self, decl: &Name) -> Option<&str> {
367        self.decl_to_module.get(decl).map(|s| s.as_str())
368    }
369    /// Get all declarations provided by a module.
370    pub fn decls_for_module(&self, module: &str) -> &[Name] {
371        self.module_to_decls
372            .get(module)
373            .map(|v| v.as_slice())
374            .unwrap_or(&[])
375    }
376    /// Get all registered module names.
377    pub fn all_module_names(&self) -> Vec<&str> {
378        self.module_to_decls.keys().map(|s| s.as_str()).collect()
379    }
380    /// Check if a declaration is registered.
381    pub fn contains_decl(&self, decl: &Name) -> bool {
382        self.decl_to_module.contains_key(decl)
383    }
384    /// Number of registered declarations.
385    pub fn num_decls(&self) -> usize {
386        self.decl_to_module.len()
387    }
388    /// Number of registered modules.
389    pub fn num_modules(&self) -> usize {
390        self.module_to_decls.len()
391    }
392}
393/// A generic counter that tracks min/max/sum for statistical summaries.
394#[allow(dead_code)]
395pub struct StatSummary {
396    count: u64,
397    sum: f64,
398    min: f64,
399    max: f64,
400}
401#[allow(dead_code)]
402impl StatSummary {
403    /// Creates an empty summary.
404    pub fn new() -> Self {
405        Self {
406            count: 0,
407            sum: 0.0,
408            min: f64::INFINITY,
409            max: f64::NEG_INFINITY,
410        }
411    }
412    /// Records a sample.
413    pub fn record(&mut self, val: f64) {
414        self.count += 1;
415        self.sum += val;
416        if val < self.min {
417            self.min = val;
418        }
419        if val > self.max {
420            self.max = val;
421        }
422    }
423    /// Returns the mean, or `None` if no samples.
424    pub fn mean(&self) -> Option<f64> {
425        if self.count == 0 {
426            None
427        } else {
428            Some(self.sum / self.count as f64)
429        }
430    }
431    /// Returns the minimum, or `None` if no samples.
432    pub fn min(&self) -> Option<f64> {
433        if self.count == 0 {
434            None
435        } else {
436            Some(self.min)
437        }
438    }
439    /// Returns the maximum, or `None` if no samples.
440    pub fn max(&self) -> Option<f64> {
441        if self.count == 0 {
442            None
443        } else {
444            Some(self.max)
445        }
446    }
447    /// Returns the count of recorded samples.
448    pub fn count(&self) -> u64 {
449        self.count
450    }
451}
452/// A fixed-size sliding window that computes a running sum.
453#[allow(dead_code)]
454pub struct SlidingSum {
455    window: Vec<f64>,
456    capacity: usize,
457    pos: usize,
458    sum: f64,
459    count: usize,
460}
461#[allow(dead_code)]
462impl SlidingSum {
463    /// Creates a sliding sum with the given window size.
464    pub fn new(capacity: usize) -> Self {
465        Self {
466            window: vec![0.0; capacity],
467            capacity,
468            pos: 0,
469            sum: 0.0,
470            count: 0,
471        }
472    }
473    /// Adds a value to the window, removing the oldest if full.
474    pub fn push(&mut self, val: f64) {
475        let oldest = self.window[self.pos];
476        self.sum -= oldest;
477        self.sum += val;
478        self.window[self.pos] = val;
479        self.pos = (self.pos + 1) % self.capacity;
480        if self.count < self.capacity {
481            self.count += 1;
482        }
483    }
484    /// Returns the current window sum.
485    pub fn sum(&self) -> f64 {
486        self.sum
487    }
488    /// Returns the window mean, or `None` if empty.
489    pub fn mean(&self) -> Option<f64> {
490        if self.count == 0 {
491            None
492        } else {
493            Some(self.sum / self.count as f64)
494        }
495    }
496    /// Returns the current window size (number of valid elements).
497    pub fn count(&self) -> usize {
498        self.count
499    }
500}
501/// A window iterator that yields overlapping windows of size `n`.
502#[allow(dead_code)]
503pub struct WindowIterator<'a, T> {
504    pub(super) data: &'a [T],
505    pub(super) pos: usize,
506    pub(super) window: usize,
507}
508#[allow(dead_code)]
509impl<'a, T> WindowIterator<'a, T> {
510    /// Creates a new window iterator.
511    pub fn new(data: &'a [T], window: usize) -> Self {
512        Self {
513            data,
514            pos: 0,
515            window,
516        }
517    }
518}
519/// Exported module containing declarations.
520#[derive(Debug, Clone)]
521pub struct ExportedModule {
522    /// Module name
523    pub name: String,
524    /// Exported legacy declarations
525    pub declarations: Vec<(Name, Declaration)>,
526    /// Exported constant info entries
527    pub constants: Vec<(Name, ConstantInfo)>,
528    /// Module dependencies (other module names)
529    pub dependencies: Vec<String>,
530    /// Module version
531    pub version: String,
532    /// Metadata (arbitrary key-value pairs)
533    pub metadata: HashMap<String, String>,
534}
535impl ExportedModule {
536    /// Create a new exported module.
537    pub fn new(name: String) -> Self {
538        Self {
539            name,
540            declarations: Vec::new(),
541            constants: Vec::new(),
542            dependencies: Vec::new(),
543            version: "0.1.0".to_string(),
544            metadata: HashMap::new(),
545        }
546    }
547    /// Add a legacy declaration to the module.
548    pub fn add_declaration(&mut self, name: Name, decl: Declaration) {
549        self.declarations.push((name, decl));
550    }
551    /// Add a ConstantInfo to the module.
552    pub fn add_constant(&mut self, name: Name, ci: ConstantInfo) {
553        self.constants.push((name, ci));
554    }
555    /// Add a dependency.
556    pub fn add_dependency(&mut self, dep: String) {
557        if !self.dependencies.contains(&dep) {
558            self.dependencies.push(dep);
559        }
560    }
561    /// Add metadata.
562    pub fn set_metadata(&mut self, key: String, value: String) {
563        self.metadata.insert(key, value);
564    }
565    /// Get all declaration names (both legacy and constant info).
566    pub fn declaration_names(&self) -> Vec<&Name> {
567        let mut names: Vec<&Name> = self.declarations.iter().map(|(name, _)| name).collect();
568        names.extend(self.constants.iter().map(|(name, _)| name));
569        names
570    }
571    /// Get the total number of entries.
572    pub fn num_entries(&self) -> usize {
573        self.declarations.len() + self.constants.len()
574    }
575    /// Check if the module is empty.
576    pub fn is_empty(&self) -> bool {
577        self.declarations.is_empty() && self.constants.is_empty()
578    }
579}
580/// A reusable scratch buffer for path computations.
581#[allow(dead_code)]
582pub struct PathBuf {
583    components: Vec<String>,
584}
585#[allow(dead_code)]
586impl PathBuf {
587    /// Creates a new empty path buffer.
588    pub fn new() -> Self {
589        Self {
590            components: Vec::new(),
591        }
592    }
593    /// Pushes a component.
594    pub fn push(&mut self, comp: impl Into<String>) {
595        self.components.push(comp.into());
596    }
597    /// Pops the last component.
598    pub fn pop(&mut self) {
599        self.components.pop();
600    }
601    /// Returns the current path as a `/`-separated string.
602    pub fn as_str(&self) -> String {
603        self.components.join("/")
604    }
605    /// Returns the depth of the path.
606    pub fn depth(&self) -> usize {
607        self.components.len()
608    }
609    /// Clears the path.
610    pub fn clear(&mut self) {
611        self.components.clear();
612    }
613}
614/// A pool of reusable string buffers.
615#[allow(dead_code)]
616pub struct StringPool {
617    free: Vec<String>,
618}
619#[allow(dead_code)]
620impl StringPool {
621    /// Creates a new empty string pool.
622    pub fn new() -> Self {
623        Self { free: Vec::new() }
624    }
625    /// Takes a string from the pool (may be empty).
626    pub fn take(&mut self) -> String {
627        self.free.pop().unwrap_or_default()
628    }
629    /// Returns a string to the pool.
630    pub fn give(&mut self, mut s: String) {
631        s.clear();
632        self.free.push(s);
633    }
634    /// Returns the number of free strings in the pool.
635    pub fn free_count(&self) -> usize {
636        self.free.len()
637    }
638}
639/// A simple key-value store backed by a sorted Vec for small maps.
640#[allow(dead_code)]
641pub struct SmallMap<K: Ord + Clone, V: Clone> {
642    entries: Vec<(K, V)>,
643}
644#[allow(dead_code)]
645impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
646    /// Creates a new empty small map.
647    pub fn new() -> Self {
648        Self {
649            entries: Vec::new(),
650        }
651    }
652    /// Inserts or replaces the value for `key`.
653    pub fn insert(&mut self, key: K, val: V) {
654        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
655            Ok(i) => self.entries[i].1 = val,
656            Err(i) => self.entries.insert(i, (key, val)),
657        }
658    }
659    /// Returns the value for `key`, or `None`.
660    pub fn get(&self, key: &K) -> Option<&V> {
661        self.entries
662            .binary_search_by_key(&key, |(k, _)| k)
663            .ok()
664            .map(|i| &self.entries[i].1)
665    }
666    /// Returns the number of entries.
667    pub fn len(&self) -> usize {
668        self.entries.len()
669    }
670    /// Returns `true` if empty.
671    pub fn is_empty(&self) -> bool {
672        self.entries.is_empty()
673    }
674    /// Returns all keys.
675    pub fn keys(&self) -> Vec<&K> {
676        self.entries.iter().map(|(k, _)| k).collect()
677    }
678    /// Returns all values.
679    pub fn values(&self) -> Vec<&V> {
680        self.entries.iter().map(|(_, v)| v).collect()
681    }
682}
683/// A dependency closure builder (transitive closure via BFS).
684#[allow(dead_code)]
685pub struct TransitiveClosure {
686    adj: Vec<Vec<usize>>,
687    n: usize,
688}
689#[allow(dead_code)]
690impl TransitiveClosure {
691    /// Creates a transitive closure builder for `n` nodes.
692    pub fn new(n: usize) -> Self {
693        Self {
694            adj: vec![Vec::new(); n],
695            n,
696        }
697    }
698    /// Adds a direct edge.
699    pub fn add_edge(&mut self, from: usize, to: usize) {
700        if from < self.n {
701            self.adj[from].push(to);
702        }
703    }
704    /// Computes all nodes reachable from `start` (including `start`).
705    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
706        let mut visited = vec![false; self.n];
707        let mut queue = std::collections::VecDeque::new();
708        queue.push_back(start);
709        while let Some(node) = queue.pop_front() {
710            if node >= self.n || visited[node] {
711                continue;
712            }
713            visited[node] = true;
714            for &next in &self.adj[node] {
715                queue.push_back(next);
716            }
717        }
718        (0..self.n).filter(|&i| visited[i]).collect()
719    }
720    /// Returns `true` if `from` can transitively reach `to`.
721    pub fn can_reach(&self, from: usize, to: usize) -> bool {
722        self.reachable_from(from).contains(&to)
723    }
724}
725/// The difference between two module versions.
726#[derive(Debug, Clone, Default)]
727pub struct ModuleDiff {
728    /// Names added in the new version.
729    pub added: Vec<Name>,
730    /// Names removed from the old version.
731    pub removed: Vec<Name>,
732    /// Names present in both but with changed content.
733    pub changed: Vec<Name>,
734}
735impl ModuleDiff {
736    /// Create an empty diff.
737    pub fn new() -> Self {
738        Self::default()
739    }
740    /// Check if the diff is empty (no changes).
741    pub fn is_empty(&self) -> bool {
742        self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty()
743    }
744    /// Total number of changed items.
745    pub fn total_changes(&self) -> usize {
746        self.added.len() + self.removed.len() + self.changed.len()
747    }
748}
749/// A set of rewrite rules.
750#[allow(dead_code)]
751pub struct RewriteRuleSet {
752    rules: Vec<RewriteRule>,
753}
754#[allow(dead_code)]
755impl RewriteRuleSet {
756    /// Creates an empty rule set.
757    pub fn new() -> Self {
758        Self { rules: Vec::new() }
759    }
760    /// Adds a rule.
761    pub fn add(&mut self, rule: RewriteRule) {
762        self.rules.push(rule);
763    }
764    /// Returns the number of rules.
765    pub fn len(&self) -> usize {
766        self.rules.len()
767    }
768    /// Returns `true` if the set is empty.
769    pub fn is_empty(&self) -> bool {
770        self.rules.is_empty()
771    }
772    /// Returns all conditional rules.
773    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
774        self.rules.iter().filter(|r| r.conditional).collect()
775    }
776    /// Returns all unconditional rules.
777    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
778        self.rules.iter().filter(|r| !r.conditional).collect()
779    }
780    /// Looks up a rule by name.
781    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
782        self.rules.iter().find(|r| r.name == name)
783    }
784}
785/// A semantic version for a module.
786#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
787pub struct ModuleVersion {
788    /// Major version number.
789    pub major: u32,
790    /// Minor version number.
791    pub minor: u32,
792    /// Patch version number.
793    pub patch: u32,
794}
795impl ModuleVersion {
796    /// Create a new version.
797    pub fn new(major: u32, minor: u32, patch: u32) -> Self {
798        Self {
799            major,
800            minor,
801            patch,
802        }
803    }
804    /// Parse a version string of the form "M.N.P".
805    pub fn parse(s: &str) -> Option<Self> {
806        let parts: Vec<&str> = s.split('.').collect();
807        if parts.len() != 3 {
808            return None;
809        }
810        let major = parts[0].parse().ok()?;
811        let minor = parts[1].parse().ok()?;
812        let patch = parts[2].parse().ok()?;
813        Some(Self {
814            major,
815            minor,
816            patch,
817        })
818    }
819    /// Whether this version is backwards compatible with `other`.
820    ///
821    /// Compatible if same major version and this is at least as new.
822    pub fn is_compatible_with(&self, other: &Self) -> bool {
823        self.major == other.major && *self >= *other
824    }
825}
826/// A token bucket rate limiter.
827#[allow(dead_code)]
828pub struct TokenBucket {
829    capacity: u64,
830    tokens: u64,
831    refill_per_ms: u64,
832    last_refill: std::time::Instant,
833}
834#[allow(dead_code)]
835impl TokenBucket {
836    /// Creates a new token bucket.
837    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
838        Self {
839            capacity,
840            tokens: capacity,
841            refill_per_ms,
842            last_refill: std::time::Instant::now(),
843        }
844    }
845    /// Attempts to consume `n` tokens.  Returns `true` on success.
846    pub fn try_consume(&mut self, n: u64) -> bool {
847        self.refill();
848        if self.tokens >= n {
849            self.tokens -= n;
850            true
851        } else {
852            false
853        }
854    }
855    fn refill(&mut self) {
856        let now = std::time::Instant::now();
857        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
858        if elapsed_ms > 0 {
859            let new_tokens = elapsed_ms * self.refill_per_ms;
860            self.tokens = (self.tokens + new_tokens).min(self.capacity);
861            self.last_refill = now;
862        }
863    }
864    /// Returns the number of currently available tokens.
865    pub fn available(&self) -> u64 {
866        self.tokens
867    }
868    /// Returns the bucket capacity.
869    pub fn capacity(&self) -> u64 {
870        self.capacity
871    }
872}
873/// A type-erased function pointer with arity tracking.
874#[allow(dead_code)]
875pub struct RawFnPtr {
876    /// The raw function pointer (stored as usize for type erasure).
877    ptr: usize,
878    arity: usize,
879    name: String,
880}
881#[allow(dead_code)]
882impl RawFnPtr {
883    /// Creates a new raw function pointer descriptor.
884    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
885        Self {
886            ptr,
887            arity,
888            name: name.into(),
889        }
890    }
891    /// Returns the arity.
892    pub fn arity(&self) -> usize {
893        self.arity
894    }
895    /// Returns the name.
896    pub fn name(&self) -> &str {
897        &self.name
898    }
899    /// Returns the raw pointer value.
900    pub fn raw(&self) -> usize {
901        self.ptr
902    }
903}
904/// Extended metadata for a module.
905#[derive(Clone, Debug, Default)]
906pub struct ModuleInfo {
907    /// The module's semantic version.
908    pub version: Option<ModuleVersion>,
909    /// Author or maintainer.
910    pub author: Option<String>,
911    /// License identifier (e.g. "MIT").
912    pub license: Option<String>,
913    /// Short description.
914    pub description: Option<String>,
915}
916impl ModuleInfo {
917    /// Create an empty info struct.
918    pub fn new() -> Self {
919        Self::default()
920    }
921    /// Attach a version.
922    pub fn with_version(mut self, v: ModuleVersion) -> Self {
923        self.version = Some(v);
924        self
925    }
926    /// Attach an author.
927    pub fn with_author(mut self, a: impl Into<String>) -> Self {
928        self.author = Some(a.into());
929        self
930    }
931    /// Attach a license.
932    pub fn with_license(mut self, l: impl Into<String>) -> Self {
933        self.license = Some(l.into());
934        self
935    }
936    /// Attach a description.
937    pub fn with_description(mut self, d: impl Into<String>) -> Self {
938        self.description = Some(d.into());
939        self
940    }
941}
942/// Module cache for managing multiple modules.
943pub struct ModuleCache {
944    /// Cached modules indexed by name
945    modules: HashMap<String, ExportedModule>,
946    /// Import order (for deterministic behavior)
947    import_order: Vec<String>,
948}
949impl ModuleCache {
950    /// Create a new module cache.
951    pub fn new() -> Self {
952        Self {
953            modules: HashMap::new(),
954            import_order: Vec::new(),
955        }
956    }
957    /// Add a module to the cache.
958    pub fn add(&mut self, module: ExportedModule) {
959        let name = module.name.clone();
960        self.modules.insert(name.clone(), module);
961        if !self.import_order.contains(&name) {
962            self.import_order.push(name);
963        }
964    }
965    /// Get a module from the cache.
966    pub fn get(&self, name: &str) -> Option<&ExportedModule> {
967        self.modules.get(name)
968    }
969    /// Check if a module is cached.
970    pub fn contains(&self, name: &str) -> bool {
971        self.modules.contains_key(name)
972    }
973    /// Get all cached module names.
974    pub fn all_modules(&self) -> Vec<&str> {
975        self.import_order.iter().map(|s| s.as_str()).collect()
976    }
977    /// Get the number of cached modules.
978    pub fn num_modules(&self) -> usize {
979        self.modules.len()
980    }
981    /// Import all cached modules into an environment (in order).
982    pub fn import_all(&self, env: &mut Environment) -> Result<(), String> {
983        for name in &self.import_order {
984            if let Some(module) = self.modules.get(name) {
985                import_module(env, module)?;
986            }
987        }
988        Ok(())
989    }
990    /// Import a specific module and its transitive dependencies.
991    pub fn import_with_deps(&self, env: &mut Environment, name: &str) -> Result<(), String> {
992        let module = self
993            .modules
994            .get(name)
995            .ok_or_else(|| format!("Module '{}' not found in cache", name))?;
996        for dep in &module.dependencies {
997            if self.contains(dep) {
998                self.import_with_deps(env, dep)?;
999            }
1000        }
1001        import_module(env, module)
1002    }
1003    /// Remove a module from the cache.
1004    pub fn remove(&mut self, name: &str) -> Option<ExportedModule> {
1005        self.import_order.retain(|n| n != name);
1006        self.modules.remove(name)
1007    }
1008    /// Clear the cache.
1009    pub fn clear(&mut self) {
1010        self.modules.clear();
1011        self.import_order.clear();
1012    }
1013}
1014/// A simple directed acyclic graph.
1015#[allow(dead_code)]
1016pub struct SimpleDag {
1017    /// `edges[i]` is the list of direct successors of node `i`.
1018    edges: Vec<Vec<usize>>,
1019}
1020#[allow(dead_code)]
1021impl SimpleDag {
1022    /// Creates a DAG with `n` nodes and no edges.
1023    pub fn new(n: usize) -> Self {
1024        Self {
1025            edges: vec![Vec::new(); n],
1026        }
1027    }
1028    /// Adds an edge from `from` to `to`.
1029    pub fn add_edge(&mut self, from: usize, to: usize) {
1030        if from < self.edges.len() {
1031            self.edges[from].push(to);
1032        }
1033    }
1034    /// Returns the successors of `node`.
1035    pub fn successors(&self, node: usize) -> &[usize] {
1036        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1037    }
1038    /// Returns `true` if `from` can reach `to` via DFS.
1039    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1040        let mut visited = vec![false; self.edges.len()];
1041        self.dfs(from, to, &mut visited)
1042    }
1043    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1044        if cur == target {
1045            return true;
1046        }
1047        if cur >= visited.len() || visited[cur] {
1048            return false;
1049        }
1050        visited[cur] = true;
1051        for &next in self.successors(cur) {
1052            if self.dfs(next, target, visited) {
1053                return true;
1054            }
1055        }
1056        false
1057    }
1058    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1059    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1060        let n = self.edges.len();
1061        let mut in_degree = vec![0usize; n];
1062        for succs in &self.edges {
1063            for &s in succs {
1064                if s < n {
1065                    in_degree[s] += 1;
1066                }
1067            }
1068        }
1069        let mut queue: std::collections::VecDeque<usize> =
1070            (0..n).filter(|&i| in_degree[i] == 0).collect();
1071        let mut order = Vec::new();
1072        while let Some(node) = queue.pop_front() {
1073            order.push(node);
1074            for &s in self.successors(node) {
1075                if s < n {
1076                    in_degree[s] -= 1;
1077                    if in_degree[s] == 0 {
1078                        queue.push_back(s);
1079                    }
1080                }
1081            }
1082        }
1083        if order.len() == n {
1084            Some(order)
1085        } else {
1086            None
1087        }
1088    }
1089    /// Returns the number of nodes.
1090    pub fn num_nodes(&self) -> usize {
1091        self.edges.len()
1092    }
1093}
1094/// Represents a rewrite rule `lhs → rhs`.
1095#[allow(dead_code)]
1096#[allow(missing_docs)]
1097pub struct RewriteRule {
1098    /// The name of the rule.
1099    pub name: String,
1100    /// A string representation of the LHS pattern.
1101    pub lhs: String,
1102    /// A string representation of the RHS.
1103    pub rhs: String,
1104    /// Whether this is a conditional rule (has side conditions).
1105    pub conditional: bool,
1106}
1107#[allow(dead_code)]
1108impl RewriteRule {
1109    /// Creates an unconditional rewrite rule.
1110    pub fn unconditional(
1111        name: impl Into<String>,
1112        lhs: impl Into<String>,
1113        rhs: impl Into<String>,
1114    ) -> Self {
1115        Self {
1116            name: name.into(),
1117            lhs: lhs.into(),
1118            rhs: rhs.into(),
1119            conditional: false,
1120        }
1121    }
1122    /// Creates a conditional rewrite rule.
1123    pub fn conditional(
1124        name: impl Into<String>,
1125        lhs: impl Into<String>,
1126        rhs: impl Into<String>,
1127    ) -> Self {
1128        Self {
1129            name: name.into(),
1130            lhs: lhs.into(),
1131            rhs: rhs.into(),
1132            conditional: true,
1133        }
1134    }
1135    /// Returns a textual representation.
1136    pub fn display(&self) -> String {
1137        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1138    }
1139}
1140/// A mutable reference stack for tracking the current "focus" in a tree traversal.
1141#[allow(dead_code)]
1142pub struct FocusStack<T> {
1143    items: Vec<T>,
1144}
1145#[allow(dead_code)]
1146impl<T> FocusStack<T> {
1147    /// Creates an empty focus stack.
1148    pub fn new() -> Self {
1149        Self { items: Vec::new() }
1150    }
1151    /// Focuses on `item`.
1152    pub fn focus(&mut self, item: T) {
1153        self.items.push(item);
1154    }
1155    /// Blurs (pops) the current focus.
1156    pub fn blur(&mut self) -> Option<T> {
1157        self.items.pop()
1158    }
1159    /// Returns the current focus, or `None`.
1160    pub fn current(&self) -> Option<&T> {
1161        self.items.last()
1162    }
1163    /// Returns the focus depth.
1164    pub fn depth(&self) -> usize {
1165        self.items.len()
1166    }
1167    /// Returns `true` if there is no current focus.
1168    pub fn is_empty(&self) -> bool {
1169        self.items.is_empty()
1170    }
1171}