1#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
2
3use std::collections::HashMap;
14use std::num::NonZeroU16;
15
16mod invariants;
17
18#[derive(Debug, Clone, serde::Deserialize)]
20pub struct RawNode {
21 #[serde(rename = "type")]
22 pub type_name: String,
23 pub named: bool,
24 #[serde(default)]
25 pub root: bool,
26 #[serde(default)]
27 pub extra: bool,
28 #[serde(default)]
29 pub fields: HashMap<String, RawCardinality>,
30 pub children: Option<RawCardinality>,
31 pub subtypes: Option<Vec<RawTypeRef>>,
32}
33
34#[derive(Debug, Clone, serde::Deserialize)]
36pub struct RawCardinality {
37 pub multiple: bool,
38 pub required: bool,
39 pub types: Vec<RawTypeRef>,
40}
41
42#[derive(Debug, Clone, serde::Deserialize)]
44pub struct RawTypeRef {
45 #[serde(rename = "type")]
46 pub type_name: String,
47 pub named: bool,
48}
49
50pub fn parse_node_types(json: &str) -> Result<Vec<RawNode>, serde_json::Error> {
52 serde_json::from_str(json)
53}
54
55pub type NodeTypeId = u16;
57
58pub type NodeFieldId = NonZeroU16;
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct Cardinality {
64 pub multiple: bool,
65 pub required: bool,
66}
67
68pub trait NodeTypes {
78 fn root(&self) -> Option<NodeTypeId>;
79 fn is_extra(&self, node_type_id: NodeTypeId) -> bool;
80
81 fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool;
82 fn field_cardinality(
83 &self,
84 node_type_id: NodeTypeId,
85 node_field_id: NodeFieldId,
86 ) -> Option<Cardinality>;
87 fn valid_field_types(
88 &self,
89 node_type_id: NodeTypeId,
90 node_field_id: NodeFieldId,
91 ) -> &[NodeTypeId];
92 fn is_valid_field_type(
93 &self,
94 node_type_id: NodeTypeId,
95 node_field_id: NodeFieldId,
96 child: NodeTypeId,
97 ) -> bool;
98
99 fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality>;
100 fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId];
101 fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool;
102}
103
104impl<T: NodeTypes + ?Sized> NodeTypes for &T {
105 fn root(&self) -> Option<NodeTypeId> {
106 (*self).root()
107 }
108 fn is_extra(&self, node_type_id: NodeTypeId) -> bool {
109 (*self).is_extra(node_type_id)
110 }
111 fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool {
112 (*self).has_field(node_type_id, node_field_id)
113 }
114 fn field_cardinality(
115 &self,
116 node_type_id: NodeTypeId,
117 node_field_id: NodeFieldId,
118 ) -> Option<Cardinality> {
119 (*self).field_cardinality(node_type_id, node_field_id)
120 }
121 fn valid_field_types(
122 &self,
123 node_type_id: NodeTypeId,
124 node_field_id: NodeFieldId,
125 ) -> &[NodeTypeId] {
126 (*self).valid_field_types(node_type_id, node_field_id)
127 }
128 fn is_valid_field_type(
129 &self,
130 node_type_id: NodeTypeId,
131 node_field_id: NodeFieldId,
132 child: NodeTypeId,
133 ) -> bool {
134 (*self).is_valid_field_type(node_type_id, node_field_id, child)
135 }
136 fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality> {
137 (*self).children_cardinality(node_type_id)
138 }
139 fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId] {
140 (*self).valid_child_types(node_type_id)
141 }
142 fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool {
143 (*self).is_valid_child_type(node_type_id, child)
144 }
145}
146
147#[derive(Debug, Clone, Copy)]
149pub struct StaticFieldInfo {
150 pub cardinality: Cardinality,
151 pub valid_types: &'static [NodeTypeId],
152}
153
154#[derive(Debug, Clone, Copy)]
156pub struct StaticChildrenInfo {
157 pub cardinality: Cardinality,
158 pub valid_types: &'static [NodeTypeId],
159}
160
161#[derive(Debug, Clone, Copy)]
166pub struct StaticNodeTypeInfo {
167 pub name: &'static str,
168 pub named: bool,
169 pub fields: &'static [(NodeFieldId, StaticFieldInfo)],
171 pub children: Option<StaticChildrenInfo>,
172}
173
174#[derive(Debug, Clone, Copy)]
179pub struct StaticNodeTypes {
180 nodes: &'static [(NodeTypeId, StaticNodeTypeInfo)],
182 extras: &'static [NodeTypeId],
184 root: Option<NodeTypeId>,
185}
186
187impl StaticNodeTypes {
188 pub const fn new(
189 nodes: &'static [(NodeTypeId, StaticNodeTypeInfo)],
190 extras: &'static [NodeTypeId],
191 root: Option<NodeTypeId>,
192 ) -> Self {
193 Self {
194 nodes,
195 extras,
196 root,
197 }
198 }
199
200 pub fn get(&self, node_type_id: NodeTypeId) -> Option<&'static StaticNodeTypeInfo> {
202 self.nodes
203 .binary_search_by_key(&node_type_id, |(node_id, _)| *node_id)
204 .ok()
205 .map(|idx| &self.nodes[idx].1)
206 }
207
208 pub fn contains(&self, node_type_id: NodeTypeId) -> bool {
210 self.nodes
211 .binary_search_by_key(&node_type_id, |(node_id, _)| *node_id)
212 .is_ok()
213 }
214
215 pub fn field(
217 &self,
218 node_type_id: NodeTypeId,
219 field_id: NodeFieldId,
220 ) -> Option<&'static StaticFieldInfo> {
221 let info = self.ensure_node(node_type_id);
222 info.fields
223 .binary_search_by_key(&field_id, |(fid, _)| *fid)
224 .ok()
225 .map(|idx| &info.fields[idx].1)
226 }
227
228 pub fn children(&self, node_type_id: NodeTypeId) -> Option<StaticChildrenInfo> {
230 self.ensure_node(node_type_id).children
231 }
232
233 pub fn extras(&self) -> &'static [NodeTypeId] {
235 self.extras
236 }
237
238 pub fn len(&self) -> usize {
239 self.nodes.len()
240 }
241
242 pub fn is_empty(&self) -> bool {
243 self.nodes.is_empty()
244 }
245
246 pub fn iter(&self) -> impl Iterator<Item = (NodeTypeId, &'static StaticNodeTypeInfo)> {
247 self.nodes.iter().map(|(id, info)| (*id, info))
248 }
249}
250
251impl NodeTypes for StaticNodeTypes {
252 fn root(&self) -> Option<NodeTypeId> {
253 self.root
254 }
255
256 fn is_extra(&self, node_type_id: NodeTypeId) -> bool {
257 self.extras.contains(&node_type_id)
258 }
259
260 fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool {
261 self.get(node_type_id).is_some_and(|info| {
262 info.fields
263 .binary_search_by_key(&node_field_id, |(fid, _)| *fid)
264 .is_ok()
265 })
266 }
267
268 fn field_cardinality(
269 &self,
270 node_type_id: NodeTypeId,
271 node_field_id: NodeFieldId,
272 ) -> Option<Cardinality> {
273 self.field(node_type_id, node_field_id)
274 .map(|f| f.cardinality)
275 }
276
277 fn valid_field_types(
278 &self,
279 node_type_id: NodeTypeId,
280 node_field_id: NodeFieldId,
281 ) -> &[NodeTypeId] {
282 self.field(node_type_id, node_field_id)
283 .map(|f| f.valid_types)
284 .unwrap_or(&[])
285 }
286
287 fn is_valid_field_type(
288 &self,
289 node_type_id: NodeTypeId,
290 node_field_id: NodeFieldId,
291 child: NodeTypeId,
292 ) -> bool {
293 self.valid_field_types(node_type_id, node_field_id)
294 .contains(&child)
295 }
296
297 fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality> {
298 self.children(node_type_id).map(|c| c.cardinality)
299 }
300
301 fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId] {
302 self.children(node_type_id)
303 .map(|c| c.valid_types)
304 .unwrap_or(&[])
305 }
306
307 fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool {
308 self.valid_child_types(node_type_id).contains(&child)
309 }
310}
311
312#[derive(Debug, Clone)]
314pub struct FieldInfo {
315 pub cardinality: Cardinality,
316 pub valid_types: Vec<NodeTypeId>,
317}
318
319#[derive(Debug, Clone)]
321pub struct ChildrenInfo {
322 pub cardinality: Cardinality,
323 pub valid_types: Vec<NodeTypeId>,
324}
325
326#[derive(Debug, Clone)]
330pub struct NodeTypeInfo {
331 pub name: String,
332 pub named: bool,
333 pub fields: HashMap<NodeFieldId, FieldInfo>,
334 pub children: Option<ChildrenInfo>,
335}
336
337#[derive(Debug, Clone)]
342pub struct DynamicNodeTypes {
343 nodes: HashMap<NodeTypeId, NodeTypeInfo>,
344 extras: Vec<NodeTypeId>,
345 root: Option<NodeTypeId>,
346}
347
348impl DynamicNodeTypes {
349 pub fn from_raw(
350 nodes: HashMap<NodeTypeId, NodeTypeInfo>,
351 extras: Vec<NodeTypeId>,
352 root: Option<NodeTypeId>,
353 ) -> Self {
354 Self {
355 nodes,
356 extras,
357 root,
358 }
359 }
360
361 pub fn build<F, G>(raw_nodes: &[RawNode], node_id_for_name: F, field_id_for_name: G) -> Self
363 where
364 F: Fn(&str, bool) -> Option<NodeTypeId>,
365 G: Fn(&str) -> Option<NodeFieldId>,
366 {
367 let mut nodes = HashMap::new();
368 let mut extras = Vec::new();
369 let mut root = None;
370
371 for raw in raw_nodes {
372 let Some(node_id) = node_id_for_name(&raw.type_name, raw.named) else {
373 continue;
374 };
375
376 if raw.root {
377 root = Some(node_id);
378 }
379
380 if raw.extra {
381 extras.push(node_id);
382 }
383
384 let mut fields = HashMap::new();
385 for (field_name, raw_card) in &raw.fields {
386 let Some(field_id) = field_id_for_name(field_name) else {
387 continue;
388 };
389
390 let valid_types = raw_card
391 .types
392 .iter()
393 .filter_map(|t| node_id_for_name(&t.type_name, t.named))
394 .collect();
395
396 fields.insert(
397 field_id,
398 FieldInfo {
399 cardinality: Cardinality {
400 multiple: raw_card.multiple,
401 required: raw_card.required,
402 },
403 valid_types,
404 },
405 );
406 }
407
408 let children = raw.children.as_ref().map(|raw_card| {
409 let valid_types = raw_card
410 .types
411 .iter()
412 .filter_map(|t| node_id_for_name(&t.type_name, t.named))
413 .collect();
414
415 ChildrenInfo {
416 cardinality: Cardinality {
417 multiple: raw_card.multiple,
418 required: raw_card.required,
419 },
420 valid_types,
421 }
422 });
423
424 nodes.insert(
425 node_id,
426 NodeTypeInfo {
427 name: raw.type_name.clone(),
428 named: raw.named,
429 fields,
430 children,
431 },
432 );
433 }
434
435 Self {
436 nodes,
437 extras,
438 root,
439 }
440 }
441
442 pub fn get(&self, node_type_id: NodeTypeId) -> Option<&NodeTypeInfo> {
443 self.nodes.get(&node_type_id)
444 }
445
446 pub fn contains(&self, node_type_id: NodeTypeId) -> bool {
447 self.nodes.contains_key(&node_type_id)
448 }
449
450 pub fn field(&self, node_type_id: NodeTypeId, field_id: NodeFieldId) -> Option<&FieldInfo> {
451 self.ensure_node(node_type_id).fields.get(&field_id)
452 }
453
454 pub fn children(&self, node_type_id: NodeTypeId) -> Option<&ChildrenInfo> {
455 self.ensure_node(node_type_id).children.as_ref()
456 }
457
458 pub fn extras(&self) -> &[NodeTypeId] {
459 &self.extras
460 }
461
462 pub fn len(&self) -> usize {
463 self.nodes.len()
464 }
465
466 pub fn is_empty(&self) -> bool {
467 self.nodes.is_empty()
468 }
469
470 pub fn iter(&self) -> impl Iterator<Item = (NodeTypeId, &NodeTypeInfo)> {
471 self.nodes.iter().map(|(&id, info)| (id, info))
472 }
473
474 pub fn sorted_node_ids(&self) -> Vec<NodeTypeId> {
476 let mut ids: Vec<_> = self.nodes.keys().copied().collect();
477 ids.sort_unstable();
478 ids
479 }
480
481 pub fn sorted_extras(&self) -> Vec<NodeTypeId> {
483 let mut ids = self.extras.clone();
484 ids.sort_unstable();
485 ids
486 }
487}
488
489impl NodeTypes for DynamicNodeTypes {
490 fn root(&self) -> Option<NodeTypeId> {
491 self.root
492 }
493
494 fn is_extra(&self, node_type_id: NodeTypeId) -> bool {
495 self.extras.contains(&node_type_id)
496 }
497
498 fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool {
499 self.nodes
500 .get(&node_type_id)
501 .is_some_and(|n| n.fields.contains_key(&node_field_id))
502 }
503
504 fn field_cardinality(
505 &self,
506 node_type_id: NodeTypeId,
507 node_field_id: NodeFieldId,
508 ) -> Option<Cardinality> {
509 self.field(node_type_id, node_field_id)
510 .map(|f| f.cardinality)
511 }
512
513 fn valid_field_types(
514 &self,
515 node_type_id: NodeTypeId,
516 node_field_id: NodeFieldId,
517 ) -> &[NodeTypeId] {
518 self.field(node_type_id, node_field_id)
519 .map(|f| f.valid_types.as_slice())
520 .unwrap_or(&[])
521 }
522
523 fn is_valid_field_type(
524 &self,
525 node_type_id: NodeTypeId,
526 node_field_id: NodeFieldId,
527 child: NodeTypeId,
528 ) -> bool {
529 self.valid_field_types(node_type_id, node_field_id)
530 .contains(&child)
531 }
532
533 fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality> {
534 self.children(node_type_id).map(|c| c.cardinality)
535 }
536
537 fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId] {
538 self.children(node_type_id)
539 .map(|c| c.valid_types.as_slice())
540 .unwrap_or(&[])
541 }
542
543 fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool {
544 self.valid_child_types(node_type_id).contains(&child)
545 }
546}
547
548#[cfg(test)]
549mod tests {
550 use super::*;
551
552 const SAMPLE_JSON: &str = r#"[
553 {
554 "type": "expression",
555 "named": true,
556 "subtypes": [
557 {"type": "identifier", "named": true},
558 {"type": "number", "named": true}
559 ]
560 },
561 {
562 "type": "function_declaration",
563 "named": true,
564 "fields": {
565 "name": {
566 "multiple": false,
567 "required": true,
568 "types": [{"type": "identifier", "named": true}]
569 },
570 "body": {
571 "multiple": false,
572 "required": true,
573 "types": [{"type": "block", "named": true}]
574 }
575 }
576 },
577 {
578 "type": "program",
579 "named": true,
580 "root": true,
581 "fields": {},
582 "children": {
583 "multiple": true,
584 "required": false,
585 "types": [{"type": "statement", "named": true}]
586 }
587 },
588 {
589 "type": "comment",
590 "named": true,
591 "extra": true
592 },
593 {
594 "type": "identifier",
595 "named": true
596 },
597 {
598 "type": "+",
599 "named": false
600 }
601 ]"#;
602
603 #[test]
604 fn parse_raw_nodes() {
605 let nodes = parse_node_types(SAMPLE_JSON).unwrap();
606 assert_eq!(nodes.len(), 6);
607
608 let expr = nodes.iter().find(|n| n.type_name == "expression").unwrap();
609 assert!(expr.named);
610 assert!(expr.subtypes.is_some());
611 assert_eq!(expr.subtypes.as_ref().unwrap().len(), 2);
612
613 let func = nodes
614 .iter()
615 .find(|n| n.type_name == "function_declaration")
616 .unwrap();
617 assert!(func.fields.contains_key("name"));
618 assert!(func.fields.contains_key("body"));
619
620 let plus = nodes.iter().find(|n| n.type_name == "+").unwrap();
621 assert!(!plus.named);
622 }
623
624 #[test]
625 fn build_dynamic_node_types() {
626 let raw = parse_node_types(SAMPLE_JSON).unwrap();
627
628 let node_ids: HashMap<(&str, bool), NodeTypeId> = [
629 (("expression", true), 1),
630 (("function_declaration", true), 2),
631 (("program", true), 3),
632 (("comment", true), 4),
633 (("identifier", true), 5),
634 (("+", false), 6),
635 (("block", true), 7),
636 (("statement", true), 8),
637 (("number", true), 9),
638 ]
639 .into_iter()
640 .collect();
641
642 let field_ids: HashMap<&str, NodeFieldId> = [
643 ("name", NonZeroU16::new(1).unwrap()),
644 ("body", NonZeroU16::new(2).unwrap()),
645 ]
646 .into_iter()
647 .collect();
648
649 let node_types = DynamicNodeTypes::build(
650 &raw,
651 |name, named| node_ids.get(&(name, named)).copied(),
652 |name| field_ids.get(name).copied(),
653 );
654
655 assert_eq!(node_types.len(), 6);
656
657 assert_eq!(node_types.root(), Some(3));
659 assert!(node_types.is_extra(4));
660 assert!(!node_types.is_extra(5));
661 assert!(node_types.has_field(2, NonZeroU16::new(1).unwrap()));
662 assert!(node_types.has_field(2, NonZeroU16::new(2).unwrap()));
663 assert!(!node_types.has_field(2, NonZeroU16::new(99).unwrap()));
664 assert!(node_types.is_valid_field_type(2, NonZeroU16::new(1).unwrap(), 5));
665 assert!(!node_types.is_valid_field_type(2, NonZeroU16::new(1).unwrap(), 7));
666 }
667
668 static TEST_VALID_TYPES_ID: [NodeTypeId; 1] = [5]; static TEST_VALID_TYPES_BLOCK: [NodeTypeId; 1] = [7]; static TEST_CHILDREN_TYPES: [NodeTypeId; 1] = [8]; static TEST_FIELDS: [(NodeFieldId, StaticFieldInfo); 2] = [
674 (
675 NonZeroU16::new(1).unwrap(),
676 StaticFieldInfo {
677 cardinality: Cardinality {
678 multiple: false,
679 required: true,
680 },
681 valid_types: &TEST_VALID_TYPES_ID,
682 },
683 ),
684 (
685 NonZeroU16::new(2).unwrap(),
686 StaticFieldInfo {
687 cardinality: Cardinality {
688 multiple: false,
689 required: true,
690 },
691 valid_types: &TEST_VALID_TYPES_BLOCK,
692 },
693 ),
694 ];
695
696 static TEST_NODES: [(NodeTypeId, StaticNodeTypeInfo); 4] = [
697 (
698 1,
699 StaticNodeTypeInfo {
700 name: "expression",
701 named: true,
702 fields: &[],
703 children: None,
704 },
705 ),
706 (
707 2,
708 StaticNodeTypeInfo {
709 name: "function_declaration",
710 named: true,
711 fields: &TEST_FIELDS,
712 children: None,
713 },
714 ),
715 (
716 3,
717 StaticNodeTypeInfo {
718 name: "program",
719 named: true,
720 fields: &[],
721 children: Some(StaticChildrenInfo {
722 cardinality: Cardinality {
723 multiple: true,
724 required: false,
725 },
726 valid_types: &TEST_CHILDREN_TYPES,
727 }),
728 },
729 ),
730 (
731 4,
732 StaticNodeTypeInfo {
733 name: "comment",
734 named: true,
735 fields: &[],
736 children: None,
737 },
738 ),
739 ];
740
741 static TEST_EXTRAS: [NodeTypeId; 1] = [4];
742
743 static TEST_STATIC_NODE_TYPES: StaticNodeTypes =
744 StaticNodeTypes::new(&TEST_NODES, &TEST_EXTRAS, Some(3));
745
746 #[test]
747 fn static_node_types_get() {
748 let info = TEST_STATIC_NODE_TYPES.get(2).unwrap();
749 assert_eq!(info.name, "function_declaration");
750 assert!(info.named);
751
752 assert!(TEST_STATIC_NODE_TYPES.get(99).is_none());
753 }
754
755 #[test]
756 fn static_node_types_contains() {
757 assert!(TEST_STATIC_NODE_TYPES.contains(1));
758 assert!(TEST_STATIC_NODE_TYPES.contains(2));
759 assert!(!TEST_STATIC_NODE_TYPES.contains(99));
760 }
761
762 #[test]
763 fn static_node_types_trait() {
764 assert_eq!(TEST_STATIC_NODE_TYPES.root(), Some(3));
766 assert!(TEST_STATIC_NODE_TYPES.is_extra(4));
767 assert!(!TEST_STATIC_NODE_TYPES.is_extra(1));
768
769 assert!(TEST_STATIC_NODE_TYPES.has_field(2, NonZeroU16::new(1).unwrap()));
770 assert!(TEST_STATIC_NODE_TYPES.has_field(2, NonZeroU16::new(2).unwrap()));
771 assert!(!TEST_STATIC_NODE_TYPES.has_field(2, NonZeroU16::new(99).unwrap()));
772 assert!(!TEST_STATIC_NODE_TYPES.has_field(1, NonZeroU16::new(1).unwrap()));
773
774 assert!(TEST_STATIC_NODE_TYPES.is_valid_field_type(2, NonZeroU16::new(1).unwrap(), 5));
775 assert!(!TEST_STATIC_NODE_TYPES.is_valid_field_type(2, NonZeroU16::new(1).unwrap(), 7));
776 assert!(TEST_STATIC_NODE_TYPES.is_valid_field_type(2, NonZeroU16::new(2).unwrap(), 7));
777
778 let field_types = TEST_STATIC_NODE_TYPES.valid_field_types(2, NonZeroU16::new(1).unwrap());
779 assert_eq!(field_types, &[5]);
780
781 let card = TEST_STATIC_NODE_TYPES
782 .field_cardinality(2, NonZeroU16::new(1).unwrap())
783 .unwrap();
784 assert!(!card.multiple);
785 assert!(card.required);
786 }
787
788 #[test]
789 fn static_node_types_children() {
790 let card = TEST_STATIC_NODE_TYPES.children_cardinality(3).unwrap();
791 assert!(card.multiple);
792 assert!(!card.required);
793
794 let child_types = TEST_STATIC_NODE_TYPES.valid_child_types(3);
795 assert_eq!(child_types, &[8]);
796
797 assert!(TEST_STATIC_NODE_TYPES.is_valid_child_type(3, 8));
798 assert!(!TEST_STATIC_NODE_TYPES.is_valid_child_type(3, 5));
799
800 assert!(TEST_STATIC_NODE_TYPES.children_cardinality(1).is_none());
801 assert!(TEST_STATIC_NODE_TYPES.valid_child_types(1).is_empty());
802 }
803
804 #[test]
805 fn static_node_types_len() {
806 assert_eq!(TEST_STATIC_NODE_TYPES.len(), 4);
807 assert!(!TEST_STATIC_NODE_TYPES.is_empty());
808 }
809
810 #[test]
811 fn static_node_types_iter() {
812 let ids: Vec<_> = TEST_STATIC_NODE_TYPES.iter().map(|(id, _)| id).collect();
813 assert_eq!(ids, vec![1, 2, 3, 4]);
814 }
815}