1 use crate::syntax::namespace::Namespace;
2 use crate::syntax::{ForeignName, Pair};
3 use proc_macro2::{Ident, TokenStream};
4 use quote::ToTokens;
5 use std::fmt::{self, Display, Write};
6 
7 // A mangled symbol consisting of segments separated by '$'.
8 // For example: cxxbridge1$string$new
9 pub(crate) struct Symbol(String);
10 
11 impl Display for Symbol {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result12     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
13         Display::fmt(&self.0, formatter)
14     }
15 }
16 
17 impl ToTokens for Symbol {
to_tokens(&self, tokens: &mut TokenStream)18     fn to_tokens(&self, tokens: &mut TokenStream) {
19         ToTokens::to_tokens(&self.0, tokens);
20     }
21 }
22 
23 impl Symbol {
push(&mut self, segment: &dyn Display)24     fn push(&mut self, segment: &dyn Display) {
25         let len_before = self.0.len();
26         if !self.0.is_empty() {
27             self.0.push('$');
28         }
29         self.0.write_fmt(format_args!("{}", segment)).unwrap();
30         assert!(self.0.len() > len_before);
31     }
32 
from_idents<'a>(it: impl Iterator<Item = &'a dyn Segment>) -> Self33     pub(crate) fn from_idents<'a>(it: impl Iterator<Item = &'a dyn Segment>) -> Self {
34         let mut symbol = Symbol(String::new());
35         for segment in it {
36             segment.write(&mut symbol);
37         }
38         assert!(!symbol.0.is_empty());
39         symbol
40     }
41 }
42 
43 pub(crate) trait Segment {
write(&self, symbol: &mut Symbol)44     fn write(&self, symbol: &mut Symbol);
45 }
46 
47 impl Segment for str {
write(&self, symbol: &mut Symbol)48     fn write(&self, symbol: &mut Symbol) {
49         symbol.push(&self);
50     }
51 }
52 
53 impl Segment for usize {
write(&self, symbol: &mut Symbol)54     fn write(&self, symbol: &mut Symbol) {
55         symbol.push(&self);
56     }
57 }
58 
59 impl Segment for Ident {
write(&self, symbol: &mut Symbol)60     fn write(&self, symbol: &mut Symbol) {
61         symbol.push(&self);
62     }
63 }
64 
65 impl Segment for Symbol {
write(&self, symbol: &mut Symbol)66     fn write(&self, symbol: &mut Symbol) {
67         symbol.push(&self);
68     }
69 }
70 
71 impl Segment for Namespace {
write(&self, symbol: &mut Symbol)72     fn write(&self, symbol: &mut Symbol) {
73         for segment in self {
74             symbol.push(segment);
75         }
76     }
77 }
78 
79 impl Segment for Pair {
write(&self, symbol: &mut Symbol)80     fn write(&self, symbol: &mut Symbol) {
81         self.namespace.write(symbol);
82         self.cxx.write(symbol);
83     }
84 }
85 
86 impl Segment for ForeignName {
write(&self, symbol: &mut Symbol)87     fn write(&self, symbol: &mut Symbol) {
88         // TODO: support C++ names containing whitespace (`unsigned int`) or
89         // non-alphanumeric characters (`operator++`).
90         self.to_string().write(symbol);
91     }
92 }
93 
94 impl<T> Segment for &'_ T
95 where
96     T: ?Sized + Segment + Display,
97 {
write(&self, symbol: &mut Symbol)98     fn write(&self, symbol: &mut Symbol) {
99         (**self).write(symbol);
100     }
101 }
102 
join(segments: &[&dyn Segment]) -> Symbol103 pub(crate) fn join(segments: &[&dyn Segment]) -> Symbol {
104     let mut symbol = Symbol(String::new());
105     for segment in segments {
106         segment.write(&mut symbol);
107     }
108     assert!(!symbol.0.is_empty());
109     symbol
110 }
111