• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kaidokert / heapless-graphs-rs / 15791628916

21 Jun 2025 03:28AM UTC coverage: 94.579% (-0.1%) from 94.725%
15791628916

Pull #12

github

web-flow
Merge af3ccbf83 into ce0622484
Pull Request #12: Rework node add/remove

194 of 263 new or added lines in 5 files covered. (73.76%)

6 existing lines in 1 file now uncovered.

6543 of 6918 relevant lines covered (94.58%)

38.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.06
/src/nodes.rs
1
// SPDX-License-Identifier: Apache-2.0
2

3
//! Node structures
4
//!
5
//! This module implements various structures to use in both
6
//! edge list graphs with associated nodes and adjacency list graphs.
7

8
use core::marker::PhantomData;
9

10
/// Node index NI array of N elements, every item is a valid node
11
///
12
/// Alternatively, use an array `[NI;N]` or a slice: `&[NI]` directly
13
#[derive(Debug)]
14
pub struct NodeStruct<const N: usize, NI>(pub [NI; N]);
15
/// Node index NI array of N elements, nodes optionally populated
16
#[derive(Debug)]
17
pub struct NodeStructOption<const N: usize, NI>(pub [Option<NI>; N]);
18

19
/// Node index NI array of N elements, with node value V, every item is a valid node
20
#[derive(Debug)]
21
pub struct NodeValueStruct<const N: usize, NI, V>(pub [(NI, V); N]);
22

23
/// Node index NI array of N elements, with node value V, optionally populated
24
#[derive(Debug)]
25
pub struct NodeValueStructOption<const N: usize, NI, V>(pub [Option<(NI, V)>; N]);
26

27
/// Node index NI array of N elements, values in parallel array, every item is a valid node
28
#[derive(Debug)]
29
pub struct NodeValueTwoArray<const N: usize, NI, V>(pub [NI; N], pub [V; N]);
30

31
#[cfg(feature = "heapless")]
32
/// [Heapless vector](heapless::Vec) of node indexes
33
#[derive(Debug, Default)]
34
pub struct NodeStructVec<const N: usize, NI>(pub heapless::Vec<NI, N>);
35

36
#[cfg(feature = "heapless")]
37
/// [Heapless vector](heapless::Vec) of optionally populated node indexes
38
#[derive(Debug, Default)]
39
pub struct NodeStructOptionVec<const N: usize, NI>(pub heapless::Vec<Option<NI>, N>);
40

41
#[cfg(feature = "heapless")]
42
/// [Heapless vector](heapless::Vec) of node indexes with values
43
#[derive(Debug, Default)]
44
pub struct NodeStructVecValue<const N: usize, NI, V>(pub heapless::Vec<(NI, V), N>);
45

46
#[cfg(feature = "heapless")]
47
/// [Heapless vector](heapless::Vec) of optionally populated node indexes with values
48
#[derive(Debug, Default)]
49
pub struct NodeStructVecOptionValue<const N: usize, NI, V>(pub heapless::Vec<Option<(NI, V)>, N>);
50

51
/* Doesn't provide DoubleEndedIterator - not practical to use
52
#[cfg(feature = "heapless")]
53
pub struct NodeStructOptionSet<const N: usize, NI>(pub heapless::FnvIndexSet<NI, N>);
54
 */
55

56
/// Reference to a node, implemented for all node structures
57
///
58
/// It's used to implement iterators [`NodeRefIterator`] and
59
/// [`NodeOwningIterator`] through a common accessor interface
60
pub trait NodeRef {
61
    type NodeIndex;
62
    /// Reference to a node at given index
63
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex>;
64
    /// Check if node at index exists
65
    fn valid_node(&self, index: usize) -> bool {
371✔
66
        index < self.capacity()
371✔
67
    }
371✔
68
    /// Total capacity of the container
69
    fn capacity(&self) -> usize;
70
}
71

72
/// Extension of [`NodeRef`] that provides access to node values
73
///
74
/// This trait allows retrieving values associated with nodes in addition
75
/// to the basic node reference functionality.
76
pub trait NodeRefValue<V>: NodeRef {
77
    /// Returns a reference to a value of a node at index
78
    fn get_node_value(&self, index: usize) -> Option<&V>;
79
}
80

81
/// Implement NodeRef for slices directly, similar to [NodeStruct]
82
impl<T> NodeRef for &[T] {
83
    type NodeIndex = T;
84

85
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
6✔
86
        self.get(index)
6✔
87
    }
6✔
88

89
    fn capacity(&self) -> usize {
12✔
90
        self.len()
12✔
91
    }
12✔
92
}
93

94
/// Implement NodeRef for fixed-size arrays, similar to [NodeStruct]
95
impl<T, const N: usize> NodeRef for [T; N] {
96
    type NodeIndex = T;
97

98
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
186✔
99
        self.get(index)
186✔
100
    }
186✔
101

102
    fn capacity(&self) -> usize {
384✔
103
        self.len()
384✔
104
    }
384✔
105
}
106

107
impl<const N: usize, NI> NodeRef for NodeStruct<N, NI> {
108
    type NodeIndex = NI;
109
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
26✔
110
        self.0.get(index)
26✔
111
    }
26✔
112
    fn capacity(&self) -> usize {
56✔
113
        self.0.len()
56✔
114
    }
56✔
115
}
116

117
impl<const N: usize, NI> Default for NodeStruct<N, NI>
118
where
119
    NI: Default,
120
{
121
    fn default() -> Self {
×
122
        Self(core::array::from_fn(|_| NI::default()))
×
123
    }
×
124
}
125

126
impl<const N: usize, NI> NodeRef for NodeStructOption<N, NI> {
127
    type NodeIndex = NI;
128
    fn valid_node(&self, index: usize) -> bool {
661✔
129
        index < self.capacity() && self.0[index].is_some()
661✔
130
    }
661✔
131
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
332✔
132
        self.0.get(index).and_then(|ni| ni.as_ref())
332✔
133
    }
332✔
134
    fn capacity(&self) -> usize {
1,163✔
135
        self.0.len()
1,163✔
136
    }
1,163✔
137
}
138

139
impl<const N: usize, NI> Default for NodeStructOption<N, NI> {
140
    fn default() -> Self {
10✔
141
        Self(core::array::from_fn(|_| None))
34✔
142
    }
10✔
143
}
144

145
impl<const N: usize, NI, V> NodeRef for NodeValueStruct<N, NI, V> {
146
    type NodeIndex = NI;
147
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
28✔
148
        self.0.get(index).map(|ni| &ni.0)
28✔
149
    }
28✔
150
    fn capacity(&self) -> usize {
65✔
151
        self.0.len()
65✔
152
    }
65✔
153
}
154

155
impl<const N: usize, NI, V> Default for NodeValueStruct<N, NI, V>
156
where
157
    NI: Default,
158
    V: Default,
159
{
160
    fn default() -> Self {
×
161
        Self(core::array::from_fn(|_| (NI::default(), V::default())))
×
162
    }
×
163
}
164

