blob: fa8e58779027ec59964126bd41c0af84881bbeed [file] [log] [blame]
David Tolnay5ea922a2020-04-19 21:58:06 -07001use crate::syntax::namespace::Namespace;
2use proc_macro2::{Ident, TokenStream};
3use quote::ToTokens;
4use std::fmt::{self, Display, Write};
5
6// A mangled symbol consisting of segments separated by '$'.
7// For example: cxxbridge02$string$new
8pub struct Symbol(String);
9
10impl Display for Symbol {
11 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
12 Display::fmt(&self.0, formatter)
13 }
14}
15
16impl ToTokens for Symbol {
17 fn to_tokens(&self, tokens: &mut TokenStream) {
18 ToTokens::to_tokens(&self.0, tokens);
19 }
20}
21
David Tolnay891061b2020-04-19 22:42:33 -070022impl From<&Ident> for Symbol {
23 fn from(ident: &Ident) -> Self {
24 Symbol(ident.to_string())
25 }
26}
27
David Tolnay5ea922a2020-04-19 21:58:06 -070028impl Symbol {
29 fn push(&mut self, segment: &dyn Display) {
30 let len_before = self.0.len();
31 if !self.0.is_empty() {
32 self.0.push('$');
33 }
34 self.0.write_fmt(format_args!("{}", segment)).unwrap();
35 assert!(self.0.len() > len_before);
36 }
37}
38
39pub trait Segment: Display {
40 fn write(&self, symbol: &mut Symbol) {
41 symbol.push(&self);
42 }
43}
44
45impl Segment for str {}
David Tolnay891061b2020-04-19 22:42:33 -070046impl Segment for usize {}
David Tolnay5ea922a2020-04-19 21:58:06 -070047impl Segment for Ident {}
David Tolnay891061b2020-04-19 22:42:33 -070048impl Segment for Symbol {}
David Tolnay5ea922a2020-04-19 21:58:06 -070049
50impl Segment for Namespace {
51 fn write(&self, symbol: &mut Symbol) {
52 for segment in self {
53 symbol.push(segment);
54 }
55 }
56}
57
58impl<T> Segment for &'_ T
59where
60 T: ?Sized + Segment,
61{
62 fn write(&self, symbol: &mut Symbol) {
63 (**self).write(symbol);
64 }
65}
66
67pub fn join(segments: &[&dyn Segment]) -> Symbol {
68 let mut symbol = Symbol(String::new());
69 for segment in segments {
70 segment.write(&mut symbol);
71 }
72 assert!(!symbol.0.is_empty());
73 symbol
74}