rink_core/loader/
registry.rs1use std::collections::{BTreeMap, BTreeSet};
2
3use crate::{
4 ast::{DatePattern, Expr},
5 runtime::Substance,
6 types::{BaseUnit, Dimensionality, Number, Numeric},
7};
8
9#[derive(Default, Debug)]
10pub struct Registry {
11 pub base_units: BTreeSet<BaseUnit>,
13 pub base_unit_long_names: BTreeMap<String, String>,
15 pub units: BTreeMap<String, Number>,
17 pub quantities: BTreeMap<Dimensionality, String>,
19 pub decomposition_units: BTreeMap<Dimensionality, String>,
22 pub prefixes: Vec<(String, Numeric)>,
24 pub definitions: BTreeMap<String, Expr>,
26 pub docs: BTreeMap<String, String>,
28 pub categories: BTreeMap<String, String>,
30 pub category_names: BTreeMap<String, String>,
32 pub datepatterns: Vec<Vec<DatePattern>>,
34 pub substances: BTreeMap<String, Substance>,
36 pub substance_symbols: BTreeMap<String, String>,
39}
40
41impl Registry {
42 fn lookup_exact(&self, name: &str) -> Option<Number> {
43 if let Some(k) = self.base_units.get(name) {
44 return Some(Number::one_unit(k.to_owned()));
45 }
46 if let Some(v) = self.units.get(name).cloned() {
47 return Some(v);
48 }
49 None
50 }
51
52 fn lookup_with_prefix(&self, name: &str) -> Option<Number> {
53 if let Some(v) = self.lookup_exact(name) {
54 return Some(v);
55 }
56 for &(ref pre, ref value) in &self.prefixes {
57 if name.starts_with(pre) {
58 if let Some(v) = self.lookup_exact(&name[pre.len()..]) {
59 return Some((&v * &Number::new(value.clone())).unwrap());
60 }
61 }
62 }
63 None
64 }
65
66 pub(crate) fn lookup(&self, name: &str) -> Option<Number> {
67 let res = self.lookup_with_prefix(name);
68 if res.is_some() {
69 return res;
70 }
71
72 if let Some(name) = name.strip_suffix('s') {
76 self.lookup_with_prefix(name)
77 } else {
78 None
79 }
80 }
81
82 fn canonicalize_exact(&self, name: &str) -> Option<String> {
83 if let Some(v) = self.base_unit_long_names.get(name) {
84 return Some(v.clone());
85 }
86 if let Some(base_unit) = self.base_units.get(name) {
87 return Some(base_unit.to_string());
88 }
89 if let Some(expr) = self.definitions.get(name) {
90 if let Expr::Unit { ref name } = *expr {
91 if let Some(canonicalized) = self.canonicalize(&*name) {
92 return Some(canonicalized);
93 } else {
94 return Some(name.clone());
95 }
96 } else {
97 return Some(name.to_owned());
99 }
100 }
101 None
102 }
103
104 fn canonicalize_with_prefix(&self, name: &str) -> Option<String> {
105 if let Some(v) = self.canonicalize_exact(name) {
106 return Some(v);
107 }
108 for &(ref prefix, ref value) in &self.prefixes {
109 if let Some(name) = name.strip_prefix(prefix) {
110 if let Some(canonicalized) = self.canonicalize_exact(name) {
111 let mut prefix = prefix;
112 for &(ref other, ref otherval) in &self.prefixes {
113 if other.len() > prefix.len() && value == otherval {
114 prefix = other;
115 }
116 }
117 return Some(format!("{}{}", prefix, canonicalized));
118 }
119 }
120 }
121 None
122 }
123
124 pub fn canonicalize(&self, name: &str) -> Option<String> {
132 let res = self.canonicalize_with_prefix(name);
133 if res.is_some() {
134 return res;
135 }
136
137 if let Some(name) = name.strip_suffix('s') {
138 self.canonicalize_with_prefix(name)
139 } else {
140 None
141 }
142 }
143}