165
impl<const N: usize, NI, V> NodeRefValue<V> for NodeValueStruct<N, NI, V> {
166
    fn get_node_value(&self, index: usize) -> Option<&V> {
25✔
167
        self.0.get(index).map(|ni| &ni.1)
25✔
168
    }
25✔
169
}
170

171
impl<const N: usize, NI, V> NodeRef for NodeValueStructOption<N, NI, V> {
172
    type NodeIndex = NI;
173
    fn valid_node(&self, index: usize) -> bool {
263✔
174
        index < self.capacity() && self.0[index].is_some()
263✔
175
    }
263✔
176
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
120✔
177
        if let Some(ni) = self.0.get(index) {
120✔
178
            ni.as_ref().map(|(ni, _)| ni)
120✔
179
        } else {
180
            None
×
181
        }
182
    }
120✔
183
    fn capacity(&self) -> usize {
514✔
184
        self.0.len()
514✔
185
    }
514✔
186
}
187
impl<const N: usize, NI, V> Default for NodeValueStructOption<N, NI, V> {
188
    fn default() -> Self {
×
189
        Self(core::array::from_fn(|_| None))
×
190
    }
×
191
}
192

193
impl<const N: usize, NI, V> NodeRefValue<V> for NodeValueStructOption<N, NI, V> {
194
    fn get_node_value(&self, index: usize) -> Option<&V> {
33✔
195
        if let Some(ni) = self.0.get(index) {
33✔
196
            ni.as_ref().map(|(_, v)| v)
32✔
197
        } else {
198
            None
1✔
199
        }
200
    }
33✔
201
}
202

203
impl<const N: usize, NI, V> NodeRef for NodeValueTwoArray<N, NI, V> {
204
    type NodeIndex = NI;
205
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
8✔
206
        self.0.get(index)
8✔
207
    }
8✔
208
    fn capacity(&self) -> usize {
18✔
209
        self.0.len()
18✔
210
    }
18✔
211
}
212

213
impl<const N: usize, NI, V> Default for NodeValueTwoArray<N, NI, V>
214
where
215
    NI: Default,
216
    V: Default,
217
{
218
    fn default() -> Self {
×
219
        Self(
×
220
            core::array::from_fn(|_| NI::default()),
×
221
            core::array::from_fn(|_| V::default()),
×
222
        )
×
223
    }
×
224
}
225

226
impl<const N: usize, NI, V> NodeRefValue<V> for NodeValueTwoArray<N, NI, V> {
227
    fn get_node_value(&self, index: usize) -> Option<&V> {
5✔
228
        self.1.get(index)
5✔
229
    }
5✔
230
}
231

232
// #region NodeStructVec variants
233

234
#[cfg(feature = "heapless")]
235
impl<const N: usize, NI> NodeRef for NodeStructVec<N, NI> {
236
    type NodeIndex = NI;
237
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
13✔
238
        self.0.get(index)
13✔
239
    }
13✔
240
    fn capacity(&self) -> usize {
21✔
241
        self.0.capacity()
21✔
242
    }
21✔
243
}
244

245
/// Implement NodeRef for heapless::Vec<NI,N>, similar to [NodeStructVec]
246
#[cfg(feature = "heapless")]
247
impl<const N: usize, NI> NodeRef for heapless::Vec<NI, N> {
248
    type NodeIndex = NI;
249
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
6✔
250
        self.get(index)
6✔
251
    }
6✔
252
    fn capacity(&self) -> usize {
12✔
253
        self.capacity()
12✔
254
    }
12✔
255
}
256

257
// #endregion NodeStructVec variants
258

259
#[cfg(feature = "heapless")]
260
impl<const N: usize, NI> NodeRef for NodeStructOptionVec<N, NI> {
261
    type NodeIndex = NI;
262
    fn valid_node(&self, index: usize) -> bool {
8✔
263
        index < self.capacity() && self.0.get(index).is_some()
8✔
264
    }
8✔
265
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
6✔
266
        self.0.get(index).and_then(|x| x.as_ref())
6✔
267
    }
6✔
268
    fn capacity(&self) -> usize {
12✔
269
        self.0.capacity()
12✔
270
    }
12✔
271
}
272

273
#[cfg(feature = "heapless")]
274
impl<const N: usize, NI, V> NodeRef for NodeStructVecValue<N, NI, V> {
275
    type NodeIndex = NI;
276
    fn valid_node(&self, index: usize) -> bool {
18✔
277
        index < self.capacity() && self.0.get(index).is_some()
18✔
278
    }
18✔
279
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
11✔
280
        self.0.get(index).map(|(ni, _)| ni)
11✔
281
    }
11✔
282
    fn capacity(&self) -> usize {
29✔
283
        self.0.capacity()
29✔
284
    }
29✔
285
}
286

287
#[cfg(feature = "heapless")]
288
impl<const N: usize, NI, V> NodeRefValue<V> for NodeStructVecValue<N, NI, V> {
289
    fn get_node_value(&self, index: usize) -> Option<&V> {
3✔
290
        self.0.get(index).map(|(_, v)| v)
3✔
291
    }
3✔
292
}
293

294
#[cfg(feature = "heapless")]
295
impl<const N: usize, NI, V> NodeRef for NodeStructVecOptionValue<N, NI, V> {
296
    type NodeIndex = NI;
297
    fn valid_node(&self, index: usize) -> bool {
40✔
298
        index < self.capacity() && self.0.get(index).is_some()
40✔
299
    }
40✔
300
    fn get_node(&self, index: usize) -> Option<&Self::NodeIndex> {
13✔
301
        self.0.get(index).and_then(|x| x.as_ref().map(|(ni, _)| ni))
13✔
302
    }
13✔
303
    fn capacity(&self) -> usize {
73✔
304
        self.0.capacity()
73✔
305
    }
73✔
306
}
307

308
#[cfg(feature = "heapless")]
309
impl<const N: usize, NI, V> NodeRefValue<V> for NodeStructVecOptionValue<N, NI, V> {
310
    fn get_node_value(&self, index: usize) -> Option<&V> {
3✔
311
        self.0.get(index).and_then(|x| x.as_ref().map(|(_, v)| v))
3✔
312
    }
3✔
313
}
314

