cxx_build/syntax/
symbol.rs

1use crate::syntax::namespace::Namespace;
2use crate::syntax::{ForeignName, Pair};
3use proc_macro2::{Ident, TokenStream};
4use quote::ToTokens;
5use std::fmt::{self, Display, Write};
6
7// A mangled symbol consisting of segments separated by '$'.
8// For example: cxxbridge1$string$new
9pub(crate) struct Symbol(String);
10
11impl Display for Symbol {
12    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
13        Display::fmt(&self.0, formatter)
14    }
15}
16
17impl ToTokens for Symbol {
18    fn to_tokens(&self, tokens: &mut TokenStream) {
19        ToTokens::to_tokens(&self.0, tokens);
20    }
21}
22
23impl Symbol {
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!("{0}", segment)format_args!("{}", segment)).unwrap();
30        if !(self.0.len() > len_before) {
    ::core::panicking::panic("assertion failed: self.0.len() > len_before")
};assert!(self.0.len() > len_before);
31    }
32
33    pub(crate) 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        if !!symbol.0.is_empty() {
    ::core::panicking::panic("assertion failed: !symbol.0.is_empty()")
};assert!(!symbol.0.is_empty());
39        symbol
40    }
41
42    #[cfg_attr(proc_macro, expect(dead_code))]
43    pub(crate) fn contains(&self, ch: char) -> bool {
44        self.0.contains(ch)
45    }
46}
47
48pub(crate) trait Segment {
49    fn write(&self, symbol: &mut Symbol);
50}
51
52impl Segment for str {
53    fn write(&self, symbol: &mut Symbol) {
54        symbol.push(&self);
55    }
56}
57
58impl Segment for usize {
59    fn write(&self, symbol: &mut Symbol) {
60        symbol.push(&self);
61    }
62}
63
64impl Segment for Ident {
65    fn write(&self, symbol: &mut Symbol) {
66        symbol.push(&self);
67    }
68}
69
70impl Segment for Symbol {
71    fn write(&self, symbol: &mut Symbol) {
72        symbol.push(&self);
73    }
74}
75
76impl Segment for Namespace {
77    fn write(&self, symbol: &mut Symbol) {
78        for segment in self {
79            symbol.push(segment);
80        }
81    }
82}
83
84impl Segment for Pair {
85    fn write(&self, symbol: &mut Symbol) {
86        self.namespace.write(symbol);
87        self.cxx.write(symbol);
88    }
89}
90
91impl Segment for ForeignName {
92    fn write(&self, symbol: &mut Symbol) {
93        // TODO: support C++ names containing whitespace (`unsigned int`) or
94        // non-alphanumeric characters (`operator++`).
95        self.to_string().write(symbol);
96    }
97}
98
99impl<T> Segment for &'_ T
100where
101    T: ?Sized + Segment + Display,
102{
103    fn write(&self, symbol: &mut Symbol) {
104        (**self).write(symbol);
105    }
106}
107
108pub(crate) fn join(segments: &[&dyn Segment]) -> Symbol {
109    let mut symbol = Symbol(String::new());
110    for segment in segments {
111        segment.write(&mut symbol);
112    }
113    if !!symbol.0.is_empty() {
    ::core::panicking::panic("assertion failed: !symbol.0.is_empty()")
};assert!(!symbol.0.is_empty());
114    symbol
115}