yang2/
iter.rs

1//
2// Copyright (c) The yang2-rs Core Contributors
3//
4// SPDX-License-Identifier: MIT
5//
6
7//! YANG iterators.
8
9use crate::context::Context;
10use crate::data::Metadata;
11use crate::schema::{SchemaModule, SchemaNode};
12use crate::utils::Binding;
13use bitflags::bitflags;
14use libyang2_sys as ffi;
15
16/// Common methods used by multiple data and schema node iterators.
17#[doc(hidden)]
18pub trait NodeIterable<'a>: Sized + Clone + PartialEq + Binding<'a> {
19    /// Returns the parent node.
20    fn parent(&self) -> Option<Self>;
21
22    /// Returns the next sibling node.
23    fn next_sibling(&self) -> Option<Self>;
24
25    /// Returns the fist child none.
26    fn first_child(&self) -> Option<Self>;
27}
28
29/// An iterator over the siblings of a node.
30#[derive(Debug)]
31pub struct Siblings<'a, T>
32where
33    T: NodeIterable<'a>,
34{
35    next: Option<T>,
36    _marker: std::marker::PhantomData<&'a T>,
37}
38
39/// An iterator over the ancestors of a node.
40#[derive(Debug)]
41pub struct Ancestors<'a, T>
42where
43    T: NodeIterable<'a>,
44{
45    next: Option<T>,
46    _marker: std::marker::PhantomData<&'a T>,
47}
48
49/// An iterator over all elements in a tree (depth-first search algorithm).
50///
51/// When traversing over schema trees, note that _actions_ and _notifications_
52/// are ignored.
53#[derive(Debug)]
54pub struct Traverse<'a, T>
55where
56    T: NodeIterable<'a>,
57{
58    start: T,
59    next: Option<T>,
60    _marker: std::marker::PhantomData<&'a T>,
61}
62
63/// An customizable iterator over the children of a node.
64#[derive(Debug)]
65pub struct Getnext<'a> {
66    flags: IterSchemaFlags,
67    last: Option<SchemaNode<'a>>,
68    parent: Option<SchemaNode<'a>>,
69    module: Option<SchemaModule<'a>>,
70}
71
72bitflags! {
73    /// Various options that control iteration behavior.
74    #[derive(Debug)]
75    pub struct IterSchemaFlags: u32 {
76        /// Return #LYS_CHOICE nodes instead of looking into them.
77        const WITH_CHOICE = ffi::LYS_GETNEXT_WITHCHOICE;
78        /// Ignore (kind of conditional) nodes within choice node.
79        const NO_CHOICE = ffi::LYS_GETNEXT_NOCHOICE;
80        /// Allow returning #LYS_CASE nodes instead of looking into them.
81        const WITH_CASE = ffi::LYS_GETNEXT_WITHCASE;
82        /// Look into non-presence container, instead of returning container
83        /// itself.
84        const INTO_NP_CONT = ffi::LYS_GETNEXT_INTONPCONT;
85        /// Provide RPC's/action's output schema nodes instead of input schema
86        /// nodes provided by default.
87        const OUTPUT = ffi::LYS_GETNEXT_OUTPUT;
88    }
89}
90
91/// An iterator over a set of nodes.
92///
93/// This is a safe wrapper around ffi::ly_set.
94#[derive(Debug)]
95pub struct Set<'a, T>
96where
97    T: NodeIterable<'a>,
98{
99    container: &'a T::Container,
100    slice: &'a [*mut T::CType],
101}
102
103/// An iterator over an array of nodes or substatements.
104///
105/// This is a safe wrapper around libyang2's
106/// [sized arrays](https://netopeer.liberouter.org/doc/libyang/libyang2/html/howto_structures.html#sizedarrays).
107#[derive(Debug)]
108pub struct Array<'a, S: Binding<'a>> {
109    context: &'a Context,
110    raw: *mut S::CType,
111    ptr_size: usize,
112    count: usize,
113}
114
115/// An iterator over a list of schema modules.
116#[derive(Debug)]
117pub struct SchemaModules<'a> {
118    context: &'a Context,
119    index: u32,
120}
121
122/// An iterator over a list of metadata.
123#[derive(Debug)]
124pub struct MetadataList<'a, 'b> {
125    next: Option<Metadata<'a, 'b>>,
126}
127
128// ===== impl Siblings =====
129
130impl<'a, T> Siblings<'a, T>
131where
132    T: NodeIterable<'a>,
133{
134    pub fn new(next: Option<T>) -> Siblings<'a, T> {
135        Siblings {
136            next,
137            _marker: std::marker::PhantomData,
138        }
139    }
140}
141
142impl<'a, T> Iterator for Siblings<'a, T>
143where
144    T: NodeIterable<'a>,
145{
146    type Item = T;
147
148    fn next(&mut self) -> Option<T> {
149        let ret = self.next.clone();
150        if let Some(next) = &self.next {
151            self.next = next.next_sibling();
152        }
153        ret
154    }
155}
156
157// ===== impl Ancestors =====
158
159impl<'a, T> Ancestors<'a, T>
160where
161    T: NodeIterable<'a>,
162{
163    pub fn new(next: Option<T>) -> Ancestors<'a, T> {
164        Ancestors {
165            next,
166            _marker: std::marker::PhantomData,
167        }
168    }
169}
170
171impl<'a, T> Iterator for Ancestors<'a, T>
172where
173    T: NodeIterable<'a>,
174{
175    type Item = T;
176
177    fn next(&mut self) -> Option<T> {
178        let node = self.next.clone();
179        if let Some(next) = &self.next {
180            self.next = next.parent();
181        }
182        node
183    }
184}
185
186// ===== impl Traverse =====
187
188impl<'a, T> Traverse<'a, T>
189where
190    T: NodeIterable<'a>,
191{
192    pub fn new(start: T) -> Traverse<'a, T> {
193        let next = start.clone();
194
195        Traverse {
196            start,
197            next: Some(next),
198            _marker: std::marker::PhantomData,
199        }
200    }
201}
202
203impl<'a, T> Iterator for Traverse<'a, T>
204where
205    T: NodeIterable<'a>,
206{
207    type Item = T;
208
209    fn next(&mut self) -> Option<T> {
210        let ret = self.next.clone();
211
212        if let Some(elem) = &mut self.next {
213            // Select element for the next run - children first.
214            let mut next_elem = elem.first_child();
215            if next_elem.is_none() {
216                // Check end condition.
217                if *elem == self.start {
218                    self.next = None;
219                    return ret;
220                }
221
222                // No children, try siblings.
223                next_elem = elem.next_sibling();
224            }
225
226            while next_elem.is_none() {
227                // Parent is already processed, go to its sibling.
228                *elem = elem.parent().unwrap();
229
230                // Check end condition.
231                if *elem == self.start {
232                    self.next = None;
233                    return ret;
234                }
235                next_elem = elem.next_sibling();
236            }
237
238            *elem = next_elem.unwrap();
239        }
240
241        ret
242    }
243}
244
245// ===== impl Getnext =====
246
247impl<'a> Getnext<'a> {
248    pub fn new(
249        flags: IterSchemaFlags,
250        parent: Option<SchemaNode<'a>>,
251        module: Option<SchemaModule<'a>>,
252    ) -> Getnext<'a> {
253        Getnext {
254            flags,
255            last: None,
256            parent,
257            module,
258        }
259    }
260}
261
262impl<'a> Iterator for Getnext<'a> {
263    type Item = SchemaNode<'a>;
264
265    fn next(&mut self) -> Option<SchemaNode<'a>> {
266        let last = self.last.take();
267        let parent = self.parent.clone();
268        let module = self.module.clone();
269
270        let last_raw =
271            last.map(|snode| snode.raw as _).unwrap_or(std::ptr::null());
272        let parent_raw = parent
273            .as_ref()
274            .map(|snode| snode.raw as _)
275            .unwrap_or(std::ptr::null());
276        let module_raw = module
277            .as_ref()
278            .map(|smodule| unsafe { (*smodule.raw).compiled } as _)
279            .unwrap_or(std::ptr::null());
280        let next = unsafe {
281            ffi::lys_getnext(
282                last_raw,
283                parent_raw,
284                module_raw,
285                self.flags.bits(),
286            )
287        };
288
289        let context = parent
290            .map(|snode| snode.context)
291            .or(module.map(|smodule| smodule.context))
292            .unwrap();
293        let next = unsafe { SchemaNode::from_raw_opt(context, next as *mut _) };
294        self.last = next.clone();
295        next
296    }
297}
298
299// ===== impl Set =====
300
301impl<'a, T> Set<'a, T>
302where
303    T: NodeIterable<'a>,
304{
305    pub fn new(
306        container: &'a T::Container,
307        slice: &'a [*mut T::CType],
308    ) -> Set<'a, T> {
309        Set { container, slice }
310    }
311}
312
313impl<'a, T> Iterator for Set<'a, T>
314where
315    T: NodeIterable<'a>,
316{
317    type Item = T;
318
319    fn next(&mut self) -> Option<T> {
320        if !self.slice.is_empty() {
321            let dnode =
322                Some(unsafe { T::from_raw(self.container, self.slice[0]) });
323            self.slice = &self.slice[1..];
324            dnode
325        } else {
326            None
327        }
328    }
329
330    fn size_hint(&self) -> (usize, Option<usize>) {
331        (0, Some(self.slice.len()))
332    }
333}
334
335unsafe impl<'a, T> Send for Set<'a, T> where T: NodeIterable<'a> {}
336unsafe impl<'a, T> Sync for Set<'a, T> where T: NodeIterable<'a> {}
337
338// ===== impl Array =====
339
340impl<'a, S> Array<'a, S>
341where
342    S: Binding<'a>,
343{
344    pub fn new(
345        context: &'a Context,
346        raw: *mut S::CType,
347        ptr_size: usize,
348    ) -> Array<'a, S> {
349        // Get the number of records in the array (equivalent to
350        // LY_ARRAY_COUNT).
351        let count = if raw.is_null() {
352            0
353        } else {
354            unsafe { (raw as *const usize).offset(-1).read() }
355        };
356
357        Array {
358            context,
359            raw,
360            ptr_size,
361            count,
362        }
363    }
364}
365
366impl<'a, S> Iterator for Array<'a, S>
367where
368    S: Binding<'a, Container = Context>,
369{
370    type Item = S;
371
372    fn next(&mut self) -> Option<S> {
373        if self.count > 0 {
374            let next = unsafe { S::from_raw_opt(self.context, self.raw) };
375            self.count -= 1;
376            self.raw = (self.raw as usize + self.ptr_size) as *mut S::CType;
377            next
378        } else {
379            None
380        }
381    }
382
383    fn size_hint(&self) -> (usize, Option<usize>) {
384        (0, Some(self.count))
385    }
386}
387
388unsafe impl<'a, S> Send for Array<'a, S> where S: NodeIterable<'a> {}
389unsafe impl<'a, S> Sync for Array<'a, S> where S: NodeIterable<'a> {}
390
391// ===== impl SchemaModules =====
392
393impl<'a> SchemaModules<'a> {
394    pub fn new(context: &'a Context, skip_internal: bool) -> SchemaModules<'a> {
395        let index = if skip_internal {
396            context.internal_module_count()
397        } else {
398            0
399        };
400        SchemaModules { context, index }
401    }
402}
403
404impl<'a> Iterator for SchemaModules<'a> {
405    type Item = SchemaModule<'a>;
406
407    fn next(&mut self) -> Option<SchemaModule<'a>> {
408        let rmodule = unsafe {
409            ffi::ly_ctx_get_module_iter(self.context.raw, &mut self.index)
410        };
411        unsafe { SchemaModule::from_raw_opt(self.context, rmodule as *mut _) }
412    }
413}
414
415// ===== impl MetadataList =====
416
417impl<'a, 'b> MetadataList<'a, 'b> {
418    pub fn new(next: Option<Metadata<'a, 'b>>) -> MetadataList<'a, 'b> {
419        MetadataList { next }
420    }
421}
422
423impl<'a, 'b> Iterator for MetadataList<'a, 'b> {
424    type Item = Metadata<'a, 'b>;
425
426    fn next(&mut self) -> Option<Metadata<'a, 'b>> {
427        let meta = self.next.clone();
428        if let Some(next) = &self.next {
429            self.next = next.next();
430        }
431        meta
432    }
433}