cfg_symbol/
source.rs

1//! Our symbol sources. You can grab symbols from here.
2//!
3//! A symbol source is meant to track the number of
4//! symbols that were generated, as well as their names
5//! (optionally).
6//! 
7//! # Examples
8//! 
9//! Grabbing the symbol at a certain position in the sequence
10//! of symbols.
11//! 
12//! ```
13//! use cfg_symbol::{Symbol, SymbolSource};
14//! let symbol: Symbol = SymbolSource::generate_fresh().nth(42).unwrap();
15//! let mut source = SymbolSource::new();
16//! assert_eq!(symbol, source.generate().nth(42).unwrap());
17//! ```
18
19use std::{
20    borrow::{Borrow, Cow},
21    collections::HashMap,
22    iter,
23    num::NonZeroU32,
24    ops,
25    rc::Rc,
26};
27
28use crate::*;
29
30/// Wrapper for a string holding a symbol's name. Meant to be cheap to clone.
31#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
32pub struct SymbolName {
33    name: Rc<str>,
34}
35
36impl ops::Deref for SymbolName {
37    type Target = str;
38
39    fn deref(&self) -> &Self::Target {
40        &self.name[..]
41    }
42}
43
44impl From<Cow<'_, str>> for SymbolName {
45    fn from(value: Cow<'_, str>) -> Self {
46        SymbolName {
47            name: Rc::from(&*value),
48        }
49    }
50}
51
52impl<'a> From<&'a str> for SymbolName {
53    fn from(value: &'a str) -> Self {
54        SymbolName {
55            name: Rc::from(value),
56        }
57    }
58}
59
60impl Borrow<str> for SymbolName {
61    fn borrow(&self) -> &str {
62        &self.name[..]
63    }
64}
65
66/// A source of numeric symbols.
67#[derive(miniserde::Serialize, miniserde::Deserialize, Clone, Debug, Default)]
68pub struct SymbolSource<T: SymbolPrimitive = NonZeroU32> {
69    next_symbol: Symbol<T>,
70    names: Vec<Option<SymbolName>>,
71}
72
73/// Shorthand for `SymbolSource::generate_fresh`.
74#[macro_export]
75macro_rules! syms {
76    () => {
77        $crate::SymbolSource::generate_fresh()
78    };
79}
80
81fn advance<T: SymbolPrimitive>(sym: &mut Symbol<T>) {
82    let n: NonZeroU32 = sym.n.into();
83    let x: T = n
84        .saturating_add(1)
85        .try_into()
86        .ok()
87        .expect("unreachable: could not convert +1");
88    *sym = Symbol { n: x };
89    debug_assert_ne!(x.into().get(), T::MAX, "ran out of Symbol space?");
90}
91
92impl<T: SymbolPrimitive> SymbolSource<T> {
93    /// Creates a source of numeric symbols with an empty symbol space.
94    pub fn new() -> Self {
95        Self {
96            next_symbol: Symbol::first(),
97            names: vec![],
98        }
99    }
100    /// Returns generated symbols.
101    pub fn sym<'a, const N: usize>(&mut self) -> [Symbol<T>; N] {
102        let mut result = [Symbol::first(); N];
103        for dest in result.iter_mut() {
104            *dest = self.next_sym(None);
105        }
106        // self.names.extend([const { None }; N]);
107        result
108    }
109    /// Returns generated symbols.
110    pub fn with_names<'a, const N: usize, S: Into<Cow<'static, str>>>(
111        &mut self,
112        names: [Option<S>; N],
113    ) -> [Symbol<T>; N] {
114        let mut result = [Symbol::first(); N];
115        for (dest, name) in result.iter_mut().zip(names.into_iter()) {
116            *dest = self.next_sym(name.map(|s| s.into()));
117        }
118        // self.names.extend([const { None }; N]);
119        result
120    }
121    /// Generates a new unique symbol.
122    pub fn next_sym(&mut self, name: Option<Cow<str>>) -> Symbol<T> {
123        let ret = self.next_symbol;
124        advance(&mut self.next_symbol);
125        self.names.push(name.map(|cow| cow.into()));
126        ret
127    }
128
129    /// Returns either the formatted name if the given `Symbol` is a gensym,
130    /// or the `Symbol`'s exact name.
131    ///
132    /// Gensyms have no names. That's why we create a 'formatted' name
133    /// with the letter `g` followed by the symbol's numeric value.
134    pub fn name_of(&self, sym: Symbol) -> Cow<'_, str> {
135        match self.names.get(sym.usize()) {
136            Some(Some(name)) => Cow::Borrowed(&name.name[..]),
137            Some(None) | None => Cow::Owned(format!("g{}", sym.usize())),
138        }
139    }
140
141    /// Returns the exact name, or `None` if the `Symbol` has no name (i.e.
142    /// is a gensym).
143    pub fn original_name_of(&self, sym: Symbol) -> Option<&str> {
144        self.names
145            .get(sym.usize())
146            .map(|v| v.as_ref().map(|v| &v.name[..]))
147            .unwrap_or(None)
148    }
149
150    /// Returns the number of symbols in use.
151    pub fn num_syms(&self) -> usize {
152        self.next_symbol.usize()
153    }
154
155    /// Returns an iterator that generates symbols.
156    pub fn generate(&mut self) -> impl Iterator<Item = Symbol<T>> + use<'_, T> {
157        Generate { source: self }
158    }
159
160    /// Iterator over all possible `Symbol`s, in order, starting with the lowest
161    /// numeric value.
162    pub fn generate_fresh() -> impl Iterator<Item = Symbol<T>> {
163        struct Unfolder<T: SymbolPrimitive>(Symbol<T>);
164
165        impl<T: SymbolPrimitive> Iterator for Unfolder<T> {
166            type Item = Symbol<T>;
167            fn next(&mut self) -> Option<Symbol<T>> {
168                let result = self.0;
169                advance(&mut self.0);
170                Some(result)
171            }
172        }
173
174        Unfolder(Symbol::first())
175    }
176
177    /// Translates symbol names according to the given mapping
178    /// beween `Symbol`s.
179    pub fn remap_symbols<F>(&mut self, mut map: F)
180    where
181        F: FnMut(Symbol<T>) -> Symbol<T>,
182    {
183        let mut new_names = vec![];
184        let mut new_source = SymbolSource::<T>::new();
185        for (name, sym) in self.names.iter().zip(new_source.generate()) {
186            let new_sym = map(sym).usize();
187            new_names
188                .extend(iter::repeat(None).take((new_sym + 1).saturating_sub(new_names.len())));
189            new_names[new_sym] = name.clone();
190        }
191        self.names = new_names;
192    }
193
194    /// Removes all the symbols with numeric value equal or higher than
195    /// the argument.
196    ///
197    /// # Panics
198    ///
199    /// Panics unless `new_len` is within `1 ..= T::MAX`.
200    pub fn truncate(&mut self, new_len: usize) {
201        assert_ne!(new_len, 0, "cannot truncate to zero length");
202        assert!(
203            new_len as u64 <= T::MAX as u64,
204            "attempt to truncate to a length that exceeds the limit"
205        );
206        self.names.truncate(new_len);
207        self.next_symbol = Symbol {
208            n: NonZeroU32::new(new_len as u32 + 1)
209                .expect("cannot truncate to this length")
210                .try_into()
211                .ok()
212                .expect("cannot truncate to this length (2)"),
213        };
214    }
215
216    /// Returns the list of `Symbol` names.
217    ///
218    /// # Performance
219    ///
220    /// Internally, bumps the reference count for every existing `SymbolName`
221    /// and copies the pointers to a newly allocated a new `Vec`,
222    pub fn names(&self) -> Vec<Option<SymbolName>> {
223        self.names.clone()
224    }
225
226    /// Creates a `HashMap` where you can access a `Symbol`
227    /// through its name.
228    pub fn name_map(&self) -> HashMap<SymbolName, Symbol> {
229        self.names
230            .iter()
231            .zip(SymbolSource::generate_fresh())
232            .filter_map(|(opt, i)| opt.clone().map(|name| (name, i)))
233            .collect::<HashMap<_, _>>()
234    }
235}
236
237/// Iterator for generating symbols.
238struct Generate<'a, T: SymbolPrimitive> {
239    source: &'a mut SymbolSource<T>,
240}
241
242impl<'a, T: SymbolPrimitive> Iterator for Generate<'a, T> {
243    type Item = Symbol<T>;
244
245    fn next(&mut self) -> Option<Self::Item> {
246        Some(self.source.next_sym(None))
247    }
248}
249
250mod miniserde_impls {
251    use super::SymbolName;
252    use miniserde::de::{Deserialize, Visitor};
253    use miniserde::{Result, make_place};
254    use miniserde::{Serialize, de, ser};
255    use std::rc::Rc;
256
257    make_place!(Place);
258
259    impl Visitor for Place<SymbolName> {
260        fn string(&mut self, s: &str) -> Result<()> {
261            self.out = Some(SymbolName { name: Rc::from(s) });
262            Ok(())
263        }
264    }
265
266    impl Deserialize for SymbolName {
267        fn begin(out: &mut Option<Self>) -> &mut dyn de::Visitor {
268            Place::new(out)
269        }
270    }
271
272    impl Serialize for SymbolName {
273        fn begin(&self) -> ser::Fragment<'_> {
274            ser::Fragment::Str(self.name.to_string().into())
275        }
276    }
277}