1fad3a1d3Sopenharmony_ciuse proc_macro2::{Delimiter, TokenStream, TokenTree}; 2fad3a1d3Sopenharmony_ciuse std::hash::{Hash, Hasher}; 3fad3a1d3Sopenharmony_ci 4fad3a1d3Sopenharmony_cipub(crate) struct TokenTreeHelper<'a>(pub &'a TokenTree); 5fad3a1d3Sopenharmony_ci 6fad3a1d3Sopenharmony_ciimpl<'a> PartialEq for TokenTreeHelper<'a> { 7fad3a1d3Sopenharmony_ci fn eq(&self, other: &Self) -> bool { 8fad3a1d3Sopenharmony_ci use proc_macro2::Spacing; 9fad3a1d3Sopenharmony_ci 10fad3a1d3Sopenharmony_ci match (self.0, other.0) { 11fad3a1d3Sopenharmony_ci (TokenTree::Group(g1), TokenTree::Group(g2)) => { 12fad3a1d3Sopenharmony_ci match (g1.delimiter(), g2.delimiter()) { 13fad3a1d3Sopenharmony_ci (Delimiter::Parenthesis, Delimiter::Parenthesis) 14fad3a1d3Sopenharmony_ci | (Delimiter::Brace, Delimiter::Brace) 15fad3a1d3Sopenharmony_ci | (Delimiter::Bracket, Delimiter::Bracket) 16fad3a1d3Sopenharmony_ci | (Delimiter::None, Delimiter::None) => {} 17fad3a1d3Sopenharmony_ci _ => return false, 18fad3a1d3Sopenharmony_ci } 19fad3a1d3Sopenharmony_ci 20fad3a1d3Sopenharmony_ci let s1 = g1.stream().into_iter(); 21fad3a1d3Sopenharmony_ci let mut s2 = g2.stream().into_iter(); 22fad3a1d3Sopenharmony_ci 23fad3a1d3Sopenharmony_ci for item1 in s1 { 24fad3a1d3Sopenharmony_ci let item2 = match s2.next() { 25fad3a1d3Sopenharmony_ci Some(item) => item, 26fad3a1d3Sopenharmony_ci None => return false, 27fad3a1d3Sopenharmony_ci }; 28fad3a1d3Sopenharmony_ci if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) { 29fad3a1d3Sopenharmony_ci return false; 30fad3a1d3Sopenharmony_ci } 31fad3a1d3Sopenharmony_ci } 32fad3a1d3Sopenharmony_ci s2.next().is_none() 33fad3a1d3Sopenharmony_ci } 34fad3a1d3Sopenharmony_ci (TokenTree::Punct(o1), TokenTree::Punct(o2)) => { 35fad3a1d3Sopenharmony_ci o1.as_char() == o2.as_char() 36fad3a1d3Sopenharmony_ci && match (o1.spacing(), o2.spacing()) { 37fad3a1d3Sopenharmony_ci (Spacing::Alone, Spacing::Alone) | (Spacing::Joint, Spacing::Joint) => true, 38fad3a1d3Sopenharmony_ci _ => false, 39fad3a1d3Sopenharmony_ci } 40fad3a1d3Sopenharmony_ci } 41fad3a1d3Sopenharmony_ci (TokenTree::Literal(l1), TokenTree::Literal(l2)) => l1.to_string() == l2.to_string(), 42fad3a1d3Sopenharmony_ci (TokenTree::Ident(s1), TokenTree::Ident(s2)) => s1 == s2, 43fad3a1d3Sopenharmony_ci _ => false, 44fad3a1d3Sopenharmony_ci } 45fad3a1d3Sopenharmony_ci } 46fad3a1d3Sopenharmony_ci} 47fad3a1d3Sopenharmony_ci 48fad3a1d3Sopenharmony_ciimpl<'a> Hash for TokenTreeHelper<'a> { 49fad3a1d3Sopenharmony_ci fn hash<H: Hasher>(&self, h: &mut H) { 50fad3a1d3Sopenharmony_ci use proc_macro2::Spacing; 51fad3a1d3Sopenharmony_ci 52fad3a1d3Sopenharmony_ci match self.0 { 53fad3a1d3Sopenharmony_ci TokenTree::Group(g) => { 54fad3a1d3Sopenharmony_ci 0u8.hash(h); 55fad3a1d3Sopenharmony_ci match g.delimiter() { 56fad3a1d3Sopenharmony_ci Delimiter::Parenthesis => 0u8.hash(h), 57fad3a1d3Sopenharmony_ci Delimiter::Brace => 1u8.hash(h), 58fad3a1d3Sopenharmony_ci Delimiter::Bracket => 2u8.hash(h), 59fad3a1d3Sopenharmony_ci Delimiter::None => 3u8.hash(h), 60fad3a1d3Sopenharmony_ci } 61fad3a1d3Sopenharmony_ci 62fad3a1d3Sopenharmony_ci for item in g.stream() { 63fad3a1d3Sopenharmony_ci TokenTreeHelper(&item).hash(h); 64fad3a1d3Sopenharmony_ci } 65fad3a1d3Sopenharmony_ci 0xffu8.hash(h); // terminator w/ a variant we don't normally hash 66fad3a1d3Sopenharmony_ci } 67fad3a1d3Sopenharmony_ci TokenTree::Punct(op) => { 68fad3a1d3Sopenharmony_ci 1u8.hash(h); 69fad3a1d3Sopenharmony_ci op.as_char().hash(h); 70fad3a1d3Sopenharmony_ci match op.spacing() { 71fad3a1d3Sopenharmony_ci Spacing::Alone => 0u8.hash(h), 72fad3a1d3Sopenharmony_ci Spacing::Joint => 1u8.hash(h), 73fad3a1d3Sopenharmony_ci } 74fad3a1d3Sopenharmony_ci } 75fad3a1d3Sopenharmony_ci TokenTree::Literal(lit) => (2u8, lit.to_string()).hash(h), 76fad3a1d3Sopenharmony_ci TokenTree::Ident(word) => (3u8, word).hash(h), 77fad3a1d3Sopenharmony_ci } 78fad3a1d3Sopenharmony_ci } 79fad3a1d3Sopenharmony_ci} 80fad3a1d3Sopenharmony_ci 81fad3a1d3Sopenharmony_cipub(crate) struct TokenStreamHelper<'a>(pub &'a TokenStream); 82fad3a1d3Sopenharmony_ci 83fad3a1d3Sopenharmony_ciimpl<'a> PartialEq for TokenStreamHelper<'a> { 84fad3a1d3Sopenharmony_ci fn eq(&self, other: &Self) -> bool { 85fad3a1d3Sopenharmony_ci let left = self.0.clone().into_iter().collect::<Vec<_>>(); 86fad3a1d3Sopenharmony_ci let right = other.0.clone().into_iter().collect::<Vec<_>>(); 87fad3a1d3Sopenharmony_ci if left.len() != right.len() { 88fad3a1d3Sopenharmony_ci return false; 89fad3a1d3Sopenharmony_ci } 90fad3a1d3Sopenharmony_ci for (a, b) in left.into_iter().zip(right) { 91fad3a1d3Sopenharmony_ci if TokenTreeHelper(&a) != TokenTreeHelper(&b) { 92fad3a1d3Sopenharmony_ci return false; 93fad3a1d3Sopenharmony_ci } 94fad3a1d3Sopenharmony_ci } 95fad3a1d3Sopenharmony_ci true 96fad3a1d3Sopenharmony_ci } 97fad3a1d3Sopenharmony_ci} 98fad3a1d3Sopenharmony_ci 99fad3a1d3Sopenharmony_ciimpl<'a> Hash for TokenStreamHelper<'a> { 100fad3a1d3Sopenharmony_ci fn hash<H: Hasher>(&self, state: &mut H) { 101fad3a1d3Sopenharmony_ci let tts = self.0.clone().into_iter().collect::<Vec<_>>(); 102fad3a1d3Sopenharmony_ci tts.len().hash(state); 103fad3a1d3Sopenharmony_ci for tt in tts { 104fad3a1d3Sopenharmony_ci TokenTreeHelper(&tt).hash(state); 105fad3a1d3Sopenharmony_ci } 106fad3a1d3Sopenharmony_ci } 107fad3a1d3Sopenharmony_ci} 108