gqlite 1.2.0 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/ext/gqliterb/.cargo/config.toml +2 -0
  3. data/ext/gqliterb/Cargo.lock +152 -135
  4. data/ext/gqliterb/Cargo.toml +4 -6
  5. data/ext/gqliterb/src/lib.rs +8 -2
  6. data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +2115 -0
  7. data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +138 -0
  8. data/ext/gqliterb/vendor/gqlitedb/askama.toml +3 -0
  9. data/ext/gqliterb/vendor/gqlitedb/benches/common/mod.rs +25 -0
  10. data/ext/gqliterb/vendor/gqlitedb/benches/common/pokec.rs +185 -0
  11. data/ext/gqliterb/vendor/gqlitedb/benches/pokec_divan.rs +137 -0
  12. data/ext/gqliterb/vendor/gqlitedb/benches/pokec_iai.rs +122 -0
  13. data/ext/gqliterb/vendor/gqlitedb/release.toml +7 -0
  14. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/arithmetic.rs +96 -0
  15. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/containers.rs +33 -0
  16. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/count.rs +35 -0
  17. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/stats.rs +168 -0
  18. data/ext/gqliterb/vendor/gqlitedb/src/aggregators.rs +74 -0
  19. data/ext/gqliterb/vendor/gqlitedb/src/capi.rs +259 -0
  20. data/ext/gqliterb/vendor/gqlitedb/src/compiler/expression_analyser.rs +431 -0
  21. data/ext/gqliterb/vendor/gqlitedb/src/compiler/variables_manager.rs +621 -0
  22. data/ext/gqliterb/vendor/gqlitedb/src/compiler.rs +1115 -0
  23. data/ext/gqliterb/vendor/gqlitedb/src/connection.rs +342 -0
  24. data/ext/gqliterb/vendor/gqlitedb/src/consts.rs +10 -0
  25. data/ext/gqliterb/vendor/gqlitedb/src/error.rs +613 -0
  26. data/ext/gqliterb/vendor/gqlitedb/src/functions/containers.rs +115 -0
  27. data/ext/gqliterb/vendor/gqlitedb/src/functions/edge.rs +20 -0
  28. data/ext/gqliterb/vendor/gqlitedb/src/functions/math.rs +44 -0
  29. data/ext/gqliterb/vendor/gqlitedb/src/functions/node.rs +16 -0
  30. data/ext/gqliterb/vendor/gqlitedb/src/functions/path.rs +80 -0
  31. data/ext/gqliterb/vendor/gqlitedb/src/functions/scalar.rs +86 -0
  32. data/ext/gqliterb/vendor/gqlitedb/src/functions/string.rs +28 -0
  33. data/ext/gqliterb/vendor/gqlitedb/src/functions/value.rs +99 -0
  34. data/ext/gqliterb/vendor/gqlitedb/src/functions.rs +410 -0
  35. data/ext/gqliterb/vendor/gqlitedb/src/graph.rs +283 -0
  36. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/evaluators.rs +1776 -0
  37. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/instructions.rs +267 -0
  38. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/mod.rs +4 -0
  39. data/ext/gqliterb/vendor/gqlitedb/src/lib.rs +41 -0
  40. data/ext/gqliterb/vendor/gqlitedb/src/parser/ast.rs +611 -0
  41. data/ext/gqliterb/vendor/gqlitedb/src/parser/gql.pest +196 -0
  42. data/ext/gqliterb/vendor/gqlitedb/src/parser/parser.rs +1183 -0
  43. data/ext/gqliterb/vendor/gqlitedb/src/parser.rs +4 -0
  44. data/ext/gqliterb/vendor/gqlitedb/src/prelude.rs +8 -0
  45. data/ext/gqliterb/vendor/gqlitedb/src/serialize_with.rs +94 -0
  46. data/ext/gqliterb/vendor/gqlitedb/src/store/pgql.rs +121 -0
  47. data/ext/gqliterb/vendor/gqlitedb/src/store/redb.rs +1262 -0
  48. data/ext/gqliterb/vendor/gqlitedb/src/store/sqlite.rs +1026 -0
  49. data/ext/gqliterb/vendor/gqlitedb/src/store.rs +439 -0
  50. data/ext/gqliterb/vendor/gqlitedb/src/tests/compiler.rs +92 -0
  51. data/ext/gqliterb/vendor/gqlitedb/src/tests/evaluators.rs +227 -0
  52. data/ext/gqliterb/vendor/gqlitedb/src/tests/parser.rs +81 -0
  53. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/redb.rs +46 -0
  54. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/sqlite.rs +46 -0
  55. data/ext/gqliterb/vendor/gqlitedb/src/tests/store.rs +470 -0
  56. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/ast.rs +356 -0
  57. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/programs.rs +455 -0
  58. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates.rs +2 -0
  59. data/ext/gqliterb/vendor/gqlitedb/src/tests.rs +39 -0
  60. data/ext/gqliterb/vendor/gqlitedb/src/utils.rs +28 -0
  61. data/ext/gqliterb/vendor/gqlitedb/src/value/compare.rs +212 -0
  62. data/ext/gqliterb/vendor/gqlitedb/src/value/contains.rs +47 -0
  63. data/ext/gqliterb/vendor/gqlitedb/src/value/value_map.rs +298 -0
  64. data/ext/gqliterb/vendor/gqlitedb/src/value.rs +609 -0
  65. data/ext/gqliterb/vendor/gqlitedb/src/value_table.rs +610 -0
  66. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/call_stats.sql +22 -0
  67. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_count_for_node.sql +3 -0
  68. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_create.sql +6 -0
  69. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete.sql +1 -0
  70. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete_by_nodes.sql +2 -0
  71. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_select.sql +139 -0
  72. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_update.sql +4 -0
  73. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_create.sql +16 -0
  74. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_delete.sql +3 -0
  75. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_create_table.sql +1 -0
  76. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_get.sql +1 -0
  77. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_set.sql +1 -0
  78. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_create.sql +1 -0
  79. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_delete.sql +1 -0
  80. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_select.sql +42 -0
  81. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_update.sql +4 -0
  82. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/table_exists.sql +5 -0
  83. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_from_1_01.sql +2 -0
  84. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_graph_from_1_01.sql +65 -0
  85. metadata +82 -2
