1use crate::node::BinOpKind;
7use crate::node::LiteralKind;
8use crate::node::NodeKind;
9use crate::node::NormalizedNode;
10use crate::node::PlaceholderKind;
11use crate::node::UnOpKind;
12use crate::stable_hasher::StableHasher;
13
14pub struct NodeEncoder {
25 hasher: StableHasher,
26}
27
28impl NodeEncoder {
29 #[must_use]
30 pub const fn new() -> Self {
31 Self {
32 hasher: StableHasher::new(),
33 }
34 }
35
36 pub fn encode(&mut self, node: &NormalizedNode) {
38 self.encode_kind(&node.kind);
39 self.hasher.write_u64(node.children.len() as u64);
40 for child in &node.children {
41 self.encode(child);
42 }
43 }
44
45 #[must_use]
47 pub const fn finish(&self) -> u64 {
48 self.hasher.finish()
49 }
50
51 fn encode_kind(&mut self, kind: &NodeKind) {
52 self.hasher.write_str(Self::kind_name(kind));
53 self.encode_payload(kind);
54 }
55
56 fn encode_payload(&mut self, kind: &NodeKind) {
58 match kind {
59 NodeKind::Literal(literal) => self.hasher.write_str(Self::literal_name(literal)),
60 NodeKind::Placeholder(placeholder, index)
61 | NodeKind::PatPlaceholder(placeholder, index)
62 | NodeKind::TypePlaceholder(placeholder, index) => {
63 self.hasher.write_str(Self::placeholder_name(*placeholder));
64 self.hasher.write_u64(*index as u64);
65 }
66 NodeKind::BinaryOp(op) => self.hasher.write_str(Self::bin_op_name(op)),
67 NodeKind::UnaryOp(op) => self.hasher.write_str(Self::un_op_name(op)),
68 NodeKind::Reference { mutable }
69 | NodeKind::PatReference { mutable }
70 | NodeKind::TypeReference { mutable } => self.hasher.write_u8(u8::from(*mutable)),
71 NodeKind::MacroCall { name } => self.hasher.write_str(name),
72 _ => {}
73 }
74 }
75
76 const fn kind_name(kind: &NodeKind) -> &'static str {
77 match kind {
78 NodeKind::Block => "Block",
79 NodeKind::LetBinding => "LetBinding",
80 NodeKind::Semi => "Semi",
81 NodeKind::Paren => "Paren",
82 NodeKind::Literal(..) => "Literal",
83 NodeKind::Placeholder(..) => "Placeholder",
84 NodeKind::BinaryOp(..) => "BinaryOp",
85 NodeKind::UnaryOp(..) => "UnaryOp",
86 NodeKind::Range => "Range",
87 NodeKind::Call => "Call",
88 NodeKind::MethodCall => "MethodCall",
89 NodeKind::FieldAccess => "FieldAccess",
90 NodeKind::Index => "Index",
91 NodeKind::Path => "Path",
92 NodeKind::Closure => "Closure",
93 NodeKind::FnSignature => "FnSignature",
94 NodeKind::Return => "Return",
95 NodeKind::Break => "Break",
96 NodeKind::Continue => "Continue",
97 NodeKind::Assign => "Assign",
98 NodeKind::Reference { .. } => "Reference",
99 NodeKind::Tuple => "Tuple",
100 NodeKind::Array => "Array",
101 NodeKind::Set => "Set",
102 NodeKind::Repeat => "Repeat",
103 NodeKind::Cast => "Cast",
104 NodeKind::StructInit => "StructInit",
105 NodeKind::Await => "Await",
106 NodeKind::Yield => "Yield",
107 NodeKind::Try => "Try",
108 NodeKind::If => "If",
109 NodeKind::Match => "Match",
110 NodeKind::MatchArm => "MatchArm",
111 NodeKind::Loop => "Loop",
112 NodeKind::While => "While",
113 NodeKind::ForLoop => "ForLoop",
114 NodeKind::LetExpr => "LetExpr",
115 NodeKind::PatWild => "PatWild",
116 NodeKind::PatPlaceholder(..) => "PatPlaceholder",
117 NodeKind::PatTuple => "PatTuple",
118 NodeKind::PatStruct => "PatStruct",
119 NodeKind::PatOr => "PatOr",
120 NodeKind::PatLiteral => "PatLiteral",
121 NodeKind::PatReference { .. } => "PatReference",
122 NodeKind::PatSlice => "PatSlice",
123 NodeKind::PatRest => "PatRest",
124 NodeKind::PatRange => "PatRange",
125 NodeKind::TypePlaceholder(..) => "TypePlaceholder",
126 NodeKind::TypeReference { .. } => "TypeReference",
127 NodeKind::TypeTuple => "TypeTuple",
128 NodeKind::TypeSlice => "TypeSlice",
129 NodeKind::TypeArray => "TypeArray",
130 NodeKind::TypePath => "TypePath",
131 NodeKind::TypeImplTrait => "TypeImplTrait",
132 NodeKind::TypeInfer => "TypeInfer",
133 NodeKind::TypeUnit => "TypeUnit",
134 NodeKind::TypeNever => "TypeNever",
135 NodeKind::FieldValue => "FieldValue",
136 NodeKind::MacroCall { .. } => "MacroCall",
137 NodeKind::Opaque => "Opaque",
138 NodeKind::None => "None",
139 }
140 }
141
142 const fn literal_name(literal: &LiteralKind) -> &'static str {
143 match literal {
144 LiteralKind::Int => "Int",
145 LiteralKind::Float => "Float",
146 LiteralKind::Str => "Str",
147 LiteralKind::ByteStr => "ByteStr",
148 LiteralKind::CStr => "CStr",
149 LiteralKind::Byte => "Byte",
150 LiteralKind::Char => "Char",
151 LiteralKind::Bool => "Bool",
152 LiteralKind::Null => "Null",
153 }
154 }
155
156 const fn placeholder_name(placeholder: PlaceholderKind) -> &'static str {
157 match placeholder {
158 PlaceholderKind::Variable => "Variable",
159 PlaceholderKind::Function => "Function",
160 PlaceholderKind::Type => "Type",
161 PlaceholderKind::Lifetime => "Lifetime",
162 PlaceholderKind::Label => "Label",
163 }
164 }
165
166 const fn bin_op_name(op: &BinOpKind) -> &'static str {
167 match op {
168 BinOpKind::Add => "Add",
169 BinOpKind::Sub => "Sub",
170 BinOpKind::Mul => "Mul",
171 BinOpKind::Div => "Div",
172 BinOpKind::Rem => "Rem",
173 BinOpKind::And => "And",
174 BinOpKind::Or => "Or",
175 BinOpKind::BitXor => "BitXor",
176 BinOpKind::BitAnd => "BitAnd",
177 BinOpKind::BitOr => "BitOr",
178 BinOpKind::Shl => "Shl",
179 BinOpKind::Shr => "Shr",
180 BinOpKind::Eq => "Eq",
181 BinOpKind::Lt => "Lt",
182 BinOpKind::Le => "Le",
183 BinOpKind::Ne => "Ne",
184 BinOpKind::Ge => "Ge",
185 BinOpKind::Gt => "Gt",
186 BinOpKind::AddAssign => "AddAssign",
187 BinOpKind::SubAssign => "SubAssign",
188 BinOpKind::MulAssign => "MulAssign",
189 BinOpKind::DivAssign => "DivAssign",
190 BinOpKind::RemAssign => "RemAssign",
191 BinOpKind::BitXorAssign => "BitXorAssign",
192 BinOpKind::BitAndAssign => "BitAndAssign",
193 BinOpKind::BitOrAssign => "BitOrAssign",
194 BinOpKind::ShlAssign => "ShlAssign",
195 BinOpKind::ShrAssign => "ShrAssign",
196 BinOpKind::FloorDiv => "FloorDiv",
197 BinOpKind::Pow => "Pow",
198 BinOpKind::In => "In",
199 BinOpKind::NotIn => "NotIn",
200 BinOpKind::Is => "Is",
201 BinOpKind::IsNot => "IsNot",
202 BinOpKind::FloorDivAssign => "FloorDivAssign",
203 BinOpKind::PowAssign => "PowAssign",
204 BinOpKind::Other => "Other",
205 }
206 }
207
208 const fn un_op_name(op: &UnOpKind) -> &'static str {
209 match op {
210 UnOpKind::Deref => "Deref",
211 UnOpKind::Not => "Not",
212 UnOpKind::Neg => "Neg",
213 UnOpKind::Other => "Other",
214 }
215 }
216}
217
218impl Default for NodeEncoder {
219 fn default() -> Self {
220 Self::new()
221 }
222}