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
use crate::type_namespaces::TypeNamespaces;
use crate::types::Type;
use proc_macro2::TokenStream;
/// A namespaced tree of types
#[derive(Default)]
pub struct TypeTree {
types: Vec<Type>,
namespaces: TypeNamespaces,
}
impl TypeTree {
/// Insert a [`Type`] into [`TypeTree`]
///
/// This recursively searchs the tree for an entry corresponding to the namespace
pub fn insert(&mut self, namespace: String, t: Type) {
if let Some(pos) = namespace.find('.') {
self.namespaces
.0
.entry(namespace[..pos].to_string())
.or_default()
.insert(namespace[pos + 1..].to_string(), t);
} else {
self.namespaces
.0
.entry(namespace)
.or_default()
.types
.push(t);
}
}
/// Turn the tree into a token stream for code generation
pub fn to_tokens<'a>(&'a self) -> impl Iterator<Item = TokenStream> + 'a {
self.types
.iter()
.map(|t| t.to_tokens())
.chain(self.namespaces.to_tokens())
}
}
#[cfg(test)]
mod tests {
use crate::TypeReader;
use crate::TypeStage;
use crate::{NamespaceTypes, TypeLimit, TypeLimits};
#[test]
fn test_dependency_inclusion() {
let reader = &TypeReader::from_os();
let mut limits = TypeLimits::new(reader);
limits
.insert(NamespaceTypes {
namespace: "windows.foundation".to_owned(),
limit: TypeLimit::All,
})
.unwrap();
limits
.insert(NamespaceTypes {
namespace: "windows.ui".to_owned(),
limit: TypeLimit::All,
})
.unwrap();
let stage = TypeStage::from_limits(reader, &limits);
// Since Windows.Foundation depends on Windows.Foundation.Collections and
// Windows.UI doesn't have dependencies, we should only see those namespaces.
let root = stage.into_tree();
// There is one root namespace.
assert!(root.namespaces.0.len() == 1);
let windows = &root.namespaces.0["Windows"];
// The Windows namespace will only contain Foundation and UI.
assert!(windows.namespaces.0.len() == 2);
let foundation = &windows.namespaces.0["Foundation"];
let ui = &windows.namespaces.0["UI"];
// The UI namespace will not contain any further namespaces.
assert!(ui.namespaces.0.is_empty());
// The Foundation namespace will contain the Collections namespace.
assert!(foundation.namespaces.0.len() == 1);
let collections = &foundation.namespaces.0["Collections"];
// The Collections namespace will not contain any further namespaces.
assert!(collections.namespaces.0.is_empty());
// The root never has any types.
assert!(root.types.is_empty());
// The Windows namespace has no types.
assert!(windows.types.is_empty());
// The UI namespace has all of its types.
assert!(ui.types.iter().any(|t| t.name().name == "Colors"));
assert!(ui.types.iter().any(|t| t.name().name == "IColorsStatics"));
// The Foundation namespace has all of its types.
assert!(foundation.types.iter().any(|t| t.name().name == "Uri"));
assert!(foundation
.types
.iter()
.any(|t| t.name().name == "IStringable"));
// The Collections namespace only has the needed types.
assert!(collections
.types
.iter()
.any(|t| t.name().name == "IVectorView`1"));
assert!(
collections
.types
.iter()
.any(|t| t.name().name == "PropertySet")
== false
);
}
}