Centralize mangled symbol joining
diff --git a/syntax/symbol.rs b/syntax/symbol.rs
new file mode 100644
index 0000000..a40baaf
--- /dev/null
+++ b/syntax/symbol.rs
@@ -0,0 +1,66 @@
+use crate::syntax::namespace::Namespace;
+use proc_macro2::{Ident, TokenStream};
+use quote::ToTokens;
+use std::fmt::{self, Display, Write};
+
+// A mangled symbol consisting of segments separated by '$'.
+// For example: cxxbridge02$string$new
+pub struct Symbol(String);
+
+impl Display for Symbol {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(&self.0, formatter)
+ }
+}
+
+impl ToTokens for Symbol {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ ToTokens::to_tokens(&self.0, tokens);
+ }
+}
+
+impl Symbol {
+ fn push(&mut self, segment: &dyn Display) {
+ let len_before = self.0.len();
+ if !self.0.is_empty() {
+ self.0.push('$');
+ }
+ self.0.write_fmt(format_args!("{}", segment)).unwrap();
+ assert!(self.0.len() > len_before);
+ }
+}
+
+pub trait Segment: Display {
+ fn write(&self, symbol: &mut Symbol) {
+ symbol.push(&self);
+ }
+}
+
+impl Segment for str {}
+impl Segment for Ident {}
+
+impl Segment for Namespace {
+ fn write(&self, symbol: &mut Symbol) {
+ for segment in self {
+ symbol.push(segment);
+ }
+ }
+}
+
+impl<T> Segment for &'_ T
+where
+ T: ?Sized + Segment,
+{
+ fn write(&self, symbol: &mut Symbol) {
+ (**self).write(symbol);
+ }
+}
+
+pub fn join(segments: &[&dyn Segment]) -> Symbol {
+ let mut symbol = Symbol(String::new());
+ for segment in segments {
+ segment.write(&mut symbol);
+ }
+ assert!(!symbol.0.is_empty());
+ symbol
+}