1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Source

use symbol::Symbol;
use symbol::repr::{SymbolRepr, FIRST_ID};

/// A source of numeric symbols.
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, Default)]
pub struct SymbolSource {
    next_id: SymbolRepr,
}

impl SymbolSource {
    /// Creates a source of numeric symbols with an empty symbol space.
    pub fn new() -> Self {
        Self::default()
    }
    /// Returns generated symbols.
    pub fn sym<T>(&mut self) -> T
        where T: SymbolContainer
    {
        T::generate(self)
    }
    /// Generates a new unique symbol.
    pub fn next_sym(&mut self) -> Symbol {
        let ret = Symbol::from(self.next_id);
        self.next_id = self.next_id.saturating_add(1 + FIRST_ID) - FIRST_ID;
        ret
    }
    /// Returns the number of symbols in use.
    pub fn num_syms(&self) -> usize {
        self.next_id as usize
    }
    /// Returns an iterator that generates symbols.
    pub fn generate(&mut self) -> Generate {
        Generate { source: self }
    }
}

/// Trait used to generate symbols.
pub trait SymbolContainer {
    /// Generates symbols.
    fn generate(source: &mut SymbolSource) -> Self;
}

macro_rules! impl_generate {
    (Symbol, next_sym, $($T:ident, $next_sym:ident,)*) => (
        impl SymbolContainer for ( Symbol $(, $T)* ) {
            fn generate(source: &mut SymbolSource) -> Self {
                (source.next_sym()
                 $(, source.$next_sym())*)
            }
        }
        impl_generate!($($T, $next_sym,)*);
    );
    // base case
    () => {}
}

impl_generate!(
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
    Symbol, next_sym, Symbol, next_sym, Symbol, next_sym, Symbol, next_sym,
);

/// Iterator for generating symbols.
pub struct Generate<'a> {
    source: &'a mut SymbolSource,
}

impl<'a> Iterator for Generate<'a> {
    type Item = Symbol;

    fn next(&mut self) -> Option<Self::Item> {
        Some(self.source.next_sym())
    }
}