1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::{btree_map::Entry as BTreeMapEntry, BTreeMap};
use std::rc::Rc;

use crate::common::FilePosition;
use crate::idl;

use super::errors::ValidationError;
use super::fieldset::Fieldset;
use super::r#enum::Enum;
use super::r#struct::Struct;
use super::r#type::UserDefinedType;
use super::service::Service;
use super::typemap::TypeMap;

#[derive(Default)]
pub struct Namespace {
    pub path: Vec<String>,
    pub types: BTreeMap<String, Rc<RefCell<UserDefinedType>>>,
    pub services: BTreeMap<String, Service>,
    pub namespaces: BTreeMap<String, Namespace>,
}

impl Namespace {
    pub(crate) fn from_idl<'a>(
        inss: impl Iterator<Item = &'a crate::idl::Namespace>,
        builtin_types: &HashMap<String, String>,
    ) -> Result<Self, ValidationError> {
        let mut ns = Self::default();
        let mut type_map = TypeMap::new();
        for ins in inss {
            ns.idl_convert(ins, &mut type_map, &builtin_types)?;
        }
        ns.resolve(&type_map)?;
        Ok(ns)
    }
    fn add_type(&mut self, type_: UserDefinedType, type_map: &mut TypeMap) {
        let type_rc = Rc::new(RefCell::new(type_));
        type_map.insert(&type_rc);
        let name = type_rc.borrow().name().to_owned();
        self.types.insert(name, type_rc);
    }
    fn idl_convert(
        &mut self,
        ins: &crate::idl::Namespace,
        type_map: &mut TypeMap,
        builtin_types: &HashMap<String, String>,
    ) -> Result<(), ValidationError> {
        let mut names: BTreeMap<String, FilePosition> = BTreeMap::new();
        for ipart in ins.parts.iter() {
            match names.entry(ipart.name().to_owned()) {
                BTreeMapEntry::Occupied(entry) => {
                    return Err(ValidationError::DuplicateIdentifier {
                        position: entry.get().clone(),
                        identifier: ipart.name().to_owned(),
                    });
                }
                BTreeMapEntry::Vacant(entry) => {
                    entry.insert(ipart.position().clone());
                }
            }
            match ipart {
                idl::NamespacePart::Enum(ienum) => {
                    self.add_type(
                        UserDefinedType::Enum(Enum::from_idl(&ienum, self, &builtin_types)),
                        type_map,
                    );
                }
                idl::NamespacePart::Struct(istruct) => {
                    self.add_type(
                        UserDefinedType::Struct(Struct::from_idl(&istruct, self, &builtin_types)),
                        type_map,
                    );
                }
                idl::NamespacePart::Fieldset(ifieldset) => {
                    self.add_type(
                        UserDefinedType::Fieldset(Fieldset::from_idl(
                            &ifieldset,
                            self,
                            &builtin_types,
                        )),
                        type_map,
                    );
                }
                idl::NamespacePart::Service(iservice) => {
                    self.services.insert(
                        iservice.name.clone(),
                        Service::from_idl(iservice, self, &builtin_types),
                    );
                    // This is done in the next step. Since services do not
                    // define any types we can ignore the merging and just
                    // delay processing of the service to the resolve step.
                }
                idl::NamespacePart::Namespace(inamespace) => {
                    let mut child_ns = Self {
                        path: self.path.clone(),
                        ..Default::default()
                    };
                    child_ns.path.push(ipart.name().to_owned());
                    child_ns.idl_convert(&inamespace, type_map, &builtin_types)?;
                    self.namespaces.insert(inamespace.name.to_owned(), child_ns);
                }
            };
        }
        Ok(())
    }
    fn resolve(&mut self, type_map: &TypeMap) -> Result<(), ValidationError> {
        for type_rc in self.types.values() {
            type_rc.borrow_mut().resolve(type_map)?;
        }
        for service in self.services.values_mut() {
            service.resolve(type_map)?;
        }
        for child_ns in self.namespaces.values_mut() {
            child_ns.resolve(type_map)?;
        }
        Ok(())
    }
    pub fn name(&self) -> &str {
        self.path.last().unwrap()
    }
}