cxxbridge_macro/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!("{}", segment)).unwrap();
30        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        assert!(!symbol.0.is_empty());
39        symbol
40    }
41}
42
43pub(crate) trait Segment {
44    fn write(&self, symbol: &mut Symbol);
45}
46
47impl Segment for str {
48    fn write(&self, symbol: &mut Symbol) {
49        symbol.push(&self);
50    }
51}
52
53impl Segment for usize {
54    fn write(&self, symbol: &mut Symbol) {
55        symbol.push(&self);
56    }
57}
58
59impl Segment for Ident {
60    fn write(&self, symbol: &mut Symbol) {
61        symbol.push(&self);
62    }
63}
64
65impl Segment for Symbol {
66    fn write(&self, symbol: &mut Symbol) {
67        symbol.push(&self);
68    }
69}
70
71impl Segment for Namespace {
72    fn write(&self, symbol: &mut Symbol) {
73        for segment in self {
74            symbol.push(segment);
75        }
76    }
77}
78
79impl Segment for Pair {
80    fn write(&self, symbol: &mut Symbol) {
81        self.namespace.write(symbol);
82        self.cxx.write(symbol);
83    }
84}
85
86impl Segment for ForeignName {
87    fn write(&self, symbol: &mut Symbol) {
88        // TODO: support C++ names containing whitespace (`unsigned int`) or
89        // non-alphanumeric characters (`operator++`).
90        self.to_string().write(symbol);
91    }
92}
93
94impl<T> Segment for &'_ T
95where
96    T: ?Sized + Segment + Display,
97{
98    fn write(&self, symbol: &mut Symbol) {
99        (**self).write(symbol);
100    }
101}
102
103pub(crate) fn join(segments: &[&dyn Segment]) -> Symbol {
104    let mut symbol = Symbol(String::new());
105    for segment in segments {
106        segment.write(&mut symbol);
107    }
108    assert!(!symbol.0.is_empty());
109    symbol
110}