ecore_rs/
repr.rs

1prelude! {}
2
3pub mod bounds;
4pub mod builtin;
5pub mod idx;
6pub mod structural;
7
8pub use bounds::Bounds;
9pub use structural::Structural;
10
11pub mod annot {
12    pub type Source = String;
13    pub type Key = String;
14    pub type Val = String;
15}
16
17/// A package/class annotation.
18///
19/// Unlike packages/classes, annotations are not stored by the factory/context. They just appear
20/// as-is in the package/class they annotate. Maybe that's not a good idea though.
21#[derive(Debug, Clone)]
22pub struct Annot {
23    source: annot::Source,
24    details: HashMap<annot::Key, annot::Val>,
25}
26
27pub type Annots = Vec<Annot>;
28
29impl std::ops::Deref for Annot {
30    type Target = HashMap<annot::Key, annot::Val>;
31    fn deref(&self) -> &Self::Target {
32        &self.details
33    }
34}
35
36impl Annot {
37    pub fn with_capacity(source: impl Into<annot::Source>, details_capa: usize) -> Self {
38        Self {
39            source: source.into(),
40            details: HashMap::with_capacity(details_capa),
41        }
42    }
43
44    pub fn shrink_to_fit(&mut self) {
45        self.details.shrink_to_fit()
46    }
47
48    pub fn source(&self) -> &str {
49        &self.source
50    }
51    pub fn details(&self) -> &HashMap<annot::Key, annot::Val> {
52        &self.details
53    }
54
55    /// Same as [`HashMap`]'s `insert` function, but fails with context on overwrite.
56    pub fn insert(&mut self, key: impl Into<annot::Key>, val: impl Into<annot::Val>) -> Res<()> {
57        let entry = self.details.entry(key.into());
58        use std::collections::hash_map::Entry::*;
59        match entry {
60            Vacant(entry) => {
61                entry.insert(val.into());
62            }
63            Occupied(entry) => {
64                let val = val.into();
65                let err = error!(@redef("annotation details key/value binding") entry.key())
66                    .with_context(format!(
67                        "trying to replace value `{}` with `{}`",
68                        entry.get(),
69                        val
70                    ));
71                return Err(err);
72            }
73        }
74        Ok(())
75    }
76}
77
78/// A sequence of package indices, understood as an **absolute** path.
79#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub struct Path {
81    last: idx::Pack,
82    path: SmallVec<[idx::Pack; 8]>,
83}
84
85impl Path {
86    pub fn new(idx: idx::Pack) -> Self {
87        Self {
88            last: idx,
89            path: smallvec![],
90        }
91    }
92
93    /// Constructs the path corresponding to a package in the context.
94    pub fn of_idx(ctx: &Ctx, idx: idx::Pack) -> Self {
95        let last = idx;
96        let mut rev_path = smallvec!();
97
98        let mut current = &ctx[idx];
99
100        while let Some(parent) = current.sup() {
101            rev_path.push(parent);
102            current = &ctx[parent];
103        }
104        rev_path.reverse();
105        let path = rev_path;
106        Self { last, path }
107    }
108
109    pub fn iter<'me>(&'me self) -> impl Iterator<Item = idx::Pack> + 'me {
110        self.path.iter().cloned().chain(Some(self.last).into_iter())
111    }
112    pub fn iter_pref<'me>(&'me self) -> impl Iterator<Item = idx::Pack> + 'me {
113        self.path.iter().cloned()
114    }
115
116    pub fn len(&self) -> usize {
117        self.pref_len() + 1
118    }
119    pub fn pref_len(&self) -> usize {
120        self.path.len()
121    }
122
123    pub fn push(&mut self, idx: idx::Pack) {
124        let to_push = mem::replace(&mut self.last, idx);
125        self.path.push(to_push)
126    }
127    pub fn pop(&mut self) -> Option<idx::Pack> {
128        self.path
129            .pop()
130            .map(|new_last| mem::replace(&mut self.last, new_last))
131    }
132    pub fn last(&self) -> idx::Pack {
133        self.last
134    }
135    pub fn first(&self) -> idx::Pack {
136        self.path.get(0).cloned().unwrap_or(self.last)
137    }
138
139    /// Suports forward-referencing.
140    fn resolve_relative_etype(
141        mut path: Path,
142        ctx: &mut Ctx,
143        s: impl AsRef<str>,
144    ) -> Res<idx::Class> {
145        let s = s.as_ref();
146        let mut bits = s.split("/").into_iter();
147        let mut next = bits.next();
148        let mut last = None;
149
150        while let Some(ident) = next {
151            next = bits.next();
152
153            if next.is_some() {
154                let p_idx = ctx.pack_idx_or_forward_ref(&path, ident)?;
155                path.push(p_idx);
156            } else {
157                last = Some(ident);
158                break;
159            }
160        }
161
162        if let Some(ident) = last {
163            ctx.get_class_idx_or_forward_ref_in(&path, ident)
164        } else {
165            bail!("illegal empty absolute `eType`: `{}`", s);
166        }
167    }
168
169    /// Resolves the value of an `eType` XML attribute.
170    ///
171    /// This function handles forward referencing, hence the mutable context.
172    pub fn resolve_etype(ctx: &mut ctx::PathCtx, s: impl AsRef<str>) -> Res<idx::Class> {
173        let s = s.as_ref();
174        if let Some(idx) = ctx.ctx().try_parse_builtin_etype(s)? {
175            return Ok(idx);
176        }
177
178        let rel_pref = "#//";
179        if s.starts_with(rel_pref) {
180            let s = &s[rel_pref.len()..];
181            Self::resolve_relative_etype(ctx.path().clone(), ctx.ctx_mut(), s)
182        } else {
183            bail!("unsupported `eType` path `{}`", s);
184        }
185    }
186
187    pub fn display(&self, ctx: &idx::PackMap<Pack>) -> String {
188        let mut res = self.path.iter().fold(String::new(), |mut s, p_idx| {
189            s.push_str(ctx[*p_idx].name());
190            s.push_str("::");
191            s
192        });
193        res.push_str(ctx[self.last].name());
194        res
195    }
196    pub fn display_sep(&self, ctx: &idx::PackMap<Pack>) -> String {
197        let mut res = self.display(ctx);
198        res.push_str("::");
199        res
200    }
201}
202
203/// A literal, which are used to specify enum variants.
204#[derive(Debug, Clone)]
205pub struct ELit {
206    name: String,
207    value: Option<String>,
208}
209
210pub type ELits = Vec<ELit>;
211
212impl ELit {
213    pub fn new(name: impl Into<String>, value: Option<impl Into<String>>) -> Self {
214        Self {
215            name: name.into(),
216            value: value.map(|s| s.into()),
217        }
218    }
219    pub fn new_name(name: impl Into<String>) -> Self {
220        Self {
221            name: name.into(),
222            value: None,
223        }
224    }
225
226    pub fn name(&self) -> &str {
227        &self.name
228    }
229    pub fn value(&self) -> Option<&str> {
230        self.value.as_ref().map(|s| s.as_str())
231    }
232}
233
234#[derive(Debug, Clone)]
235pub struct Param {
236    name: String,
237    bounds: Bounds,
238    typ: idx::Class,
239}
240
241pub type Params = Vec<Param>;
242
243impl Param {
244    pub fn new(name: impl Into<String>, bounds: impl Into<Bounds>, typ: idx::Class) -> Self {
245        Self {
246            name: name.into(),
247            bounds: bounds.into(),
248            typ,
249        }
250    }
251
252    pub fn name(&self) -> &str {
253        &self.name
254    }
255    pub fn bounds(&self) -> &Bounds {
256        &self.bounds
257    }
258    pub fn typ(&self) -> idx::Class {
259        self.typ
260    }
261}
262
263#[derive(Debug, Clone)]
264pub struct Operation {
265    name: String,
266    typ: Option<idx::Class>,
267    parameters: Params,
268}
269
270pub type Operations = Vec<Operation>;
271
272impl Operation {
273    pub fn with_capacity(
274        name: impl Into<String>,
275        typ: Option<idx::Class>,
276        param_capa: usize,
277    ) -> Self {
278        Self {
279            name: name.into(),
280            typ: typ,
281            parameters: Params::with_capacity(param_capa),
282        }
283    }
284    pub fn new(name: impl Into<String>, typ: Option<idx::Class>) -> Self {
285        Self::with_capacity(name, typ, 3)
286    }
287    pub fn add_parameter(&mut self, param: Param) {
288        self.parameters.push(param)
289    }
290
291    pub fn name(&self) -> &str {
292        &self.name
293    }
294    pub fn typ(&self) -> Option<idx::Class> {
295        self.typ
296    }
297    pub fn parameters(&self) -> &Params {
298        &self.parameters
299    }
300}
301
302#[derive(Debug)]
303pub struct Class {
304    pub idx: idx::Class,
305    pub path: Path,
306    concrete: bool,
307    is_interface: bool,
308    typ: String,
309    name: String,
310    inst_name: Option<String>,
311    literals: Vec<ELit>,
312    annotations: Annots,
313    sup: BTreeSet<idx::Class>,
314    sub: BTreeSet<idx::Class>,
315    structural: Vec<Structural>,
316    operations: Operations,
317}
318
319impl HasAnnots for Class {
320    fn annotations(&self) -> &Annots {
321        &self.annotations
322    }
323    fn annotations_mut(&mut self) -> &mut Annots {
324        &mut self.annotations
325    }
326}
327impl HasStructural for Class {
328    fn structural(&self) -> &[Structural] {
329        &self.structural
330    }
331    fn structural_mut(&mut self) -> &mut Vec<repr::Structural> {
332        &mut self.structural
333    }
334}
335
336impl Class {
337    pub fn new(
338        idx: idx::Class,
339        path: Path,
340        typ: impl Into<String>,
341        name: impl Into<String>,
342        inst_name: Option<impl Into<String>>,
343        is_abstract: Option<bool>,
344        is_interface: Option<bool>,
345    ) -> Self {
346        Self {
347            idx,
348            path,
349            typ: typ.into(),
350            name: name.into(),
351            inst_name: inst_name.map(Into::into),
352            concrete: !is_abstract.unwrap_or(false),
353            is_interface: is_interface.unwrap_or(false),
354            literals: ELits::with_capacity(7),
355            annotations: Annots::with_capacity(3),
356            sup: BTreeSet::new(),
357            sub: BTreeSet::new(),
358            structural: Vec::with_capacity(5),
359            operations: Operations::with_capacity(7),
360        }
361    }
362
363    pub fn shrink_to_fit(&mut self) {
364        // keep this so that we know when a new field is added, and update this thing
365        let Self {
366            idx: _,
367            path: _,
368            typ: _,
369            name: _,
370            inst_name: _,
371            concrete: _,
372            is_interface: _,
373            literals,
374            annotations,
375            sup: _,
376            sub: _,
377            structural,
378            operations,
379        } = self;
380        literals.shrink_to_fit();
381        annotations.shrink_to_fit();
382        structural.shrink_to_fit();
383        operations.shrink_to_fit();
384    }
385
386    #[inline]
387    pub fn is_concrete(&self) -> bool {
388        self.concrete
389    }
390    #[inline]
391    pub fn is_interface(&self) -> bool {
392        self.is_interface
393    }
394    #[inline]
395    pub fn is_abstract(&self) -> bool {
396        !self.is_concrete()
397    }
398    #[inline]
399    pub fn name(&self) -> &str {
400        &self.name
401    }
402    #[inline]
403    pub fn inst_name(&self) -> Option<&str> {
404        self.inst_name.as_ref().map(|s| s.as_str())
405    }
406
407    pub fn annotations(&self) -> &Annots {
408        &self.annotations
409    }
410    pub fn add_annotation(&mut self, annot: Annot) {
411        self.annotations.push(annot)
412    }
413
414    pub fn literals(&self) -> &ELits {
415        &self.literals
416    }
417    pub fn add_literal(&mut self, lit: ELit) {
418        self.literals.push(lit)
419    }
420
421    pub fn operations(&self) -> &Operations {
422        &self.operations
423    }
424    pub fn add_operation(&mut self, op: Operation) {
425        self.operations.push(op)
426    }
427
428    pub fn typ(&self) -> &String {
429        &self.typ
430    }
431
432    pub fn sup(&self) -> &BTreeSet<idx::Class> {
433        &self.sup
434    }
435    pub fn add_sup(&mut self, sup: idx::Class) -> bool {
436        self.sup.insert(sup)
437    }
438
439    pub fn sub(&self) -> &BTreeSet<idx::Class> {
440        &self.sub
441    }
442    pub fn add_sub(&mut self, sub: idx::Class) -> bool {
443        self.sub.insert(sub)
444    }
445
446    pub fn structural(&self) -> &[Structural] {
447        &self.structural
448    }
449    pub fn add_structural(&mut self, val: impl Into<Structural>) {
450        self.structural.push(val.into())
451    }
452
453    pub fn display(&self, ctx: &Ctx) -> String {
454        format!("{}/{}", self.path.display(ctx.packs()), self.name)
455    }
456}
457
458#[derive(Debug, Clone)]
459pub struct Pack {
460    pub idx: idx::Pack,
461    sup: Option<idx::Pack>,
462    sub: BTreeSet<idx::Pack>,
463    name: String,
464    classes: BTreeSet<idx::Class>,
465    annotations: Annots,
466}
467
468impl Pack {
469    pub fn with_capacity(idx: idx::Pack, name: impl Into<String>, sup: Option<idx::Pack>) -> Self {
470        Self {
471            idx,
472            sup,
473            sub: BTreeSet::new(),
474            name: name.into(),
475            classes: BTreeSet::new(),
476            annotations: Annots::with_capacity(3),
477        }
478    }
479    pub fn new(idx: idx::Pack, name: impl Into<String>, sup: Option<idx::Pack>) -> Self {
480        Self::with_capacity(idx, name, sup)
481    }
482
483    /// A package is empty if it has nothing but an index, a name, and optionnaly a `sup`.
484    pub fn is_empty(&self) -> bool {
485        self.sub.is_empty() && self.classes.is_empty() && self.annotations.is_empty()
486    }
487
488    pub fn path(&self, ctx: &Ctx) -> Path {
489        Path::of_idx(ctx, self.idx)
490    }
491
492    pub fn annotations(&self) -> &Annots {
493        &self.annotations
494    }
495    pub fn add_annotation(&mut self, annot: Annot) {
496        self.annotations.push(annot)
497    }
498
499    pub fn sup(&self) -> Option<idx::Pack> {
500        self.sup
501    }
502    pub fn set_sup(&mut self, sup: idx::Pack) -> Option<idx::Pack> {
503        mem::replace(&mut self.sup, Some(sup))
504    }
505    pub fn has_sup(&mut self, sup: idx::Pack) -> bool {
506        self.sup == Some(sup)
507    }
508
509    pub fn sub(&self) -> &BTreeSet<idx::Pack> {
510        &self.sub
511    }
512    pub fn add_sub(&mut self, sub: idx::Pack) -> bool {
513        self.sub.insert(sub)
514    }
515    pub fn has_sub(&self, sub: idx::Pack) -> bool {
516        self.sub.contains(&sub)
517    }
518
519    pub fn name(&self) -> &str {
520        &self.name
521    }
522
523    pub fn classes(&self) -> &BTreeSet<idx::Class> {
524        &self.classes
525    }
526    pub fn classes_insert(&mut self, idx: idx::Class) -> bool {
527        self.classes.insert(idx)
528    }
529}