1use std::collections::{HashMap, HashSet};
2use std::hash::{BuildHasherDefault, Hasher};
3
4#[derive(Default, Clone, Copy)]
18pub struct FastHasher {
19 hash: u64,
20}
21
22const SEED: u64 = 0xf135_7aea_2e62_a9c5;
23
24impl FastHasher {
25 #[inline]
26 fn add(&mut self, word: u64) {
27 self.hash = self.hash.wrapping_add(word).wrapping_mul(SEED);
28 }
29}
30
31impl Hasher for FastHasher {
32 #[inline]
33 fn write(&mut self, bytes: &[u8]) {
34 let mut chunks = bytes.chunks_exact(8);
35 for c in &mut chunks {
36 self.add(u64::from_le_bytes(c.try_into().expect("chunk of 8")));
37 }
38 let rest = chunks.remainder();
39 if !rest.is_empty() {
40 let mut buf = [0u8; 8];
41 buf[..rest.len()].copy_from_slice(rest);
42 self.add(u64::from_le_bytes(buf));
43 }
44 }
45 #[inline]
46 fn write_u8(&mut self, i: u8) {
47 self.add(i as u64);
48 }
49 #[inline]
50 fn write_u32(&mut self, i: u32) {
51 self.add(i as u64);
52 }
53 #[inline]
54 fn write_u64(&mut self, i: u64) {
55 self.add(i);
56 }
57 #[inline]
58 fn write_usize(&mut self, i: usize) {
59 self.add(i as u64);
60 }
61 #[inline]
62 fn finish(&self) -> u64 {
63 self.hash.rotate_left(26)
64 }
65}
66
67pub type FastBuildHasher = BuildHasherDefault<FastHasher>;
68pub type FastMap<K, V> = HashMap<K, V, FastBuildHasher>;
69pub type FastSet<T> = HashSet<T, FastBuildHasher>;
70pub type FieldMap = FastMap<&'static str, FieldValue>;
74
75pub fn intern(key: &str) -> &'static str {
80 use std::cell::RefCell;
81 use std::sync::{Mutex, OnceLock};
82 thread_local! {
83 static LOCAL: RefCell<FastSet<&'static str>> = RefCell::new(FastSet::default());
84 }
85 static GLOBAL: OnceLock<Mutex<FastSet<&'static str>>> = OnceLock::new();
86 if let Some(k) = LOCAL.with(|l| l.borrow().get(key).copied()) {
87 return k;
88 }
89 let k = {
90 let mut global = GLOBAL.get_or_init(Default::default).lock().unwrap();
91 match global.get(key) {
92 Some(k) => *k,
93 None => {
94 let k: &'static str = Box::leak(key.to_owned().into_boxed_str());
95 global.insert(k);
96 k
97 }
98 }
99 };
100 LOCAL.with(|l| l.borrow_mut().insert(k));
101 k
102}
103
104#[derive(Debug, Clone)]
105pub enum FieldValue {
106 Text(String),
107 TextList(Vec<String>),
110 Resource(String),
111 ResourceList(Vec<String>),
112}
113
114#[derive(Debug, Clone)]
124pub struct Element {
125 class: &'static ClassDef,
126 mrid: String,
127 fields: FieldMap,
128 duplicate_fields: FastSet<&'static str>,
131 langs: Option<Box<Langs>>,
135 also: Option<Box<Types>>,
141}
142
143type Langs = Vec<(&'static str, Box<str>)>;
145
146type Types = Vec<&'static ClassDef>;
148
149impl Element {
150 pub fn new(class: &'static ClassDef, mrid: String) -> Self {
151 Self { class, mrid, fields: FieldMap::default(), duplicate_fields: FastSet::default(), langs: None, also: None }
152 }
153
154 pub fn with_fields(class: &'static ClassDef, mrid: String, fields: FieldMap) -> Self {
155 Self { class, mrid, fields, duplicate_fields: FastSet::default(), langs: None, also: None }
156 }
157
158 pub fn class(&self) -> &'static ClassDef {
159 self.class
160 }
161
162 pub fn types(&self) -> impl Iterator<Item = &'static ClassDef> + '_ {
165 std::iter::once(self.class).chain(self.also.iter().flat_map(|v| v.iter().copied()))
166 }
167
168 pub(crate) fn add_type(&mut self, other: &'static ClassDef, reg: &TypeRegistry) -> bool {
173 if self.types().any(|c| c.qualified == other.qualified) {
174 return false;
175 }
176 let promote = reg.chain(other).iter().any(|c| c.qualified == self.class.qualified);
177 let kept = if promote { std::mem::replace(&mut self.class, other) } else { other };
178 self.also.get_or_insert_with(Default::default).push(kept);
179 promote
180 }
181
182 pub fn mrid(&self) -> &str {
183 &self.mrid
184 }
185
186 pub fn type_name(&self) -> &'static str {
189 self.class.qualified
190 }
191
192 pub fn local_name(&self) -> &'static str {
194 self.class.local
195 }
196
197 pub fn type_ns(&self) -> &'static str {
199 self.class.ns
200 }
201
202 pub fn fields(&self) -> &FieldMap {
203 &self.fields
204 }
205
206 pub fn duplicate_fields(&self) -> &FastSet<&'static str> {
207 &self.duplicate_fields
208 }
209
210 pub fn langs(&self, key: &str) -> impl Iterator<Item = &str> {
214 self.langs.iter().flat_map(|l| l.iter()).filter(move |(k, _)| *k == key).map(|(_, l)| &**l)
215 }
216
217 pub fn add_lang(&mut self, key: &'static str, lang: &str) {
219 self.langs.get_or_insert_with(Default::default).push((key, lang.into()));
220 }
221
222 pub fn get(&self, attr: &str) -> Option<&FieldValue> {
223 self.fields.get(attr)
224 }
225
226 pub fn get_str(&self, attr: &str) -> Option<&str> {
227 match self.fields.get(attr) {
228 Some(FieldValue::Text(s)) => Some(s.as_str()),
229 Some(FieldValue::TextList(v)) => v.first().map(String::as_str),
230 _ => None,
231 }
232 }
233
234 pub fn get_f64(&self, attr: &str) -> Option<f64> {
235 self.get_str(attr)?.parse().ok()
236 }
237
238 pub fn get_bool(&self, attr: &str) -> Option<bool> {
239 match self.get_str(attr)? {
240 "true" | "1" => Some(true),
241 "false" | "0" => Some(false),
242 _ => None,
243 }
244 }
245
246 pub fn get_refs(&self, attr: &str) -> &[String] {
252 match self.fields.get(attr) {
253 Some(FieldValue::Resource(s)) => std::slice::from_ref(s),
254 Some(FieldValue::ResourceList(v)) => v.as_slice(),
255 _ => &[],
256 }
257 }
258
259 pub fn get_ref(&self, attr: &str) -> Option<&str> {
261 self.get_refs(attr).first().map(String::as_str)
262 }
263
264 pub fn add_field(&mut self, key: &'static str, val: FieldValue) {
267 match &val {
268 FieldValue::Resource(new_ref) => match self.fields.get_mut(key) {
269 Some(FieldValue::ResourceList(list)) => {
270 list.push(new_ref.clone());
271 self.duplicate_fields.insert(key);
272 return;
273 }
274 Some(existing @ FieldValue::Resource(_)) => {
275 let FieldValue::Resource(old) = std::mem::replace(existing, FieldValue::ResourceList(Vec::new())) else {
276 unreachable!()
277 };
278 *existing = FieldValue::ResourceList(vec![old, new_ref.clone()]);
279 self.duplicate_fields.insert(key);
280 return;
281 }
282 _ => {}
283 },
284 FieldValue::Text(new_text) => match self.fields.get_mut(key) {
285 Some(FieldValue::TextList(list)) => {
286 list.push(new_text.clone());
287 self.duplicate_fields.insert(key);
288 return;
289 }
290 Some(existing @ FieldValue::Text(_)) => {
291 let FieldValue::Text(old) = std::mem::replace(existing, FieldValue::TextList(Vec::new())) else {
292 unreachable!()
293 };
294 *existing = FieldValue::TextList(vec![old, new_text.clone()]);
295 self.duplicate_fields.insert(key);
296 return;
297 }
298 _ => {}
299 },
300 _ => {
301 if self.fields.contains_key(key) {
302 self.duplicate_fields.insert(key);
303 }
304 }
305 }
306 self.fields.insert(key, val);
307 }
308
309 pub fn merge_from(&mut self, other: &Element) {
312 for (k, v) in &other.fields {
313 match v {
314 FieldValue::ResourceList(new_list) => match self.fields.get_mut(k) {
315 Some(FieldValue::ResourceList(existing)) => existing.extend(new_list.iter().cloned()),
316 _ => {
317 self.fields.insert(*k, v.clone());
318 }
319 },
320 _ => {
321 self.fields.insert(*k, v.clone());
322 if let Some(l) = self.langs.as_mut() {
324 l.retain(|(key, _)| key != k);
325 }
326 for lang in other.langs(k) {
327 self.add_lang(k, lang);
328 }
329 }
330 }
331 }
332 }
333
334 pub fn to_json_value(&self) -> serde_json::Value {
337 let mut map = serde_json::Map::with_capacity(self.fields.len() + 1);
338 map.insert("id".to_string(), serde_json::Value::String(self.mrid.clone()));
339 for (k, v) in &self.fields {
340 map.insert(k.to_string(), field_to_json(v));
341 }
342 serde_json::Value::Object(map)
343 }
344
345 pub fn from_json(
349 class: &'static ClassDef,
350 reg: &TypeRegistry,
351 value: &serde_json::Value,
352 ) -> Result<Self, String> {
353 let obj = value.as_object().ok_or("element is not a JSON object")?;
354 let mrid = obj.get("id").and_then(|v| v.as_str()).ok_or("element has no \"id\"")?.to_string();
355 let mut fields = FieldMap::default();
356 for (k, v) in obj {
357 if k == "id" || k == "_type" {
358 continue;
359 }
360 let is_ref = reg.attr(class, k).is_some_and(|a| a.kind != AttrKind::Literal);
361 let value = match v {
362 serde_json::Value::String(s) if is_ref => FieldValue::Resource(s.clone()),
363 serde_json::Value::String(s) => FieldValue::Text(s.clone()),
364 serde_json::Value::Array(items) => {
365 let items: Vec<String> = items
366 .iter()
367 .map(|i| i.as_str().map(str::to_string).ok_or(format!("{k}: list item is not a string")))
368 .collect::<Result<_, _>>()?;
369 if is_ref { FieldValue::ResourceList(items) } else { FieldValue::TextList(items) }
370 }
371 other => return Err(format!("{k}: expected a string or an array, got {other}")),
372 };
373 fields.insert(reg.field_key(class, k), value);
374 }
375 Ok(Self::with_fields(class, mrid, fields))
376 }
377}
378
379fn field_to_json(v: &FieldValue) -> serde_json::Value {
380 match v {
381 FieldValue::Text(s) | FieldValue::Resource(s) => serde_json::Value::String(s.clone()),
382 FieldValue::TextList(v) | FieldValue::ResourceList(v) => {
383 serde_json::Value::Array(v.iter().cloned().map(serde_json::Value::String).collect())
384 }
385 }
386}
387
388#[derive(Debug, Clone, Copy, PartialEq, Eq)]
392pub enum AttrKind {
393 Literal,
395 Association,
397 Enum,
399}
400
401#[derive(Debug)]
403pub struct AttrDef {
404 pub id: &'static str,
406 pub ns: &'static str,
408 pub kind: AttrKind,
409 pub range: &'static str,
412 pub is_list: bool,
413 pub used: bool,
417 pub xsd: &'static str,
420 pub value_ns: &'static str,
423 pub origins: &'static [&'static str],
425}
426
427#[derive(Debug)]
431pub struct Schema {
432 pub classes: &'static [ClassDef],
433 pub profiles: &'static [(&'static str, &'static str)],
436 pub namespaces: &'static [(&'static str, &'static str)],
438}
439
440#[derive(Debug)]
442pub struct ClassDef {
443 pub ns: &'static str,
444 pub local: &'static str,
445 pub qualified: &'static str,
447 pub super_class: Option<usize>,
449 pub concrete: bool,
450 pub attrs: &'static [AttrDef],
454 pub origins: &'static [&'static str],
455}
456
457impl ClassDef {
458 pub fn attr(&self, id: &str) -> Option<&'static AttrDef> {
460 self.attrs.iter().find(|a| a.id == id)
461 }
462}
463
464#[derive(Default)]
472pub struct TypeRegistry {
473 by_ns: FastMap<&'static str, FastMap<&'static str, &'static ClassDef>>,
474 bare: FastMap<&'static str, &'static ClassDef>,
475 by_type_name: FastMap<&'static str, &'static ClassDef>,
476 declared: FastMap<&'static str, FastMap<&'static str, &'static AttrDef>>,
479 chain: FastMap<&'static str, Vec<&'static ClassDef>>,
481 families: Vec<FamilyTable>,
483}
484
485struct FamilyTable {
488 id: &'static str,
489 prefix: &'static str,
490 schema: &'static Schema,
491 attrs: FastMap<&'static str, &'static AttrDef>,
494}
495
496impl TypeRegistry {
497 pub fn new() -> Self {
498 Self::default()
499 }
500
501 pub fn add_family(&mut self, id: &'static str, schema: &'static Schema, bare_fallback: bool) {
505 let classes = schema.classes;
506 let prefix = classes
507 .first()
508 .and_then(|c| c.qualified.strip_suffix(c.local))
509 .unwrap_or("");
510 let mut by_id = FastMap::default();
511 for class in classes {
512 for a in class.attrs {
513 by_id.entry(a.id).or_insert(a);
514 }
515 }
516 self.families.push(FamilyTable { id, prefix, schema, attrs: by_id });
517 for class in classes {
518 self.by_ns.entry(class.ns).or_default().insert(class.local, class);
519 self.by_type_name.insert(class.qualified, class);
520 if bare_fallback {
521 self.bare.insert(class.local, class);
522 }
523 let mut attrs = FastMap::default();
524 let mut chain = Vec::new();
525 let mut next = Some(class);
526 while let Some(c) = next {
527 for a in c.attrs {
528 attrs.entry(a.id).or_insert(a);
529 }
530 chain.push(c);
531 next = c.super_class.map(|i| &classes[i]);
532 }
533 chain.reverse();
534 self.declared.insert(class.qualified, attrs);
535 self.chain.insert(class.qualified, chain);
536 }
537 }
538
539 pub fn ns_table(&self, ns: &str) -> Option<&FastMap<&'static str, &'static ClassDef>> {
541 self.by_ns.get(ns)
542 }
543
544 pub fn bare(&self) -> &FastMap<&'static str, &'static ClassDef> {
545 &self.bare
546 }
547
548 pub fn by_type_name(&self, name: &str) -> Option<&'static ClassDef> {
549 self.by_type_name.get(name).copied()
550 }
551
552 pub fn attr(&self, class: &ClassDef, id: &str) -> Option<&'static AttrDef> {
554 self.declared.get(class.qualified)?.get(id).copied()
555 }
556
557 pub fn declared(&self, class: &ClassDef) -> Option<&FastMap<&'static str, &'static AttrDef>> {
560 self.declared.get(class.qualified)
561 }
562
563 pub fn field_key(&self, class: &ClassDef, id: &str) -> &'static str {
565 self.attr(class, id).map_or_else(|| intern(id), |a| a.id)
566 }
567
568 pub fn chain(&self, class: &ClassDef) -> &[&'static ClassDef] {
570 self.chain.get(class.qualified).map_or(&[], Vec::as_slice)
571 }
572
573 pub fn concrete_descendants(&self, qualified: &str) -> Vec<&'static str> {
576 let mut out: Vec<&'static str> = self
577 .chain
578 .iter()
579 .filter(|(_, chain)| chain.iter().any(|c| c.qualified == qualified))
580 .filter_map(|(q, _)| self.by_type_name.get(q).filter(|c| c.concrete).map(|c| c.qualified))
581 .collect();
582 out.sort_unstable();
583 out
584 }
585
586 pub fn attrs(&self, class: &ClassDef) -> impl Iterator<Item = &'static AttrDef> + '_ {
588 self.declared.get(class.qualified).into_iter().flat_map(|m| m.values().copied())
589 }
590
591 pub fn schema(&self, family: &str) -> Option<&'static Schema> {
593 self.family(family).map(|f| f.schema)
594 }
595
596 fn family(&self, id: &str) -> Option<&FamilyTable> {
597 self.families.iter().find(|f| f.id == id)
598 }
599
600 pub fn family_of(&self, type_name: &str) -> Option<&'static str> {
602 self.families
604 .iter()
605 .filter(|f| type_name.starts_with(f.prefix))
606 .max_by_key(|f| f.prefix.len())
607 .map(|f| f.id)
608 }
609
610 pub fn family_attr(&self, family: &str, id: &str) -> Option<&'static AttrDef> {
613 self.family(family)?.attrs.get(id).copied()
614 }
615
616 pub fn attr_of(&self, class: &ClassDef, key: &str) -> Option<&'static AttrDef> {
619 self.attr(class, key)
620 .or_else(|| self.family_attr(self.family_of(class.qualified)?, key))
621 }
622}