webwire_cli/schema/
namespace.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::collections::{btree_map::Entry as BTreeMapEntry, BTreeMap};
4use std::rc::Rc;
5
6use crate::common::FilePosition;
7use crate::idl;
8
9use super::errors::ValidationError;
10use super::fieldset::Fieldset;
11use super::r#enum::Enum;
12use super::r#struct::Struct;
13use super::r#type::UserDefinedType;
14use super::service::Service;
15use super::typemap::TypeMap;
16
17#[derive(Default)]
18pub struct Namespace {
19    pub path: Vec<String>,
20    pub types: BTreeMap<String, UserDefinedType>,
21    pub services: BTreeMap<String, Service>,
22    pub namespaces: BTreeMap<String, Namespace>,
23}
24
25impl Namespace {
26    pub(crate) fn from_idl<'a>(
27        inss: impl Iterator<Item = &'a crate::idl::Namespace>,
28        builtin_types: &HashMap<String, String>,
29    ) -> Result<Self, ValidationError> {
30        let mut ns = Self::default();
31        let mut type_map = TypeMap::new();
32        for ins in inss {
33            ns.idl_convert(ins, &mut type_map, &builtin_types)?;
34        }
35        ns.resolve(&type_map)?;
36        Ok(ns)
37    }
38    fn add_type(&mut self, type_: UserDefinedType, type_map: &mut TypeMap) {
39        type_map.insert(&type_);
40        self.types.insert(type_.fqtn().name.to_owned(), type_);
41    }
42    fn idl_convert(
43        &mut self,
44        ins: &crate::idl::Namespace,
45        type_map: &mut TypeMap,
46        builtin_types: &HashMap<String, String>,
47    ) -> Result<(), ValidationError> {
48        let mut names: BTreeMap<String, FilePosition> = BTreeMap::new();
49        for ipart in ins.parts.iter() {
50            match names.entry(ipart.name().to_owned()) {
51                BTreeMapEntry::Occupied(entry) => {
52                    return Err(ValidationError::DuplicateIdentifier {
53                        position: entry.get().clone(),
54                        identifier: ipart.name().to_owned(),
55                    });
56                }
57                BTreeMapEntry::Vacant(entry) => {
58                    entry.insert(ipart.position().clone());
59                }
60            }
61            match ipart {
62                idl::NamespacePart::Enum(ienum) => {
63                    self.add_type(
64                        UserDefinedType::Enum(Rc::new(RefCell::new(Enum::from_idl(
65                            &ienum,
66                            self,
67                            &builtin_types,
68                        )))),
69                        type_map,
70                    );
71                }
72                idl::NamespacePart::Struct(istruct) => {
73                    self.add_type(
74                        UserDefinedType::Struct(Rc::new(RefCell::new(Struct::from_idl(
75                            &istruct,
76                            self,
77                            &builtin_types,
78                        )))),
79                        type_map,
80                    );
81                }
82                idl::NamespacePart::Fieldset(ifieldset) => {
83                    self.add_type(
84                        UserDefinedType::Fieldset(Rc::new(RefCell::new(Fieldset::from_idl(
85                            &ifieldset,
86                            self,
87                            &builtin_types,
88                        )))),
89                        type_map,
90                    );
91                }
92                idl::NamespacePart::Service(iservice) => {
93                    self.services.insert(
94                        iservice.name.clone(),
95                        Service::from_idl(iservice, self, &builtin_types),
96                    );
97                    // This is done in the next step. Since services do not
98                    // define any types we can ignore the merging and just
99                    // delay processing of the service to the resolve step.
100                }
101                idl::NamespacePart::Namespace(inamespace) => {
102                    let mut child_ns = Self {
103                        path: self.path.clone(),
104                        ..Default::default()
105                    };
106                    child_ns.path.push(ipart.name().to_owned());
107                    child_ns.idl_convert(&inamespace, type_map, &builtin_types)?;
108                    self.namespaces.insert(inamespace.name.to_owned(), child_ns);
109                }
110            };
111        }
112        Ok(())
113    }
114    fn resolve(&mut self, type_map: &TypeMap) -> Result<(), ValidationError> {
115        for ud_type in self.types.values_mut() {
116            ud_type.resolve(type_map)?;
117        }
118        for service in self.services.values_mut() {
119            service.resolve(type_map)?;
120        }
121        for child_ns in self.namespaces.values_mut() {
122            child_ns.resolve(type_map)?;
123        }
124        Ok(())
125    }
126    pub fn name(&self) -> &str {
127        self.path.last().unwrap()
128    }
129}