blob: e4f703e8b3852ec6dc94a034c598352d3ad7f2a3 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnayc43b44e2017-12-30 23:55:54 -05009use std::hash::{Hash, Hasher};
10
Alex Crichton9a4dca22018-03-28 06:32:19 -070011use proc_macro2::{Delimiter, TokenStream, TokenTree};
David Tolnaycc543712018-01-08 11:29:54 -080012
David Tolnayc43b44e2017-12-30 23:55:54 -050013pub struct TokenTreeHelper<'a>(pub &'a TokenTree);
14
David Tolnayc43b44e2017-12-30 23:55:54 -050015impl<'a> PartialEq for TokenTreeHelper<'a> {
16 fn eq(&self, other: &Self) -> bool {
17 use proc_macro2::Spacing;
18
Alex Crichton9a4dca22018-03-28 06:32:19 -070019 match (self.0, other.0) {
20 (&TokenTree::Group(ref g1), &TokenTree::Group(ref g2)) => {
21 match (g1.delimiter(), g2.delimiter()) {
David Tolnayc43b44e2017-12-30 23:55:54 -050022 (Delimiter::Parenthesis, Delimiter::Parenthesis)
23 | (Delimiter::Brace, Delimiter::Brace)
24 | (Delimiter::Bracket, Delimiter::Bracket)
25 | (Delimiter::None, Delimiter::None) => {}
26 _ => return false,
27 }
28
Alex Crichton9a4dca22018-03-28 06:32:19 -070029 let s1 = g1.stream().clone().into_iter();
30 let mut s2 = g2.stream().clone().into_iter();
David Tolnayc43b44e2017-12-30 23:55:54 -050031
32 for item1 in s1 {
33 let item2 = match s2.next() {
34 Some(item) => item,
35 None => return false,
36 };
37 if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
38 return false;
39 }
40 }
41 s2.next().is_none()
42 }
Alex Crichtona74a1c82018-05-16 10:20:44 -070043 (&TokenTree::Punct(ref o1), &TokenTree::Punct(ref o2)) => {
44 o1.as_char() == o2.as_char() && match (o1.spacing(), o2.spacing()) {
David Tolnayc43b44e2017-12-30 23:55:54 -050045 (Spacing::Alone, Spacing::Alone) | (Spacing::Joint, Spacing::Joint) => true,
46 _ => false,
47 }
48 }
Alex Crichton9a4dca22018-03-28 06:32:19 -070049 (&TokenTree::Literal(ref l1), &TokenTree::Literal(ref l2)) => {
David Tolnayc43b44e2017-12-30 23:55:54 -050050 l1.to_string() == l2.to_string()
51 }
Alex Crichtona74a1c82018-05-16 10:20:44 -070052 (&TokenTree::Ident(ref s1), &TokenTree::Ident(ref s2)) => s1 == s2,
David Tolnayc43b44e2017-12-30 23:55:54 -050053 _ => false,
54 }
55 }
56}
57
David Tolnayc43b44e2017-12-30 23:55:54 -050058impl<'a> Hash for TokenTreeHelper<'a> {
59 fn hash<H: Hasher>(&self, h: &mut H) {
60 use proc_macro2::Spacing;
61
Alex Crichton9a4dca22018-03-28 06:32:19 -070062 match *self.0 {
63 TokenTree::Group(ref g) => {
David Tolnayc43b44e2017-12-30 23:55:54 -050064 0u8.hash(h);
Alex Crichton9a4dca22018-03-28 06:32:19 -070065 match g.delimiter() {
David Tolnayc43b44e2017-12-30 23:55:54 -050066 Delimiter::Parenthesis => 0u8.hash(h),
67 Delimiter::Brace => 1u8.hash(h),
68 Delimiter::Bracket => 2u8.hash(h),
69 Delimiter::None => 3u8.hash(h),
70 }
71
Alex Crichton9a4dca22018-03-28 06:32:19 -070072 for item in g.stream().clone() {
David Tolnayc43b44e2017-12-30 23:55:54 -050073 TokenTreeHelper(&item).hash(h);
74 }
75 0xffu8.hash(h); // terminator w/ a variant we don't normally hash
76 }
Alex Crichtona74a1c82018-05-16 10:20:44 -070077 TokenTree::Punct(ref op) => {
David Tolnayc43b44e2017-12-30 23:55:54 -050078 1u8.hash(h);
Alex Crichtona74a1c82018-05-16 10:20:44 -070079 op.as_char().hash(h);
Alex Crichton9a4dca22018-03-28 06:32:19 -070080 match op.spacing() {
David Tolnayc43b44e2017-12-30 23:55:54 -050081 Spacing::Alone => 0u8.hash(h),
82 Spacing::Joint => 1u8.hash(h),
83 }
84 }
Alex Crichton9a4dca22018-03-28 06:32:19 -070085 TokenTree::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
Alex Crichtona74a1c82018-05-16 10:20:44 -070086 TokenTree::Ident(ref word) => (3u8, word).hash(h),
David Tolnayc43b44e2017-12-30 23:55:54 -050087 }
88 }
89}
90
David Tolnayc43b44e2017-12-30 23:55:54 -050091pub struct TokenStreamHelper<'a>(pub &'a TokenStream);
92
David Tolnayc43b44e2017-12-30 23:55:54 -050093impl<'a> PartialEq for TokenStreamHelper<'a> {
94 fn eq(&self, other: &Self) -> bool {
95 let left = self.0.clone().into_iter().collect::<Vec<_>>();
96 let right = other.0.clone().into_iter().collect::<Vec<_>>();
97 if left.len() != right.len() {
98 return false;
99 }
100 for (a, b) in left.into_iter().zip(right) {
101 if TokenTreeHelper(&a) != TokenTreeHelper(&b) {
102 return false;
103 }
104 }
105 true
106 }
107}
108
David Tolnayc43b44e2017-12-30 23:55:54 -0500109impl<'a> Hash for TokenStreamHelper<'a> {
110 fn hash<H: Hasher>(&self, state: &mut H) {
111 let tts = self.0.clone().into_iter().collect::<Vec<_>>();
112 tts.len().hash(state);
113 for tt in tts {
114 TokenTreeHelper(&tt).hash(state);
115 }
116 }
117}