315
macro_rules! define_node_iterator {
316
    (
317
        $(#[$attr:meta])*
318
        $name:ident,
319
        $(lifetime: $lifetime:lifetime,)?
320
        struct_ref: $struct_ref:ty,
321
        item: $item:ty,
322
        $(where_clause: $where_clause:tt,)?
323
        get_node: $get_node:expr
324
    ) => {
325
        $(#[$attr])*
326
        #[derive(Clone)]
327
        pub struct $name<$($lifetime,)? T> {
328
            struct_ref: $struct_ref,
329
            index: usize,
330
            last_index: usize,
331
            back_index: usize,
332
            last_back_index: usize,
333
            overflow: bool,
334
        }
335
        impl<$($lifetime,)? T> $name<$($lifetime,)? T>
336
        where
337
            T: NodeRef,
338
            $( T::NodeIndex: $where_clause )?
339
        {
340
            pub fn new(struct_ref: $struct_ref) -> Self {
382✔
341
                let cap = struct_ref.capacity();
382✔
342
                Self {
382✔
343
                    struct_ref,
382✔
344
                    index: 0,
382✔
345
                    last_index: 0,
382✔
346
                    back_index: cap,
382✔
347
                    last_back_index: cap,
382✔
348
                    overflow: false,
382✔
349
                }
382✔
350
            }
382✔
351
        }
352

353
        impl<$($lifetime,)? T> Iterator for $name<$($lifetime,)? T>
354
        where
355
            T: NodeRef,
356
            $( T::NodeIndex: $where_clause )?
357
        {
358
            type Item = $item;
359
            fn next(&mut self) -> Option<Self::Item> {
1,005✔
360
                while !self.struct_ref.valid_node(self.index) {
1,342✔
361
                    self.index += 1;
583✔
362
                    if self.index >= self.struct_ref.capacity() {
583✔
363
                        return None;
246✔
364
                    }
337✔
365
                }
366
                if self.index < self.back_index {
759✔
367
                    self.last_index = self.index;
759✔
368
                    self.index += 1;
759✔
369
                    ($get_node)(self.struct_ref.get_node(self.last_index))
759✔
370
                } else {
371
                    None
×
372
                }
373
            }
1,005✔
374
        }
375

376
        impl<$($lifetime,)? T> DoubleEndedIterator for $name<$($lifetime,)? T>
377
        where
378
            T: NodeRef,
379
            $( T::NodeIndex: $where_clause )?
380
        {
381
            fn next_back(&mut self) -> Option<Self::Item> {
13✔
382
                if self.overflow {
13✔
383
                    return None;
1✔
384
                }
12✔
385
                while !self.struct_ref.valid_node(self.back_index) {
19✔
386
                    if let Some(val) = self.back_index.checked_sub(1) {
7✔
387
                        self.back_index = val;
7✔
388
                    } else {
7✔
389
                        return None;
×
390
                    }
391
                }
392
                if self.back_index >= self.index {
12✔
393
                    self.last_back_index = self.back_index;
10✔
394
                    (self.back_index, self.overflow) = self.back_index.overflowing_sub(1);
10✔
395
                    ($get_node)(self.struct_ref.get_node(self.last_back_index))
10✔
396
                } else {
397
                    None
2✔
398
                }
399
            }
13✔
400
        }
401
    }
402
}
403

404
define_node_iterator!(
405
    /// By-reference iterator over the nodes, for any struct that implements [`NodeRef`]
406
    NodeRefIterator,
407
    lifetime: 'a,
408
    struct_ref: &'a T,
409
    item: &'a T::NodeIndex,
410
    get_node: |node| node
769✔
411
);
412

413
define_node_iterator!(
414
    /// Owning iterator over the nodes, for any struct that implements [`NodeRef`]
415
    NodeOwningIterator,
416
    struct_ref: T,
417
    item: T::NodeIndex,
418
    where_clause: Copy,
419
    get_node: |node: Option<&T::NodeIndex> | node.copied()
×
420
);
421

422
/// Iterator that yields node value refs with indices
423
pub struct NodeStructValueIterator<'a, T, V> {
424
    inner: NodeRefIterator<'a, T>,
425
    _phantom: PhantomData<&'a V>,
426
}
427

428
impl<'a, T, V> Iterator for NodeStructValueIterator<'a, T, V>
429
where
430
    T: NodeRefValue<V>,
431
{
432
    type Item = (&'a T::NodeIndex, Option<&'a V>);
433
    fn next(&mut self) -> Option<Self::Item> {
52✔
434
        while self.inner.index < self.inner.struct_ref.capacity() {
52✔
435
            if let Some(node_index) = self.inner.next() {
44✔
436
                let val = self.inner.struct_ref.get_node_value(self.inner.last_index);
44✔
437
                return Some((node_index, val));
44✔
438
            }
×
439
        }
440
        None
8✔
441
    }
52✔
442
}
443

444
impl<'a, T, V> DoubleEndedIterator for NodeStructValueIterator<'a, T, V>
445
where
446
    T: NodeRefValue<V> + NodeRef,
447
    V: 'a,
448
    Self: 'a,
449
{
450
    fn next_back(&mut self) -> Option<Self::Item> {
13✔
451
        if let Some(node_index) = self.inner.next_back() {
13✔
452
            let val = self
10✔
453
                .inner
10✔
454
                .struct_ref
10✔
455
                .get_node_value(self.inner.last_back_index);
10✔
456
            Some((node_index, val))
10✔
457
        } else {
458
            None
3✔
459
        }
460
    }
13✔
461
}
462

463
macro_rules! node_struct_into_iter {
464
    ($struct_name:ident, $($gen:ident), *) => {
465
        impl<const N: usize, $($gen,)* > IntoIterator for $struct_name<N, $($gen,)*>
466
        where Self: NodeRef<NodeIndex = NI>, NI: Copy
467
        {
468
            type IntoIter = NodeOwningIterator<Self>;
469
            type Item = < NodeOwningIterator<Self > as Iterator>::Item;
470
            fn into_iter(self) -> Self::IntoIter {
×
471
                NodeOwningIterator::new(self)
×
472
            }
×
473
        }
474
    };
475
}
476

477
node_struct_into_iter!(NodeStruct, NI);
478
node_struct_into_iter!(NodeStructOption, NI);
479
node_struct_into_iter!(NodeValueStruct, NI, V);
480
node_struct_into_iter!(NodeValueStructOption, NI, V);
481
node_struct_into_iter!(NodeValueTwoArray, NI, V);
482

483
#[cfg(feature = "heapless")]
484
node_struct_into_iter!(NodeStructVec, NI);
485
#[cfg(feature = "heapless")]
486
node_struct_into_iter!(NodeStructOptionVec, NI);
487
#[cfg(feature = "heapless")]
488
node_struct_into_iter!(NodeStructVecValue, NI, V);
489
#[cfg(feature = "heapless")]
490
node_struct_into_iter!(NodeStructVecOptionValue, NI, V);
491

492
/// Provide a reference iterator over nodes
493
/// Trait for iterating over nodes in a node collection
494
///
495
/// Provides read-only iteration over node references. This trait is
496
/// automatically implemented for any type that implements [`NodeRef`].
497
pub trait NodesIterable {
498
    type Node;
499
    // todo: Maybe doesn't need to be DoubleEnded
500
    type Iter<'a>: DoubleEndedIterator<Item = &'a Self::Node>
501
    where
502
        Self: 'a;
503
    /// Return iterator that yields node references
504
    fn iter_nodes(&self) -> Self::Iter<'_>;
505
}
506
impl<T> NodesIterable for T
507
where
508
    T: NodeRef,
509
{
510
    type Node = T::NodeIndex;
511
    type Iter<'a>
512
        = NodeRefIterator<'a, T>
513
    where
514
        Self: 'a;
515

516
    fn iter_nodes(&self) -> Self::Iter<'_> {
364✔
517
        NodeRefIterator::new(self)
364✔
518
    }
364✔
519
}
520

