Skip to main content

oxilean_kernel/typeclasses/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use crate::{Expr, Name};
7use std::collections::HashMap;
8
9/// A pool of reusable string buffers.
10#[allow(dead_code)]
11pub struct StringPool {
12    free: Vec<String>,
13}
14#[allow(dead_code)]
15impl StringPool {
16    /// Creates a new empty string pool.
17    pub fn new() -> Self {
18        Self { free: Vec::new() }
19    }
20    /// Takes a string from the pool (may be empty).
21    pub fn take(&mut self) -> String {
22        self.free.pop().unwrap_or_default()
23    }
24    /// Returns a string to the pool.
25    pub fn give(&mut self, mut s: String) {
26        s.clear();
27        self.free.push(s);
28    }
29    /// Returns the number of free strings in the pool.
30    pub fn free_count(&self) -> usize {
31        self.free.len()
32    }
33}
34/// Priority levels for instance selection.
35#[allow(dead_code)]
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
37pub enum InstancePriority {
38    /// Low priority (fallback).
39    Low = 0,
40    /// Normal priority.
41    #[default]
42    Normal = 100,
43    /// High priority (preferred over Normal).
44    High = 200,
45    /// Forced priority (always chosen).
46    Forced = 1000,
47}
48impl InstancePriority {
49    /// Convert a numeric priority to an `InstancePriority`.
50    #[allow(dead_code)]
51    pub fn from_u32(n: u32) -> Self {
52        match n {
53            0..=50 => InstancePriority::Low,
54            51..=150 => InstancePriority::Normal,
55            151..=500 => InstancePriority::High,
56            _ => InstancePriority::Forced,
57        }
58    }
59    /// Numeric value.
60    #[allow(dead_code)]
61    pub fn value(self) -> u32 {
62        self as u32
63    }
64}
65/// A versioned record that stores a history of values.
66#[allow(dead_code)]
67pub struct VersionedRecord<T: Clone> {
68    /// Every earlier value, oldest first: version `n` is `earlier[n]`.
69    earlier: Vec<T>,
70    /// The latest value (version `earlier.len()`), declared last so it drops last.
71    current: T,
72}
73#[allow(dead_code)]
74impl<T: Clone> VersionedRecord<T> {
75    /// Creates a new record with an initial value.
76    pub fn new(initial: T) -> Self {
77        Self {
78            earlier: Vec::new(),
79            current: initial,
80        }
81    }
82    /// Updates the record with a new version.
83    pub fn update(&mut self, val: T) {
84        let previous = std::mem::replace(&mut self.current, val);
85        self.earlier.push(previous);
86    }
87    /// Returns the current (latest) value.
88    pub fn current(&self) -> &T {
89        &self.current
90    }
91    /// Returns the value at version `n` (0-indexed), or `None`.
92    pub fn at_version(&self, n: usize) -> Option<&T> {
93        match self.earlier.get(n) {
94            Some(value) => Some(value),
95            None if n == self.earlier.len() => Some(&self.current),
96            None => None,
97        }
98    }
99    /// Returns the version number of the current value.
100    pub fn version(&self) -> usize {
101        self.earlier.len()
102    }
103    /// Returns `true` if more than one version exists.
104    pub fn has_history(&self) -> bool {
105        !self.earlier.is_empty()
106    }
107}
108/// A simple decision tree node for rule dispatching.
109#[allow(dead_code)]
110#[allow(missing_docs)]
111pub enum DecisionNode {
112    /// A leaf with an action string.
113    Leaf(String),
114    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
115    Branch {
116        key: String,
117        val: String,
118        yes_branch: Box<DecisionNode>,
119        no_branch: Box<DecisionNode>,
120    },
121}
122#[allow(dead_code)]
123impl DecisionNode {
124    /// Evaluates the decision tree with the given context.
125    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
126        match self {
127            DecisionNode::Leaf(action) => action.as_str(),
128            DecisionNode::Branch {
129                key,
130                val,
131                yes_branch,
132                no_branch,
133            } => {
134                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
135                if actual == val.as_str() {
136                    yes_branch.evaluate(ctx)
137                } else {
138                    no_branch.evaluate(ctx)
139                }
140            }
141        }
142    }
143    /// Returns the depth of the decision tree.
144    pub fn depth(&self) -> usize {
145        match self {
146            DecisionNode::Leaf(_) => 0,
147            DecisionNode::Branch {
148                yes_branch,
149                no_branch,
150                ..
151            } => 1 + yes_branch.depth().max(no_branch.depth()),
152        }
153    }
154}
155/// Represents a rewrite rule `lhs → rhs`.
156#[allow(dead_code)]
157#[allow(missing_docs)]
158pub struct RewriteRule {
159    /// The name of the rule.
160    pub name: String,
161    /// A string representation of the LHS pattern.
162    pub lhs: String,
163    /// A string representation of the RHS.
164    pub rhs: String,
165    /// Whether this is a conditional rule (has side conditions).
166    pub conditional: bool,
167}
168#[allow(dead_code)]
169impl RewriteRule {
170    /// Creates an unconditional rewrite rule.
171    pub fn unconditional(
172        name: impl Into<String>,
173        lhs: impl Into<String>,
174        rhs: impl Into<String>,
175    ) -> Self {
176        Self {
177            name: name.into(),
178            lhs: lhs.into(),
179            rhs: rhs.into(),
180            conditional: false,
181        }
182    }
183    /// Creates a conditional rewrite rule.
184    pub fn conditional(
185        name: impl Into<String>,
186        lhs: impl Into<String>,
187        rhs: impl Into<String>,
188    ) -> Self {
189        Self {
190            name: name.into(),
191            lhs: lhs.into(),
192            rhs: rhs.into(),
193            conditional: true,
194        }
195    }
196    /// Returns a textual representation.
197    pub fn display(&self) -> String {
198        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
199    }
200}
201/// Statistics about typeclass resolution.
202#[allow(dead_code)]
203#[derive(Debug, Clone, Default)]
204pub struct TypeClassStats {
205    /// Number of successful instance lookups.
206    pub cache_hits: u64,
207    /// Number of failed instance lookups.
208    pub cache_misses: u64,
209    /// Total instance resolution calls.
210    pub total_lookups: u64,
211    /// Number of instances registered.
212    pub instances_registered: u64,
213    /// Number of classes registered.
214    pub classes_registered: u64,
215}
216impl TypeClassStats {
217    /// Create zeroed stats.
218    #[allow(dead_code)]
219    pub fn new() -> Self {
220        Self::default()
221    }
222    /// Hit rate for instance resolution (0.0–1.0).
223    #[allow(dead_code)]
224    pub fn hit_rate(&self) -> f64 {
225        if self.total_lookups == 0 {
226            1.0
227        } else {
228            self.cache_hits as f64 / self.total_lookups as f64
229        }
230    }
231    /// Merge another stats object.
232    #[allow(dead_code)]
233    pub fn merge(&mut self, other: &Self) {
234        self.cache_hits += other.cache_hits;
235        self.cache_misses += other.cache_misses;
236        self.total_lookups += other.total_lookups;
237        self.instances_registered += other.instances_registered;
238        self.classes_registered += other.classes_registered;
239    }
240}
241/// A type-erased function pointer with arity tracking.
242#[allow(dead_code)]
243pub struct RawFnPtr {
244    /// The raw function pointer (stored as usize for type erasure).
245    ptr: usize,
246    arity: usize,
247    name: String,
248}
249#[allow(dead_code)]
250impl RawFnPtr {
251    /// Creates a new raw function pointer descriptor.
252    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
253        Self {
254            ptr,
255            arity,
256            name: name.into(),
257        }
258    }
259    /// Returns the arity.
260    pub fn arity(&self) -> usize {
261        self.arity
262    }
263    /// Returns the name.
264    pub fn name(&self) -> &str {
265        &self.name
266    }
267    /// Returns the raw pointer value.
268    pub fn raw(&self) -> usize {
269        self.ptr
270    }
271}
272/// A simple key-value store backed by a sorted Vec for small maps.
273#[allow(dead_code)]
274pub struct SmallMap<K: Ord + Clone, V: Clone> {
275    entries: Vec<(K, V)>,
276}
277#[allow(dead_code)]
278impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
279    /// Creates a new empty small map.
280    pub fn new() -> Self {
281        Self {
282            entries: Vec::new(),
283        }
284    }
285    /// Inserts or replaces the value for `key`.
286    pub fn insert(&mut self, key: K, val: V) {
287        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
288            Ok(i) => self.entries[i].1 = val,
289            Err(i) => self.entries.insert(i, (key, val)),
290        }
291    }
292    /// Returns the value for `key`, or `None`.
293    pub fn get(&self, key: &K) -> Option<&V> {
294        self.entries
295            .binary_search_by_key(&key, |(k, _)| k)
296            .ok()
297            .map(|i| &self.entries[i].1)
298    }
299    /// Returns the number of entries.
300    pub fn len(&self) -> usize {
301        self.entries.len()
302    }
303    /// Returns `true` if empty.
304    pub fn is_empty(&self) -> bool {
305        self.entries.is_empty()
306    }
307    /// Returns all keys.
308    pub fn keys(&self) -> Vec<&K> {
309        self.entries.iter().map(|(k, _)| k).collect()
310    }
311    /// Returns all values.
312    pub fn values(&self) -> Vec<&V> {
313        self.entries.iter().map(|(_, v)| v).collect()
314    }
315}
316/// A layered typeclass registry that supports scoped instance introduction.
317///
318/// Useful for local `instance` declarations inside tactics or proofs.
319#[allow(dead_code)]
320#[derive(Debug, Default)]
321pub struct LayeredTypeClassRegistry {
322    /// Stack of local registries (outermost first).
323    layers: Vec<TypeClassRegistry>,
324    /// Global base registry.
325    global: TypeClassRegistry,
326}
327impl LayeredTypeClassRegistry {
328    /// Create a new empty layered registry.
329    #[allow(dead_code)]
330    pub fn new() -> Self {
331        Self {
332            layers: Vec::new(),
333            global: TypeClassRegistry::new(),
334        }
335    }
336    /// Push a new empty layer.
337    #[allow(dead_code)]
338    pub fn push_layer(&mut self) {
339        self.layers.push(TypeClassRegistry::new());
340    }
341    /// Pop the topmost layer.
342    #[allow(dead_code)]
343    pub fn pop_layer(&mut self) {
344        self.layers.pop();
345    }
346    /// Register an instance in the top layer (or global if no layers).
347    #[allow(dead_code)]
348    pub fn add_instance(&mut self, inst: Instance) {
349        if let Some(top) = self.layers.last_mut() {
350            top.register_instance(inst);
351        } else {
352            self.global.register_instance(inst);
353        }
354    }
355    /// Register a class in the global registry.
356    #[allow(dead_code)]
357    pub fn add_class(&mut self, class: TypeClass) {
358        self.global.register_class(class);
359    }
360    /// Find an instance by searching from the top layer to global.
361    #[allow(dead_code)]
362    pub fn find_instance(&self, class: &Name, ty: &Expr) -> Option<&Instance> {
363        for layer in self.layers.iter().rev() {
364            let found = layer.find_instances(class, ty);
365            if let Some(inst) = found.into_iter().next() {
366                return Some(inst);
367            }
368        }
369        self.global.find_instances(class, ty).into_iter().next()
370    }
371    /// Current number of layers.
372    #[allow(dead_code)]
373    pub fn depth(&self) -> usize {
374        self.layers.len()
375    }
376    /// Total instance count across all layers.
377    #[allow(dead_code)]
378    pub fn total_instances(&self) -> usize {
379        let layer_total: usize = self.layers.iter().map(|l| l.instances.len()).sum();
380        layer_total + self.global.instances.len()
381    }
382}
383/// A flat list of substitution pairs `(from, to)`.
384#[allow(dead_code)]
385pub struct FlatSubstitution {
386    pairs: Vec<(String, String)>,
387}
388#[allow(dead_code)]
389impl FlatSubstitution {
390    /// Creates an empty substitution.
391    pub fn new() -> Self {
392        Self { pairs: Vec::new() }
393    }
394    /// Adds a pair.
395    pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
396        self.pairs.push((from.into(), to.into()));
397    }
398    /// Applies all substitutions to `s` (leftmost-first order).
399    pub fn apply(&self, s: &str) -> String {
400        let mut result = s.to_string();
401        for (from, to) in &self.pairs {
402            result = result.replace(from.as_str(), to.as_str());
403        }
404        result
405    }
406    /// Returns the number of pairs.
407    pub fn len(&self) -> usize {
408        self.pairs.len()
409    }
410    /// Returns `true` if empty.
411    pub fn is_empty(&self) -> bool {
412        self.pairs.is_empty()
413    }
414}
415/// The registry that holds all type class and instance declarations.
416#[derive(Clone, Debug, Default)]
417pub struct TypeClassRegistry {
418    /// All registered classes, keyed by class name.
419    pub(super) classes: HashMap<String, TypeClass>,
420    /// All registered instances, in registration order.
421    pub(super) instances: Vec<Instance>,
422    /// Cache from (class, type-repr) → instance index.
423    instance_cache: HashMap<(String, String), usize>,
424}
425impl TypeClassRegistry {
426    /// Create an empty registry.
427    pub fn new() -> Self {
428        Self {
429            classes: HashMap::new(),
430            instances: Vec::new(),
431            instance_cache: HashMap::new(),
432        }
433    }
434    /// Register a type class.
435    pub fn register_class(&mut self, class: TypeClass) {
436        self.classes.insert(class.name.to_string(), class);
437    }
438    /// Look up a class by name.
439    pub fn get_class(&self, name: &Name) -> Option<&TypeClass> {
440        self.classes.get(&name.to_string())
441    }
442    /// Check whether a name refers to a registered class.
443    pub fn is_class(&self, name: &Name) -> bool {
444        self.classes.contains_key(&name.to_string())
445    }
446    /// Number of registered classes.
447    pub fn class_count(&self) -> usize {
448        self.classes.len()
449    }
450    /// Iterate over all class names.
451    pub fn class_names(&self) -> impl Iterator<Item = &String> {
452        self.classes.keys()
453    }
454    /// Get all classes that extend the given super-class.
455    pub fn subclasses_of(&self, super_name: &Name) -> Vec<&TypeClass> {
456        self.classes
457            .values()
458            .filter(|c| c.has_super(super_name))
459            .collect()
460    }
461    /// Register an instance.
462    pub fn register_instance(&mut self, instance: Instance) {
463        self.instance_cache
464            .remove(&(instance.class.to_string(), format!("{:?}", instance.ty)));
465        self.instances.push(instance);
466    }
467    /// Search for instances of the given class for the given type.
468    pub fn find_instances(&self, class: &Name, ty: &Expr) -> Vec<&Instance> {
469        self.instances
470            .iter()
471            .filter(|inst| &inst.class == class && instances_match(ty, &inst.ty))
472            .collect()
473    }
474    /// Find the best (highest priority, lowest number) instance.
475    pub fn find_best_instance(&self, class: &Name, ty: &Expr) -> InstanceSearchResult {
476        let mut candidates: Vec<&Instance> = self.find_instances(class, ty);
477        if candidates.is_empty() {
478            return InstanceSearchResult::NotFound;
479        }
480        candidates.sort_by_key(|i| i.priority);
481        let best_priority = candidates[0].priority;
482        let top: Vec<&Instance> = candidates
483            .iter()
484            .filter(|i| i.priority == best_priority)
485            .copied()
486            .collect();
487        if top.len() == 1 {
488            InstanceSearchResult::Found(top[0].clone())
489        } else {
490            InstanceSearchResult::Ambiguous(top.into_iter().cloned().collect())
491        }
492    }
493    /// Number of registered instances.
494    pub fn instance_count(&self) -> usize {
495        self.instances.len()
496    }
497    /// Remove all local instances.
498    pub fn clear_local_instances(&mut self) {
499        self.instances.retain(|i| !i.is_local);
500        self.instance_cache.clear();
501    }
502    /// Get all instances for a given class, sorted by priority.
503    pub fn instances_for_class(&self, class: &Name) -> Vec<&Instance> {
504        let mut result: Vec<&Instance> = self
505            .instances
506            .iter()
507            .filter(|i| &i.class == class)
508            .collect();
509        result.sort_by_key(|i| i.priority);
510        result
511    }
512    /// Get instances that match a given type predicate.
513    pub fn filter_instances<F>(&self, predicate: F) -> Vec<&Instance>
514    where
515        F: Fn(&Instance) -> bool,
516    {
517        self.instances.iter().filter(|i| predicate(i)).collect()
518    }
519    /// Get the projection expression for a method in a class (method index → projection).
520    pub fn method_projection(&self, class: &Name, method: &Name) -> Option<Expr> {
521        let cls = self.get_class(class)?;
522        let m = cls.find_method(method)?;
523        Some(build_method_projection(class, method, m.index))
524    }
525    /// Summarize the registry.
526    pub fn summary(&self) -> String {
527        format!(
528            "TypeClassRegistry {{ classes: {}, instances: {} }}",
529            self.classes.len(),
530            self.instances.len()
531        )
532    }
533}
534impl TypeClassRegistry {
535    /// Take a snapshot of the current instance count.
536    pub fn snapshot(&self) -> RegistrySnapshot {
537        RegistrySnapshot {
538            instance_count: self.instances.len(),
539        }
540    }
541    /// Restore the registry to a previously taken snapshot (removes instances added after).
542    pub fn restore(&mut self, snapshot: RegistrySnapshot) {
543        self.instances.truncate(snapshot.instance_count);
544        self.instance_cache.clear();
545    }
546}
547/// A pair of `StatSummary` values tracking before/after a transformation.
548#[allow(dead_code)]
549pub struct TransformStat {
550    before: StatSummary,
551    after: StatSummary,
552}
553#[allow(dead_code)]
554impl TransformStat {
555    /// Creates a new transform stat recorder.
556    pub fn new() -> Self {
557        Self {
558            before: StatSummary::new(),
559            after: StatSummary::new(),
560        }
561    }
562    /// Records a before value.
563    pub fn record_before(&mut self, v: f64) {
564        self.before.record(v);
565    }
566    /// Records an after value.
567    pub fn record_after(&mut self, v: f64) {
568        self.after.record(v);
569    }
570    /// Returns the mean reduction ratio (after/before).
571    pub fn mean_ratio(&self) -> Option<f64> {
572        let b = self.before.mean()?;
573        let a = self.after.mean()?;
574        if b.abs() < f64::EPSILON {
575            return None;
576        }
577        Some(a / b)
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 snapshot of a `TypeClassRegistry` for backtracking during elaboration.
615#[derive(Debug)]
616pub struct RegistrySnapshot {
617    instance_count: usize,
618}
619/// A set of rewrite rules.
620#[allow(dead_code)]
621pub struct RewriteRuleSet {
622    rules: Vec<RewriteRule>,
623}
624#[allow(dead_code)]
625impl RewriteRuleSet {
626    /// Creates an empty rule set.
627    pub fn new() -> Self {
628        Self { rules: Vec::new() }
629    }
630    /// Adds a rule.
631    pub fn add(&mut self, rule: RewriteRule) {
632        self.rules.push(rule);
633    }
634    /// Returns the number of rules.
635    pub fn len(&self) -> usize {
636        self.rules.len()
637    }
638    /// Returns `true` if the set is empty.
639    pub fn is_empty(&self) -> bool {
640        self.rules.is_empty()
641    }
642    /// Returns all conditional rules.
643    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
644        self.rules.iter().filter(|r| r.conditional).collect()
645    }
646    /// Returns all unconditional rules.
647    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
648        self.rules.iter().filter(|r| !r.conditional).collect()
649    }
650    /// Looks up a rule by name.
651    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
652        self.rules.iter().find(|r| r.name == name)
653    }
654}
655/// A sparse vector: stores only non-default elements.
656#[allow(dead_code)]
657pub struct SparseVec<T: Default + Clone + PartialEq> {
658    entries: std::collections::HashMap<usize, T>,
659    default_: T,
660    logical_len: usize,
661}
662#[allow(dead_code)]
663impl<T: Default + Clone + PartialEq> SparseVec<T> {
664    /// Creates a new sparse vector with logical length `len`.
665    pub fn new(len: usize) -> Self {
666        Self {
667            entries: std::collections::HashMap::new(),
668            default_: T::default(),
669            logical_len: len,
670        }
671    }
672    /// Sets element at `idx`.
673    pub fn set(&mut self, idx: usize, val: T) {
674        if val == self.default_ {
675            self.entries.remove(&idx);
676        } else {
677            self.entries.insert(idx, val);
678        }
679    }
680    /// Gets element at `idx`.
681    pub fn get(&self, idx: usize) -> &T {
682        self.entries.get(&idx).unwrap_or(&self.default_)
683    }
684    /// Returns the logical length.
685    pub fn len(&self) -> usize {
686        self.logical_len
687    }
688    /// Returns whether the collection is empty.
689    pub fn is_empty(&self) -> bool {
690        self.len() == 0
691    }
692    /// Returns the number of non-default elements.
693    pub fn nnz(&self) -> usize {
694        self.entries.len()
695    }
696}
697/// A non-empty list (at least one element guaranteed).
698#[allow(dead_code)]
699pub struct NonEmptyVec<T> {
700    head: T,
701    tail: Vec<T>,
702}
703#[allow(dead_code)]
704impl<T> NonEmptyVec<T> {
705    /// Creates a non-empty vec with a single element.
706    pub fn singleton(val: T) -> Self {
707        Self {
708            head: val,
709            tail: Vec::new(),
710        }
711    }
712    /// Pushes an element.
713    pub fn push(&mut self, val: T) {
714        self.tail.push(val);
715    }
716    /// Returns a reference to the first element.
717    pub fn first(&self) -> &T {
718        &self.head
719    }
720    /// Returns a reference to the last element.
721    pub fn last(&self) -> &T {
722        self.tail.last().unwrap_or(&self.head)
723    }
724    /// Returns the number of elements.
725    pub fn len(&self) -> usize {
726        1 + self.tail.len()
727    }
728    /// Returns whether the collection is empty.
729    pub fn is_empty(&self) -> bool {
730        self.len() == 0
731    }
732    /// Returns all elements as a Vec.
733    pub fn to_vec(&self) -> Vec<&T> {
734        let mut v = vec![&self.head];
735        v.extend(self.tail.iter());
736        v
737    }
738}
739/// A fixed-size sliding window that computes a running sum.
740#[allow(dead_code)]
741pub struct SlidingSum {
742    window: Vec<f64>,
743    capacity: usize,
744    pos: usize,
745    sum: f64,
746    count: usize,
747}
748#[allow(dead_code)]
749impl SlidingSum {
750    /// Creates a sliding sum with the given window size.
751    pub fn new(capacity: usize) -> Self {
752        Self {
753            window: vec![0.0; capacity],
754            capacity,
755            pos: 0,
756            sum: 0.0,
757            count: 0,
758        }
759    }
760    /// Adds a value to the window, removing the oldest if full.
761    pub fn push(&mut self, val: f64) {
762        let oldest = self.window[self.pos];
763        self.sum -= oldest;
764        self.sum += val;
765        self.window[self.pos] = val;
766        self.pos = (self.pos + 1) % self.capacity;
767        if self.count < self.capacity {
768            self.count += 1;
769        }
770    }
771    /// Returns the current window sum.
772    pub fn sum(&self) -> f64 {
773        self.sum
774    }
775    /// Returns the window mean, or `None` if empty.
776    pub fn mean(&self) -> Option<f64> {
777        if self.count == 0 {
778            None
779        } else {
780            Some(self.sum / self.count as f64)
781        }
782    }
783    /// Returns the current window size (number of valid elements).
784    pub fn count(&self) -> usize {
785        self.count
786    }
787}
788/// A write-once cell.
789#[allow(dead_code)]
790pub struct WriteOnce<T> {
791    value: std::cell::Cell<Option<T>>,
792}
793#[allow(dead_code)]
794impl<T: Copy> WriteOnce<T> {
795    /// Creates an empty write-once cell.
796    pub fn new() -> Self {
797        Self {
798            value: std::cell::Cell::new(None),
799        }
800    }
801    /// Writes a value.  Returns `false` if already written.
802    pub fn write(&self, val: T) -> bool {
803        if self.value.get().is_some() {
804            return false;
805        }
806        self.value.set(Some(val));
807        true
808    }
809    /// Returns the value if written.
810    pub fn read(&self) -> Option<T> {
811        self.value.get()
812    }
813    /// Returns `true` if the value has been written.
814    pub fn is_written(&self) -> bool {
815        self.value.get().is_some()
816    }
817}
818/// A simple stack-based calculator for arithmetic expressions.
819#[allow(dead_code)]
820pub struct StackCalc {
821    stack: Vec<i64>,
822}
823#[allow(dead_code)]
824impl StackCalc {
825    /// Creates a new empty calculator.
826    pub fn new() -> Self {
827        Self { stack: Vec::new() }
828    }
829    /// Pushes an integer literal.
830    pub fn push(&mut self, n: i64) {
831        self.stack.push(n);
832    }
833    /// Replaces the top two values, `b` on top of `a`, with `op(a, b)` and
834    /// returns it.  Returns `None`, leaving the stack unchanged, if it holds
835    /// fewer than two values.
836    fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
837        let (rest_len, a, b) = match self.stack[..] {
838            [ref rest @ .., a, b] => (rest.len(), a, b),
839            _ => return None,
840        };
841        let value = op(a, b);
842        self.stack.truncate(rest_len);
843        self.stack.push(value);
844        Some(value)
845    }
846    /// Adds the top two values and returns the sum, which replaces them.
847    /// Returns `None`, leaving the stack unchanged, if it holds fewer than
848    /// two values.
849    pub fn add(&mut self) -> Option<i64> {
850        self.apply_binary(|a, b| a + b)
851    }
852    /// Subtracts top from second and returns the difference, which replaces
853    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
854    /// than two values.
855    pub fn sub(&mut self) -> Option<i64> {
856        self.apply_binary(|a, b| a - b)
857    }
858    /// Multiplies the top two values and returns the product, which replaces
859    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
860    /// than two values.
861    pub fn mul(&mut self) -> Option<i64> {
862        self.apply_binary(|a, b| a * b)
863    }
864    /// Peeks the top value.
865    pub fn peek(&self) -> Option<i64> {
866        self.stack.last().copied()
867    }
868    /// Returns the stack depth.
869    pub fn depth(&self) -> usize {
870        self.stack.len()
871    }
872}
873/// A counter that can measure elapsed time between snapshots.
874#[allow(dead_code)]
875pub struct Stopwatch {
876    start: crate::wall_clock::Instant,
877    splits: Vec<f64>,
878}
879#[allow(dead_code)]
880impl Stopwatch {
881    /// Creates and starts a new stopwatch.
882    pub fn start() -> Self {
883        Self {
884            start: crate::wall_clock::Instant::now(),
885            splits: Vec::new(),
886        }
887    }
888    /// Records a split time (elapsed since start).
889    pub fn split(&mut self) {
890        self.splits.push(self.elapsed_ms());
891    }
892    /// Returns total elapsed milliseconds since start.
893    pub fn elapsed_ms(&self) -> f64 {
894        self.start.elapsed().as_secs_f64() * 1000.0
895    }
896    /// Returns all recorded split times.
897    pub fn splits(&self) -> &[f64] {
898        &self.splits
899    }
900    /// Returns the number of splits.
901    pub fn num_splits(&self) -> usize {
902        self.splits.len()
903    }
904}
905/// A tagged union for representing a simple two-case discriminated union.
906#[allow(dead_code)]
907pub enum Either2<A, B> {
908    /// The first alternative.
909    First(A),
910    /// The second alternative.
911    Second(B),
912}
913#[allow(dead_code)]
914impl<A, B> Either2<A, B> {
915    /// Returns `true` if this is the first alternative.
916    pub fn is_first(&self) -> bool {
917        matches!(self, Either2::First(_))
918    }
919    /// Returns `true` if this is the second alternative.
920    pub fn is_second(&self) -> bool {
921        matches!(self, Either2::Second(_))
922    }
923    /// Returns the first value if present.
924    pub fn first(self) -> Option<A> {
925        match self {
926            Either2::First(a) => Some(a),
927            _ => None,
928        }
929    }
930    /// Returns the second value if present.
931    pub fn second(self) -> Option<B> {
932        match self {
933            Either2::Second(b) => Some(b),
934            _ => None,
935        }
936    }
937    /// Maps over the first alternative.
938    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
939        match self {
940            Either2::First(a) => Either2::First(f(a)),
941            Either2::Second(b) => Either2::Second(b),
942        }
943    }
944}
945/// A hierarchical configuration tree.
946#[allow(dead_code)]
947pub struct ConfigNode {
948    key: String,
949    value: Option<String>,
950    children: Vec<ConfigNode>,
951}
952#[allow(dead_code)]
953impl ConfigNode {
954    /// Creates a leaf config node with a value.
955    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
956        Self {
957            key: key.into(),
958            value: Some(value.into()),
959            children: Vec::new(),
960        }
961    }
962    /// Creates a section node with children.
963    pub fn section(key: impl Into<String>) -> Self {
964        Self {
965            key: key.into(),
966            value: None,
967            children: Vec::new(),
968        }
969    }
970    /// Adds a child node.
971    pub fn add_child(&mut self, child: ConfigNode) {
972        self.children.push(child);
973    }
974    /// Returns the key.
975    pub fn key(&self) -> &str {
976        &self.key
977    }
978    /// Returns the value, or `None` for section nodes.
979    pub fn value(&self) -> Option<&str> {
980        self.value.as_deref()
981    }
982    /// Returns the number of children.
983    pub fn num_children(&self) -> usize {
984        self.children.len()
985    }
986    /// Looks up a dot-separated path.
987    pub fn lookup(&self, path: &str) -> Option<&str> {
988        let mut parts = path.splitn(2, '.');
989        let head = parts.next()?;
990        let tail = parts.next();
991        if head != self.key {
992            return None;
993        }
994        match tail {
995            None => self.value.as_deref(),
996            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
997        }
998    }
999    fn lookup_relative(&self, path: &str) -> Option<&str> {
1000        let mut parts = path.splitn(2, '.');
1001        let head = parts.next()?;
1002        let tail = parts.next();
1003        if head != self.key {
1004            return None;
1005        }
1006        match tail {
1007            None => self.value.as_deref(),
1008            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1009        }
1010    }
1011}
1012/// An instance resolver that always returns `None`.
1013#[derive(Debug)]
1014pub struct NullResolver;
1015/// A window iterator that yields overlapping windows of size `n`.
1016#[allow(dead_code)]
1017pub struct WindowIterator<'a, T> {
1018    pub(super) data: &'a [T],
1019    pub(super) pos: usize,
1020    pub(super) window: usize,
1021}
1022#[allow(dead_code)]
1023impl<'a, T> WindowIterator<'a, T> {
1024    /// Creates a new window iterator.
1025    pub fn new(data: &'a [T], window: usize) -> Self {
1026        Self {
1027            data,
1028            pos: 0,
1029            window,
1030        }
1031    }
1032}
1033/// A generic counter that tracks min/max/sum for statistical summaries.
1034#[allow(dead_code)]
1035pub struct StatSummary {
1036    count: u64,
1037    sum: f64,
1038    min: f64,
1039    max: f64,
1040}
1041#[allow(dead_code)]
1042impl StatSummary {
1043    /// Creates an empty summary.
1044    pub fn new() -> Self {
1045        Self {
1046            count: 0,
1047            sum: 0.0,
1048            min: f64::INFINITY,
1049            max: f64::NEG_INFINITY,
1050        }
1051    }
1052    /// Records a sample.
1053    pub fn record(&mut self, val: f64) {
1054        self.count += 1;
1055        self.sum += val;
1056        if val < self.min {
1057            self.min = val;
1058        }
1059        if val > self.max {
1060            self.max = val;
1061        }
1062    }
1063    /// Returns the mean, or `None` if no samples.
1064    pub fn mean(&self) -> Option<f64> {
1065        if self.count == 0 {
1066            None
1067        } else {
1068            Some(self.sum / self.count as f64)
1069        }
1070    }
1071    /// Returns the minimum, or `None` if no samples.
1072    pub fn min(&self) -> Option<f64> {
1073        if self.count == 0 {
1074            None
1075        } else {
1076            Some(self.min)
1077        }
1078    }
1079    /// Returns the maximum, or `None` if no samples.
1080    pub fn max(&self) -> Option<f64> {
1081        if self.count == 0 {
1082            None
1083        } else {
1084            Some(self.max)
1085        }
1086    }
1087    /// Returns the count of recorded samples.
1088    pub fn count(&self) -> u64 {
1089        self.count
1090    }
1091}
1092/// A mutable reference stack for tracking the current "focus" in a tree traversal.
1093#[allow(dead_code)]
1094pub struct FocusStack<T> {
1095    items: Vec<T>,
1096}
1097#[allow(dead_code)]
1098impl<T> FocusStack<T> {
1099    /// Creates an empty focus stack.
1100    pub fn new() -> Self {
1101        Self { items: Vec::new() }
1102    }
1103    /// Focuses on `item`.
1104    pub fn focus(&mut self, item: T) {
1105        self.items.push(item);
1106    }
1107    /// Blurs (pops) the current focus.
1108    pub fn blur(&mut self) -> Option<T> {
1109        self.items.pop()
1110    }
1111    /// Returns the current focus, or `None`.
1112    pub fn current(&self) -> Option<&T> {
1113        self.items.last()
1114    }
1115    /// Returns the focus depth.
1116    pub fn depth(&self) -> usize {
1117        self.items.len()
1118    }
1119    /// Returns `true` if there is no current focus.
1120    pub fn is_empty(&self) -> bool {
1121        self.items.is_empty()
1122    }
1123}
1124/// A token bucket rate limiter.
1125#[allow(dead_code)]
1126pub struct TokenBucket {
1127    capacity: u64,
1128    tokens: u64,
1129    refill_per_ms: u64,
1130    last_refill: crate::wall_clock::Instant,
1131}
1132#[allow(dead_code)]
1133impl TokenBucket {
1134    /// Creates a new token bucket.
1135    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1136        Self {
1137            capacity,
1138            tokens: capacity,
1139            refill_per_ms,
1140            last_refill: crate::wall_clock::Instant::now(),
1141        }
1142    }
1143    /// Attempts to consume `n` tokens.  Returns `true` on success.
1144    pub fn try_consume(&mut self, n: u64) -> bool {
1145        self.refill();
1146        if self.tokens >= n {
1147            self.tokens -= n;
1148            true
1149        } else {
1150            false
1151        }
1152    }
1153    fn refill(&mut self) {
1154        let now = crate::wall_clock::Instant::now();
1155        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1156        if elapsed_ms > 0 {
1157            let new_tokens = elapsed_ms * self.refill_per_ms;
1158            self.tokens = (self.tokens + new_tokens).min(self.capacity);
1159            self.last_refill = now;
1160        }
1161    }
1162    /// Returns the number of currently available tokens.
1163    pub fn available(&self) -> u64 {
1164        self.tokens
1165    }
1166    /// Returns the bucket capacity.
1167    pub fn capacity(&self) -> u64 {
1168        self.capacity
1169    }
1170}
1171/// A complete set of method implementations for an instance.
1172#[allow(dead_code)]
1173#[derive(Clone, Debug, Default)]
1174pub struct InstanceImpl {
1175    /// Map from method name to implementation.
1176    impls: Vec<MethodImpl>,
1177}
1178impl InstanceImpl {
1179    /// Create an empty implementation set.
1180    #[allow(dead_code)]
1181    pub fn new() -> Self {
1182        Self::default()
1183    }
1184    /// Add a method implementation.
1185    #[allow(dead_code)]
1186    pub fn add(&mut self, impl_: MethodImpl) {
1187        self.impls.push(impl_);
1188    }
1189    /// Get the implementation for a method.
1190    #[allow(dead_code)]
1191    pub fn get(&self, method: &Name) -> Option<&MethodImpl> {
1192        self.impls.iter().find(|m| &m.method_name == method)
1193    }
1194    /// Number of implemented methods.
1195    #[allow(dead_code)]
1196    pub fn len(&self) -> usize {
1197        self.impls.len()
1198    }
1199    /// Check if empty.
1200    #[allow(dead_code)]
1201    pub fn is_empty(&self) -> bool {
1202        self.impls.is_empty()
1203    }
1204    /// Count default implementations.
1205    #[allow(dead_code)]
1206    pub fn count_defaults(&self) -> usize {
1207        self.impls.iter().filter(|m| m.is_default).count()
1208    }
1209    /// All method names.
1210    #[allow(dead_code)]
1211    pub fn method_names(&self) -> Vec<&Name> {
1212        self.impls.iter().map(|m| &m.method_name).collect()
1213    }
1214}
1215/// A dependency closure builder (transitive closure via BFS).
1216#[allow(dead_code)]
1217pub struct TransitiveClosure {
1218    adj: Vec<Vec<usize>>,
1219    n: usize,
1220}
1221#[allow(dead_code)]
1222impl TransitiveClosure {
1223    /// Creates a transitive closure builder for `n` nodes.
1224    pub fn new(n: usize) -> Self {
1225        Self {
1226            adj: vec![Vec::new(); n],
1227            n,
1228        }
1229    }
1230    /// Adds a direct edge.
1231    pub fn add_edge(&mut self, from: usize, to: usize) {
1232        if from < self.n {
1233            self.adj[from].push(to);
1234        }
1235    }
1236    /// Computes all nodes reachable from `start` (including `start`).
1237    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
1238        let mut visited = vec![false; self.n];
1239        let mut queue = std::collections::VecDeque::new();
1240        queue.push_back(start);
1241        while let Some(node) = queue.pop_front() {
1242            if node >= self.n || visited[node] {
1243                continue;
1244            }
1245            visited[node] = true;
1246            for &next in &self.adj[node] {
1247                queue.push_back(next);
1248            }
1249        }
1250        (0..self.n).filter(|&i| visited[i]).collect()
1251    }
1252    /// Returns `true` if `from` can transitively reach `to`.
1253    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1254        self.reachable_from(from).contains(&to)
1255    }
1256}
1257/// A simple directed acyclic graph.
1258#[allow(dead_code)]
1259pub struct SimpleDag {
1260    /// `edges[i]` is the list of direct successors of node `i`.
1261    edges: Vec<Vec<usize>>,
1262}
1263#[allow(dead_code)]
1264impl SimpleDag {
1265    /// Creates a DAG with `n` nodes and no edges.
1266    pub fn new(n: usize) -> Self {
1267        Self {
1268            edges: vec![Vec::new(); n],
1269        }
1270    }
1271    /// Adds an edge from `from` to `to`.
1272    pub fn add_edge(&mut self, from: usize, to: usize) {
1273        if from < self.edges.len() {
1274            self.edges[from].push(to);
1275        }
1276    }
1277    /// Returns the successors of `node`.
1278    pub fn successors(&self, node: usize) -> &[usize] {
1279        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1280    }
1281    /// Returns `true` if `from` can reach `to` via DFS.
1282    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1283        let mut visited = vec![false; self.edges.len()];
1284        self.dfs(from, to, &mut visited)
1285    }
1286    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1287        if cur == target {
1288            return true;
1289        }
1290        if cur >= visited.len() || visited[cur] {
1291            return false;
1292        }
1293        visited[cur] = true;
1294        for &next in self.successors(cur) {
1295            if self.dfs(next, target, visited) {
1296                return true;
1297            }
1298        }
1299        false
1300    }
1301    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1302    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1303        let n = self.edges.len();
1304        let mut in_degree = vec![0usize; n];
1305        for succs in &self.edges {
1306            for &s in succs {
1307                if s < n {
1308                    in_degree[s] += 1;
1309                }
1310            }
1311        }
1312        let mut queue: std::collections::VecDeque<usize> =
1313            (0..n).filter(|&i| in_degree[i] == 0).collect();
1314        let mut order = Vec::new();
1315        while let Some(node) = queue.pop_front() {
1316            order.push(node);
1317            for &s in self.successors(node) {
1318                if s < n {
1319                    in_degree[s] -= 1;
1320                    if in_degree[s] == 0 {
1321                        queue.push_back(s);
1322                    }
1323                }
1324            }
1325        }
1326        if order.len() == n {
1327            Some(order)
1328        } else {
1329            None
1330        }
1331    }
1332    /// Returns the number of nodes.
1333    pub fn num_nodes(&self) -> usize {
1334        self.edges.len()
1335    }
1336}
1337/// A type class declaration.
1338///
1339/// For example, `class Add (α : Type)` declares a type class named `Add` with
1340/// one type parameter and one method `add : α → α → α`.
1341#[derive(Clone, Debug)]
1342pub struct TypeClass {
1343    /// Name of the class (e.g., `Add`, `Mul`, `Inhabited`).
1344    pub name: Name,
1345    /// Names of the type parameters.
1346    pub params: Vec<Name>,
1347    /// The full type of the class (as a Pi-type).
1348    pub ty: Expr,
1349    /// Methods declared in the class, in declaration order.
1350    pub methods: Vec<Method>,
1351    /// Names of super-classes that instances must also implement.
1352    pub super_classes: Vec<Name>,
1353    /// Whether this class is in Prop (proof-irrelevant).
1354    pub is_prop: bool,
1355}
1356impl TypeClass {
1357    /// Create a new type class with no methods or super-classes.
1358    pub fn new(name: Name, params: Vec<Name>, ty: Expr) -> Self {
1359        Self {
1360            name,
1361            params,
1362            ty,
1363            methods: Vec::new(),
1364            super_classes: Vec::new(),
1365            is_prop: false,
1366        }
1367    }
1368    /// Add a method to the class.
1369    pub fn add_method(&mut self, method: Method) {
1370        self.methods.push(method);
1371    }
1372    /// Add a super-class dependency.
1373    pub fn add_super(&mut self, super_name: Name) {
1374        self.super_classes.push(super_name);
1375    }
1376    /// Mark this class as living in Prop.
1377    pub fn mark_prop(mut self) -> Self {
1378        self.is_prop = true;
1379        self
1380    }
1381    /// Look up a method by name.
1382    pub fn find_method(&self, name: &Name) -> Option<&Method> {
1383        self.methods.iter().find(|m| &m.name == name)
1384    }
1385    /// Check whether the class has a super-class with the given name.
1386    pub fn has_super(&self, name: &Name) -> bool {
1387        self.super_classes.contains(name)
1388    }
1389    /// Count methods in the class.
1390    pub fn method_count(&self) -> usize {
1391        self.methods.len()
1392    }
1393    /// Check whether the class has any methods.
1394    pub fn is_empty(&self) -> bool {
1395        self.methods.is_empty()
1396    }
1397    /// Iterate over all method names.
1398    pub fn method_names(&self) -> impl Iterator<Item = &Name> {
1399        self.methods.iter().map(|m| &m.name)
1400    }
1401    /// Check whether the class has any super-classes.
1402    pub fn has_super_classes(&self) -> bool {
1403        !self.super_classes.is_empty()
1404    }
1405    /// Number of type parameters.
1406    pub fn arity(&self) -> usize {
1407        self.params.len()
1408    }
1409}
1410/// An instance of a type class.
1411///
1412/// For example, `instance : Add Nat` is an instance of `Add` for the type `Nat`.
1413#[derive(Clone, Debug)]
1414pub struct Instance {
1415    /// The class this is an instance of.
1416    pub class: Name,
1417    /// The type argument(s) for this instance.
1418    pub ty: Expr,
1419    /// Search priority (lower number = searched first).
1420    pub priority: i32,
1421    /// Implementations of each method (method name → expression).
1422    pub methods: HashMap<String, Expr>,
1423    /// Optional name for the instance declaration.
1424    pub instance_name: Option<Name>,
1425    /// Whether this is a local (hypothetical) instance.
1426    pub is_local: bool,
1427}
1428impl Instance {
1429    /// Create a new anonymous instance with default priority.
1430    pub fn new(class: Name, ty: Expr) -> Self {
1431        Self {
1432            class,
1433            ty,
1434            priority: 100,
1435            methods: HashMap::new(),
1436            instance_name: None,
1437            is_local: false,
1438        }
1439    }
1440    /// Create a named instance.
1441    pub fn named(class: Name, ty: Expr, name: Name) -> Self {
1442        Self {
1443            class,
1444            ty,
1445            priority: 100,
1446            methods: HashMap::new(),
1447            instance_name: Some(name),
1448            is_local: false,
1449        }
1450    }
1451    /// Set the priority.
1452    pub fn with_priority(mut self, priority: i32) -> Self {
1453        self.priority = priority;
1454        self
1455    }
1456    /// Mark as a local instance.
1457    pub fn as_local(mut self) -> Self {
1458        self.is_local = true;
1459        self
1460    }
1461    /// Add an implementation for a method.
1462    pub fn add_method_impl(&mut self, method_name: impl Into<String>, impl_expr: Expr) {
1463        self.methods.insert(method_name.into(), impl_expr);
1464    }
1465    /// Look up the implementation of a method.
1466    pub fn get_method_impl(&self, method_name: &str) -> Option<&Expr> {
1467        self.methods.get(method_name)
1468    }
1469    /// Check whether all methods of the given class are implemented.
1470    pub fn implements_all(&self, class: &TypeClass) -> bool {
1471        class
1472            .methods
1473            .iter()
1474            .all(|m| self.methods.contains_key(&m.name.to_string()))
1475    }
1476    /// Number of implemented methods.
1477    pub fn implemented_count(&self) -> usize {
1478        self.methods.len()
1479    }
1480    /// Check whether this instance has a name.
1481    pub fn is_named(&self) -> bool {
1482        self.instance_name.is_some()
1483    }
1484}
1485/// A single method belonging to a type class.
1486#[derive(Clone, Debug)]
1487pub struct Method {
1488    /// Name of the method.
1489    pub name: Name,
1490    /// Type signature of the method (as a kernel expression).
1491    pub ty: Expr,
1492    /// Whether the method has a default implementation.
1493    pub has_default: bool,
1494    /// Index of this method in the class declaration (0-based).
1495    pub index: usize,
1496}
1497impl Method {
1498    /// Create a new method without a default implementation.
1499    pub fn new(name: Name, ty: Expr, index: usize) -> Self {
1500        Self {
1501            name,
1502            ty,
1503            has_default: false,
1504            index,
1505        }
1506    }
1507    /// Create a method that has a default implementation.
1508    pub fn with_default(name: Name, ty: Expr, index: usize) -> Self {
1509        Self {
1510            name,
1511            ty,
1512            has_default: true,
1513            index,
1514        }
1515    }
1516    /// Return a copy marked as having a default.
1517    pub fn set_default(mut self) -> Self {
1518        self.has_default = true;
1519        self
1520    }
1521}
1522/// Represents a class hierarchy edge (parent → child relationship).
1523#[derive(Clone, Debug, PartialEq, Eq)]
1524pub struct ClassEdge {
1525    /// The parent class.
1526    pub parent: Name,
1527    /// The child class that extends the parent.
1528    pub child: Name,
1529}
1530impl ClassEdge {
1531    /// Create a new class hierarchy edge.
1532    pub fn new(parent: Name, child: Name) -> Self {
1533        Self { parent, child }
1534    }
1535}
1536/// A label set for a graph node.
1537#[allow(dead_code)]
1538pub struct LabelSet {
1539    labels: Vec<String>,
1540}
1541#[allow(dead_code)]
1542impl LabelSet {
1543    /// Creates a new empty label set.
1544    pub fn new() -> Self {
1545        Self { labels: Vec::new() }
1546    }
1547    /// Adds a label (deduplicates).
1548    pub fn add(&mut self, label: impl Into<String>) {
1549        let s = label.into();
1550        if !self.labels.contains(&s) {
1551            self.labels.push(s);
1552        }
1553    }
1554    /// Returns `true` if `label` is present.
1555    pub fn has(&self, label: &str) -> bool {
1556        self.labels.iter().any(|l| l == label)
1557    }
1558    /// Returns the count of labels.
1559    pub fn count(&self) -> usize {
1560        self.labels.len()
1561    }
1562    /// Returns all labels.
1563    pub fn all(&self) -> &[String] {
1564        &self.labels
1565    }
1566}
1567/// A method implementation override for derived instances.
1568#[allow(dead_code)]
1569#[derive(Clone, Debug)]
1570pub struct MethodImpl {
1571    /// Method name.
1572    pub method_name: Name,
1573    /// Implementation expression.
1574    pub impl_expr: Expr,
1575    /// Whether this uses a default implementation.
1576    pub is_default: bool,
1577}
1578impl MethodImpl {
1579    /// Create a custom method implementation.
1580    #[allow(dead_code)]
1581    pub fn custom(method: Name, expr: Expr) -> Self {
1582        Self {
1583            method_name: method,
1584            impl_expr: expr,
1585            is_default: false,
1586        }
1587    }
1588    /// Create a default method implementation.
1589    #[allow(dead_code)]
1590    pub fn default_impl(method: Name, expr: Expr) -> Self {
1591        Self {
1592            method_name: method,
1593            impl_expr: expr,
1594            is_default: true,
1595        }
1596    }
1597}
1598/// Result of a type class search.
1599#[derive(Clone, Debug)]
1600pub enum InstanceSearchResult {
1601    /// A unique instance was found.
1602    Found(Instance),
1603    /// Multiple instances matched (ambiguity).
1604    Ambiguous(Vec<Instance>),
1605    /// No instance was found.
1606    NotFound,
1607}
1608impl InstanceSearchResult {
1609    /// Returns `true` if a unique instance was found.
1610    pub fn is_found(&self) -> bool {
1611        matches!(self, InstanceSearchResult::Found(_))
1612    }
1613    /// Returns `true` if the search was ambiguous.
1614    pub fn is_ambiguous(&self) -> bool {
1615        matches!(self, InstanceSearchResult::Ambiguous(_))
1616    }
1617    /// Extract the unique instance, if any.
1618    pub fn into_instance(self) -> Option<Instance> {
1619        match self {
1620            InstanceSearchResult::Found(inst) => Some(inst),
1621            _ => None,
1622        }
1623    }
1624}