• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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