521
/// Trait for iterating over nodes with their associated values
522
///
523
/// Extends [`NodesIterable`] to provide iteration over both nodes and their
524
/// values. This trait is automatically implemented for any type that implements
525
/// [`NodeRefValue`].
526
pub trait NodesValuesIterable<V>: NodesIterable {
527
    type IterValues<'a>: DoubleEndedIterator<Item = (&'a Self::Node, Option<&'a V>)>
528
    where
529
        <Self as NodesIterable>::Node: 'a,
530
        Self: 'a,
531
        V: 'a;
532
    fn iter_nodes_values(&self) -> Self::IterValues<'_>;
533
}
534

535
impl<T, V> NodesValuesIterable<V> for T
536
where
537
    T: NodeRefValue<V>,
538
{
539
    type IterValues<'a>
540
        = NodeStructValueIterator<'a, T, V>
541
    where
542
        <T as NodeRef>::NodeIndex: 'a,
543
        Self: 'a,
544
        V: 'a;
545
    fn iter_nodes_values(&self) -> Self::IterValues<'_> {
18✔
546
        Self::IterValues {
18✔
547
            inner: NodeRefIterator::new(self),
18✔
548
            _phantom: Default::default(),
18✔
549
        }
18✔
550
    }
18✔
551
}
552

553
/// Trait for converting node collections into owning iterators
554
///
555
/// This trait provides a way to consume a node collection and obtain an
556
/// iterator that owns the nodes. It's automatically implemented for any
557
/// type that implements [`IntoIterator`].
558
pub trait IntoNodesIterator {
559
    type Node;
560
    type NodeOwningIterator: Iterator<Item = Self::Node>;
561
    /// Returns an iterator over nodes
562
    fn into_nodes_iterator(self) -> Self::NodeOwningIterator;
563
}
564

565
impl<T> IntoNodesIterator for T
566
where
567
    T: IntoIterator,
568
    T::Item: PartialEq,
569
    <T as IntoIterator>::IntoIter: DoubleEndedIterator,
570
{
571
    type Node = T::Item;
572
    type NodeOwningIterator = T::IntoIter;
573
    fn into_nodes_iterator(self) -> Self::NodeOwningIterator {
×
574
        self.into_iter()
×
575
    }
×
576
}
577

578
/// Trait for node collections that support adding and removing nodes
579
///
580
/// This trait allows dynamic addition and removal of nodes to/from a node collection,
581
/// returning the index where the node was inserted/removed if successful.
582
pub trait MutableNodes<NI: PartialEq> {
583
    fn add(&mut self, node: NI) -> Option<usize>;
584
    fn remove(&mut self, node: NI) -> Option<usize>;
585
}
586

587
/// Trait for node collections that support adding and removing nodes with associated values
588
///
589
/// This trait allows dynamic addition and removal of nodes along with their values to/from a
590
/// node collection, returning the index where the node was inserted/removed if successful.
591
pub trait MutableNodeValue<NI: PartialEq, V> {
592
    fn add_value(&mut self, node: NI, value: V) -> Option<usize>;
593
    fn remove(&mut self, node: NI) -> Option<usize>;
594
}
595

596
impl<const N: usize, NI: PartialEq> MutableNodes<NI> for NodeStructOption<N, NI> {
597
    fn add(&mut self, node: NI) -> Option<usize> {
19✔
598
        if let Some(index) = self.0.iter().position(|opt| opt.is_none()) {
44✔
599
            self.0[index] = Some(node);
15✔
600
            return Some(index);
15✔
601
        }
4✔
602
        None
4✔
603
    }
19✔
604

605
    fn remove(&mut self, node: NI) -> Option<usize> {
3✔
606
        if let Some(index) = self.0.iter().position(|opt| opt.as_ref() == Some(&node)) {
8✔
607
            self.0[index] = None;
2✔
608
            return Some(index);
2✔
609
        }
1✔
610
        None
1✔
611
    }
3✔
612
}
613

614
impl<const N: usize, NI: PartialEq, V> MutableNodeValue<NI, V> for NodeValueStructOption<N, NI, V> {
615
    fn add_value(&mut self, node: NI, value: V) -> Option<usize> {
11✔
616
        if let Some(index) = self.0.iter().position(|opt| opt.is_none()) {
30✔
617
            self.0[index] = Some((node, value));
10✔
618
            return Some(index);
10✔
619
        }
1✔
620
        None
1✔
621
    }
11✔
622

623
    fn remove(&mut self, node: NI) -> Option<usize> {
4✔
624
        if let Some(index) = self
4✔
625
            .0
4✔
626
            .iter()
4✔
627
            .position(|opt| opt.as_ref().map(|(ni, _)| ni) == Some(&node))
12✔
628
        {
629
            self.0[index] = None;
3✔
630
            return Some(index);
3✔
631
        }
1✔
632
        None
1✔
633
    }
4✔
634
}
635

636
// Dual implementation: NodeValueStructOption can also implement MutableNodes
637
// by using Default values when no explicit value is provided
638
impl<const N: usize, NI: PartialEq, V: Default> MutableNodes<NI>
639
    for NodeValueStructOption<N, NI, V>
640
{
641
    fn add(&mut self, node: NI) -> Option<usize> {
2✔
642
        // Add with default value
2✔
643
        self.add_value(node, V::default())
2✔
644
    }
2✔
645

646
    fn remove(&mut self, node: NI) -> Option<usize> {
1✔
647
        // Reuse existing remove logic from MutableNodeValue
1✔
648
        <Self as MutableNodeValue<NI, V>>::remove(self, node)
1✔
649
    }
1✔
650
}
651

652
#[cfg(feature = "heapless")]
653
impl<const N: usize, NI: PartialEq> MutableNodes<NI> for NodeStructVec<N, NI> {
654
    fn add(&mut self, node: NI) -> Option<usize> {
3✔
655
        self.0.push(node).ok().map(|_| self.0.len() - 1)
3✔
656
    }
3✔
657

658
    fn remove(&mut self, node: NI) -> Option<usize> {
1✔
659
        if let Some(index) = self.0.iter().position(|ni| *ni == node) {
2✔
660
            self.0.remove(index);
1✔
661
            return Some(index);
1✔
UNCOV
662
        }
×
663
        None
×
664
    }
1✔
665
}
666

667
#[cfg(feature = "heapless")]
668
impl<const N: usize, NI: PartialEq> MutableNodes<NI> for NodeStructOptionVec<N, NI> {
NEW
669
    fn add(&mut self, node: NI) -> Option<usize> {
×
NEW
670
        if let Some(index) = self.0.iter().position(|opt| opt.is_none()) {
×
NEW
671
            self.0[index] = Some(node);
×
NEW
672
            return Some(index);
×
NEW
673
        }
×
NEW
674
        self.0.push(Some(node)).ok().map(|_| self.0.len() - 1)
×
NEW
675
    }
×
676

677
    fn remove(&mut self, node: NI) -> Option<usize> {
×
678
        if let Some(index) = self.0.iter().position(|opt| opt.as_ref() == Some(&node)) {
×
679
            self.0[index] = None;
×
UNCOV
680
            return Some(index);
×
UNCOV
681
        }
×
UNCOV
682
        None
×
683
    }
×
684
}
685

