1use crate::syntax::map::UnorderedMap as Map; 2use crate::syntax::Api; 3use proc_macro2::Ident; 4 5pub struct NamespaceEntries<'a> { 6 direct: Vec<&'a Api>, 7 nested: Vec<(&'a Ident, NamespaceEntries<'a>)>, 8} 9 10impl<'a> NamespaceEntries<'a> { 11 pub fn new(apis: Vec<&'a Api>) -> Self { 12 sort_by_inner_namespace(apis, 0) 13 } 14 15 pub fn direct_content(&self) -> &[&'a Api] { 16 &self.direct 17 } 18 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 24fn 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)] 52mod 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] 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 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 129 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), 138 type_token: Token), 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), 152 trusted: false, 153 }) 154 } 155} 156