gir_parser/
repository.rs

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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use std::{collections::HashMap, path::Path};

use xmlserde_derives::XmlDeserialize;

use crate::{namespace::Namespace, version::Version, ParserError};

#[derive(Clone, Debug, XmlDeserialize)]
#[xmlserde(root = b"include")]
#[xmlserde(deny_unknown_fields)]
pub struct NamespaceInclude {
    #[xmlserde(name = b"name", ty = "attr")]
    name: String,
    #[xmlserde(name = b"version", ty = "attr")]
    version: Version,
}

impl NamespaceInclude {
    pub fn as_package(&self) -> String {
        format!("{}-{}", self.name, self.version)
    }

    pub fn as_package_file(&self) -> String {
        format!("{}-{}.gir", self.name, self.version)
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn version(&self) -> &Version {
        &self.version
    }
}

#[derive(Clone, Debug, XmlDeserialize)]
#[xmlserde(root = b"c:include")]
#[xmlserde(deny_unknown_fields)]
pub struct HeaderInclude {
    #[xmlserde(name = b"name", ty = "attr")]
    name: String,
}

impl HeaderInclude {
    pub fn name(&self) -> &str {
        &self.name
    }
}

#[derive(Clone, Debug, XmlDeserialize)]
#[xmlserde(root = b"package")]
#[xmlserde(deny_unknown_fields)]
pub struct Package {
    #[xmlserde(name = b"name", ty = "attr")]
    name: String,
}

impl Package {
    pub fn name(&self) -> &str {
        &self.name
    }
}

#[derive(Clone, Debug, XmlDeserialize)]
#[xmlserde(root = b"repository")]
#[xmlserde(deny_unknown_fields)]
pub struct Repository {
    #[xmlserde(name = b"version", ty = "attr")]
    version: Option<Version>,
    #[xmlserde(name = b"c:identifier-prefixes", ty = "attr")]
    c_identifier_prefixes: Option<String>,
    #[xmlserde(name = b"c:symbol-prefixes", ty = "attr")]
    c_symbol_prefixes: Option<String>,
    #[xmlserde(name = b"xmlns", ty = "attr")]
    _xmlns: Option<String>,
    #[xmlserde(name = b"xmlns:c", ty = "attr")]
    _xmlns_c: Option<String>,
    #[xmlserde(name = b"xmlns:glib", ty = "attr")]
    _xmlns_glib: Option<String>,
    #[xmlserde(name = b"include", ty = "child")]
    includes: Vec<NamespaceInclude>,
    #[xmlserde(name = b"c:include", ty = "child")]
    c_includes: Vec<HeaderInclude>,
    #[xmlserde(name = b"package", ty = "child")]
    packages: Vec<Package>,
    #[xmlserde(name = b"namespace", ty = "child")]
    namespace: Namespace,
}

impl Repository {
    pub fn from_path_follow_namespaces_and_cache(
        cache: &mut HashMap<String, Self>,
        package_file: &str,
        girs_dirs: impl AsRef<Path>,
    ) -> Result<(), ParserError> {
        let repo = Self::from_path(girs_dirs.as_ref().join(package_file))?;
        if cache.contains_key(package_file) {
            return Ok(());
        }
        for namespace in repo.namespace_includes() {
            if !cache.contains_key(&namespace.as_package_file()) {
                Self::from_path_follow_namespaces_and_cache(
                    cache,
                    &namespace.as_package_file(),
                    girs_dirs.as_ref(),
                )?;
            }
        }
        debug_assert_eq!(
            package_file,
            format!(
                "{}-{}.gir",
                repo.namespace().name(),
                repo.namespace().version()
            )
        );
        cache.insert(package_file.to_owned(), repo);
        Ok(())
    }

    pub fn from_path_follow_namespaces(
        package_file: &str,
        girs_dirs: impl AsRef<Path>,
    ) -> Result<HashMap<String, Self>, ParserError> {
        let mut output = HashMap::new();
        Self::from_path_follow_namespaces_and_cache(&mut output, package_file, girs_dirs)?;
        Ok(output)
    }

    pub fn from_path(path: impl AsRef<Path>) -> Result<Self, ParserError> {
        let content = std::fs::read_to_string(path)?;
        let repository = xmlserde::xml_deserialize_from_str(&content).map_err(ParserError::Xml)?;
        Ok(repository)
    }

    pub fn version(&self) -> Option<&Version> {
        self.version.as_ref()
    }

    // TODO: split this by ","
    pub fn c_identifier_prefixes(&self) -> Option<&str> {
        self.c_identifier_prefixes.as_deref()
    }

    // TODO: split this by ","
    pub fn c_symbol_prefixes(&self) -> Option<&str> {
        self.c_symbol_prefixes.as_deref()
    }

    pub fn namespace_includes(&self) -> &[NamespaceInclude] {
        &self.includes
    }

    pub fn header_includes(&self) -> &[HeaderInclude] {
        &self.c_includes
    }

    pub fn packages(&self) -> &[Package] {
        &self.packages
    }

    pub fn namespace(&self) -> &Namespace {
        &self.namespace
    }
}