686
#[cfg(feature = "heapless")]
687
impl<const N: usize, NI: PartialEq, V> MutableNodeValue<NI, V> for NodeStructVecValue<N, NI, V> {
688
    fn add_value(&mut self, node: NI, value: V) -> Option<usize> {
3✔
689
        self.0.push((node, value)).ok().map(|_| self.0.len() - 1)
3✔
690
    }
3✔
691

692
    fn remove(&mut self, node: NI) -> Option<usize> {
1✔
693
        if let Some(index) = self.0.iter().position(|(ni, _)| *ni == node) {
2✔
694
            self.0.remove(index);
1✔
695
            return Some(index);
1✔
696
        }
×
697
        None
×
698
    }
1✔
699
}
700

701
#[cfg(feature = "heapless")]
702
impl<const N: usize, NI: PartialEq, V> MutableNodeValue<NI, V>
703
    for NodeStructVecOptionValue<N, NI, V>
704
{
705
    fn add_value(&mut self, node: NI, value: V) -> Option<usize> {
5✔
706
        if let Some(index) = self.0.iter().position(|opt| opt.is_none()) {
5✔
707
            self.0[index] = Some((node, value));
1✔
708
            return Some(index);
1✔
709
        }
4✔
710
        self.0
4✔
711
            .push(Some((node, value)))
4✔
712
            .ok()
4✔
713
            .map(|_| self.0.len() - 1)
4✔
714
    }
5✔
715

716
    fn remove(&mut self, node: NI) -> Option<usize> {
1✔
717
        if let Some(index) = self
1✔
718
            .0
1✔
719
            .iter()
1✔
720
            .position(|opt| opt.as_ref().map(|(ni, _)| ni) == Some(&node))
1✔
721
        {
722
            self.0[index] = None;
1✔
723
            return Some(index);
1✔
UNCOV
724
        }
×
UNCOV
725
        None
×
726
    }
1✔
727
}
728

729
// Dual implementation: NodeStructVecOptionValue can also implement MutableNodes
730
// by using Default values when no explicit value is provided
731
#[cfg(feature = "heapless")]
732
impl<const N: usize, NI: PartialEq, V: Default> MutableNodes<NI>
733
    for NodeStructVecOptionValue<N, NI, V>
734
{
735
    fn add(&mut self, node: NI) -> Option<usize> {
2✔
736
        // Add with default value
2✔
737
        self.add_value(node, V::default())
2✔
738
    }
2✔
739

740
    fn remove(&mut self, node: NI) -> Option<usize> {
1✔
741
        // Reuse existing remove logic from MutableNodeValue
1✔
742
        <Self as MutableNodeValue<NI, V>>::remove(self, node)
1✔
743
    }
1✔
744
}
745

