133d722a9Sopenharmony_ciuse crate::syntax::namespace::Namespace;
233d722a9Sopenharmony_ciuse crate::syntax::{ForeignName, Pair};
333d722a9Sopenharmony_ciuse proc_macro2::{Ident, TokenStream};
433d722a9Sopenharmony_ciuse quote::ToTokens;
533d722a9Sopenharmony_ciuse std::fmt::{self, Display, Write};
633d722a9Sopenharmony_ci
733d722a9Sopenharmony_ci// A mangled symbol consisting of segments separated by '$'.
833d722a9Sopenharmony_ci// For example: cxxbridge1$string$new
933d722a9Sopenharmony_cipub struct Symbol(String);
1033d722a9Sopenharmony_ci
1133d722a9Sopenharmony_ciimpl Display for Symbol {
1233d722a9Sopenharmony_ci    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1333d722a9Sopenharmony_ci        Display::fmt(&self.0, formatter)
1433d722a9Sopenharmony_ci    }
1533d722a9Sopenharmony_ci}
1633d722a9Sopenharmony_ci
1733d722a9Sopenharmony_ciimpl ToTokens for Symbol {
1833d722a9Sopenharmony_ci    fn to_tokens(&self, tokens: &mut TokenStream) {
1933d722a9Sopenharmony_ci        ToTokens::to_tokens(&self.0, tokens);
2033d722a9Sopenharmony_ci    }
2133d722a9Sopenharmony_ci}
2233d722a9Sopenharmony_ci
2333d722a9Sopenharmony_ciimpl Symbol {
2433d722a9Sopenharmony_ci    fn push(&mut self, segment: &dyn Display) {
2533d722a9Sopenharmony_ci        let len_before = self.0.len();
2633d722a9Sopenharmony_ci        if !self.0.is_empty() {
2733d722a9Sopenharmony_ci            self.0.push('$');
2833d722a9Sopenharmony_ci        }
2933d722a9Sopenharmony_ci        self.0.write_fmt(format_args!("{}", segment)).unwrap();
3033d722a9Sopenharmony_ci        assert!(self.0.len() > len_before);
3133d722a9Sopenharmony_ci    }
3233d722a9Sopenharmony_ci
3333d722a9Sopenharmony_ci    pub fn from_idents<'a>(it: impl Iterator<Item = &'a dyn Segment>) -> Self {
3433d722a9Sopenharmony_ci        let mut symbol = Symbol(String::new());
3533d722a9Sopenharmony_ci        for segment in it {
3633d722a9Sopenharmony_ci            segment.write(&mut symbol);
3733d722a9Sopenharmony_ci        }
3833d722a9Sopenharmony_ci        assert!(!symbol.0.is_empty());
3933d722a9Sopenharmony_ci        symbol
4033d722a9Sopenharmony_ci    }
4133d722a9Sopenharmony_ci}
4233d722a9Sopenharmony_ci
4333d722a9Sopenharmony_cipub trait Segment {
4433d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol);
4533d722a9Sopenharmony_ci}
4633d722a9Sopenharmony_ci
4733d722a9Sopenharmony_ciimpl Segment for str {
4833d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
4933d722a9Sopenharmony_ci        symbol.push(&self);
5033d722a9Sopenharmony_ci    }
5133d722a9Sopenharmony_ci}
5233d722a9Sopenharmony_ci
5333d722a9Sopenharmony_ciimpl Segment for usize {
5433d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
5533d722a9Sopenharmony_ci        symbol.push(&self);
5633d722a9Sopenharmony_ci    }
5733d722a9Sopenharmony_ci}
5833d722a9Sopenharmony_ci
5933d722a9Sopenharmony_ciimpl Segment for Ident {
6033d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
6133d722a9Sopenharmony_ci        symbol.push(&self);
6233d722a9Sopenharmony_ci    }
6333d722a9Sopenharmony_ci}
6433d722a9Sopenharmony_ci
6533d722a9Sopenharmony_ciimpl Segment for Symbol {
6633d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
6733d722a9Sopenharmony_ci        symbol.push(&self);
6833d722a9Sopenharmony_ci    }
6933d722a9Sopenharmony_ci}
7033d722a9Sopenharmony_ci
7133d722a9Sopenharmony_ciimpl Segment for Namespace {
7233d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
7333d722a9Sopenharmony_ci        for segment in self {
7433d722a9Sopenharmony_ci            symbol.push(segment);
7533d722a9Sopenharmony_ci        }
7633d722a9Sopenharmony_ci    }
7733d722a9Sopenharmony_ci}
7833d722a9Sopenharmony_ci
7933d722a9Sopenharmony_ciimpl Segment for Pair {
8033d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
8133d722a9Sopenharmony_ci        self.namespace.write(symbol);
8233d722a9Sopenharmony_ci        self.cxx.write(symbol);
8333d722a9Sopenharmony_ci    }
8433d722a9Sopenharmony_ci}
8533d722a9Sopenharmony_ci
8633d722a9Sopenharmony_ciimpl Segment for ForeignName {
8733d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
8833d722a9Sopenharmony_ci        // TODO: support C++ names containing whitespace (`unsigned int`) or
8933d722a9Sopenharmony_ci        // non-alphanumeric characters (`operator++`).
9033d722a9Sopenharmony_ci        self.to_string().write(symbol);
9133d722a9Sopenharmony_ci    }
9233d722a9Sopenharmony_ci}
9333d722a9Sopenharmony_ci
9433d722a9Sopenharmony_ciimpl<T> Segment for &'_ T
9533d722a9Sopenharmony_ciwhere
9633d722a9Sopenharmony_ci    T: ?Sized + Segment + Display,
9733d722a9Sopenharmony_ci{
9833d722a9Sopenharmony_ci    fn write(&self, symbol: &mut Symbol) {
9933d722a9Sopenharmony_ci        (**self).write(symbol);
10033d722a9Sopenharmony_ci    }
10133d722a9Sopenharmony_ci}
10233d722a9Sopenharmony_ci
10333d722a9Sopenharmony_cipub fn join(segments: &[&dyn Segment]) -> Symbol {
10433d722a9Sopenharmony_ci    let mut symbol = Symbol(String::new());
10533d722a9Sopenharmony_ci    for segment in segments {
10633d722a9Sopenharmony_ci        segment.write(&mut symbol);
10733d722a9Sopenharmony_ci    }
10833d722a9Sopenharmony_ci    assert!(!symbol.0.is_empty());
10933d722a9Sopenharmony_ci    symbol
11033d722a9Sopenharmony_ci}
111