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 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 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 /// For example, for taking a symbol and then making a new symbol
43 /// for a vec of that symbol.
prefix_with(&self, prefix: &str) -> Symbol44 pub fn prefix_with(&self, prefix: &str) -> Symbol {
45 Symbol(format!("{}{}", prefix, self.to_string()))
46 }
47 }
48
49 pub trait Segment {
write(&self, symbol: &mut Symbol)50 fn write(&self, symbol: &mut Symbol);
51 }
52
53 impl Segment for str {
write(&self, symbol: &mut Symbol)54 fn write(&self, symbol: &mut Symbol) {
55 symbol.push(&self);
56 }
57 }
58
59 impl Segment for usize {
write(&self, symbol: &mut Symbol)60 fn write(&self, symbol: &mut Symbol) {
61 symbol.push(&self);
62 }
63 }
64
65 impl Segment for Ident {
write(&self, symbol: &mut Symbol)66 fn write(&self, symbol: &mut Symbol) {
67 symbol.push(&self);
68 }
69 }
70
71 impl Segment for Symbol {
write(&self, symbol: &mut Symbol)72 fn write(&self, symbol: &mut Symbol) {
73 symbol.push(&self);
74 }
75 }
76
77 impl Segment for Namespace {
write(&self, symbol: &mut Symbol)78 fn write(&self, symbol: &mut Symbol) {
79 for segment in self {
80 symbol.push(segment);
81 }
82 }
83 }
84
85 impl Segment for Pair {
write(&self, symbol: &mut Symbol)86 fn write(&self, symbol: &mut Symbol) {
87 self.namespace.write(symbol);
88 self.cxx.write(symbol);
89 }
90 }
91
92 impl Segment for ForeignName {
write(&self, symbol: &mut Symbol)93 fn write(&self, symbol: &mut Symbol) {
94 // TODO: support C++ names containing whitespace (`unsigned int`) or
95 // non-alphanumeric characters (`operator++`).
96 self.to_string().write(symbol);
97 }
98 }
99
100 impl<T> Segment for &'_ T
101 where
102 T: ?Sized + Segment + Display,
103 {
write(&self, symbol: &mut Symbol)104 fn write(&self, symbol: &mut Symbol) {
105 (**self).write(symbol);
106 }
107 }
108
join(segments: &[&dyn Segment]) -> Symbol109 pub fn join(segments: &[&dyn Segment]) -> Symbol {
110 let mut symbol = Symbol(String::new());
111 for segment in segments {
112 segment.write(&mut symbol);
113 }
114 assert!(!symbol.0.is_empty());
115 symbol
116 }
117