746
#[cfg(test)]
747
mod tests {
748
    use super::*;
749
    use crate::tests::collect;
750
    use core::fmt::Debug;
751

752
    fn iterate_over<N, NI>(nodes: &N, cmp: &[NI])
16✔
753
    where
16✔
754
        N: NodesIterable<Node = NI> + ?Sized,
16✔
755
        NI: core::fmt::Debug + Default + PartialEq + Copy,
16✔
756
    {
16✔
757
        let mut collect_array: [NI; 8] = core::array::from_fn(|_| NI::default());
128✔
758
        for node in nodes.iter_nodes().zip(collect_array.iter_mut()) {
47✔
759
            *node.1 = *node.0;
47✔
760
        }
47✔
761

762
        let final_slice = &collect_array[..cmp.len()];
16✔
763
        assert_eq!(final_slice, cmp);
16✔
764
        // Ensure we can loop twice and didn't consume anything
765
        for _node in nodes.iter_nodes().zip(collect_array.iter_mut()) {}
47✔
766
    }
16✔
767

768
    static EXPECTED: [usize; 3] = [1, 3, 2];
769

770
    #[test]
771
    fn test_node_array_iter() {
1✔
772
        let nodes = [1, 3, 2];
1✔
773
        iterate_over(&nodes, &EXPECTED);
1✔
774
        assert_eq!(3 * 8, core::mem::size_of_val(&nodes));
1✔
775
    }
1✔
776

777
    #[test]
778
    fn test_node_slice_iter() {
1✔
779
        let nodes = [1, 3, 2].as_slice();
1✔
780
        iterate_over(&nodes, &EXPECTED);
1✔
781
        assert_eq!(2 * 8, core::mem::size_of_val(&nodes));
1✔
782
    }
1✔
783

784
    #[test]
785
    fn test_nodestruct_iter() {
1✔
786
        let nodes = NodeStruct([1, 3, 2]);
1✔
787
        iterate_over(&nodes, &EXPECTED);
1✔
788
        assert_eq!(3 * 8, core::mem::size_of_val(&nodes));
1✔
789
    }
1✔
790

791
    #[test]
792
    fn test_node_iter_option_all() {
1✔
793
        let nodes = NodeStructOption([Some(1), Some(3), Some(2)]);
1✔
794
        iterate_over(&nodes, &EXPECTED);
1✔
795
        assert_eq!(3 * 8 * 2, core::mem::size_of_val(&nodes));
1✔
796
    }
1✔
797

798
    #[test]
799
    fn test_node_iter_option_some() {
1✔
800
        let nodes = NodeStructOption([None, Some(1), Some(3), None, Some(2)]);
1✔
801
        iterate_over(&nodes, &EXPECTED);
1✔
802
        assert_eq!(5 * 8 * 2, core::mem::size_of_val(&nodes));
1✔
803
    }
1✔
804

805
    #[test]
806
    fn test_node_iter_value() {
1✔
807
        let nodes = NodeValueStruct([(1, "a"), (3, "b"), (2, "c")]);
1✔
808
        iterate_over(&nodes, &EXPECTED);
1✔
809
        assert_eq!(3 * 8 * 3, core::mem::size_of_val(&nodes));
1✔
810
    }
1✔
811

812
    #[test]
813
    fn test_node_iter_value_option_all() {
1✔
814
        let nodes = NodeValueStructOption([Some((1, "a")), Some((3, "b")), Some((2, "c"))]);
1✔
815
        iterate_over(&nodes, &EXPECTED);
1✔
816
        assert_eq!(3 * 8 * 3, core::mem::size_of_val(&nodes));
1✔
817
    }
1✔
818

819
    #[test]
820
    fn test_node_iter_value_option_some() {
1✔
821
        let nodes =
1✔
822
            NodeValueStructOption([None, Some((1, "a")), Some((3, "b")), None, Some((2, "c"))]);
1✔
823
        iterate_over(&nodes, &EXPECTED);
1✔
824
        assert_eq!(5 * 8 * 3, core::mem::size_of_val(&nodes));
1✔
825
    }
1✔
826

827
    #[test]
828
    fn test_node_iter_value_two_array() {
1✔
829
        let nodes = NodeValueTwoArray([1, 3, 2], ["a", "b", "c"]);
1✔
830
        iterate_over(&nodes, &EXPECTED);
1✔
831
        assert_eq!(3 * 8 * 3, core::mem::size_of_val(&nodes));
1✔
832
    }
1✔
833

834
    #[cfg(feature = "heapless")]
835
    #[test]
836
    fn test_node_iter_vec() {
1✔
837
        let nodes = NodeStructVec::<3, _>(heapless::Vec::from_slice(&[1, 3, 2]).unwrap());
1✔
838
        iterate_over(&nodes, &EXPECTED);
1✔
839
    }
1✔
840

841
    #[cfg(feature = "heapless")]
842
    #[test]
843
    fn test_node_iter_vec_heapless() {
1✔
844
        let nodes = heapless::Vec::<_, 3>::from_slice(&[1, 3, 2]).unwrap();
1✔
845
        iterate_over(&nodes, &EXPECTED);
1✔
846
    }
1✔
847

848
    #[cfg(feature = "heapless")]
849
    #[test]
850
    fn test_node_iter_vec_option() {
1✔
851
        let nodes = NodeStructOptionVec::<3, _>(
1✔
852
            heapless::Vec::from_slice(&[Some(1), Some(3), Some(2)]).unwrap(),
1✔
853
        );
1✔
854
        iterate_over(&nodes, &EXPECTED);
1✔
855
    }
1✔
856

857
    #[cfg(feature = "heapless")]
858
    #[test]
859
    fn test_node_iter_vec_option_value() {
1✔
860
        let nodes = NodeStructVecOptionValue::<3, _, _>(
1✔
861
            heapless::Vec::from_slice(&[Some((1, "a")), Some((3, "b")), Some((2, "c"))]).unwrap(),
1✔
862
        );
1✔
863
        iterate_over(&nodes, &EXPECTED);
1✔
864
    }
1✔
865

866
    #[cfg(feature = "heapless")]
867
    #[test]
868
    fn test_node_iter_vec_value() {
1✔
869
        let nodes = NodeStructVecValue::<3, _, _>(
1✔
870
            heapless::Vec::from_slice(&[(1, "a"), (3, "b"), (2, "c")]).unwrap(),
1✔
871
        );
1✔
872
        iterate_over(&nodes, &EXPECTED);
1✔
873
    }
1✔
874

875
    #[test]
876
    fn test_node_get_values() {
1✔
877
        fn test_value<V, T: NodeRefValue<V>>(nodes: &T, idx: usize, val: Option<&V>)
15✔
878
        where
15✔
879
            V: PartialEq + core::fmt::Debug,
15✔
880
        {
15✔
881
            assert_eq!(nodes.get_node_value(idx), val);
15✔
882
        }
15✔
883
        fn test_123<T: NodeRefValue<&'static str>>(nodes: &T) {
5✔
884
            test_value(nodes, 1, Some(&"b"));
5✔
885
            test_value(nodes, 2, Some(&"c"));
5✔
886
            test_value(nodes, 3, None);
5✔
887
        }
5✔
888
        test_123(&NodeValueStruct([(1, "a"), (3, "b"), (2, "c")]));
1✔
889
        test_123(&NodeValueStructOption([
1✔
890
            Some((1, "a")),
1✔
891
            Some((3, "b")),
1✔
892
            Some((2, "c")),
1✔
893
        ]));
1✔
894
        test_123(&NodeValueTwoArray([1, 3, 2], ["a", "b", "c"]));
1✔
895
        #[cfg(feature = "heapless")]
1✔
896
        {
1✔
897
            test_123(&NodeStructVecValue::<3, _, _>(
1✔
898
                heapless::Vec::from_slice(&[(1, "a"), (3, "b"), (2, "c")]).unwrap(),
1✔
899
            ));
1✔
900
            test_123(&NodeStructVecOptionValue::<3, _, _>(
1✔
901
                heapless::Vec::from_slice(&[Some((1, "a")), Some((3, "b")), Some((2, "c"))])
1✔
902
                    .unwrap(),
1✔
903
            ));
1✔
904
        }
1✔
905
    }
1✔
906

907
    fn add_node<NI: PartialEq, T: MutableNodes<NI>>(f: &mut T, to_add: NI) -> Option<usize> {
4✔
908
        f.add(to_add)
4✔
909
    }
4✔
910
    fn add_node_value<NI: PartialEq, V, T: MutableNodeValue<NI, V>>(
1✔
911
        f: &mut T,
1✔
912
        to_add: NI,
1✔
913
        value: V,
1✔
914
    ) -> Option<usize> {
1✔
915
        f.add_value(to_add, value)
1✔
916
    }
1✔
917
    fn remove_node_value<NI: PartialEq, V, T: MutableNodeValue<NI, V>>(
1✔
918
        f: &mut T,
1✔
919
        to_remove: NI,
1✔
920
    ) -> Option<usize> {
1✔
921
        f.remove(to_remove)
1✔
922
    }
1✔
923
    fn remove_node<NI: PartialEq, T: MutableNodes<NI>>(f: &mut T, to_remove: NI) -> Option<usize> {
1✔
924
        f.remove(to_remove)
1✔
925
    }
1✔
926

927
    #[test]
928
    fn test_mutable_nodes() {
1✔
929
        let mut nodes = NodeStructOption([None, Some(1), Some(3), None, Some(2)]);
1✔
930
        assert_eq!(add_node(&mut nodes, 4), Some(0));
1✔
931
        assert_eq!(remove_node(&mut nodes, 3), Some(2));
1✔
932
        iterate_over(&nodes, &[4, 1, 2]);
1✔
933
        assert_eq!(add_node(&mut nodes, 5), Some(2));
1✔
934
        assert_eq!(add_node(&mut nodes, 8), Some(3));
1✔
935
        assert_eq!(add_node(&mut nodes, 100), None);
1✔
936
    }
1✔
937
    #[test]
938
    fn test_mutable_value_nodes() {
1✔
939
        let mut nodes =
1✔
940
            NodeValueStructOption([Some((5_u8, Some('b'))), None, Some((2, Some('x')))]);
1✔
941
        assert_eq!(add_node_value(&mut nodes, 4, Some('c')), Some(1));
1✔
942
        assert_eq!(remove_node_value(&mut nodes, 2), Some(2));
1✔
943
        iterate_over(&nodes, &[5, 4]);
1✔
944
    }
1✔
945
    #[test]
