diff options
Diffstat (limited to 'xtask')
-rw-r--r-- | xtask/Cargo.toml | 3 | ||||
-rw-r--r-- | xtask/src/ast_src.rs | 22 | ||||
-rw-r--r-- | xtask/src/codegen/gen_syntax.rs | 87 | ||||
-rw-r--r-- | xtask/src/codegen/rust.ungram | 621 | ||||
-rw-r--r-- | xtask/src/metrics.rs | 132 |
5 files changed, 416 insertions, 449 deletions
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 8140da87f..1a1140b04 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml | |||
@@ -15,5 +15,6 @@ flate2 = "1.0" | |||
15 | pico-args = "0.3.1" | 15 | pico-args = "0.3.1" |
16 | proc-macro2 = "1.0.8" | 16 | proc-macro2 = "1.0.8" |
17 | quote = "1.0.2" | 17 | quote = "1.0.2" |
18 | ungrammar = "0.1.0" | 18 | ungrammar = "1.1.1" |
19 | walkdir = "2.3.1" | 19 | walkdir = "2.3.1" |
20 | write-json = "0.1.0" | ||
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index 114898e38..adc191254 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs | |||
@@ -113,12 +113,12 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
113 | "TUPLE_TYPE", | 113 | "TUPLE_TYPE", |
114 | "NEVER_TYPE", | 114 | "NEVER_TYPE", |
115 | "PATH_TYPE", | 115 | "PATH_TYPE", |
116 | "POINTER_TYPE", | 116 | "PTR_TYPE", |
117 | "ARRAY_TYPE", | 117 | "ARRAY_TYPE", |
118 | "SLICE_TYPE", | 118 | "SLICE_TYPE", |
119 | "REFERENCE_TYPE", | 119 | "REF_TYPE", |
120 | "PLACEHOLDER_TYPE", | 120 | "INFER_TYPE", |
121 | "FN_POINTER_TYPE", | 121 | "FN_PTR_TYPE", |
122 | "FOR_TYPE", | 122 | "FOR_TYPE", |
123 | "IMPL_TRAIT_TYPE", | 123 | "IMPL_TRAIT_TYPE", |
124 | "DYN_TRAIT_TYPE", | 124 | "DYN_TRAIT_TYPE", |
@@ -126,13 +126,13 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
126 | "PAREN_PAT", | 126 | "PAREN_PAT", |
127 | "REF_PAT", | 127 | "REF_PAT", |
128 | "BOX_PAT", | 128 | "BOX_PAT", |
129 | "BIND_PAT", | 129 | "IDENT_PAT", |
130 | "PLACEHOLDER_PAT", | 130 | "WILDCARD_PAT", |
131 | "DOT_DOT_PAT", | 131 | "REST_PAT", |
132 | "PATH_PAT", | 132 | "PATH_PAT", |
133 | "RECORD_PAT", | 133 | "RECORD_PAT", |
134 | "RECORD_FIELD_PAT_LIST", | 134 | "RECORD_PAT_FIELD_LIST", |
135 | "RECORD_FIELD_PAT", | 135 | "RECORD_PAT_FIELD", |
136 | "TUPLE_STRUCT_PAT", | 136 | "TUPLE_STRUCT_PAT", |
137 | "TUPLE_PAT", | 137 | "TUPLE_PAT", |
138 | "SLICE_PAT", | 138 | "SLICE_PAT", |
@@ -144,7 +144,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
144 | "ARRAY_EXPR", | 144 | "ARRAY_EXPR", |
145 | "PAREN_EXPR", | 145 | "PAREN_EXPR", |
146 | "PATH_EXPR", | 146 | "PATH_EXPR", |
147 | "LAMBDA_EXPR", | 147 | "CLOSURE_EXPR", |
148 | "IF_EXPR", | 148 | "IF_EXPR", |
149 | "WHILE_EXPR", | 149 | "WHILE_EXPR", |
150 | "CONDITION", | 150 | "CONDITION", |
@@ -208,7 +208,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
208 | "LIFETIME_PARAM", | 208 | "LIFETIME_PARAM", |
209 | "TYPE_PARAM", | 209 | "TYPE_PARAM", |
210 | "CONST_PARAM", | 210 | "CONST_PARAM", |
211 | "TYPE_ARG_LIST", | 211 | "GENERIC_ARG_LIST", |
212 | "LIFETIME_ARG", | 212 | "LIFETIME_ARG", |
213 | "TYPE_ARG", | 213 | "TYPE_ARG", |
214 | "ASSOC_TYPE_ARG", | 214 | "ASSOC_TYPE_ARG", |
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index 45b788bdb..cafad8070 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs | |||
@@ -10,7 +10,7 @@ use std::{ | |||
10 | 10 | ||
11 | use proc_macro2::{Punct, Spacing}; | 11 | use proc_macro2::{Punct, Spacing}; |
12 | use quote::{format_ident, quote}; | 12 | use quote::{format_ident, quote}; |
13 | use ungrammar::{Grammar, Rule}; | 13 | use ungrammar::{rust_grammar, Grammar, Rule}; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC}, | 16 | ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC}, |
@@ -19,9 +19,7 @@ use crate::{ | |||
19 | }; | 19 | }; |
20 | 20 | ||
21 | pub fn generate_syntax(mode: Mode) -> Result<()> { | 21 | pub fn generate_syntax(mode: Mode) -> Result<()> { |
22 | let grammar = include_str!("rust.ungram") | 22 | let grammar = rust_grammar(); |
23 | .parse::<Grammar>() | ||
24 | .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err)); | ||
25 | let ast = lower(&grammar); | 23 | let ast = lower(&grammar); |
26 | 24 | ||
27 | let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); | 25 | let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); |
@@ -153,25 +151,10 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> { | |||
153 | quote!(impl ast::#trait_name for #name {}) | 151 | quote!(impl ast::#trait_name for #name {}) |
154 | }); | 152 | }); |
155 | 153 | ||
156 | ( | 154 | let ast_node = if en.name == "Stmt" { |
155 | quote! {} | ||
156 | } else { | ||
157 | quote! { | 157 | quote! { |
158 | #[pretty_doc_comment_placeholder_workaround] | ||
159 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
160 | pub enum #name { | ||
161 | #(#variants(#variants),)* | ||
162 | } | ||
163 | |||
164 | #(#traits)* | ||
165 | }, | ||
166 | quote! { | ||
167 | #( | ||
168 | impl From<#variants> for #name { | ||
169 | fn from(node: #variants) -> #name { | ||
170 | #name::#variants(node) | ||
171 | } | ||
172 | } | ||
173 | )* | ||
174 | |||
175 | impl AstNode for #name { | 158 | impl AstNode for #name { |
176 | fn can_cast(kind: SyntaxKind) -> bool { | 159 | fn can_cast(kind: SyntaxKind) -> bool { |
177 | match kind { | 160 | match kind { |
@@ -196,6 +179,28 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> { | |||
196 | } | 179 | } |
197 | } | 180 | } |
198 | } | 181 | } |
182 | } | ||
183 | }; | ||
184 | |||
185 | ( | ||
186 | quote! { | ||
187 | #[pretty_doc_comment_placeholder_workaround] | ||
188 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
189 | pub enum #name { | ||
190 | #(#variants(#variants),)* | ||
191 | } | ||
192 | |||
193 | #(#traits)* | ||
194 | }, | ||
195 | quote! { | ||
196 | #( | ||
197 | impl From<#variants> for #name { | ||
198 | fn from(node: #variants) -> #name { | ||
199 | #name::#variants(node) | ||
200 | } | ||
201 | } | ||
202 | )* | ||
203 | #ast_node | ||
199 | }, | 204 | }, |
200 | ) | 205 | ) |
201 | }) | 206 | }) |
@@ -476,7 +481,13 @@ impl Field { | |||
476 | }; | 481 | }; |
477 | format_ident!("{}_token", name) | 482 | format_ident!("{}_token", name) |
478 | } | 483 | } |
479 | Field::Node { name, .. } => format_ident!("{}", name), | 484 | Field::Node { name, .. } => { |
485 | if name == "type" { | ||
486 | format_ident!("ty") | ||
487 | } else { | ||
488 | format_ident!("{}", name) | ||
489 | } | ||
490 | } | ||
480 | } | 491 | } |
481 | } | 492 | } |
482 | fn ty(&self) -> proc_macro2::Ident { | 493 | fn ty(&self) -> proc_macro2::Ident { |
@@ -491,13 +502,7 @@ fn lower(grammar: &Grammar) -> AstSrc { | |||
491 | let mut res = AstSrc::default(); | 502 | let mut res = AstSrc::default(); |
492 | res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()]; | 503 | res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()]; |
493 | 504 | ||
494 | let nodes = grammar | 505 | let nodes = grammar.iter().collect::<Vec<_>>(); |
495 | .iter() | ||
496 | .filter(|&node| match grammar[node].rule { | ||
497 | Rule::Node(it) if it == node => false, | ||
498 | _ => true, | ||
499 | }) | ||
500 | .collect::<Vec<_>>(); | ||
501 | 506 | ||
502 | for &node in &nodes { | 507 | for &node in &nodes { |
503 | let name = grammar[node].name.clone(); | 508 | let name = grammar[node].name.clone(); |
@@ -531,6 +536,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> { | |||
531 | for alternative in alternatives { | 536 | for alternative in alternatives { |
532 | match alternative { | 537 | match alternative { |
533 | Rule::Node(it) => variants.push(grammar[*it].name.clone()), | 538 | Rule::Node(it) => variants.push(grammar[*it].name.clone()), |
539 | Rule::Token(it) if grammar[*it].name == ";" => (), | ||
534 | _ => return None, | 540 | _ => return None, |
535 | } | 541 | } |
536 | } | 542 | } |
@@ -572,6 +578,24 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r | |||
572 | } | 578 | } |
573 | Rule::Labeled { label: l, rule } => { | 579 | Rule::Labeled { label: l, rule } => { |
574 | assert!(label.is_none()); | 580 | assert!(label.is_none()); |
581 | let manually_implemented = matches!( | ||
582 | l.as_str(), | ||
583 | "lhs" | ||
584 | | "rhs" | ||
585 | | "then_branch" | ||
586 | | "else_branch" | ||
587 | | "start" | ||
588 | | "end" | ||
589 | | "op" | ||
590 | | "index" | ||
591 | | "base" | ||
592 | | "value" | ||
593 | | "trait" | ||
594 | | "self_ty" | ||
595 | ); | ||
596 | if manually_implemented { | ||
597 | return; | ||
598 | } | ||
575 | lower_rule(acc, grammar, Some(l), rule); | 599 | lower_rule(acc, grammar, Some(l), rule); |
576 | } | 600 | } |
577 | Rule::Seq(rules) | Rule::Alt(rules) => { | 601 | Rule::Seq(rules) | Rule::Alt(rules) => { |
@@ -687,6 +711,9 @@ fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str | |||
687 | 711 | ||
688 | fn extract_enum_traits(ast: &mut AstSrc) { | 712 | fn extract_enum_traits(ast: &mut AstSrc) { |
689 | for enm in &mut ast.enums { | 713 | for enm in &mut ast.enums { |
714 | if enm.name == "Stmt" { | ||
715 | continue; | ||
716 | } | ||
690 | let nodes = &ast.nodes; | 717 | let nodes = &ast.nodes; |
691 | let mut variant_traits = enm | 718 | let mut variant_traits = enm |
692 | .variants | 719 | .variants |
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram index 375df301f..aca23890c 100644 --- a/xtask/src/codegen/rust.ungram +++ b/xtask/src/codegen/rust.ungram | |||
@@ -1,3 +1,63 @@ | |||
1 | //*************************// | ||
2 | // Names, Paths and Macros // | ||
3 | //*************************// | ||
4 | |||
5 | Name = | ||
6 | 'ident' | ||
7 | |||
8 | NameRef = | ||
9 | 'ident' | 'int_number' | ||
10 | |||
11 | Path = | ||
12 | (qualifier:Path '::')? segment:PathSegment | ||
13 | |||
14 | PathSegment = | ||
15 | 'crate' | 'self' | 'super' | ||
16 | | '::' NameRef | ||
17 | | NameRef GenericArgList? | ||
18 | | NameRef ParamList RetType? | ||
19 | | '<' PathType ('as' PathType)? '>' | ||
20 | |||
21 | GenericArgList = | ||
22 | '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' | ||
23 | |||
24 | GenericArg = | ||
25 | TypeArg | ||
26 | | AssocTypeArg | ||
27 | | LifetimeArg | ||
28 | | ConstArg | ||
29 | |||
30 | TypeArg = | ||
31 | Type | ||
32 | |||
33 | AssocTypeArg = | ||
34 | NameRef (':' TypeBoundList | '=' Type) | ||
35 | |||
36 | LifetimeArg = | ||
37 | 'lifetime' | ||
38 | |||
39 | ConstArg = | ||
40 | Expr | ||
41 | |||
42 | MacroCall = | ||
43 | Attr* Path '!' Name? TokenTree ';'? | ||
44 | |||
45 | TokenTree = | ||
46 | '(' ')' | ||
47 | | '{' '}' | ||
48 | | '[' ']' | ||
49 | |||
50 | MacroItems = | ||
51 | Item* | ||
52 | |||
53 | MacroStmts = | ||
54 | statements:Stmt* | ||
55 | Expr? | ||
56 | |||
57 | //*************************// | ||
58 | // Items // | ||
59 | //*************************// | ||
60 | |||
1 | SourceFile = | 61 | SourceFile = |
2 | 'shebang'? | 62 | 'shebang'? |
3 | Attr* | 63 | Attr* |
@@ -61,22 +121,22 @@ ParamList = | |||
61 | SelfParam = | 121 | SelfParam = |
62 | Attr* ( | 122 | Attr* ( |
63 | ('&' 'lifetime'?)? 'mut'? 'self' | 123 | ('&' 'lifetime'?)? 'mut'? 'self' |
64 | | 'mut'? 'self' ':' ty:TypeRef | 124 | | 'mut'? 'self' ':' Type |
65 | ) | 125 | ) |
66 | 126 | ||
67 | Param = | 127 | Param = |
68 | Attr* ( | 128 | Attr* ( |
69 | Pat (':' ty:TypeRef) | 129 | Pat (':' Type) |
70 | | ty:TypeRef | 130 | | Type |
71 | | '...' | 131 | | '...' |
72 | ) | 132 | ) |
73 | 133 | ||
74 | RetType = | 134 | RetType = |
75 | '->' ty:TypeRef | 135 | '->' Type |
76 | 136 | ||
77 | TypeAlias = | 137 | TypeAlias = |
78 | Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause? | 138 | Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause? |
79 | '=' ty:TypeRef ';' | 139 | '=' Type ';' |
80 | 140 | ||
81 | Struct = | 141 | Struct = |
82 | Attr* Visibility? 'struct' Name GenericParamList? ( | 142 | Attr* Visibility? 'struct' Name GenericParamList? ( |
@@ -88,13 +148,13 @@ RecordFieldList = | |||
88 | '{' fields:(RecordField (',' RecordField)* ','?)? '}' | 148 | '{' fields:(RecordField (',' RecordField)* ','?)? '}' |
89 | 149 | ||
90 | RecordField = | 150 | RecordField = |
91 | Attr* Visibility? Name ':' ty:TypeRef | 151 | Attr* Visibility? Name ':' Type |
92 | 152 | ||
93 | TupleFieldList = | 153 | TupleFieldList = |
94 | '(' fields:(TupleField (',' TupleField)* ','?)? ')' | 154 | '(' fields:(TupleField (',' TupleField)* ','?)? ')' |
95 | 155 | ||
96 | TupleField = | 156 | TupleField = |
97 | Attr* Visibility? ty:TypeRef | 157 | Attr* Visibility? Type |
98 | 158 | ||
99 | FieldList = | 159 | FieldList = |
100 | RecordFieldList | 160 | RecordFieldList |
@@ -114,12 +174,17 @@ Union = | |||
114 | Attr* Visibility? 'union' Name GenericParamList? WhereClause? | 174 | Attr* Visibility? 'union' Name GenericParamList? WhereClause? |
115 | RecordFieldList | 175 | RecordFieldList |
116 | 176 | ||
177 | AdtDef = | ||
178 | Enum | ||
179 | | Struct | ||
180 | | Union | ||
181 | |||
117 | Const = | 182 | Const = |
118 | Attr* Visibility? 'default'? 'const' (Name | '_') ':' ty:TypeRef | 183 | Attr* Visibility? 'default'? 'const' (Name | '_') ':' Type |
119 | '=' body:Expr ';' | 184 | '=' body:Expr ';' |
120 | 185 | ||
121 | Static = | 186 | Static = |
122 | Attr* Visibility? 'static'? 'mut'? Name ':' ty:TypeRef | 187 | Attr* Visibility? 'static'? 'mut'? Name ':' Type |
123 | '=' body:Expr ';' | 188 | '=' body:Expr ';' |
124 | 189 | ||
125 | Trait = | 190 | Trait = |
@@ -131,18 +196,17 @@ AssocItemList = | |||
131 | '{' Attr* AssocItem* '}' | 196 | '{' Attr* AssocItem* '}' |
132 | 197 | ||
133 | AssocItem = | 198 | AssocItem = |
134 | Fn | 199 | Const |
135 | | TypeAlias | 200 | | Fn |
136 | | Const | ||
137 | | MacroCall | 201 | | MacroCall |
202 | | TypeAlias | ||
138 | 203 | ||
139 | Impl = | 204 | Impl = |
140 | Attr* Visibility? | 205 | Attr* Visibility? |
141 | 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? ( | 206 | 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? |
142 | TypeRef | 207 | ('!'? target_trait:Type 'for')? target_type:Type |
143 | | '!'? TypeRef 'for' TypeRef | 208 | WhereClause? |
144 | ) WhereClause? | 209 | AssocItemList |
145 | AssocItemList | ||
146 | 210 | ||
147 | ExternBlock = | 211 | ExternBlock = |
148 | Attr* Abi ExternItemList | 212 | Attr* Abi ExternItemList |
@@ -157,20 +221,26 @@ GenericParamList = | |||
157 | '<' (GenericParam (',' GenericParam)* ','?)? '>' | 221 | '<' (GenericParam (',' GenericParam)* ','?)? '>' |
158 | 222 | ||
159 | GenericParam = | 223 | GenericParam = |
160 | LifetimeParam | 224 | ConstParam |
225 | | LifetimeParam | ||
161 | | TypeParam | 226 | | TypeParam |
162 | | ConstParam | ||
163 | 227 | ||
164 | TypeParam = | 228 | TypeParam = |
165 | Attr* Name (':' TypeBoundList?)? | 229 | Attr* Name (':' TypeBoundList?)? |
166 | ('=' default_type:TypeRef)? | 230 | ('=' default_type:Type)? |
167 | 231 | ||
168 | ConstParam = | 232 | ConstParam = |
169 | Attr* 'const' Name ':' ty:TypeRef | 233 | Attr* 'const' Name ':' Type |
170 | ('=' default_val:Expr)? | 234 | ('=' default_val:Expr)? |
171 | 235 | ||
172 | LifetimeParam = | 236 | LifetimeParam = |
173 | Attr* 'lifetime' | 237 | Attr* 'lifetime' (':' TypeBoundList?)? |
238 | |||
239 | WhereClause = | ||
240 | 'where' predicates:(WherePred (',' WherePred)* ','?) | ||
241 | |||
242 | WherePred = | ||
243 | ('for' GenericParamList)? ('lifetime' | Type) ':' TypeBoundList | ||
174 | 244 | ||
175 | Visibility = | 245 | Visibility = |
176 | 'pub' ('(' | 246 | 'pub' ('(' |
@@ -183,362 +253,335 @@ Visibility = | |||
183 | Attr = | 253 | Attr = |
184 | '#' '!'? '[' Path ('=' Literal | TokenTree)? ']' | 254 | '#' '!'? '[' Path ('=' Literal | TokenTree)? ']' |
185 | 255 | ||
186 | ParenType = | 256 | //****************************// |
187 | '(' ty:TypeRef ')' | 257 | // Statements and Expressions // |
258 | //****************************// | ||
188 | 259 | ||
189 | TupleType = | 260 | Stmt = |
190 | '(' fields:TypeRef* ')' | 261 | ExprStmt |
262 | | Item | ||
263 | | LetStmt | ||
191 | 264 | ||
192 | NeverType = | 265 | LetStmt = |
193 | '!' | 266 | Attr* 'let' Pat (':' Type)? |
267 | '=' initializer:Expr ';' | ||
194 | 268 | ||
195 | PathType = | 269 | ExprStmt = |
196 | Path | 270 | Attr* Expr ';'? |
197 | 271 | ||
198 | PointerType = | 272 | Expr = |
199 | '*' ('const' | 'mut') ty:TypeRef | 273 | ArrayExpr |
274 | | AwaitExpr | ||
275 | | BinExpr | ||
276 | | BlockExpr | ||
277 | | BoxExpr | ||
278 | | BreakExpr | ||
279 | | CallExpr | ||
280 | | CastExpr | ||
281 | | ClosureExpr | ||
282 | | ContinueExpr | ||
283 | | EffectExpr | ||
284 | | FieldExpr | ||
285 | | ForExpr | ||
286 | | IfExpr | ||
287 | | IndexExpr | ||
288 | | Literal | ||
289 | | LoopExpr | ||
290 | | MacroCall | ||
291 | | MatchExpr | ||
292 | | MethodCallExpr | ||
293 | | ParenExpr | ||
294 | | PathExpr | ||
295 | | PrefixExpr | ||
296 | | RangeExpr | ||
297 | | RecordExpr | ||
298 | | RefExpr | ||
299 | | ReturnExpr | ||
300 | | TryExpr | ||
301 | | TupleExpr | ||
302 | | WhileExpr | ||
200 | 303 | ||
201 | ArrayType = | 304 | Literal = |
202 | '[' ty:TypeRef ';' Expr ']' | 305 | Attr* value:( |
306 | 'int_number' | 'float_number' | ||
307 | | 'string' | 'raw_string' | ||
308 | | 'byte_string' | 'raw_byte_string' | ||
309 | | 'true' | 'false' | ||
310 | | 'char' | 'byte' | ||
311 | ) | ||
203 | 312 | ||
204 | SliceType = | 313 | PathExpr = |
205 | '[' ty:TypeRef ']' | 314 | Attr* Path |
206 | 315 | ||
207 | ReferenceType = | 316 | BlockExpr = |
208 | '&' 'lifetime'? 'mut'? ty:TypeRef | 317 | '{' |
318 | Attr* | ||
319 | statements:Stmt* | ||
320 | Expr? | ||
321 | '}' | ||
209 | 322 | ||
210 | PlaceholderType = | 323 | RefExpr = |
211 | '_' | 324 | Attr* '&' ('raw' |'mut' | 'const') Expr |
212 | 325 | ||
213 | FnPointerType = | 326 | TryExpr = |
214 | Abi 'unsafe'? 'fn' ParamList RetType? | 327 | Attr* Expr '?' |
215 | 328 | ||
216 | ForType = | 329 | EffectExpr = |
217 | 'for' GenericParamList ty:TypeRef | 330 | Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr |
218 | 331 | ||
219 | ImplTraitType = | 332 | PrefixExpr = |
220 | 'impl' TypeBoundList | 333 | Attr* op:('-' | '!' | '*') Expr |
221 | 334 | ||
222 | DynTraitType = | 335 | BinExpr = |
223 | 'dyn' TypeBoundList | 336 | Attr* |
337 | lhs:Expr | ||
338 | op:( | ||
339 | '||' | '&&' | ||
340 | | '==' | '!=' | '<=' | '>=' | '<' | '>' | ||
341 | | '+' | '*' | '-' | '/' | '%' | '<<' | '>>' | '^' | '|' | '&' | ||
342 | | '=' | '+=' | '/=' | '*=' | '%=' | '>>=' | '<<=' | '-=' | '|=' | '&=' | '^=' | ||
343 | ) | ||
344 | rhs:Expr | ||
224 | 345 | ||
225 | TupleExpr = | 346 | CastExpr = |
226 | Attr* '(' Expr* ')' | 347 | Attr* Expr 'as' Type |
348 | |||
349 | ParenExpr = | ||
350 | Attr* '(' Attr* Expr ')' | ||
227 | 351 | ||
228 | ArrayExpr = | 352 | ArrayExpr = |
229 | Attr* '[' (Expr* | Expr ';' Expr) ']' | 353 | Attr* '[' Attr* ( |
354 | (Expr (',' Expr)* ','?)? | ||
355 | | Expr ';' Expr | ||
356 | ) ']' | ||
230 | 357 | ||
231 | ParenExpr = | 358 | IndexExpr = |
232 | Attr* '(' Expr ')' | 359 | Attr* base:Expr '[' index:Expr ']' |
233 | 360 | ||
234 | PathExpr = | 361 | TupleExpr = |
235 | Path | 362 | Attr* '(' Attr* fields:(Expr (',' Expr)* ','?)? ')' |
363 | |||
364 | RecordExpr = | ||
365 | Path RecordExprFieldList | ||
366 | |||
367 | RecordExprFieldList = | ||
368 | '{' | ||
369 | Attr* | ||
370 | fields:(RecordExprField (',' RecordExprField)* ','?) | ||
371 | ('..' spread:Expr)? | ||
372 | '}' | ||
373 | |||
374 | RecordExprField = | ||
375 | Attr* NameRef (':' Expr)? | ||
376 | |||
377 | CallExpr = | ||
378 | Attr* Expr ArgList | ||
379 | |||
380 | ArgList = | ||
381 | '(' args:(Expr (',' Expr)* ','?)? ')' | ||
382 | |||
383 | MethodCallExpr = | ||
384 | Attr* Expr '.' NameRef GenericArgList? ArgList | ||
385 | |||
386 | FieldExpr = | ||
387 | Attr* Expr '.' NameRef | ||
236 | 388 | ||
237 | LambdaExpr = | 389 | ClosureExpr = |
238 | Attr* 'static'? 'async'? 'move'? ParamList RetType? | 390 | Attr* 'static'? 'async'? 'move'? ParamList RetType? |
239 | body:Expr | 391 | body:Expr |
240 | 392 | ||
241 | IfExpr = | 393 | IfExpr = |
242 | Attr* 'if' Condition | 394 | Attr* 'if' Condition then_branch:BlockExpr |
395 | ('else' else_branch:(IfExpr | BlockExpr))? | ||
243 | 396 | ||
244 | Condition = | 397 | Condition = |
245 | 'let' Pat '=' Expr | 398 | 'let' Pat '=' Expr |
246 | | Expr | 399 | | Expr |
247 | 400 | ||
248 | EffectExpr = | ||
249 | Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr | ||
250 | |||
251 | LoopExpr = | 401 | LoopExpr = |
252 | Attr* Label? 'loop' | 402 | Attr* Label? 'loop' |
253 | loop_body:BlockExpr? | 403 | loop_body:BlockExpr |
254 | 404 | ||
255 | ForExpr = | 405 | ForExpr = |
256 | Attr* Label? 'for' Pat 'in' iterable:Expr | 406 | Attr* Label? 'for' Pat 'in' iterable:Expr |
257 | loop_body:BlockExpr? | 407 | loop_body:BlockExpr |
258 | 408 | ||
259 | WhileExpr = | 409 | WhileExpr = |
260 | Attr* Label? 'while' Condition | 410 | Attr* Label? 'while' Condition |
261 | loop_body:BlockExpr? | 411 | loop_body:BlockExpr |
262 | 412 | ||
263 | ContinueExpr = | 413 | Label = |
264 | Attr* 'continue' 'lifetime'? | 414 | 'lifetime' |
265 | 415 | ||
266 | BreakExpr = | 416 | BreakExpr = |
267 | Attr* 'break' 'lifetime'? Expr? | 417 | Attr* 'break' 'lifetime'? Expr? |
268 | 418 | ||
269 | Label = | 419 | ContinueExpr = |
270 | 'lifetime' | 420 | Attr* 'continue' 'lifetime'? |
271 | |||
272 | BlockExpr = | ||
273 | Attr* Label | ||
274 | '{' | ||
275 | Item* | ||
276 | statements:Stmt* | ||
277 | Expr? | ||
278 | '}' | ||
279 | 421 | ||
280 | ReturnExpr = | 422 | RangeExpr = |
281 | Attr* 'return' Expr | 423 | Attr* start:Expr? op:('..' | '..=') end:Expr? |
282 | 424 | ||
283 | CallExpr = | 425 | MatchExpr = |
284 | Attr* Expr ArgList | 426 | Attr* 'match' Expr MatchArmList |
285 | 427 | ||
286 | MethodCallExpr = | 428 | MatchArmList = |
287 | Attr* Expr '.' NameRef TypeArgList? ArgList | 429 | '{' |
430 | Attr* | ||
431 | arms:MatchArm* | ||
432 | '}' | ||
288 | 433 | ||
289 | ArgList = | 434 | MatchArm = |
290 | '(' args:Expr* ')' | 435 | Attr* Pat guard:MatchGuard? '=>' Expr ','? |
291 | 436 | ||
292 | FieldExpr = | 437 | MatchGuard = |
293 | Attr* Expr '.' NameRef | 438 | 'if' Expr |
294 | 439 | ||
295 | IndexExpr = | 440 | ReturnExpr = |
296 | Attr* '[' ']' | 441 | Attr* 'return' Expr? |
297 | 442 | ||
298 | AwaitExpr = | 443 | AwaitExpr = |
299 | Attr* Expr '.' 'await' | 444 | Attr* Expr '.' 'await' |
300 | 445 | ||
301 | TryExpr = | ||
302 | Attr* Expr '?' | ||
303 | |||
304 | CastExpr = | ||
305 | Attr* Expr 'as' ty:TypeRef | ||
306 | |||
307 | RefExpr = | ||
308 | Attr* '&' ('raw' | 'mut' | 'const') Expr | ||
309 | |||
310 | PrefixExpr = | ||
311 | Attr* Expr | ||
312 | |||
313 | BoxExpr = | 446 | BoxExpr = |
314 | Attr* 'box' Expr | 447 | Attr* 'box' Expr |
315 | 448 | ||
316 | RangeExpr = | 449 | //*************************// |
317 | Attr* | 450 | // Types // |
451 | //*************************// | ||
318 | 452 | ||
319 | BinExpr = | 453 | Type = |
320 | Attr* | 454 | ArrayType |
321 | 455 | | DynTraitType | |
322 | Literal = | 456 | | FnPointerType |
323 | 'int_number' | 457 | | ForType |
458 | | ImplTraitType | ||
459 | | InferType | ||
460 | | NeverType | ||
461 | | ParenType | ||
462 | | PathType | ||
463 | | PointerType | ||
464 | | ReferenceType | ||
465 | | SliceType | ||
466 | | TupleType | ||
324 | 467 | ||
325 | MatchExpr = | 468 | ParenType = |
326 | Attr* 'match' Expr MatchArmList | 469 | '(' Type ')' |
327 | 470 | ||
328 | MatchArmList = | 471 | NeverType = |
329 | '{' arms:MatchArm* '}' | 472 | '!' |
330 | 473 | ||
331 | MatchArm = | 474 | PathType = |
332 | Attr* Pat guard:MatchGuard? '=>' Expr | 475 | Path |
333 | 476 | ||
334 | MatchGuard = | 477 | TupleType = |
335 | 'if' Expr | 478 | '(' fields:(Type (',' Type)* ','?)? ')' |
336 | 479 | ||
337 | RecordExpr = | 480 | PointerType = |
338 | Path RecordExprFieldList | 481 | '*' ('const' | 'mut') Type |
339 | 482 | ||
340 | RecordExprFieldList = | 483 | ReferenceType = |
341 | '{' | 484 | '&' 'lifetime'? 'mut'? Type |
342 | fields:RecordExprField* | ||
343 | ('..' spread:Expr)? | ||
344 | '}' | ||
345 | 485 | ||
346 | RecordExprField = | 486 | ArrayType = |
347 | Attr* NameRef (':' Expr)? | 487 | '[' Type ';' Expr ']' |
348 | 488 | ||
349 | OrPat = | 489 | SliceType = |
350 | Pat* | 490 | '[' Type ']' |
351 | 491 | ||
352 | ParenPat = | 492 | InferType = |
353 | '(' Pat ')' | 493 | '_' |
354 | 494 | ||
355 | RefPat = | 495 | FnPointerType = |
356 | '&' 'mut'? Pat | 496 | 'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType? |
357 | 497 | ||
358 | BoxPat = | 498 | ForType = |
359 | 'box' Path | 499 | 'for' GenericParamList Type |
360 | 500 | ||
361 | BindPat = | 501 | ImplTraitType = |
362 | Attr* 'ref'? 'mut'? Name ('@' Pat)? | 502 | 'impl' TypeBoundList |
363 | 503 | ||
364 | PlaceholderPat = | 504 | DynTraitType = |
365 | '_' | 505 | 'dyn' TypeBoundList |
366 | 506 | ||
367 | DotDotPat = | 507 | TypeBoundList = |
368 | '..' | 508 | bounds:(TypeBound ('+' TypeBound)* '+'?) |
369 | 509 | ||
370 | PathPat = | 510 | TypeBound = |
371 | Path | 511 | 'lifetime' |
512 | | '?'? Type | ||
372 | 513 | ||
373 | SlicePat = | 514 | //************************// |
374 | '[' args:Pat* ']' | 515 | // Patterns // |
516 | //************************// | ||
375 | 517 | ||
376 | RangePat = | 518 | Pat = |
377 | '..' | '..=' | 519 | IdentPat |
520 | | BoxPat | ||
521 | | RestPat | ||
522 | | LiteralPat | ||
523 | | MacroPat | ||
524 | | OrPat | ||
525 | | ParenPat | ||
526 | | PathPat | ||
527 | | WildcardPat | ||
528 | | RangePat | ||
529 | | RecordPat | ||
530 | | RefPat | ||
531 | | SlicePat | ||
532 | | TuplePat | ||
533 | | TupleStructPat | ||
378 | 534 | ||
379 | LiteralPat = | 535 | LiteralPat = |
380 | Literal | 536 | Literal |
381 | 537 | ||
382 | MacroPat = | 538 | IdentPat = |
383 | MacroCall | 539 | Attr* 'ref'? 'mut'? Name ('@' Pat)? |
540 | |||
541 | WildcardPat = | ||
542 | '_' | ||
543 | |||
544 | RangePat = | ||
545 | start:Pat op:('..' | '..=') end:Pat | ||
546 | |||
547 | RefPat = | ||
548 | '&' 'mut'? Pat | ||
384 | 549 | ||
385 | RecordPat = | 550 | RecordPat = |
386 | Path RecordFieldPatList | 551 | Path RecordPatFieldList |
387 | 552 | ||
388 | RecordFieldPatList = | 553 | RecordPatFieldList = |
389 | '{' | 554 | '{' |
390 | record_field_pats:RecordFieldPat* | 555 | fields:(RecordPatField (',' RecordPatField)* ','?) |
391 | BindPat* | ||
392 | '..'? | 556 | '..'? |
393 | '}' | 557 | '}' |
394 | 558 | ||
395 | RecordFieldPat = | 559 | RecordPatField = |
396 | Attr* NameRef ':' Pat | 560 | Attr* (NameRef ':')? Pat |
397 | 561 | ||
398 | TupleStructPat = | 562 | TupleStructPat = |
399 | Path '(' args:Pat* ')' | 563 | Path '(' fields:(Pat (',' Pat)* ','?)? ')' |
400 | 564 | ||
401 | TuplePat = | 565 | TuplePat = |
402 | '(' args:Pat* ')' | 566 | '(' fields:(Pat (',' Pat)* ','?)? ')' |
403 | |||
404 | Name = | ||
405 | 'ident' | ||
406 | |||
407 | NameRef = | ||
408 | 'ident' | 'int_number' | ||
409 | |||
410 | MacroCall = | ||
411 | Attr* Path '!' Name? TokenTree ';'? | ||
412 | |||
413 | MacroDef = | ||
414 | Name TokenTree | ||
415 | |||
416 | TokenTree = | ||
417 | '(' ')' | '{' '}' | '[' ']' | ||
418 | |||
419 | MacroItems = | ||
420 | Item* | ||
421 | |||
422 | MacroStmts = | ||
423 | statements:Stmt* | ||
424 | Expr? | ||
425 | |||
426 | TypeBound = | ||
427 | 'lifetime' | 'const'? TypeRef | ||
428 | |||
429 | TypeBoundList = | ||
430 | bounds:TypeBound* | ||
431 | |||
432 | WherePred = | ||
433 | ('for' GenericParamList)? ('lifetime' | TypeRef) ':' TypeBoundList | ||
434 | |||
435 | WhereClause = | ||
436 | 'where' predicates:WherePred* | ||
437 | |||
438 | ExprStmt = | ||
439 | Attr* Expr ';' | ||
440 | |||
441 | LetStmt = | ||
442 | Attr* 'let' Pat (':' ty:TypeRef) | ||
443 | '=' initializer:Expr ';' | ||
444 | |||
445 | Path = | ||
446 | (qualifier:Path '::')? segment:PathSegment | ||
447 | |||
448 | PathSegment = | ||
449 | '::' | 'crate' | 'self' | 'super' | ||
450 | | '<' NameRef TypeArgList ParamList RetType PathType '>' | ||
451 | |||
452 | TypeArgList = | ||
453 | '::'? '<' | ||
454 | TypeArg* | ||
455 | LifetimeArg* | ||
456 | AssocTypeArg* | ||
457 | ConstArg* | ||
458 | '>' | ||
459 | 567 | ||
460 | TypeArg = | 568 | ParenPat = |
461 | TypeRef | 569 | '(' Pat ')' |
462 | |||
463 | AssocTypeArg = | ||
464 | NameRef (':' TypeBoundList | '=' TypeRef) | ||
465 | |||
466 | LifetimeArg = | ||
467 | 'lifetime' | ||
468 | 570 | ||
469 | ConstArg = | 571 | SlicePat = |
470 | Literal | BlockExpr BlockExpr | 572 | '[' (Pat (',' Pat)* ','?)? ']' |
471 | 573 | ||
472 | AdtDef = | 574 | PathPat = |
473 | Struct | 575 | Path |
474 | | Enum | ||
475 | | Union | ||
476 | 576 | ||
477 | TypeRef = | 577 | OrPat = |
478 | ParenType | 578 | (Pat ('|' Pat)* '|'?) |
479 | | TupleType | ||
480 | | NeverType | ||
481 | | PathType | ||
482 | | PointerType | ||
483 | | ArrayType | ||
484 | | SliceType | ||
485 | | ReferenceType | ||
486 | | PlaceholderType | ||
487 | | FnPointerType | ||
488 | | ForType | ||
489 | | ImplTraitType | ||
490 | | DynTraitType | ||
491 | 579 | ||
492 | Stmt = | 580 | BoxPat = |
493 | LetStmt | 581 | 'box' Pat |
494 | | ExprStmt | ||
495 | 582 | ||
496 | Pat = | 583 | RestPat = |
497 | OrPat | 584 | '..' |
498 | | ParenPat | ||
499 | | RefPat | ||
500 | | BoxPat | ||
501 | | BindPat | ||
502 | | PlaceholderPat | ||
503 | | DotDotPat | ||
504 | | PathPat | ||
505 | | RecordPat | ||
506 | | TupleStructPat | ||
507 | | TuplePat | ||
508 | | SlicePat | ||
509 | | RangePat | ||
510 | | LiteralPat | ||
511 | | MacroPat | ||
512 | 585 | ||
513 | Expr = | 586 | MacroPat = |
514 | TupleExpr | 587 | MacroCall |
515 | | ArrayExpr | ||
516 | | ParenExpr | ||
517 | | PathExpr | ||
518 | | LambdaExpr | ||
519 | | IfExpr | ||
520 | | LoopExpr | ||
521 | | ForExpr | ||
522 | | WhileExpr | ||
523 | | ContinueExpr | ||
524 | | BreakExpr | ||
525 | | Label | ||
526 | | BlockExpr | ||
527 | | ReturnExpr | ||
528 | | MatchExpr | ||
529 | | RecordExpr | ||
530 | | CallExpr | ||
531 | | IndexExpr | ||
532 | | MethodCallExpr | ||
533 | | FieldExpr | ||
534 | | AwaitExpr | ||
535 | | TryExpr | ||
536 | | EffectExpr | ||
537 | | CastExpr | ||
538 | | RefExpr | ||
539 | | PrefixExpr | ||
540 | | RangeExpr | ||
541 | | BinExpr | ||
542 | | Literal | ||
543 | | MacroCall | ||
544 | | BoxExpr | ||
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index 9ac3fa51d..4bade2c7e 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | collections::BTreeMap, | 2 | collections::BTreeMap, |
3 | env, | 3 | env, |
4 | fmt::{self, Write as _}, | ||
5 | io::Write as _, | 4 | io::Write as _, |
6 | path::Path, | 5 | path::Path, |
7 | time::{Instant, SystemTime, UNIX_EPOCH}, | 6 | time::{Instant, SystemTime, UNIX_EPOCH}, |
@@ -127,40 +126,21 @@ impl Metrics { | |||
127 | self.metrics.insert(name.into(), (value, unit)); | 126 | self.metrics.insert(name.into(), (value, unit)); |
128 | } | 127 | } |
129 | 128 | ||
130 | fn json(&self) -> Json { | 129 | fn json(&self) -> String { |
131 | let mut json = Json::default(); | 130 | let mut buf = String::new(); |
132 | self.to_json(&mut json); | 131 | self.to_json(write_json::object(&mut buf)); |
133 | json | 132 | buf |
134 | } | 133 | } |
135 | fn to_json(&self, json: &mut Json) { | ||
136 | json.begin_object(); | ||
137 | { | ||
138 | json.field("host"); | ||
139 | self.host.to_json(json); | ||
140 | |||
141 | json.field("timestamp"); | ||
142 | let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); | ||
143 | json.number(timestamp.as_secs() as f64); | ||
144 | 134 | ||
145 | json.field("revision"); | 135 | fn to_json(&self, mut obj: write_json::Object<'_>) { |
146 | json.string(&self.revision); | 136 | self.host.to_json(obj.object("host")); |
147 | 137 | let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); | |
148 | json.field("metrics"); | 138 | obj.number("timestamp", timestamp.as_secs() as f64); |
149 | json.begin_object(); | 139 | obj.string("revision", &self.revision); |
150 | { | 140 | let mut metrics = obj.object("metrics"); |
151 | for (k, (value, unit)) in &self.metrics { | 141 | for (k, (value, unit)) in &self.metrics { |
152 | json.field(k); | 142 | metrics.array(k).number(*value as f64).string(unit); |
153 | json.begin_array(); | ||
154 | { | ||
155 | json.number(*value as f64); | ||
156 | json.string(unit); | ||
157 | } | ||
158 | json.end_array(); | ||
159 | } | ||
160 | } | ||
161 | json.end_object() | ||
162 | } | 143 | } |
163 | json.end_object(); | ||
164 | } | 144 | } |
165 | } | 145 | } |
166 | 146 | ||
@@ -189,91 +169,7 @@ impl Host { | |||
189 | Ok(line[field.len()..].trim().to_string()) | 169 | Ok(line[field.len()..].trim().to_string()) |
190 | } | 170 | } |
191 | } | 171 | } |
192 | fn to_json(&self, json: &mut Json) { | 172 | fn to_json(&self, mut obj: write_json::Object<'_>) { |
193 | json.begin_object(); | 173 | obj.string("os", &self.os).string("cpu", &self.cpu).string("mem", &self.mem); |
194 | { | ||
195 | json.field("os"); | ||
196 | json.string(&self.os); | ||
197 | |||
198 | json.field("cpu"); | ||
199 | json.string(&self.cpu); | ||
200 | |||
201 | json.field("mem"); | ||
202 | json.string(&self.mem); | ||
203 | } | ||
204 | json.end_object(); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | struct State { | ||
209 | obj: bool, | ||
210 | first: bool, | ||
211 | } | ||
212 | |||
213 | #[derive(Default)] | ||
214 | struct Json { | ||
215 | stack: Vec<State>, | ||
216 | buf: String, | ||
217 | } | ||
218 | |||
219 | impl Json { | ||
220 | fn begin_object(&mut self) { | ||
221 | self.stack.push(State { obj: true, first: true }); | ||
222 | self.buf.push('{'); | ||
223 | } | ||
224 | fn end_object(&mut self) { | ||
225 | self.stack.pop(); | ||
226 | self.buf.push('}') | ||
227 | } | ||
228 | fn begin_array(&mut self) { | ||
229 | self.stack.push(State { obj: false, first: true }); | ||
230 | self.buf.push('['); | ||
231 | } | ||
232 | fn end_array(&mut self) { | ||
233 | self.stack.pop(); | ||
234 | self.buf.push(']') | ||
235 | } | ||
236 | fn field(&mut self, name: &str) { | ||
237 | self.object_comma(); | ||
238 | self.string_token(name); | ||
239 | self.buf.push(':'); | ||
240 | } | ||
241 | fn string(&mut self, value: &str) { | ||
242 | self.array_comma(); | ||
243 | self.string_token(value); | ||
244 | } | ||
245 | fn string_token(&mut self, value: &str) { | ||
246 | self.buf.push('"'); | ||
247 | self.buf.extend(value.escape_default()); | ||
248 | self.buf.push('"'); | ||
249 | } | ||
250 | fn number(&mut self, value: f64) { | ||
251 | self.array_comma(); | ||
252 | write!(self.buf, "{}", value).unwrap(); | ||
253 | } | ||
254 | |||
255 | fn array_comma(&mut self) { | ||
256 | let state = self.stack.last_mut().unwrap(); | ||
257 | if state.obj { | ||
258 | return; | ||
259 | } | ||
260 | if !state.first { | ||
261 | self.buf.push(','); | ||
262 | } | ||
263 | state.first = false; | ||
264 | } | ||
265 | |||
266 | fn object_comma(&mut self) { | ||
267 | let state = self.stack.last_mut().unwrap(); | ||
268 | if !state.first { | ||
269 | self.buf.push(','); | ||
270 | } | ||
271 | state.first = false; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | impl fmt::Display for Json { | ||
276 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
277 | write!(f, "{}", self.buf) | ||
278 | } | 174 | } |
279 | } | 175 | } |