Centralize mangled symbol joining
diff --git a/syntax/mangle.rs b/syntax/mangle.rs
index a109951..f2616d2 100644
--- a/syntax/mangle.rs
+++ b/syntax/mangle.rs
@@ -1,10 +1,18 @@
use crate::syntax::namespace::Namespace;
-use crate::syntax::ExternFn;
+use crate::syntax::{symbol, ExternFn};
+
+const CXXBRIDGE: &str = "cxxbridge02";
+
+macro_rules! join {
+ ($($segment:expr),*) => {
+ symbol::join(&[$(&$segment),*])
+ };
+}
pub fn extern_fn(namespace: &Namespace, efn: &ExternFn) -> String {
- let receiver = match &efn.receiver {
- Some(receiver) => receiver.ident.to_string() + "$",
- None => String::new(),
- };
- format!("{}cxxbridge02${}{}", namespace, receiver, efn.ident)
+ match &efn.receiver {
+ Some(receiver) => join!(namespace, CXXBRIDGE, receiver.ident, efn.ident),
+ None => join!(namespace, CXXBRIDGE, efn.ident),
+ }
+ .to_string()
}
diff --git a/syntax/mod.rs b/syntax/mod.rs
index b7ca6b7..81b1a2f 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -11,6 +11,7 @@
pub mod namespace;
mod parse;
pub mod set;
+mod symbol;
mod tokens;
pub mod types;
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
+}