946
    fn node_values_iterable() {
1✔
947
        fn test<NI, V, T>(t: &T, cmp: &[V])
4✔
948
        where
4✔
949
            NI: PartialEq + Debug,
4✔
950
            V: Default + Debug + Copy + PartialEq,
4✔
951
            T: NodesValuesIterable<V, Node = NI>,
4✔
952
        {
4✔
953
            let mut collect_array = [V::default(); 16];
4✔
954
            let mut len = 0;
4✔
955
            for (src, dst) in t.iter_nodes_values().zip(collect_array.iter_mut()) {
13✔
956
                if let Some(v) = src.1 {
13✔
957
                    *dst = *v;
13✔
958
                    len += 1;
13✔
959
                }
13✔
960
            }
961
            assert_eq!(&collect_array[..len], cmp);
4✔
962
        }
4✔
963
        fn test_from_front_back<NI, V, T>(
7✔
964
            t: &T,
7✔
965
            from_front: isize,
7✔
966
            vfront: Option<&V>,
7✔
967
            from_back: isize,
7✔
968
            vback: Option<&V>,
7✔
969
        ) where
7✔
970
            NI: PartialEq + Debug,
7✔
971
            V: Default + Debug + Copy + PartialEq,
7✔
972
            T: NodesValuesIterable<V, Node = NI>,
7✔
973
        {
7✔
974
            let mut iterator = t.iter_nodes_values();
7✔
975
            if from_front >= 0 {
7✔
976
                assert_eq!(
4✔
977
                    iterator.nth(from_front as usize).map(|v| v.1.unwrap()),
4✔
978
                    vfront
4✔
979
                );
4✔
980
            }
3✔
981
            assert_eq!(
7✔
982
                iterator.rev().nth(from_back as usize).map(|v| v.1.unwrap()),
7✔
983
                vback
7✔
984
            )
7✔
985
        }
7✔
986
        let values = NodeValueStruct([(1_usize, "a"), (3, "b"), (2, "c")]);
1✔
987
        test(&values, &["a", "b", "c"]);
1✔
988
        test_from_front_back(&values, 0, Some(&"a"), 0, Some(&"c"));
1✔
989
        test_from_front_back(&values, 1, Some(&"b"), 0, Some(&"c"));
1✔
990
        test_from_front_back(&values, 2, Some(&"c"), 0, None);
1✔
991
        test_from_front_back(&values, 3, None, 3, None);
1✔
992
        test_from_front_back(&values, -1, None, 1, Some(&"b"));
1✔
993
        test_from_front_back(&values, -1, None, 2, Some(&"a"));
1✔
994
        test_from_front_back(&values, -1, None, 3, None);
1✔
995
        let values = NodeValueTwoArray([1_usize, 2], ["xf", "bz"]);
1✔
996
        test(&values, &["xf", "bz"]);
1✔
997
        let values = NodeValueStructOption([
1✔
998
            Some((1, 'b')),
1✔
999
            None,
1✔
1000
            None,
1✔
1001
            Some((2, 'f')),
1✔
1002
            None,
1✔
1003
            Some((3, 'x')),
1✔
1004
            None,
1✔
1005
            None,
1✔
1006
            Some((4, 'y')),
1✔
1007
            Some((100, 'z')),
1✔
1008
        ]);
1✔
1009
        test(&values, &['b', 'f', 'x', 'y', 'z']);
1✔
1010
        let values = NodeValueStructOption([
1✔
1011
            Some((1, Some('b'))),
1✔
1012
            None,
1✔
1013
            Some((2, None)),
1✔
1014
            Some((100, Some('z'))),
1✔
1015
        ]);
1✔
1016
        test(&values, &[Some('b'), None, Some('z')]);
1✔
1017
    }
1✔
1018

1019
    #[test]
1020
    fn test_mutable_node_value_comprehensive() {
1✔
1021
        // Test NodeValueStructOption
1✔
1022
        let mut nodes = NodeValueStructOption::<5, u32, &str>([None; 5]);
1✔
1023

1✔
1024
        // Test add_value
1✔
1025
        assert_eq!(nodes.add_value(1, "hello"), Some(0));
1✔
1026
        assert_eq!(nodes.add_value(2, "world"), Some(1));
1✔
1027
        assert_eq!(nodes.add_value(3, "test"), Some(2));
1✔
1028

1029
        // Verify current state
1030
        let mut collected = [0u32; 8];
1✔
1031
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1032
        assert_eq!(slice, &[1, 2, 3]);
1✔
1033

1034
        // Test remove (disambiguate since this type implements both traits)
1035
        assert_eq!(
1✔
1036
            <NodeValueStructOption<5, u32, &str> as MutableNodeValue<u32, &str>>::remove(
1✔
1037
                &mut nodes, 2
1✔
1038
            ),
1✔
1039
            Some(1)
1✔
1040
        ); // Remove middle element
1✔
1041
        assert_eq!(
1✔
1042
            <NodeValueStructOption<5, u32, &str> as MutableNodeValue<u32, &str>>::remove(
1✔
1043
                &mut nodes, 999
1✔
1044
            ),
1✔
1045
            None
1✔
1046
        ); // Remove non-existent
1✔
1047

1048
        // Verify after removal
1049
        let mut collected = [0u32; 8];
1✔
1050
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1051
        assert_eq!(slice, &[1, 3]);
1✔
1052

1053
        // Test that removed slot can be reused
1054
        assert_eq!(nodes.add_value(4, "reuse"), Some(1));
1✔
1055

1056
        // Fill remaining capacity
1057
        assert_eq!(nodes.add_value(5, "five"), Some(3));
1✔
1058
        assert_eq!(nodes.add_value(6, "six"), Some(4));
1✔
1059

1060
        // Verify full state
1061
        let mut collected = [0u32; 8];
1✔
1062
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1063
        assert_eq!(slice, &[1, 4, 3, 5, 6]);
1✔
1064

1065
        // Test capacity limits
1066
        assert_eq!(nodes.add_value(7, "overflow"), None);
1✔
1067
    }
1✔
1068

1069
    #[cfg(feature = "heapless")]
1070
    #[test]
1071
    fn test_mutable_node_value_vec_types() {
1✔
1072
        // Test NodeStructVecValue
1✔
1073
        let mut vec_nodes = NodeStructVecValue::<5, u32, i32>(heapless::Vec::new());
1✔
1074

1✔
1075
        // Test add_value - should append to end
1✔
1076
        assert_eq!(vec_nodes.add_value(10, 100), Some(0));
1✔
1077
        assert_eq!(vec_nodes.add_value(20, 200), Some(1));
1✔
1078
        assert_eq!(vec_nodes.add_value(30, 300), Some(2));
1✔
1079

1080
        // Verify state
1081
        let mut collected = [0u32; 8];
1✔
1082
        let slice = collect(vec_nodes.iter_nodes().copied(), &mut collected);
1✔
1083
        assert_eq!(slice, &[10, 20, 30]);
1✔
1084

1085
        // Test remove from middle - should shift elements
1086
        assert_eq!(vec_nodes.remove(20), Some(1));
1✔
1087

1088
        // Verify remaining elements
1089
        let mut collected = [0u32; 8];
1✔
1090
        let slice = collect(vec_nodes.iter_nodes().copied(), &mut collected);
1✔
1091
        assert_eq!(slice, &[10, 30]);
1✔
1092
    }
1✔
1093

1094
    #[test]