@@ -0,0 +1,455 @@
1
+ use crate::{
2
+ error, functions,
3
+ graph::EdgeDirectivity,
4
+ interpreter::{instructions::*, Program},
5
+ ValueMap,
6
+ };
7
+
8
+ fn create_variable_size(persistent_variables: usize, temporary_variables: usize) -> VariablesSizes
9
+ {
10
+ VariablesSizes {
11
+ temporary_variables,
12
+ persistent_variables,
13
+ }
14
+ }
15
+
16
+ pub(crate) fn simple_create() -> Program
17
+ {
18
+ vec![Block::Create {
19
+ actions: vec![CreateAction {
20
+ instructions: vec![
21
+ Instruction::Push {
22
+ value: ValueMap::default().into(),
23
+ },
24
+ Instruction::CreateNodeLiteral {
25
+ labels: Default::default(),
26
+ },
27
+ ],
28
+ variables: vec![None],
29
+ }],
30
+ variables_size: create_variable_size(0, 0),
31
+ }]
32
+ }
33
+
34
+ pub(crate) fn create_named_node() -> Program
35
+ {
36
+ vec![
37
+ Block::Create {
38
+ actions: vec![CreateAction {
39
+ instructions: vec![
40
+ Instruction::Push {
41
+ value: "foo".into(),
42
+ },
43
+ Instruction::CreateMap {
44
+ keys: vec!["name".into()],
45
+ },
46
+ Instruction::CreateNodeLiteral {
47
+ labels: Default::default(),
48
+ },
49
+ ],
50
+ variables: vec![Some(0)],
51
+ }],
52
+ variables_size: create_variable_size(1, 0),
53
+ },
54
+ Block::Return {
55
+ variables: vec![(
56
+ "p".into(),
57
+ RWExpression {
58
+ col_id: 1,
59
+ instructions: vec![
60
+ Instruction::GetVariable { col_id: 0 },
61
+ Instruction::MemberAccess {
62
+ path: vec!["name".into()],
63
+ },
64
+ ],
65
+ aggregations: Default::default(),
66
+ },
67
+ )],
68
+ filter: vec![],
69
+ modifiers: Modifiers {
70
+ limit: None,
71
+ skip: None,
72
+ order_by: vec![],
73
+ },
74
+ variables_size: create_variable_size(2, 0),
75
+ },
76
+ ]
77
+ }
78
+
79
+ /// Program for `CREATE (n {id: 12, name: 'foo'}) RETURN n.id AS id, n.name AS p`
80
+ pub(crate) fn create_named_node_double_return() -> Program
81
+ {
82
+ vec![
83
+ Block::Create {
84
+ actions: vec![CreateAction {
85
+ instructions: vec![
86
+ Instruction::Push { value: 12.into() },
87
+ Instruction::Push {
88
+ value: "foo".into(),
89
+ },
90
+ Instruction::CreateMap {
91
+ keys: vec!["id".into(), "name".into()],
92
+ },
93
+ Instruction::CreateNodeLiteral {
94
+ labels: Default::default(),
95
+ },
96
+ ],
97
+ variables: vec![Some(0)],
98
+ }],
99
+ variables_size: create_variable_size(1, 0),
100
+ },
101
+ Block::Return {
102
+ variables: vec![
103
+ (
104
+ "id".into(),
105
+ RWExpression {
106
+ col_id: 1,
107
+ instructions: vec![
108
+ Instruction::GetVariable { col_id: 0 },
109
+ Instruction::MemberAccess {
110
+ path: vec!["id".into()],
111
+ },
112
+ ],
113
+ aggregations: Default::default(),
114
+ },
115
+ ),
116
+ (
117
+ "p".into(),
118
+ RWExpression {
119
+ col_id: 2,
120
+ instructions: vec![
121
+ Instruction::GetVariable { col_id: 0 },
122
+ Instruction::MemberAccess {
123
+ path: vec!["name".into()],
124
+ },
125
+ ],
126
+ aggregations: Default::default(),
127
+ },
128
+ ),
129
+ ],
130
+ filter: vec![],
131
+ modifiers: Modifiers {
132
+ limit: None,
133
+ skip: None,
134
+ order_by: vec![],
135
+ },
136
+ variables_size: create_variable_size(3, 0),
137
+ },
138
+ ]
139
+ }
140
+
141
+ /// Program for `WITH 1 AS n, 2 AS m WITH n AS a, m AS b RETURN a`
142
+ pub(crate) fn double_with_return() -> Program
143
+ {
144
+ vec![
145
+ Block::With {
146
+ variables: vec![
147
+ RWExpression {
148
+ col_id: 0,
149
+ instructions: vec![Instruction::Push { value: 1.into() }],
150
+ aggregations: vec![],
151
+ },
152
+ RWExpression {
153
+ col_id: 1,
154
+ instructions: vec![Instruction::Push { value: 2.into() }],
155
+ aggregations: vec![],
156
+ },
157
+ ],
158
+ filter: vec![],
159
+ modifiers: Modifiers {
160
+ limit: None,
161
+ skip: None,
162
+ order_by: vec![],
163
+ },
164
+ variables_size: create_variable_size(2, 0),
165
+ },
166
+ Block::With {
167
+ variables: vec![
168
+ RWExpression {
169
+ col_id: 2,
170
+ instructions: vec![Instruction::GetVariable { col_id: 0 }],
171
+ aggregations: vec![],
172
+ },
173
+ RWExpression {
174
+ col_id: 3,
175
+ instructions: vec![Instruction::GetVariable { col_id: 1 }],
176
+ aggregations: vec![],
177
+ },
178
+ ],
179
+ filter: vec![],
180
+ modifiers: Modifiers {
181
+ limit: None,
182
+ skip: None,
183
+ order_by: vec![],
184
+ },
185
+ variables_size: create_variable_size(4, 0),
186
+ },
187
+ Block::Return {
188
+ variables: vec![(
189
+ "a".into(),
190
+ RWExpression {
191
+ col_id: 0,
192
+ instructions: vec![Instruction::GetVariable { col_id: 0 }],
193
+ aggregations: vec![],
194
+ },
195
+ )],
196
+ filter: vec![],
197
+ modifiers: Modifiers {
198
+ limit: None,
199
+ skip: None,
200
+ order_by: vec![],
201
+ },
202
+ variables_size: create_variable_size(2, 0),
203
+ },
204
+ ]
205
+ }
206
+
207
+ /// Program for `UNWIND [0] AS i RETURN i`
208
+ pub(crate) fn unwind() -> Program
209
+ {
210
+ vec![
211
+ Block::Unwind {
212
+ col_id: 0,
213
+ instructions: vec![
214
+ Instruction::Push { value: 0.into() },
215
+ Instruction::CreateArray { length: 1 },
216
+ ],
217
+ variables_size: VariablesSizes {
218
+ persistent_variables: 1,
219
+ temporary_variables: 0,
220
+ },
221
+ },
222
+ Block::Return {
223
+ variables: vec![(
224
+ "i".into(),
225
+ RWExpression {
226
+ col_id: 0,
227
+ instructions: vec![Instruction::GetVariable { col_id: 0 }],
228
+ aggregations: vec![],
229
+ },
230
+ )],
231
+ filter: vec![],
232
+ modifiers: Modifiers {
233
+ limit: None,
234
+ skip: None,
235
+ order_by: vec![],
236
+ },
237
+ variables_size: create_variable_size(1, 0),
238
+ },
239
+ ]
240
+ }
241
+
242
+ /// Program for `MATCH (n)-[]->(n) RETURN n`
243
+ pub(crate) fn match_loop() -> Program
244
+ {
245
+ vec![
246
+ Block::BlockMatch {
247
+ blocks: vec![BlockMatch::MatchEdge {
248
+ instructions: vec![
249
+ Instruction::Push {
250
+ value: ValueMap::default().into(),
251
+ },
252
+ Instruction::CreateNodeQuery { labels: vec![] },
253
+ Instruction::Push {
254
+ value: ValueMap::default().into(),
255
+ },
256
+ Instruction::CreateNodeQuery { labels: vec![] },
257
+ Instruction::Push {
258
+ value: ValueMap::default().into(),
259
+ },
260
+ Instruction::CreateEdgeQuery { labels: vec![] },
261
+ ],
262
+ left_variable: Some(0),
263
+ edge_variable: None,
264
+ right_variable: Some(0),
265
+ path_variable: None,
266
+ filter: vec![],
267
+ directivity: EdgeDirectivity::Directed,
268
+ }],
269
+ filter: vec![],
270
+ optional: false,
271
+ variables_size: VariablesSizes {
272
+ persistent_variables: 1,
273
+ temporary_variables: 0,
274
+ },
275
+ },
276
+ Block::Return {
277
+ variables: vec![(
278
+ "n".into(),
279
+ RWExpression {
280
+ col_id: 0,
281
+ instructions: vec![Instruction::GetVariable { col_id: 0 }],
282
+ aggregations: vec![],
283
+ },
284
+ )],
285
+ filter: vec![],
286
+ modifiers: Modifiers {
287
+ limit: None,
288
+ skip: None,
289
+ order_by: vec![],
290
+ },
291
+ variables_size: create_variable_size(1, 0),
292
+ },
293
+ ]
294
+ }
295
+
296
+ /// Program for `OPTIONAL MATCH (a) RETURN a`
297
+ pub(crate) fn optional_match() -> Program
298
+ {
299
+ vec![
300
+ Block::BlockMatch {
301
+ blocks: vec![BlockMatch::MatchNode {
302
+ instructions: vec![
303
+ Instruction::Push {
304
+ value: ValueMap::default().into(),
305
+ },
306
+ Instruction::CreateNodeQuery { labels: vec![] },
307
+ ],
308
+ variable: Some(0),
309
+ filter: vec![],
310
+ }],
311
+ filter: vec![],
312
+ optional: true,
313
+ variables_size: create_variable_size(1, 0),
314
+ },
315
+ Block::Return {
316
+ variables: vec![(
317
+ "a".into(),
318
+ RWExpression {
319
+ col_id: 0,
320
+ instructions: vec![Instruction::GetVariable { col_id: 0 }],
321
+ aggregations: vec![],
322
+ },
323
+ )],
324
+ filter: vec![],
325
+ modifiers: Modifiers {
326
+ limit: None,
327
+ skip: None,
328
+ order_by: vec![],
329
+ },
330
+ variables_size: create_variable_size(1, 0),
331
+ },
332
+ ]
333
+ }
334
+
335
+ /// Program for `MATCH (a) RETURN COUNT(*)`
336
+ pub(crate) fn match_count(function_manager: &functions::Manager) -> Program
337
+ {
338
+ vec![
339
+ Block::BlockMatch {
340
+ blocks: vec![BlockMatch::MatchNode {
341
+ instructions: vec![
342
+ Instruction::Push {
343
+ value: ValueMap::default().into(),
344
+ },
345
+ Instruction::CreateNodeQuery { labels: vec![] },
346
+ ],
347
+ variable: Some(0),
348
+ filter: vec![],
349
+ }],
350
+ filter: vec![],
351
+ optional: false,
352
+ variables_size: VariablesSizes {
353
+ persistent_variables: 1,
354
+ temporary_variables: 0,
355
+ },
356
+ },
357
+ Block::Return {
358
+ variables: vec![(
359
+ "count(*)".into(),
360
+ RWExpression {
361
+ col_id: 1,
362
+ instructions: vec![Instruction::GetVariable { col_id: 1 }],
363
+ aggregations: vec![(
364
+ 1,
365
+ RWAggregation {
366
+ init_instructions: vec![],
367
+ argument_instructions: vec![Instruction::Push { value: 0.into() }],
368
+ aggregator: function_manager
369
+ .get_aggregator::<error::CompileTimeError>("count")
370
+ .unwrap(),
371
+ },
372
+ )],
373
+ },
374
+ )],
375
+ filter: vec![],
376
+ modifiers: Modifiers {
377
+ limit: None,
378
+ skip: None,
379
+ order_by: vec![],
380
+ },
381
+ variables_size: create_variable_size(2, 1),
382
+ },
383
+ ]
384
+ }
385
+
386
+ /// Program for `MATCH (n) RETURN n.name, count(n.num)`
387
+ pub(crate) fn aggregation(function_manager: &functions::Manager) -> Program
388
+ {
389
+ vec![
390
+ Block::BlockMatch {
391
+ blocks: vec![BlockMatch::MatchNode {
392
+ instructions: vec![
393
+ Instruction::Push {
394
+ value: ValueMap::default().into(),
395
+ },
396
+ Instruction::CreateNodeQuery { labels: vec![] },
397
+ ],
398
+ variable: Some(0),
399
+ filter: vec![],
400
+ }],
401
+ filter: vec![],
402
+ optional: false,
403
+ variables_size: VariablesSizes {
404
+ persistent_variables: 1,
405
+ temporary_variables: 0,
406
+ },
407
+ },
408
+ Block::Return {
409
+ variables: vec![
410
+ (
411
+ "n.name".into(),
412
+ RWExpression {
413
+ col_id: 1,
414
+ instructions: vec![
415
+ Instruction::GetVariable { col_id: 0 },
416
+ Instruction::MemberAccess {
417
+ path: vec!["name".into()],
418
+ },
419
+ ],
420
+ aggregations: Default::default(),
421
+ },
422
+ ),
423
+ (
424
+ "count(n.num)".into(),
425
+ RWExpression {
426
+ col_id: 2,
427
+ instructions: vec![Instruction::GetVariable { col_id: 2 }],
428
+ aggregations: vec![(
429
+ 2,
430
+ RWAggregation {
431
+ init_instructions: vec![],
432
+ argument_instructions: vec![
433
+ Instruction::GetVariable { col_id: 0 },
434
+ Instruction::MemberAccess {
435
+ path: vec!["num".into()],
436
+ },
437
+ ],
438
+ aggregator: function_manager
439
+ .get_aggregator::<error::CompileTimeError>("count")
440
+ .unwrap(),
441
+ },
442
+ )],
443
+ },
444
+ ),
445
+ ],
446
+ filter: vec![],
447
+ modifiers: Modifiers {
448
+ limit: None,
449
+ skip: None,
450
+ order_by: vec![],
451
+ },
452
+ variables_size: create_variable_size(3, 1),
453
+ },
454
+ ]
455
+ }
@@ -0,0 +1,2 @@
1
+ pub(crate) mod ast;
2
+ pub(crate) mod programs;
@@ -0,0 +1,39 @@
1
+ mod compiler;
2
+ mod evaluators;
3
+ mod parser;
4
+ mod store;
5
+ mod templates;
6
+
7
+ pub(crate) fn create_tmp_file() -> ccutils::temporary::TemporaryFile
8
+ {
9
+ ccutils::temporary::TemporaryFile::builder()
10
+ .should_create_file(false)
11
+ .label("gqlite")
12
+ .create()
13
+ }
14
+
15
+ fn check_stats<TStore: crate::store::Store>(
16
+ store: &TStore,
17
+ transaction: Option<&mut TStore::TransactionBox>,
18
+ nodes_count: usize,
19
+ edges_count: usize,
20
+ labels_node_count: usize,
21
+ properties_count: usize,
22
+ )
23
+ {
24
+ let stats = match transaction
25
+ {
26
+ Some(mut tx) => store.compute_statistics(&mut tx).unwrap(),
27
+ None =>
28
+ {
29
+ // use crate::store::TransactionBoxable;
30
+ let mut tx = store.begin_read().unwrap();
31
+ store.compute_statistics(&mut tx).unwrap()
32
+ }
33
+ };
34
+
35
+ assert_eq!(stats.nodes_count, nodes_count);
36
+ assert_eq!(stats.edges_count, edges_count);
37
+ assert_eq!(stats.labels_nodes_count, labels_node_count);
38
+ assert_eq!(stats.properties_count, properties_count);
39
+ }
@@ -0,0 +1,28 @@
1
+ use std::fmt::{Debug, Display};
2
+
3
+ use serde::{Deserialize, Serialize};
4
+
5
+ #[derive(Serialize, Deserialize)]
6
+ pub struct Version
7
+ {
8
+ pub major: u16,
9
+ pub minor: u16,
10
+ #[serde(alias = "revision", alias = "release")]
11
+ pub patch: u16,
12
+ }
13
+
14
+ impl Debug for Version
15
+ {
16
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
17
+ {
18
+ <Self as Display>::fmt(self, f)
19
+ }
20
+ }
21
+
22
+ impl Display for Version
23
+ {
24
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
25
+ {
26
+ f.write_fmt(format_args!("{}.{}.{}", self.major, self.minor, self.patch))
27
+ }
28
+ }