1 use crate::util::ToIdent; 2 use proc_macro2::{Literal, TokenStream}; 3 use quote::{quote, ToTokens}; 4 use syn::Ident; 5 6 pub struct TableStack { 7 tables: Vec<(Ident, [u8; 256])>, 8 shift: u8, 9 } 10 11 pub struct TableView<'a> { 12 ident: &'a Ident, 13 table: &'a mut [u8; 256], 14 mask: u8, 15 } 16 17 impl TableStack { new() -> Self18 pub fn new() -> Self { 19 TableStack { 20 tables: vec![("COMPACT_TABLE_0".to_ident(), [0; 256])], 21 shift: 0, 22 } 23 } 24 view(&mut self) -> TableView25 pub fn view(&mut self) -> TableView { 26 let mask = if self.shift < 8 { 27 // Reusing existing table with a shifted mask 28 let mask = 1u8 << self.shift; 29 30 self.shift += 1; 31 32 mask 33 } else { 34 // Need to create a new table 35 let ident = format!("COMPACT_TABLE_{}", self.tables.len()).to_ident(); 36 37 self.tables.push((ident, [0; 256])); 38 self.shift = 1; 39 40 1 41 }; 42 43 let (ref ident, ref mut table) = self.tables.last_mut().unwrap(); 44 45 TableView { ident, table, mask } 46 } 47 } 48 49 impl<'a> TableView<'a> { ident(&self) -> &'a Ident50 pub fn ident(&self) -> &'a Ident { 51 self.ident 52 } 53 flag(&mut self, byte: u8)54 pub fn flag(&mut self, byte: u8) { 55 self.table[byte as usize] |= self.mask; 56 } 57 mask(&self) -> Literal58 pub fn mask(&self) -> Literal { 59 Literal::u8_unsuffixed(self.mask) 60 } 61 } 62 63 impl ToTokens for TableStack { to_tokens(&self, out: &mut TokenStream)64 fn to_tokens(&self, out: &mut TokenStream) { 65 if self.shift == 0 { 66 return; 67 } 68 69 for (ident, table) in self.tables.iter() { 70 let bytes = table.iter().copied().map(Literal::u8_unsuffixed); 71 72 out.extend(quote! { 73 static #ident: [u8; 256] = [#(#bytes),*]; 74 }); 75 } 76 } 77 } 78