1095
    fn test_mutable_nodes_edge_cases() {
1✔
1096
        let mut nodes = NodeStructOption::<3, u32>([Some(1), None, Some(3)]);
1✔
1097

1✔
1098
        // Verify initial state
1✔
1099
        let mut collected = [0u32; 8];
1✔
1100
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1101
        assert_eq!(slice, &[1, 3]);
1✔
1102

1103
        // Test adding to middle slot
1104
        assert_eq!(nodes.add(2), Some(1));
1✔
1105

1106
        let mut collected = [0u32; 8];
1✔
1107
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1108
        assert_eq!(slice, &[1, 2, 3]);
1✔
1109

1110
        // Test removing and re-adding to same slot
1111
        assert_eq!(nodes.remove(2), Some(1));
1✔
1112
        assert_eq!(nodes.add(4), Some(1)); // Should reuse slot 1
1✔
1113

1114
        let mut collected = [0u32; 8];
1✔
1115
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1116
        assert_eq!(slice, &[1, 4, 3]);
1✔
1117

1118
        // Test full capacity
1119
        assert_eq!(nodes.add(5), None);
1✔
1120

1121
        // Test removing non-existent
1122
        assert_eq!(nodes.remove(999), None);
1✔
1123
    }
1✔
1124

1125
    #[cfg(feature = "heapless")]
1126
    #[test]
1127
    fn test_option_value_container_gaps() {
1✔
1128
        // Start with a simple test - just verify basic functionality
1✔
1129
        let mut nodes = NodeStructVecOptionValue::<8, u32, i32>(heapless::Vec::new());
1✔
1130

1✔
1131
        // Add one element
1✔
1132
        assert_eq!(nodes.add_value(1, 10), Some(0));
1✔
1133

1134
        // Verify state
1135
        let mut collected = [0u32; 8];
1✔
1136
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1137
        assert_eq!(slice, &[1]);
1✔
1138

1139
        // Add second element
1140
        assert_eq!(nodes.add_value(2, 20), Some(1));
1✔
1141

1142
        // Verify state
1143
        let mut collected = [0u32; 8];
1✔
1144
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1145
        assert_eq!(slice, &[1, 2]);
1✔
1146
    }
1✔
1147

1148
    #[cfg(feature = "heapless")]
1149
    #[test]
1150
    fn test_vec_behavior_basic() {
1✔
1151
        // Test basic Vec behavior for MutableNodes
1✔
1152
        let mut vec_nodes = NodeStructVec::<5, u32>(heapless::Vec::new());
1✔
1153

1✔
1154
        // Add elements
1✔
1155
        assert_eq!(vec_nodes.add(1), Some(0));
1✔
1156
        assert_eq!(vec_nodes.add(2), Some(1));
1✔
1157
        assert_eq!(vec_nodes.add(3), Some(2));
1✔
1158

1159
        // Verify state
1160
        let mut collected = [0u32; 8];
1✔
1161
        let slice = collect(vec_nodes.iter_nodes().copied(), &mut collected);
1✔
1162
        assert_eq!(slice, &[1, 2, 3]);
1✔
1163

1164
        // Remove middle element (should shift)
1165
        assert_eq!(vec_nodes.remove(2), Some(1));
1✔
1166

1167
        let mut collected = [0u32; 8];
1✔
1168
        let slice = collect(vec_nodes.iter_nodes().copied(), &mut collected);
1✔
1169
        assert_eq!(slice, &[1, 3]); // 3 shifted down
1✔
1170
    }
1✔
1171

1172
    #[test]
1173
    fn test_dual_trait_implementation() {
1✔
1174
        // Test that NodeValueStructOption implements both traits when V: Default
1✔
1175
        let mut nodes = NodeValueStructOption::<5, u32, i32>([None; 5]);
1✔
1176

1✔
1177
        // Use as MutableNodes (adds with default values)
1✔
1178
        assert_eq!(nodes.add(1), Some(0)); // Adds (1, 0) since i32::default() = 0
1✔
1179
        assert_eq!(nodes.add(2), Some(1)); // Adds (2, 0)
1✔
1180

1181
        // Use as MutableNodeValue (adds with explicit values)
1182
        assert_eq!(nodes.add_value(3, 100), Some(2)); // Adds (3, 100)
1✔
1183

1184
        // Verify all nodes exist
1185
        let mut collected = [0u32; 8];
1✔
1186
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1187
        assert_eq!(slice, &[1, 2, 3]);
1✔
1188

1189
        // Verify values - nodes added via MutableNodes have default values
1190
        assert_eq!(nodes.0[0], Some((1, 0))); // Default value
1✔
1191
        assert_eq!(nodes.0[1], Some((2, 0))); // Default value
1✔
1192
        assert_eq!(nodes.0[2], Some((3, 100))); // Explicit value
1✔
1193

1194
        // Remove works from either trait (need to disambiguate since both traits have remove)
1195
        assert_eq!(
1✔
1196
            <NodeValueStructOption<5, u32, i32> as MutableNodes<u32>>::remove(&mut nodes, 2),
1✔
1197
            Some(1)
1✔
1198
        );
1✔
1199

1200
        let mut collected = [0u32; 8];
1✔
1201
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1202
        assert_eq!(slice, &[1, 3]);
1✔
1203
    }
1✔
1204

1205
    #[cfg(feature = "heapless")]
1206
    #[test]
1207
    fn test_dual_trait_heapless_vec() {
1✔
1208
        // Test that NodeStructVecOptionValue implements both traits when V: Default
1✔
1209
        let mut nodes = NodeStructVecOptionValue::<8, u32, &str>(heapless::Vec::new());
1✔
1210

1✔
1211
        // Use as MutableNodes (adds with default values)
1✔
1212
        assert_eq!(nodes.add(1), Some(0)); // Adds (1, "") since &str::default() = ""
1✔
1213

1214
        // Use as MutableNodeValue (adds with explicit values)
1215
        assert_eq!(nodes.add_value(2, "hello"), Some(1));
1✔
1216

1217
        // Verify both approaches work
1218
        let mut collected = [0u32; 8];
1✔
1219
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1220
        assert_eq!(slice, &[1, 2]);
1✔
1221

1222
        // Verify values
1223
        assert_eq!(nodes.0[0], Some((1, ""))); // Default value
1✔
1224
        assert_eq!(nodes.0[1], Some((2, "hello"))); // Explicit value
1✔
1225

1226
        // Remove middle to create gap, then test gap filling (disambiguate remove call)
1227
        assert_eq!(
1✔
1228
            <NodeStructVecOptionValue<8, u32, &str> as MutableNodes<u32>>::remove(&mut nodes, 1),
1✔
1229
            Some(0)
1✔
1230
        );
1✔
1231

1232
        // Add new element - should fill the gap
1233
        assert_eq!(nodes.add(3), Some(0));
1✔
1234

1235
        let mut collected = [0u32; 8];
1✔
1236
        let slice = collect(nodes.iter_nodes().copied(), &mut collected);
1✔
1237
        assert_eq!(slice, &[3, 2]);
1✔
1238
    }
1✔
1239
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc