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,212 @@
1
+ use std::cmp;
2
+
3
+ use itertools::Itertools;
4
+
5
+ use crate::prelude::*;
6
+
7
+ pub(crate) enum Ordering
8
+ {
9
+ Equal,
10
+ Different,
11
+ Less,
12
+ Greater,
13
+ ComparedNull,
14
+ Null,
15
+ }
16
+
17
+ impl From<cmp::Ordering> for Ordering
18
+ {
19
+ fn from(value: cmp::Ordering) -> Self
20
+ {
21
+ match value
22
+ {
23
+ cmp::Ordering::Equal => Ordering::Equal,
24
+ cmp::Ordering::Greater => Ordering::Greater,
25
+ cmp::Ordering::Less => Ordering::Less,
26
+ }
27
+ }
28
+ }
29
+
30
+ fn compare_map(lhs: &value::ValueMap, rhs: &value::ValueMap) -> Ordering
31
+ {
32
+ if lhs.len() == rhs.len()
33
+ {
34
+ lhs
35
+ .iter()
36
+ .sorted_by(|(lk, _), (rk, _)| lk.cmp(rk))
37
+ .zip(rhs.iter().sorted_by(|(lk, _), (rk, _)| lk.cmp(rk)))
38
+ .map(|((lhs_k, lhs_v), (rhs_k, rhs_v))| {
39
+ let cmp = lhs_k.cmp(rhs_k);
40
+ match cmp
41
+ {
42
+ std::cmp::Ordering::Equal => compare(lhs_v, rhs_v),
43
+ o => o.into(),
44
+ }
45
+ })
46
+ .find(|p| match p
47
+ {
48
+ Ordering::Equal => false,
49
+ _ => true,
50
+ })
51
+ .unwrap_or(Ordering::Equal)
52
+ }
53
+ else if lhs.len() < rhs.len()
54
+ {
55
+ Ordering::Less
56
+ }
57
+ else
58
+ {
59
+ Ordering::Greater
60
+ }
61
+ }
62
+
63
+ fn compare_f64(lhs: &f64, rhs: &f64) -> Ordering
64
+ {
65
+ if lhs.is_nan() || rhs.is_nan()
66
+ {
67
+ Ordering::Different
68
+ }
69
+ else
70
+ {
71
+ lhs.total_cmp(rhs).into()
72
+ }
73
+ }
74
+
75
+ fn compare_node(lhs: &graph::Node, rhs: &graph::Node) -> Ordering
76
+ {
77
+ lhs.key.uuid.cmp(&rhs.key.uuid).into()
78
+ }
79
+
80
+ pub(crate) fn compare(lhs: &value::Value, rhs: &value::Value) -> Ordering
81
+ {
82
+ use value::Value;
83
+ match lhs
84
+ {
85
+ Value::Null => Ordering::ComparedNull,
86
+ Value::Boolean(bl) => match rhs
87
+ {
88
+ Value::Boolean(br) => bl.cmp(br).into(),
89
+ Value::Null => Ordering::ComparedNull,
90
+ _ => Ordering::Null,
91
+ },
92
+ Value::Integer(il) => match rhs
93
+ {
94
+ Value::Integer(ir) => il.cmp(ir).into(),
95
+ Value::Float(fr) => compare_f64(&(*il as f64), fr),
96
+ Value::Null => Ordering::ComparedNull,
97
+ _ => Ordering::Null,
98
+ },
99
+ Value::Float(fl) => match rhs
100
+ {
101
+ Value::Integer(ir) => compare_f64(fl, &(*ir as f64)),
102
+ Value::Float(fr) => compare_f64(fl, fr),
103
+ Value::Null => Ordering::ComparedNull,
104
+ _ => Ordering::Null,
105
+ },
106
+ Value::String(sl) => match rhs
107
+ {
108
+ Value::String(sr) => sl.cmp(sr).into(),
109
+ Value::Null => Ordering::ComparedNull,
110
+ _ => Ordering::Null,
111
+ },
112
+ Value::Array(al) => match rhs
113
+ {
114
+ Value::Array(ar) =>
115
+ {
116
+ if al.len() < ar.len()
117
+ {
118
+ Ordering::Less
119
+ }
120
+ else if al.len() > ar.len()
121
+ {
122
+ Ordering::Greater
123
+ }
124
+ else
125
+ {
126
+ let mut comp_to_null = false;
127
+ let mut compare_equal = true;
128
+ let comp = al
129
+ .iter()
130
+ .zip(ar.iter())
131
+ .find_map(|(l, r)| match compare(l, r)
132
+ {
133
+ Ordering::Equal => None,
134
+ Ordering::Null | Ordering::Different =>
135
+ {
136
+ compare_equal = false;
137
+ None
138
+ }
139
+ Ordering::Greater => Some(Ordering::Greater),
140
+ Ordering::Less => Some(Ordering::Less),
141
+ Ordering::ComparedNull =>
142
+ {
143
+ comp_to_null = true;
144
+ None
145
+ }
146
+ });
147
+
148
+ // Due to opencypher madness, if you compare [nil, 2] with [1, 2] this should return null because of the nil/1 comparison,
149
+ // however [nil, 2] with [1, "2"] should return false because 2 != "2" 🤦
150
+ match (comp, comp_to_null, compare_equal)
151
+ {
152
+ // Some imply either greater or lesser, in which case, return the value unless a comparison to null was made
153
+ (Some(o), false, _) => o,
154
+ (Some(_), true, _) => Ordering::ComparedNull,
155
+ // If equal, check if a comparison to null was made
156
+ (None, true, true) => Ordering::ComparedNull,
157
+ (None, false, true) => Ordering::Equal,
158
+ // If false, ignore comparison to null
159
+ (None, _, false) => Ordering::Null,
160
+ }
161
+ }
162
+ }
163
+ Value::Null => Ordering::ComparedNull,
164
+ _ => Ordering::Null,
165
+ },
166
+ Value::Map(lhs) => match rhs
167
+ {
168
+ Value::Map(rhs) => compare_map(lhs, rhs),
169
+ _ => Ordering::Null,
170
+ },
171
+ Value::Node(lhs) => match rhs
172
+ {
173
+ Value::Node(rhs) => compare_node(lhs, rhs),
174
+ _ => Ordering::Null,
175
+ },
176
+ Value::Edge(lhs) => match rhs
177
+ {
178
+ Value::Edge(rhs) =>
179
+ {
180
+ lhs.key.uuid.cmp(&rhs.key.uuid).into()
181
+ // let labels_cmp = lhs.labels.cmp(&rhs.labels);
182
+ // match labels_cmp
183
+ // {
184
+ // std::cmp::Ordering::Equal => compare_map(&lhs.properties, &rhs.properties),
185
+ // o => o.into(),
186
+ // }
187
+ }
188
+ _ => Ordering::Null,
189
+ },
190
+ Value::Path(lhs) => match rhs
191
+ {
192
+ Value::Path(rhs) =>
193
+ {
194
+ let labels_cmp = lhs.labels.cmp(&rhs.labels);
195
+ match labels_cmp
196
+ {
197
+ std::cmp::Ordering::Equal => match compare_map(&lhs.properties, &rhs.properties)
198
+ {
199
+ Ordering::Equal => match compare_node(&lhs.source, &rhs.source)
200
+ {
201
+ Ordering::Equal => compare_node(&lhs.destination, &rhs.destination),
202
+ o => o,
203
+ },
204
+ o => o,
205
+ },
206
+ o => o.into(),
207
+ }
208
+ }
209
+ _ => Ordering::Null,
210
+ },
211
+ }
212
+ }
@@ -0,0 +1,47 @@
1
+ use crate::prelude::*;
2
+
3
+ pub(crate) enum ContainResult
4
+ {
5
+ True,
6
+ False,
7
+ ComparedNull,
8
+ }
9
+
10
+ /// Compute contains, according to OpenCypher specification, specifically handling the comparison with null.
11
+ pub(crate) fn contains(container: &Vec<value::Value>, value: &value::Value) -> ContainResult
12
+ {
13
+ if value.is_null()
14
+ {
15
+ if container.is_empty()
16
+ {
17
+ ContainResult::False
18
+ }
19
+ else
20
+ {
21
+ ContainResult::ComparedNull
22
+ }
23
+ }
24
+ else
25
+ {
26
+ let mut has_compared_to_null = false;
27
+ for v_c in container.iter()
28
+ {
29
+ use value::ContainResult;
30
+ match value::compare(v_c, &value)
31
+ {
32
+ value::Ordering::Equal => return ContainResult::True,
33
+ value::Ordering::ComparedNull => has_compared_to_null = true,
34
+ _ =>
35
+ {}
36
+ }
37
+ }
38
+ if has_compared_to_null
39
+ {
40
+ ContainResult::ComparedNull
41
+ }
42
+ else
43
+ {
44
+ ContainResult::False
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,298 @@
1
+ use itertools::Itertools;
2
+ use serde::{Deserialize, Serialize};
3
+ use std::{
4
+ hash::Hash,
5
+ ops::{Deref, DerefMut},
6
+ };
7
+
8
+ use crate::{prelude::*, Value};
9
+
10
+ type ValueMapInner = std::collections::HashMap<String, Value>;
11
+
12
+ /// A map of values.
13
+ #[derive(Debug, PartialEq, Default, Clone, Deserialize, Serialize)]
14
+ pub struct ValueMap(ValueMapInner);
15
+
16
+ impl ValueMap
17
+ {
18
+ /// Create a default value map.
19
+ pub fn new() -> Self
20
+ {
21
+ Self::default()
22
+ }
23
+ pub(crate) fn remove_null(self) -> Self
24
+ {
25
+ self
26
+ .into_iter()
27
+ .filter(|(_, v)| !v.is_null())
28
+ .map(|(k, v)| (k, v.remove_null()))
29
+ .collect()
30
+ }
31
+ pub(crate) fn remove_value<'a>(
32
+ &mut self,
33
+ field: Option<&'a String>,
34
+ mut path: impl Iterator<Item = &'a String>,
35
+ ) -> crate::Result<()>
36
+ {
37
+ if let Some(field) = field
38
+ {
39
+ if let Some(next_field) = path.next()
40
+ {
41
+ let v = self.get_mut(field);
42
+ match v
43
+ {
44
+ Some(Value::Map(o)) =>
45
+ {
46
+ o.remove_value(Some(next_field), path)?;
47
+ }
48
+ None =>
49
+ {}
50
+ _ => Err(InternalError::Unimplemented(
51
+ "remove_value should get a better error",
52
+ ))?, // TODO
53
+ }
54
+ }
55
+ else
56
+ {
57
+ self.remove(field);
58
+ }
59
+ }
60
+ else
61
+ {
62
+ Err(InternalError::Unimplemented(
63
+ "remove_value should get a better error",
64
+ ))? // TODO
65
+ }
66
+ Ok(())
67
+ }
68
+ pub(crate) fn add_values<'a>(
69
+ &mut self,
70
+ field: Option<&'a String>,
71
+ mut path: impl Iterator<Item = &'a String>,
72
+ value: ValueMap,
73
+ ) -> crate::Result<()>
74
+ {
75
+ if let Some(field) = field
76
+ {
77
+ let v = self.get_mut(field);
78
+
79
+ if let Some(next_field) = path.next()
80
+ {
81
+ match v
82
+ {
83
+ Some(Value::Map(o)) =>
84
+ {
85
+ o.add_values(Some(next_field), path, value)?;
86
+ }
87
+ None =>
88
+ {
89
+ let mut o = ValueMap::new();
90
+ o.set_value(Some(next_field), path, value.remove_null().into())?;
91
+ self.insert(field.to_owned(), o.into());
92
+ }
93
+ _ => Err(InternalError::Unimplemented(
94
+ "add_values should get a better error",
95
+ ))?, // TODO
96
+ }
97
+ }
98
+ else
99
+ {
100
+ match v
101
+ {
102
+ Some(v) =>
103
+ {
104
+ match v
105
+ {
106
+ Value::Map(object) =>
107
+ {
108
+ for (k, v) in value.into_iter()
109
+ {
110
+ if v.is_null()
111
+ {
112
+ object.remove(&k);
113
+ }
114
+ else
115
+ {
116
+ object.insert(k, v);
117
+ }
118
+ }
119
+ }
120
+ _ => Err(InternalError::Unimplemented(
121
+ "add_values should get a better error",
122
+ ))?, // TODO
123
+ }
124
+ }
125
+ None =>
126
+ {
127
+ self.insert(field.to_owned(), value.remove_null().into());
128
+ }
129
+ }
130
+ }
131
+ }
132
+ else
133
+ {
134
+ for (k, v) in value.into_iter()
135
+ {
136
+ if v.is_null()
137
+ {
138
+ self.remove(&k);
139
+ }
140
+ else
141
+ {
142
+ self.insert(k, v);
143
+ }
144
+ }
145
+ }
146
+ Ok(())
147
+ }
148
+ pub(crate) fn set_value<'a>(
149
+ &mut self,
150
+ field: Option<&'a String>,
151
+ mut path: impl Iterator<Item = &'a String>,
152
+ value: Value,
153
+ ) -> crate::Result<()>
154
+ {
155
+ if let Some(field) = field
156
+ {
157
+ let v = self.get_mut(field);
158
+
159
+ if let Some(next_field) = path.next()
160
+ {
161
+ match v
162
+ {
163
+ Some(Value::Map(o)) =>
164
+ {
165
+ o.set_value(Some(next_field), path, value)?;
166
+ }
167
+ None =>
168
+ {
169
+ if !value.is_null()
170
+ {
171
+ let mut o = ValueMap::new();
172
+ o.set_value(Some(next_field), path, value)?;
173
+ self.insert(field.to_owned(), o.into());
174
+ }
175
+ }
176
+ _ => Err(InternalError::Unimplemented(
177
+ "update_value should get a better error",
178
+ ))?, // TODO
179
+ }
180
+ }
181
+ else
182
+ {
183
+ if value.is_null()
184
+ {
185
+ self.remove(field);
186
+ }
187
+ else
188
+ {
189
+ match v
190
+ {
191
+ Some(v) =>
192
+ {
193
+ *v = value;
194
+ }
195
+ None =>
196
+ {
197
+ self.insert(field.to_owned(), value);
198
+ }
199
+ }
200
+ }
201
+ }
202
+
203
+ Ok(())
204
+ }
205
+ else
206
+ {
207
+ match value
208
+ {
209
+ Value::Map(o) =>
210
+ {
211
+ *self = o;
212
+ Ok(())
213
+ }
214
+ _ => Err(InternalError::Unimplemented("set_value should get a better error").into()), // TODO
215
+ }
216
+ }
217
+ }
218
+ }
219
+
220
+ impl Hash for ValueMap
221
+ {
222
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H)
223
+ {
224
+ for (k, v) in self.0.iter().sorted_by(|(lk, _), (rk, _)| lk.cmp(rk))
225
+ {
226
+ k.hash(state);
227
+ v.hash(state);
228
+ }
229
+ }
230
+ }
231
+
232
+ impl Deref for ValueMap
233
+ {
234
+ type Target = ValueMapInner;
235
+ fn deref(&self) -> &Self::Target
236
+ {
237
+ &self.0
238
+ }
239
+ }
240
+
241
+ impl DerefMut for ValueMap
242
+ {
243
+ fn deref_mut(&mut self) -> &mut Self::Target
244
+ {
245
+ &mut self.0
246
+ }
247
+ }
248
+
249
+ impl FromIterator<(String, Value)> for ValueMap
250
+ {
251
+ /// Constructs a `HashMap<K, V>` from an iterator of key-value pairs.
252
+ ///
253
+ /// If the iterator produces any pairs with equal keys,
254
+ /// all but one of the corresponding values will be dropped.
255
+ fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> ValueMap
256
+ {
257
+ let mut map = ValueMapInner::with_hasher(Default::default());
258
+ map.extend(iter);
259
+ ValueMap(map)
260
+ }
261
+ }
262
+
263
+ impl IntoIterator for ValueMap
264
+ {
265
+ type Item = (String, Value);
266
+ type IntoIter = <ValueMapInner as IntoIterator>::IntoIter;
267
+ fn into_iter(self) -> Self::IntoIter
268
+ {
269
+ self.0.into_iter()
270
+ }
271
+ }
272
+
273
+ impl<const N: usize> From<[(String, Value); N]> for ValueMap
274
+ {
275
+ fn from(arr: [(String, Value); N]) -> Self
276
+ {
277
+ Self(ValueMapInner::from_iter(arr))
278
+ }
279
+ }
280
+
281
+ impl std::fmt::Display for ValueMap
282
+ {
283
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
284
+ {
285
+ write!(f, "{{")?;
286
+ self.iter().enumerate().for_each(|(n, (k, v))| {
287
+ if n == 0
288
+ {
289
+ write!(f, "{}: {}", k, v).unwrap();
290
+ }
291
+ else
292
+ {
293
+ write!(f, ", {}: {}", k, v).unwrap();
294
+ }
295
+ });
296
+ write!(f, "}}")
297
+ }
298
+ }