use crate::declaration::ConstantInfo;
use crate::{
BinderInfo, Declaration, Environment, Expr, FVarId, Level, LevelMVarId, Literal, Name,
};
use std::collections::HashMap;
use super::functions::import_module;
#[allow(dead_code)]
pub struct TransformStat {
before: StatSummary,
after: StatSummary,
}
#[allow(dead_code)]
impl TransformStat {
pub fn new() -> Self {
Self {
before: StatSummary::new(),
after: StatSummary::new(),
}
}
pub fn record_before(&mut self, v: f64) {
self.before.record(v);
}
pub fn record_after(&mut self, v: f64) {
self.after.record(v);
}
pub fn mean_ratio(&self) -> Option<f64> {
let b = self.before.mean()?;
let a = self.after.mean()?;
if b.abs() < f64::EPSILON {
return None;
}
Some(a / b)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IntegrityCheckResult {
Ok,
EmptyModule,
DuplicateNames(Vec<Name>),
BadMagicNumber,
UnsupportedVersion(u32),
}
#[allow(dead_code)]
pub struct LabelSet {
labels: Vec<String>,
}
#[allow(dead_code)]
impl LabelSet {
pub fn new() -> Self {
Self { labels: Vec::new() }
}
pub fn add(&mut self, label: impl Into<String>) {
let s = label.into();
if !self.labels.contains(&s) {
self.labels.push(s);
}
}
pub fn has(&self, label: &str) -> bool {
self.labels.iter().any(|l| l == label)
}
pub fn count(&self) -> usize {
self.labels.len()
}
pub fn all(&self) -> &[String] {
&self.labels
}
}
#[allow(dead_code)]
pub struct ConfigNode {
key: String,
value: Option<String>,
children: Vec<ConfigNode>,
}
#[allow(dead_code)]
impl ConfigNode {
pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
Self {
key: key.into(),
value: Some(value.into()),
children: Vec::new(),
}
}
pub fn section(key: impl Into<String>) -> Self {
Self {
key: key.into(),
value: None,
children: Vec::new(),
}
}
pub fn add_child(&mut self, child: ConfigNode) {
self.children.push(child);
}
pub fn key(&self) -> &str {
&self.key
}
pub fn value(&self) -> Option<&str> {
self.value.as_deref()
}
pub fn num_children(&self) -> usize {
self.children.len()
}
pub fn lookup(&self, path: &str) -> Option<&str> {
let mut parts = path.splitn(2, '.');
let head = parts.next()?;
let tail = parts.next();
if head != self.key {
return None;
}
match tail {
None => self.value.as_deref(),
Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
}
}
fn lookup_relative(&self, path: &str) -> Option<&str> {
let mut parts = path.splitn(2, '.');
let head = parts.next()?;
let tail = parts.next();
if head != self.key {
return None;
}
match tail {
None => self.value.as_deref(),
Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
}
}
}
#[derive(Debug, Default)]
pub struct ModuleDependencyGraph {
edges: HashMap<String, Vec<String>>,
}
impl ModuleDependencyGraph {
pub fn new() -> Self {
Self::default()
}
pub fn add_module(&mut self, name: String) {
self.edges.entry(name).or_default();
}
pub fn add_dep(&mut self, from: String, to: String) {
self.edges.entry(from).or_default().push(to);
}
pub fn from_cache(cache: &ModuleCache) -> Self {
let mut g = Self::new();
for name in cache.all_modules() {
g.add_module(name.to_string());
if let Some(module) = cache.get(name) {
for dep in &module.dependencies {
g.add_dep(name.to_string(), dep.clone());
}
}
}
g
}
pub fn topological_order(&self) -> Result<Vec<String>, String> {
use std::collections::VecDeque;
let mut in_degree: HashMap<String, usize> = HashMap::new();
for (node, deps) in &self.edges {
in_degree.entry(node.clone()).or_insert(0);
for dep in deps {
in_degree.entry(dep.clone()).or_insert(0);
}
}
for deps in self.edges.values() {
for dep in deps {
*in_degree.entry(dep.clone()).or_insert(0) += 0;
}
}
let mut in_degree: HashMap<String, usize> = HashMap::new();
for node in self.edges.keys() {
let deps = self.edges.get(node).map(|v| v.len()).unwrap_or(0);
in_degree.insert(node.clone(), deps);
}
let mut queue: VecDeque<String> = in_degree
.iter()
.filter(|(_, d)| **d == 0)
.map(|(k, _)| k.clone())
.collect();
let mut order = Vec::new();
while let Some(node) = queue.pop_front() {
order.push(node.clone());
for (other, deps) in &self.edges {
if deps.contains(&node) {
let deg = in_degree
.get_mut(other)
.expect("node must exist in in_degree map");
*deg = deg.saturating_sub(1);
if *deg == 0 {
queue.push_back(other.clone());
}
}
}
}
if order.len() != self.edges.len() {
Err("Cycle detected in module dependency graph".to_string())
} else {
Ok(order)
}
}
pub fn depends_on(&self, a: &str, b: &str) -> bool {
if let Some(deps) = self.edges.get(a) {
if deps.iter().any(|d| d == b) {
return true;
}
deps.iter().any(|d| self.depends_on(d, b))
} else {
false
}
}
pub fn num_modules(&self) -> usize {
self.edges.len()
}
}
#[allow(dead_code)]
pub struct VersionedRecord<T: Clone> {
history: Vec<T>,
}
#[allow(dead_code)]
impl<T: Clone> VersionedRecord<T> {
pub fn new(initial: T) -> Self {
Self {
history: vec![initial],
}
}
pub fn update(&mut self, val: T) {
self.history.push(val);
}
pub fn current(&self) -> &T {
self.history
.last()
.expect("VersionedRecord history is always non-empty after construction")
}
pub fn at_version(&self, n: usize) -> Option<&T> {
self.history.get(n)
}
pub fn version(&self) -> usize {
self.history.len() - 1
}
pub fn has_history(&self) -> bool {
self.history.len() > 1
}
}
#[allow(dead_code)]
pub struct NonEmptyVec<T> {
head: T,
tail: Vec<T>,
}
#[allow(dead_code)]
impl<T> NonEmptyVec<T> {
pub fn singleton(val: T) -> Self {
Self {
head: val,
tail: Vec::new(),
}
}
pub fn push(&mut self, val: T) {
self.tail.push(val);
}
pub fn first(&self) -> &T {
&self.head
}
pub fn last(&self) -> &T {
self.tail.last().unwrap_or(&self.head)
}
pub fn len(&self) -> usize {
1 + self.tail.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn to_vec(&self) -> Vec<&T> {
let mut v = vec![&self.head];
v.extend(self.tail.iter());
v
}
}
#[derive(Debug, Default)]
pub struct ModuleRegistry {
decl_to_module: HashMap<Name, String>,
module_to_decls: HashMap<String, Vec<Name>>,
}
impl ModuleRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, decl_name: Name, module_name: String) {
self.decl_to_module
.insert(decl_name.clone(), module_name.clone());
self.module_to_decls
.entry(module_name)
.or_default()
.push(decl_name);
}
pub fn register_module(&mut self, module: &ExportedModule) {
for name in module.declaration_names() {
self.register(name.clone(), module.name.clone());
}
}
pub fn module_for(&self, decl: &Name) -> Option<&str> {
self.decl_to_module.get(decl).map(|s| s.as_str())
}
pub fn decls_for_module(&self, module: &str) -> &[Name] {
self.module_to_decls
.get(module)
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn all_module_names(&self) -> Vec<&str> {
self.module_to_decls.keys().map(|s| s.as_str()).collect()
}
pub fn contains_decl(&self, decl: &Name) -> bool {
self.decl_to_module.contains_key(decl)
}
pub fn num_decls(&self) -> usize {
self.decl_to_module.len()
}
pub fn num_modules(&self) -> usize {
self.module_to_decls.len()
}
}
#[allow(dead_code)]
pub struct StatSummary {
count: u64,
sum: f64,
min: f64,
max: f64,
}
#[allow(dead_code)]
impl StatSummary {
pub fn new() -> Self {
Self {
count: 0,
sum: 0.0,
min: f64::INFINITY,
max: f64::NEG_INFINITY,
}
}
pub fn record(&mut self, val: f64) {
self.count += 1;
self.sum += val;
if val < self.min {
self.min = val;
}
if val > self.max {
self.max = val;
}
}
pub fn mean(&self) -> Option<f64> {
if self.count == 0 {
None
} else {
Some(self.sum / self.count as f64)
}
}
pub fn min(&self) -> Option<f64> {
if self.count == 0 {
None
} else {
Some(self.min)
}
}
pub fn max(&self) -> Option<f64> {
if self.count == 0 {
None
} else {
Some(self.max)
}
}
pub fn count(&self) -> u64 {
self.count
}
}
#[allow(dead_code)]
pub struct SlidingSum {
window: Vec<f64>,
capacity: usize,
pos: usize,
sum: f64,
count: usize,
}
#[allow(dead_code)]
impl SlidingSum {
pub fn new(capacity: usize) -> Self {
Self {
window: vec![0.0; capacity],
capacity,
pos: 0,
sum: 0.0,
count: 0,
}
}
pub fn push(&mut self, val: f64) {
let oldest = self.window[self.pos];
self.sum -= oldest;
self.sum += val;
self.window[self.pos] = val;
self.pos = (self.pos + 1) % self.capacity;
if self.count < self.capacity {
self.count += 1;
}
}
pub fn sum(&self) -> f64 {
self.sum
}
pub fn mean(&self) -> Option<f64> {
if self.count == 0 {
None
} else {
Some(self.sum / self.count as f64)
}
}
pub fn count(&self) -> usize {
self.count
}
}
#[allow(dead_code)]
pub struct WindowIterator<'a, T> {
pub(super) data: &'a [T],
pub(super) pos: usize,
pub(super) window: usize,
}
#[allow(dead_code)]
impl<'a, T> WindowIterator<'a, T> {
pub fn new(data: &'a [T], window: usize) -> Self {
Self {
data,
pos: 0,
window,
}
}
}
#[derive(Debug, Clone)]
pub struct ExportedModule {
pub name: String,
pub declarations: Vec<(Name, Declaration)>,
pub constants: Vec<(Name, ConstantInfo)>,
pub dependencies: Vec<String>,
pub version: String,
pub metadata: HashMap<String, String>,
}
impl ExportedModule {
pub fn new(name: String) -> Self {
Self {
name,
declarations: Vec::new(),
constants: Vec::new(),
dependencies: Vec::new(),
version: "0.1.1".to_string(),
metadata: HashMap::new(),
}
}
pub fn add_declaration(&mut self, name: Name, decl: Declaration) {
self.declarations.push((name, decl));
}
pub fn add_constant(&mut self, name: Name, ci: ConstantInfo) {
self.constants.push((name, ci));
}
pub fn add_dependency(&mut self, dep: String) {
if !self.dependencies.contains(&dep) {
self.dependencies.push(dep);
}
}
pub fn set_metadata(&mut self, key: String, value: String) {
self.metadata.insert(key, value);
}
pub fn declaration_names(&self) -> Vec<&Name> {
let mut names: Vec<&Name> = self.declarations.iter().map(|(name, _)| name).collect();
names.extend(self.constants.iter().map(|(name, _)| name));
names
}
pub fn num_entries(&self) -> usize {
self.declarations.len() + self.constants.len()
}
pub fn is_empty(&self) -> bool {
self.declarations.is_empty() && self.constants.is_empty()
}
}
#[allow(dead_code)]
pub struct PathBuf {
components: Vec<String>,
}
#[allow(dead_code)]
impl PathBuf {
pub fn new() -> Self {
Self {
components: Vec::new(),
}
}
pub fn push(&mut self, comp: impl Into<String>) {
self.components.push(comp.into());
}
pub fn pop(&mut self) {
self.components.pop();
}
pub fn as_str(&self) -> String {
self.components.join("/")
}
pub fn depth(&self) -> usize {
self.components.len()
}
pub fn clear(&mut self) {
self.components.clear();
}
}
#[allow(dead_code)]
pub struct StringPool {
free: Vec<String>,
}
#[allow(dead_code)]
impl StringPool {
pub fn new() -> Self {
Self { free: Vec::new() }
}
pub fn take(&mut self) -> String {
self.free.pop().unwrap_or_default()
}
pub fn give(&mut self, mut s: String) {
s.clear();
self.free.push(s);
}
pub fn free_count(&self) -> usize {
self.free.len()
}
}
#[allow(dead_code)]
pub struct SmallMap<K: Ord + Clone, V: Clone> {
entries: Vec<(K, V)>,
}
#[allow(dead_code)]
impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn insert(&mut self, key: K, val: V) {
match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
Ok(i) => self.entries[i].1 = val,
Err(i) => self.entries.insert(i, (key, val)),
}
}
pub fn get(&self, key: &K) -> Option<&V> {
self.entries
.binary_search_by_key(&key, |(k, _)| k)
.ok()
.map(|i| &self.entries[i].1)
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn keys(&self) -> Vec<&K> {
self.entries.iter().map(|(k, _)| k).collect()
}
pub fn values(&self) -> Vec<&V> {
self.entries.iter().map(|(_, v)| v).collect()
}
}
#[allow(dead_code)]
pub struct TransitiveClosure {
adj: Vec<Vec<usize>>,
n: usize,
}
#[allow(dead_code)]
impl TransitiveClosure {
pub fn new(n: usize) -> Self {
Self {
adj: vec![Vec::new(); n],
n,
}
}
pub fn add_edge(&mut self, from: usize, to: usize) {
if from < self.n {
self.adj[from].push(to);
}
}
pub fn reachable_from(&self, start: usize) -> Vec<usize> {
let mut visited = vec![false; self.n];
let mut queue = std::collections::VecDeque::new();
queue.push_back(start);
while let Some(node) = queue.pop_front() {
if node >= self.n || visited[node] {
continue;
}
visited[node] = true;
for &next in &self.adj[node] {
queue.push_back(next);
}
}
(0..self.n).filter(|&i| visited[i]).collect()
}
pub fn can_reach(&self, from: usize, to: usize) -> bool {
self.reachable_from(from).contains(&to)
}
}
#[derive(Debug, Clone, Default)]
pub struct ModuleDiff {
pub added: Vec<Name>,
pub removed: Vec<Name>,
pub changed: Vec<Name>,
}
impl ModuleDiff {
pub fn new() -> Self {
Self::default()
}
pub fn is_empty(&self) -> bool {
self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty()
}
pub fn total_changes(&self) -> usize {
self.added.len() + self.removed.len() + self.changed.len()
}
}
#[allow(dead_code)]
pub struct RewriteRuleSet {
rules: Vec<RewriteRule>,
}
#[allow(dead_code)]
impl RewriteRuleSet {
pub fn new() -> Self {
Self { rules: Vec::new() }
}
pub fn add(&mut self, rule: RewriteRule) {
self.rules.push(rule);
}
pub fn len(&self) -> usize {
self.rules.len()
}
pub fn is_empty(&self) -> bool {
self.rules.is_empty()
}
pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
self.rules.iter().filter(|r| r.conditional).collect()
}
pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
self.rules.iter().filter(|r| !r.conditional).collect()
}
pub fn get(&self, name: &str) -> Option<&RewriteRule> {
self.rules.iter().find(|r| r.name == name)
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ModuleVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
impl ModuleVersion {
pub fn new(major: u32, minor: u32, patch: u32) -> Self {
Self {
major,
minor,
patch,
}
}
pub fn parse(s: &str) -> Option<Self> {
let parts: Vec<&str> = s.split('.').collect();
if parts.len() != 3 {
return None;
}
let major = parts[0].parse().ok()?;
let minor = parts[1].parse().ok()?;
let patch = parts[2].parse().ok()?;
Some(Self {
major,
minor,
patch,
})
}
pub fn is_compatible_with(&self, other: &Self) -> bool {
self.major == other.major && *self >= *other
}
}
#[allow(dead_code)]
pub struct TokenBucket {
capacity: u64,
tokens: u64,
refill_per_ms: u64,
last_refill: std::time::Instant,
}
#[allow(dead_code)]
impl TokenBucket {
pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
Self {
capacity,
tokens: capacity,
refill_per_ms,
last_refill: std::time::Instant::now(),
}
}
pub fn try_consume(&mut self, n: u64) -> bool {
self.refill();
if self.tokens >= n {
self.tokens -= n;
true
} else {
false
}
}
fn refill(&mut self) {
let now = std::time::Instant::now();
let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
if elapsed_ms > 0 {
let new_tokens = elapsed_ms * self.refill_per_ms;
self.tokens = (self.tokens + new_tokens).min(self.capacity);
self.last_refill = now;
}
}
pub fn available(&self) -> u64 {
self.tokens
}
pub fn capacity(&self) -> u64 {
self.capacity
}
}
#[allow(dead_code)]
pub struct RawFnPtr {
ptr: usize,
arity: usize,
name: String,
}
#[allow(dead_code)]
impl RawFnPtr {
pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
Self {
ptr,
arity,
name: name.into(),
}
}
pub fn arity(&self) -> usize {
self.arity
}
pub fn name(&self) -> &str {
&self.name
}
pub fn raw(&self) -> usize {
self.ptr
}
}
#[derive(Clone, Debug, Default)]
pub struct ModuleInfo {
pub version: Option<ModuleVersion>,
pub author: Option<String>,
pub license: Option<String>,
pub description: Option<String>,
}
impl ModuleInfo {
pub fn new() -> Self {
Self::default()
}
pub fn with_version(mut self, v: ModuleVersion) -> Self {
self.version = Some(v);
self
}
pub fn with_author(mut self, a: impl Into<String>) -> Self {
self.author = Some(a.into());
self
}
pub fn with_license(mut self, l: impl Into<String>) -> Self {
self.license = Some(l.into());
self
}
pub fn with_description(mut self, d: impl Into<String>) -> Self {
self.description = Some(d.into());
self
}
}
pub struct ModuleCache {
modules: HashMap<String, ExportedModule>,
import_order: Vec<String>,
}
impl ModuleCache {
pub fn new() -> Self {
Self {
modules: HashMap::new(),
import_order: Vec::new(),
}
}
pub fn add(&mut self, module: ExportedModule) {
let name = module.name.clone();
self.modules.insert(name.clone(), module);
if !self.import_order.contains(&name) {
self.import_order.push(name);
}
}
pub fn get(&self, name: &str) -> Option<&ExportedModule> {
self.modules.get(name)
}
pub fn contains(&self, name: &str) -> bool {
self.modules.contains_key(name)
}
pub fn all_modules(&self) -> Vec<&str> {
self.import_order.iter().map(|s| s.as_str()).collect()
}
pub fn num_modules(&self) -> usize {
self.modules.len()
}
pub fn import_all(&self, env: &mut Environment) -> Result<(), String> {
for name in &self.import_order {
if let Some(module) = self.modules.get(name) {
import_module(env, module)?;
}
}
Ok(())
}
pub fn import_with_deps(&self, env: &mut Environment, name: &str) -> Result<(), String> {
let module = self
.modules
.get(name)
.ok_or_else(|| format!("Module '{}' not found in cache", name))?;
for dep in &module.dependencies {
if self.contains(dep) {
self.import_with_deps(env, dep)?;
}
}
import_module(env, module)
}
pub fn remove(&mut self, name: &str) -> Option<ExportedModule> {
self.import_order.retain(|n| n != name);
self.modules.remove(name)
}
pub fn clear(&mut self) {
self.modules.clear();
self.import_order.clear();
}
}
#[allow(dead_code)]
pub struct SimpleDag {
edges: Vec<Vec<usize>>,
}
#[allow(dead_code)]
impl SimpleDag {
pub fn new(n: usize) -> Self {
Self {
edges: vec![Vec::new(); n],
}
}
pub fn add_edge(&mut self, from: usize, to: usize) {
if from < self.edges.len() {
self.edges[from].push(to);
}
}
pub fn successors(&self, node: usize) -> &[usize] {
self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
}
pub fn can_reach(&self, from: usize, to: usize) -> bool {
let mut visited = vec![false; self.edges.len()];
self.dfs(from, to, &mut visited)
}
fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
if cur == target {
return true;
}
if cur >= visited.len() || visited[cur] {
return false;
}
visited[cur] = true;
for &next in self.successors(cur) {
if self.dfs(next, target, visited) {
return true;
}
}
false
}
pub fn topological_sort(&self) -> Option<Vec<usize>> {
let n = self.edges.len();
let mut in_degree = vec![0usize; n];
for succs in &self.edges {
for &s in succs {
if s < n {
in_degree[s] += 1;
}
}
}
let mut queue: std::collections::VecDeque<usize> =
(0..n).filter(|&i| in_degree[i] == 0).collect();
let mut order = Vec::new();
while let Some(node) = queue.pop_front() {
order.push(node);
for &s in self.successors(node) {
if s < n {
in_degree[s] -= 1;
if in_degree[s] == 0 {
queue.push_back(s);
}
}
}
}
if order.len() == n {
Some(order)
} else {
None
}
}
pub fn num_nodes(&self) -> usize {
self.edges.len()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct RewriteRule {
pub name: String,
pub lhs: String,
pub rhs: String,
pub conditional: bool,
}
#[allow(dead_code)]
impl RewriteRule {
pub fn unconditional(
name: impl Into<String>,
lhs: impl Into<String>,
rhs: impl Into<String>,
) -> Self {
Self {
name: name.into(),
lhs: lhs.into(),
rhs: rhs.into(),
conditional: false,
}
}
pub fn conditional(
name: impl Into<String>,
lhs: impl Into<String>,
rhs: impl Into<String>,
) -> Self {
Self {
name: name.into(),
lhs: lhs.into(),
rhs: rhs.into(),
conditional: true,
}
}
pub fn display(&self) -> String {
format!("{}: {} → {}", self.name, self.lhs, self.rhs)
}
}
#[allow(dead_code)]
pub struct FocusStack<T> {
items: Vec<T>,
}
#[allow(dead_code)]
impl<T> FocusStack<T> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn focus(&mut self, item: T) {
self.items.push(item);
}
pub fn blur(&mut self) -> Option<T> {
self.items.pop()
}
pub fn current(&self) -> Option<&T> {
self.items.last()
}
pub fn depth(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}