cairo_lang_syntax/node/
element_list.rs

1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use super::SyntaxGroup;
5use crate::node::{SyntaxNode, TypedSyntaxNode};
6
7// A typed view of an element list node.
8// STEP=1 means a sequence of elements (e.g. sequence of trivia elements).
9// STEP=2 means a separated sequence (e.g. argument list separated by `,`).
10#[derive(Clone, Debug, Eq, Hash, PartialEq)]
11pub struct ElementList<T: TypedSyntaxNode, const STEP: usize> {
12    pub node: SyntaxNode,
13    phantom: PhantomData<T>,
14}
15impl<T: TypedSyntaxNode, const STEP: usize> ElementList<T, STEP> {
16    pub fn new(node: SyntaxNode) -> Self {
17        Self { node, phantom: PhantomData {} }
18    }
19}
20impl<T: TypedSyntaxNode> ElementList<T, 1> {
21    pub fn elements_vec(&self, db: &dyn SyntaxGroup) -> Vec<T> {
22        self.elements(db).collect()
23    }
24    pub fn elements<'a>(
25        &self,
26        db: &'a dyn SyntaxGroup,
27    ) -> impl ExactSizeIterator<Item = T> + DoubleEndedIterator + 'a {
28        ElementListRawIter::new(self.node.get_children(db)).map(move |x| T::from_syntax_node(db, x))
29    }
30    pub fn has_tail(&self, _db: &dyn SyntaxGroup) -> bool {
31        false
32    }
33}
34impl<T: TypedSyntaxNode> ElementList<T, 2> {
35    pub fn elements_vec(&self, db: &dyn SyntaxGroup) -> Vec<T> {
36        self.elements(db).collect()
37    }
38    pub fn elements<'a>(
39        &self,
40        db: &'a dyn SyntaxGroup,
41    ) -> impl ExactSizeIterator<Item = T> + DoubleEndedIterator + 'a {
42        ElementListRawIter::new(self.node.get_children(db))
43            .step_by(2)
44            .map(move |x| T::from_syntax_node(db, x))
45    }
46    pub fn has_tail(&self, db: &dyn SyntaxGroup) -> bool {
47        !self.node.get_children(db).len().is_multiple_of(2)
48    }
49}
50
51/// Iterator over the raw elements of an `ElementList`.
52struct ElementListRawIter {
53    /// The `Arc` storing the actual node.
54    _data: Arc<[SyntaxNode]>,
55    /// Actual iterator over the elements.
56    iter: std::slice::Iter<'static, SyntaxNode>,
57}
58
59impl ElementListRawIter {
60    fn new(data: Arc<[SyntaxNode]>) -> Self {
61        // We leak the Arc to get a 'static reference, and keep the Arc in the struct to avoid
62        // leaks.
63        let ptr: *const [SyntaxNode] = Arc::as_ptr(&data);
64        let slice: &'static [SyntaxNode] = unsafe { std::mem::transmute(&*ptr) };
65        let iter = slice.iter();
66        Self { _data: data, iter }
67    }
68}
69
70impl Iterator for ElementListRawIter {
71    type Item = SyntaxNode;
72
73    fn next(&mut self) -> Option<Self::Item> {
74        self.iter.next().copied()
75    }
76    fn size_hint(&self) -> (usize, Option<usize>) {
77        self.iter.size_hint()
78    }
79}
80impl ExactSizeIterator for ElementListRawIter {
81    fn len(&self) -> usize {
82        self.iter.len()
83    }
84}
85impl DoubleEndedIterator for ElementListRawIter {
86    fn next_back(&mut self) -> Option<Self::Item> {
87        self.iter.next_back().copied()
88    }
89}