Skip to main content

squote/
token_stream.rs

1use std::borrow::Cow;
2
3/// A stream of tokens
4#[derive(Debug, Clone)]
5pub struct TokenStream {
6    inner: String,
7}
8
9impl TokenStream {
10    /// Create a new `TokenStream`
11    pub fn new() -> Self {
12        Self {
13            inner: String::new(),
14        }
15    }
16
17    /// Appends an identifier to the stream
18    ///
19    /// note: a space will be inserted before the identifier
20    pub fn append(&mut self, ident: Ident) {
21        self.push_space();
22        self.inner.push_str(ident.as_str())
23    }
24
25    /// Appends another stream to the stream
26    ///
27    /// note: a space will be inserted before the other stream
28    pub fn combine(&mut self, other: &TokenStream) {
29        self.push_space();
30        self.inner.push_str(&other.inner)
31    }
32
33    /// View the stream as a string
34    pub fn as_str(&self) -> &str {
35        &self.inner
36    }
37
38    /// Convert the stream into a `String`
39    pub fn into_string(self) -> String {
40        self.inner
41    }
42
43    /// Parse the token stream as something
44    ///
45    /// Mostly used with `proc_macro2::TokenStream` or `proc_macro::TokenStream`
46    pub fn parse<T: std::str::FromStr>(self) -> Result<T, T::Err> {
47        self.into_string().parse()
48    }
49
50    pub(crate) fn push_space(&mut self) {
51        match self.last_char() {
52            None | Some(' ') => {}
53            _ => self.inner.push(' '),
54        }
55    }
56
57    pub(crate) fn push(&mut self, c: char) {
58        self.inner.push(c)
59    }
60
61    pub(crate) fn push_str(&mut self, str: &str) {
62        self.inner.push_str(str)
63    }
64
65    fn last_char(&self) -> Option<char> {
66        self.inner.chars().last()
67    }
68}
69
70impl std::iter::FromIterator<TokenStream> for TokenStream {
71    fn from_iter<I: IntoIterator<Item = TokenStream>>(iter: I) -> Self {
72        iter.into_iter()
73            .fold(None, |accum: Option<TokenStream>, n| {
74                let mut ts = accum.unwrap_or_else(TokenStream::new);
75                ts.combine(&n);
76                Some(ts)
77            })
78            .unwrap_or(TokenStream::new())
79    }
80}
81
82/// An identifier
83#[derive(Clone, Debug)]
84pub struct Ident {
85    inner: Cow<'static, str>,
86}
87
88impl Ident {
89    /// Create a new `Identifier`
90    pub fn new<T: Into<Cow<'static, str>>>(str: T) -> Self {
91        Self { inner: str.into() }
92    }
93
94    /// View the identifier as a string
95    pub fn as_str(&self) -> &str {
96        &*self.inner
97    }
98}
99
100impl std::fmt::Display for Ident {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        write!(f, "{}", self.as_str())
103    }
104}
105impl PartialEq<&str> for Ident {
106    fn eq(&self, other: &&str) -> bool {
107        self.as_str() == *other
108    }
109}
110
111/// A delimiter around a block of code
112#[derive(Copy, Clone)]
113pub enum Delimiter {
114    /// `[]`
115    Bracket,
116    /// `{}`
117    Brace,
118    /// `()`
119    Parenthesis,
120}
121
122impl Delimiter {
123    /// The opening delimiter
124    pub fn open(self) -> char {
125        match self {
126            Delimiter::Bracket => '[',
127            Delimiter::Brace => '{',
128            Delimiter::Parenthesis => '(',
129        }
130    }
131
132    /// The closing delimiter
133    pub fn close(self) -> char {
134        match self {
135            Delimiter::Bracket => ']',
136            Delimiter::Brace => '}',
137            Delimiter::Parenthesis => ')',
138        }
139    }
140}
141
142/// A literal of some sort
143pub struct Literal {
144    inner: String,
145}
146
147macro_rules! unsuffixed {
148    ($ty:ty => $name:ident) => {
149        pub fn $name(n: $ty) -> Self {
150            Self {
151                inner: n.to_string(),
152            }
153        }
154    };
155}
156
157impl Literal {
158    unsuffixed!(u32 => u32_unsuffixed);
159    unsuffixed!(u16 => u16_unsuffixed);
160    unsuffixed!(u8 => u8_unsuffixed);
161
162    pub fn byte_string(s: &[u8]) -> Self {
163        Self {
164            inner: format!(
165                "b\"{}\"",
166                std::str::from_utf8(s).expect("Could not turn bytes into byte literal")
167            ),
168        }
169    }
170
171    pub fn as_str(&self) -> &str {
172        &self.inner
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179    #[test]
180    fn accept_owned_and_borrowed() {
181        assert_eq!(
182            Ident::new("hello").as_str(),
183            Ident::new(String::from("hello")).as_str()
184        );
185    }
186}
187
188impl std::fmt::Display for TokenStream {
189    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190        write!(f, "{}", self.as_str())
191    }
192}