1 use crate::syntax::map::UnorderedMap as Map;
2 use crate::syntax::Api;
3 use proc_macro2::Ident;
4
5 pub struct NamespaceEntries<'a> {
6 direct: Vec<&'a Api>,
7 nested: Vec<(&'a Ident, NamespaceEntries<'a>)>,
8 }
9
10 impl<'a> NamespaceEntries<'a> {
new(apis: Vec<&'a Api>) -> Self11 pub fn new(apis: Vec<&'a Api>) -> Self {
12 sort_by_inner_namespace(apis, 0)
13 }
14
direct_content(&self) -> &[&'a Api]15 pub fn direct_content(&self) -> &[&'a Api] {
16 &self.direct
17 }
18
nested_content(&self) -> impl Iterator<Item = (&'a Ident, &NamespaceEntries<'a>)>19 pub fn nested_content(&self) -> impl Iterator<Item = (&'a Ident, &NamespaceEntries<'a>)> {
20 self.nested.iter().map(|(k, entries)| (*k, entries))
21 }
22 }
23
sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries24 fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries {
25 let mut direct = Vec::new();
26 let mut nested_namespaces = Vec::new();
27 let mut index_of_namespace = Map::new();
28
29 for api in &apis {
30 if let Some(first_ns_elem) = api.namespace().iter().nth(depth) {
31 match index_of_namespace.get(first_ns_elem) {
32 None => {
33 index_of_namespace.insert(first_ns_elem, nested_namespaces.len());
34 nested_namespaces.push((first_ns_elem, vec![*api]));
35 }
36 Some(&index) => nested_namespaces[index].1.push(*api),
37 }
38 continue;
39 }
40 direct.push(*api);
41 }
42
43 let nested = nested_namespaces
44 .into_iter()
45 .map(|(k, apis)| (k, sort_by_inner_namespace(apis, depth + 1)))
46 .collect();
47
48 NamespaceEntries { direct, nested }
49 }
50
51 #[cfg(test)]
52 mod tests {
53 use super::NamespaceEntries;
54 use crate::syntax::attrs::OtherAttrs;
55 use crate::syntax::cfg::CfgExpr;
56 use crate::syntax::namespace::Namespace;
57 use crate::syntax::{Api, Doc, ExternType, ForeignName, Lang, Lifetimes, Pair};
58 use proc_macro2::{Ident, Span};
59 use std::iter::FromIterator;
60 use syn::punctuated::Punctuated;
61 use syn::Token;
62
63 #[test]
test_ns_entries_sort()64 fn test_ns_entries_sort() {
65 let apis = &[
66 make_api(None, "C"),
67 make_api(None, "A"),
68 make_api(Some("G"), "E"),
69 make_api(Some("D"), "F"),
70 make_api(Some("G"), "H"),
71 make_api(Some("D::K"), "L"),
72 make_api(Some("D::K"), "M"),
73 make_api(None, "B"),
74 make_api(Some("D"), "I"),
75 make_api(Some("D"), "J"),
76 ];
77
78 let root = NamespaceEntries::new(Vec::from_iter(apis));
79
80 // ::
81 let root_direct = root.direct_content();
82 assert_eq!(root_direct.len(), 3);
83 assert_ident(root_direct[0], "C");
84 assert_ident(root_direct[1], "A");
85 assert_ident(root_direct[2], "B");
86
87 let mut root_nested = root.nested_content();
88 let (id, g) = root_nested.next().unwrap();
89 assert_eq!(id, "G");
90 let (id, d) = root_nested.next().unwrap();
91 assert_eq!(id, "D");
92 assert!(root_nested.next().is_none());
93
94 // ::G
95 let g_direct = g.direct_content();
96 assert_eq!(g_direct.len(), 2);
97 assert_ident(g_direct[0], "E");
98 assert_ident(g_direct[1], "H");
99
100 let mut g_nested = g.nested_content();
101 assert!(g_nested.next().is_none());
102
103 // ::D
104 let d_direct = d.direct_content();
105 assert_eq!(d_direct.len(), 3);
106 assert_ident(d_direct[0], "F");
107 assert_ident(d_direct[1], "I");
108 assert_ident(d_direct[2], "J");
109
110 let mut d_nested = d.nested_content();
111 let (id, k) = d_nested.next().unwrap();
112 assert_eq!(id, "K");
113
114 // ::D::K
115 let k_direct = k.direct_content();
116 assert_eq!(k_direct.len(), 2);
117 assert_ident(k_direct[0], "L");
118 assert_ident(k_direct[1], "M");
119 }
120
assert_ident(api: &Api, expected: &str)121 fn assert_ident(api: &Api, expected: &str) {
122 if let Api::CxxType(cxx_type) = api {
123 assert_eq!(cxx_type.name.cxx.to_string(), expected);
124 } else {
125 unreachable!()
126 }
127 }
128
make_api(ns: Option<&str>, ident: &str) -> Api129 fn make_api(ns: Option<&str>, ident: &str) -> Api {
130 let ns = ns.map_or(Namespace::ROOT, |ns| syn::parse_str(ns).unwrap());
131 Api::CxxType(ExternType {
132 cfg: CfgExpr::Unconditional,
133 lang: Lang::Rust,
134 doc: Doc::new(),
135 derives: Vec::new(),
136 attrs: OtherAttrs::none(),
137 visibility: Token![pub](Span::call_site()),
138 type_token: Token![type](Span::call_site()),
139 name: Pair {
140 namespace: ns,
141 cxx: ForeignName::parse(ident, Span::call_site()).unwrap(),
142 rust: Ident::new(ident, Span::call_site()),
143 },
144 generics: Lifetimes {
145 lt_token: None,
146 lifetimes: Punctuated::new(),
147 gt_token: None,
148 },
149 colon_token: None,
150 bounds: Vec::new(),
151 semi_token: Token![;](Span::call_site()),
152 trusted: false,
153 })
154 }
155 }
156