once_list2/
once_list.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use ::allocator_api2::alloc::{Allocator, Global};
16use ::allocator_api2::boxed::Box;
17use ::std::fmt::Debug;
18use ::std::hash::Hash;
19#[cfg(feature = "nightly")]
20use ::std::marker::Unsize;
21use ::std::ops::DerefMut;
22
23use crate::cache_mode::{CacheMode, NextSlot, NoCache, WithLen, WithTail, WithTailLen};
24use crate::cons::Cons;
25use crate::iter::{IntoIter, Iter, IterMut};
26#[cfg(feature = "nightly")]
27use crate::OnceCell;
28
29/// A single linked list which behaves like [`std::cell::OnceCell`], but for multiple values.
30///
31/// This is a type alias of the internal implementation type. The default caching mode is `NoCache`.
32pub type OnceList<T, A = Global> = OnceListCore<T, A, NoCache>;
33
34/// A `OnceList` variant with tail caching enabled.
35pub type OnceListWithTail<T, A = Global> = OnceListCore<T, A, WithTail<T, A>>;
36
37/// A `OnceList` variant with length caching enabled (O(1) `len()`).
38pub type OnceListWithLen<T, A = Global> = OnceListCore<T, A, WithLen<T, A>>;
39
40/// A `OnceList` variant with both tail and length caching enabled.
41pub type OnceListWithTailLen<T, A = Global> = OnceListCore<T, A, WithTailLen<T, A>>;
42///
43/// # Usage
44///
45/// A simple example:
46///
47/// ```rust
48/// use once_list2::OnceList;
49///
50/// // Create a new empty list. Note that the variable is immutable.
51/// let list = OnceList::<i32>::new();
52///
53/// // You can push values to the list without the need for mutability.
54/// list.push(1);
55/// list.push(2);
56///
57/// // Or you can push multiple values at once.
58/// list.extend([3, 4, 5]);
59///
60/// // You can iterate over the list.
61/// assert_eq!(list.iter().copied().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5]);
62///
63/// // Some methods are mutable only.
64/// let mut list_mut = list;
65///
66/// // You can remove (take) a value from the list.
67/// let removed = list_mut.remove(|&x| x % 2 == 0);
68/// assert_eq!(removed, Some(2));
69/// assert_eq!(list_mut.iter().copied().collect::<Vec<_>>(), vec![1, 3, 4, 5]);
70/// ```
71///
72/// # Caching modes (optional)
73///
74/// You can choose a mode depending on what you want to optimize:
75///
76/// - **No cache (default)**:
77///   - `OnceList::<T>::new()`
78///   - `OnceList::<T, A>::new_in(alloc)`
79///   - `push_back()`: O(n), `len()`: O(n)
80///
81/// - **Len cache** (O(1) `len()`):
82///   - Type: `once_list2::OnceListWithLen<T, A>`
83///   - Constructors: `OnceListWithLen::<T>::new()` / `OnceListWithLen::<T, A>::new_in(alloc)`
84///
85/// - **Tail cache** (fast repeated tail inserts):
86///   - Type: `once_list2::OnceListWithTail<T, A>`
87///   - Constructors: `OnceListWithTail::<T>::new()` / `OnceListWithTail::<T, A>::new_in(alloc)`
88///   - Note: This mode caches the *next insertion slot* and speeds up operations that need to find
89///     the tail insertion point (e.g. `push_back()` / `extend()`), but it does not make `back()` O(1).
90///
91/// - **Tail + len cache**:
92///   - Type: `once_list2::OnceListWithTailLen<T, A>`
93///   - Constructors: `OnceListWithTailLen::<T>::new()` / `OnceListWithTailLen::<T, A>::new_in(alloc)`
94///
95/// These modes keep the same behavior guarantees (including the iterator observing newly pushed values).
96///
97/// # Unsized types support
98///
99/// You can use the [unsized types] like `str`, `[u8]` or `dyn Display` as the value type of the `OnceList`.
100///
101/// If you are using the stable rust compiler, you can only use the `dyn Any` type as the unsized type.
102/// (Strictly speaking, you can use ANY type as the unsized type, but you can't do any actual operations
103/// like pushing, removing, etc.)
104///
105/// In the nightly compiler and with the `nightly` feature enabled, the additional methods like `push_unsized`
106/// and `remove_unsized_as` become available:
107///
108/// ```rust
109/// # #[cfg(not(feature = "nightly"))]
110/// # fn main() {}
111/// # #[cfg(feature = "nightly")]
112/// # fn main() {
113/// // This code only works with the nightly compiler and the `nightly` feature enabled.
114///
115/// use once_list2::OnceList;
116///
117/// // Creating a `OnceList` for `[i32]`, the unsized type.
118/// let list = OnceList::<[i32]>::new();
119///
120/// list.push_unsized([1] /* A sized array type, `[i32; 1]`, can be coerced into [i32].*/);
121/// list.push_unsized([2, 3] /* Same for `[i32; 2] type. */);
122///
123/// // The normal methods like `iter` are available because it returns a reference to the value.
124/// assert_eq!(list.iter().nth(0).unwrap(), &[1]);
125/// assert_eq!(list.iter().nth(1).unwrap(), &[2, 3]);
126///
127/// let mut list_mut = list;
128///
129/// // `remove_unsized_as` method allows you to check the unsized value type and remove it.
130/// let removed: Option<[i32; 2]> = unsafe {
131///     list_mut.remove_unsized_as(|x| if x.len() == 2 {
132///         Some(x.try_into().unwrap())
133///     } else {
134///         None
135///     })
136/// };
137/// // The removed value is an array, not a slice!
138/// assert_eq!(removed, Some([2, 3]));
139/// # }
140/// ```
141/// [unsized types]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
142///
143/// # Note about docs
144///
145/// The method implementations live on [`OnceListCore`]. The user-facing type aliases like
146/// [`OnceList`] and [`OnceListWithTail`] point to this type.
147#[derive(Clone)]
148pub struct OnceListCore<T: ?Sized, A: Allocator = Global, C = NoCache> {
149    pub(crate) head_slot: NextSlot<T, A>,
150    pub(crate) alloc: A,
151    pub(crate) cache_mode: C,
152}
153
154// Per-mode `new()`/`new_in()` constructors.
155//
156// Note: These do not conflict with `OnceList::new()` because `OnceList` is a type alias
157// for `OnceListCore<_, _, NoCache>`, so the mode is fixed when calling `OnceList::new()`.
158
159impl<T: ?Sized> OnceListCore<T, Global, WithLen<T, Global>> {
160    pub fn new() -> Self {
161        Self {
162            head_slot: NextSlot::new(),
163            alloc: Global,
164            cache_mode: WithLen::new(),
165        }
166    }
167}
168
169impl<T: ?Sized, A: Allocator> OnceListCore<T, A, WithLen<T, A>> {
170    pub fn new_in(alloc: A) -> Self {
171        Self {
172            head_slot: NextSlot::new(),
173            alloc,
174            cache_mode: WithLen::new(),
175        }
176    }
177}
178
179impl<T: ?Sized> OnceListCore<T, Global, WithTail<T, Global>> {
180    pub fn new() -> Self {
181        Self {
182            head_slot: NextSlot::new(),
183            alloc: Global,
184            cache_mode: WithTail::new(),
185        }
186    }
187}
188
189impl<T: ?Sized, A: Allocator> OnceListCore<T, A, WithTail<T, A>> {
190    pub fn new_in(alloc: A) -> Self {
191        Self {
192            head_slot: NextSlot::new(),
193            alloc,
194            cache_mode: WithTail::new(),
195        }
196    }
197}
198
199impl<T: ?Sized> OnceListCore<T, Global, WithTailLen<T, Global>> {
200    pub fn new() -> Self {
201        Self {
202            head_slot: NextSlot::new(),
203            alloc: Global,
204            cache_mode: WithTailLen::new(),
205        }
206    }
207}
208
209impl<T: ?Sized, A: Allocator> OnceListCore<T, A, WithTailLen<T, A>> {
210    pub fn new_in(alloc: A) -> Self {
211        Self {
212            head_slot: NextSlot::new(),
213            alloc,
214            cache_mode: WithTailLen::new(),
215        }
216    }
217}
218
219impl<T: ?Sized> OnceListCore<T, Global, NoCache> {
220    /// Creates a new empty `OnceList`. This method does not allocate.
221    pub fn new() -> Self {
222        Self {
223            head_slot: NextSlot::new(),
224            alloc: Global,
225            cache_mode: NoCache,
226        }
227    }
228}
229
230impl<T: ?Sized, A: Allocator> OnceListCore<T, A, NoCache> {
231    /// Creates a new empty `OnceList` with the given allocator. This method does not allocate.
232    pub fn new_in(alloc: A) -> Self {
233        Self {
234            head_slot: NextSlot::new(),
235            alloc,
236            cache_mode: NoCache,
237        }
238    }
239}
240
241impl<T: ?Sized, A: Allocator, C> OnceListCore<T, A, C> {
242    /// Returns the number of values in the list.
243    ///
244    /// - O(1) if the current cache mode caches length
245    /// - O(n) otherwise
246    pub fn len(&self) -> usize
247    where
248        C: CacheMode<T, A>,
249    {
250        if let Some(n) = self.cache_mode.cached_len() {
251            return n;
252        }
253        self.iter().count()
254    }
255
256    /// Returns `true` if the list is empty.
257    pub fn is_empty(&self) -> bool {
258        self.head_slot.get().is_none()
259    }
260
261    /// Returns `true` if the list contains the value.
262    pub fn contains(&self, val: &T) -> bool
263    where
264        T: PartialEq,
265    {
266        self.iter().any(|v| v == val)
267    }
268
269    /// Returns the front value, if it exists.
270    pub fn front(&self) -> Option<&T> {
271        self.head_slot.get().map(|c| &c.val)
272    }
273
274    /// Returns a mutable reference to the front value, if it exists.
275    pub fn front_mut(&mut self) -> Option<&mut T> {
276        self.head_slot.get_mut().map(|c| &mut c.val)
277    }
278
279    /// Returns the back value, if it exists.
280    /// This method is O(n).
281    pub fn back(&self) -> Option<&T> {
282        let mut last_opt = None;
283        let mut next_cell = &self.head_slot;
284        while let Some(next_box) = next_cell.get() {
285            last_opt = Some(&next_box.val);
286            next_cell = &next_box.next;
287        }
288        last_opt
289    }
290
291    /// Returns a mutable reference to the back value, if it exists.
292    /// This method is O(n).
293    pub fn back_mut(&mut self) -> Option<&mut T> {
294        let mut last_opt = None;
295        let mut next_cell = &mut self.head_slot;
296        while let Some(next_box) = next_cell.get_mut() {
297            let next_cons = Box::deref_mut(next_box);
298            last_opt = Some(&mut next_cons.val);
299            next_cell = &mut next_cons.next;
300        }
301        last_opt
302    }
303
304    /// Returns the front value, if it exists.
305    ///
306    /// This is an alias of [`OnceListCore::front`].
307    pub fn first(&self) -> Option<&T> {
308        self.front()
309    }
310
311    /// Returns a mutable reference to the front value, if it exists.
312    ///
313    /// This is an alias of [`OnceListCore::front_mut`].
314    pub fn first_mut(&mut self) -> Option<&mut T> {
315        self.front_mut()
316    }
317
318    /// Returns the back value, if it exists.
319    ///
320    /// This is an alias of [`OnceListCore::back`].
321    pub fn last(&self) -> Option<&T> {
322        self.back()
323    }
324
325    /// Returns a mutable reference to the back value, if it exists.
326    ///
327    /// This is an alias of [`OnceListCore::back_mut`].
328    pub fn last_mut(&mut self) -> Option<&mut T> {
329        self.back_mut()
330    }
331
332    /// Returns an iterator over the `&T` references in the list.
333    pub fn iter(&self) -> Iter<'_, T, A> {
334        Iter::new(&self.head_slot)
335    }
336
337    /// Returns an iterator over the `&mut T` references in the list.
338    pub fn iter_mut(&mut self) -> IterMut<'_, T, A> {
339        IterMut::new(&mut self.head_slot)
340    }
341
342    /// Returns an allocator of this struct.
343    pub fn allocator(&self) -> &A {
344        &self.alloc
345    }
346}
347
348impl<T: ?Sized, A: Allocator, C> OnceListCore<T, A, C>
349where
350    C: CacheMode<T, A>,
351{
352    /// Clears the list, dropping all values.
353    pub fn clear(&mut self) {
354        self.head_slot = NextSlot::new();
355        self.cache_mode.on_clear();
356        self.cache_mode.on_structure_change();
357    }
358}
359
360impl<T: ?Sized, A: Allocator, C> OnceListCore<T, A, C>
361where
362    C: CacheMode<T, A>,
363{
364    /// Removes the first value in the list that matches the predicate, and returns the value as a boxed value.
365    ///
366    /// This method supports the unsized value type `T` as well.
367    ///
368    /// Note that even though this method returns a boxed value, the box is something re-allcoated.
369    /// So this method might not be efficient as you expect.
370    #[cfg(feature = "nightly")]
371    #[cfg_attr(feature = "nightly", doc(cfg(feature = "nightly")))]
372    pub fn remove_into_box<P>(&mut self, pred: P) -> Option<Box<T, A>>
373    where
374        P: FnMut(&T) -> bool,
375    {
376        self.remove_inner(pred, |boxed_cons| boxed_cons.box_into_inner_box())
377    }
378
379    /// Removes the first value in the list that matches the predicate, and returns the value.
380    ///
381    /// The predicate function `pred` should return `Some(&U)` if the value is found,
382    /// and the returned reference `&U` must be the same address as the value given in the `pred`.
383    ///
384    /// # Safety
385    /// This method is unsafe because it requires the predicate to return a reference to the same address as the value.
386    #[cfg(feature = "nightly")]
387    #[cfg_attr(feature = "nightly", doc(cfg(feature = "nightly")))]
388    pub unsafe fn remove_unsized_as<P, U>(&mut self, mut pred: P) -> Option<U>
389    where
390        P: FnMut(&T) -> Option<&U>,
391    {
392        use ::allocator_api2::alloc;
393        use ::std::cell::Cell;
394
395        let found_sized_ptr: Cell<Option<*const U>> = Cell::new(None);
396        self.remove_inner(
397            |val| {
398                if let Some(val) = pred(val) {
399                    found_sized_ptr.set(Some(val as *const U));
400                    true
401                } else {
402                    false
403                }
404            },
405            |boxed_cons| -> U {
406                // Given the boxed cons with the unsized value type `T`,
407                // and returns the sized type value `U` by value (i.e. out of the box).
408
409                // We are sure the `found_sized_ptr` is set when `remove_inner` calls this closure.
410                let found_sized_ptr: *const U = match found_sized_ptr.get() {
411                    Some(p) => p,
412                    None => unreachable!("remove_unsized_as: missing found pointer"),
413                };
414
415                let cons_layout = alloc::Layout::for_value::<Cons<T, T, A>>(&boxed_cons);
416                let (cons_ptr, alloc) = Box::into_non_null_with_allocator(boxed_cons);
417                let val_ptr = &unsafe { cons_ptr.as_ref() }.val as *const T;
418
419                // Double check the ptr returned by the `pred` is the same as the pointer we extracted from the cons.
420                debug_assert_eq!(val_ptr as *const U, found_sized_ptr);
421
422                // Load (memcpy) the value into the output variable.
423                let result = unsafe { ::std::ptr::read(val_ptr as *const U) };
424
425                // Free the cons memory.
426                unsafe { alloc.deallocate(cons_ptr.cast(), cons_layout) };
427
428                result
429            },
430        )
431    }
432
433    /// An inner implementeation for `remove_xxx` methods.
434    pub(crate) fn remove_inner<P, F, U>(&mut self, mut pred: P, mut f: F) -> Option<U>
435    where
436        P: FnMut(&T) -> bool,
437        F: FnMut(Box<Cons<T, T, A>, A>) -> U,
438    {
439        // Any structural change through `&mut self` invalidates the cached tail slot.
440        self.cache_mode.on_structure_change();
441
442        let mut next_cell = &mut self.head_slot;
443        while let Some(next_ref) = next_cell.get() {
444            if pred(&next_ref.val) {
445                // Safe because we are sure the `next_cell` value is set.
446                let Some(mut next_box) = next_cell.take() else {
447                    unreachable!("remove_inner: next_cell had value but take() returned None");
448                };
449
450                // reconnect the list
451                if let Some(next_next) = next_box.next.take() {
452                    let _ = next_cell.set(next_next);
453                }
454
455                self.cache_mode.on_remove_success();
456                return Some(f(next_box));
457            }
458            // Safe because we are sure the `next_cell` value is set.
459            let Some(next_box) = next_cell.get_mut() else {
460                unreachable!("remove_inner: next_cell had value but get_mut() returned None");
461            };
462            next_cell = &mut next_box.next;
463        }
464        None
465    }
466}
467
468impl<T: ?Sized, A: Allocator + Clone, C> OnceListCore<T, A, C>
469where
470    C: CacheMode<T, A>,
471{
472    /// An unsized version of the [`OnceList::push`] method.
473    ///
474    /// You can push a sized value to the list. For exaple, you can push `[i32; 3]` to the list of `[i32]`.
475    #[cfg(feature = "nightly")]
476    #[cfg_attr(feature = "nightly", doc(cfg(feature = "nightly")))]
477    pub fn push_unsized<U: Unsize<T>>(&self, val: U) -> &U {
478        let boxed_cons = Cons::new_boxed(val, self.alloc.clone());
479        self.push_inner(boxed_cons, |c| unsafe { &*(c as *const T as *const U) })
480    }
481
482    /// An inner implementation for the `push_xxx` methods.
483    pub(crate) fn push_inner<F, U>(&self, mut new_cons: Box<Cons<T, T, A>, A>, f: F) -> &U
484    where
485        F: FnOnce(&T) -> &U,
486    {
487        let mut next_cell = self.cache_mode.tail_slot_opt().unwrap_or(&self.head_slot);
488        loop {
489            match next_cell.try_insert2(new_cons) {
490                Ok(new_cons) => {
491                    self.cache_mode.on_push_success(&new_cons.next);
492                    return f(&new_cons.val);
493                }
494                Err((cur_cons, new_cons2)) => {
495                    next_cell = &cur_cons.next;
496                    new_cons = new_cons2;
497                }
498            }
499        }
500    }
501}
502
503impl<T, A: Allocator, C> OnceListCore<T, A, C>
504where
505    C: CacheMode<T, A>,
506{
507    /// Removes the front value from the list, and returns it.
508    ///
509    /// This method is O(1).
510    pub fn pop_front(&mut self) -> Option<T> {
511        self.remove(|_| true)
512    }
513
514    /// Find a first value in the list matches the predicate, remove that item from the list,
515    /// and then returns that value.
516    pub fn remove<P>(&mut self, mut pred: P) -> Option<T>
517    where
518        P: FnMut(&T) -> bool,
519    {
520        self.remove_inner(&mut pred, |boxed_cons| Box::into_inner(boxed_cons).val)
521    }
522}
523
524impl<T, A: Allocator + Clone, C> OnceListCore<T, A, C>
525where
526    C: CacheMode<T, A>,
527{
528    /// Appends a value to the back of the list, and returns the reference to that value.
529    ///
530    /// Note that this method takes `&self`, not `&mut self`.
531    pub fn push_back(&self, val: T) -> &T {
532        let boxed_cons = Box::new_in(Cons::new(val), A::clone(&self.alloc));
533        self.push_inner(boxed_cons, |c| c)
534    }
535
536    /// Appends a value to the list, and returns the reference to that value.
537    ///
538    /// Note that this method takes `&self`, not `&mut self`.
539    pub fn push(&self, val: T) -> &T {
540        self.push_back(val)
541    }
542
543    /// An almost same method with the [`std::iter::Extend::extend`],
544    /// though this method takes `&self` instead of `&mut self`.
545    ///
546    /// [`std::iter::Extend::extend`]: https://doc.rust-lang.org/std/iter/trait.Extend.html#tymethod.extend
547    pub fn extend<U: IntoIterator<Item = T>>(&self, iter: U) {
548        let alloc = self.allocator();
549
550        // Prefer the cached tail insertion slot when available, otherwise fall back to the head.
551        //
552        // IMPORTANT: Use `try_insert2` and retry on contention so that this method never drops
553        // values under `sync` (OnceLock) mode.
554        let mut next_cell = self.cache_mode.tail_slot_opt().unwrap_or(&self.head_slot);
555
556        for val in iter {
557            let mut new_cons = Box::new_in(Cons::new(val), A::clone(alloc));
558            loop {
559                match next_cell.try_insert2(new_cons) {
560                    Ok(inserted) => {
561                        self.cache_mode.on_push_success(&inserted.next);
562                        next_cell = &inserted.next;
563                        break;
564                    }
565                    Err((cur_cons, new_cons2)) => {
566                        next_cell = &cur_cons.next;
567                        new_cons = new_cons2;
568                    }
569                }
570            }
571        }
572    }
573}
574
575impl<T: ?Sized, A: Allocator + Default, C: Default> Default for OnceListCore<T, A, C> {
576    fn default() -> Self {
577        Self {
578            head_slot: NextSlot::new(),
579            alloc: A::default(),
580            cache_mode: C::default(),
581        }
582    }
583}
584
585impl<T: ?Sized + Debug, A: Allocator, C> Debug for OnceListCore<T, A, C>
586where
587    C: CacheMode<T, A>,
588{
589    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
590        f.debug_list().entries(self.iter()).finish()
591    }
592}
593
594impl<T: ?Sized + PartialEq, A: Allocator, C> PartialEq for OnceListCore<T, A, C>
595where
596    C: CacheMode<T, A>,
597{
598    fn eq(&self, other: &Self) -> bool {
599        self.iter().eq(other.iter())
600    }
601}
602
603impl<T: ?Sized + Eq, A: Allocator, C> Eq for OnceListCore<T, A, C> where C: CacheMode<T, A> {}
604
605impl<T: ?Sized + Hash, A: Allocator, C> Hash for OnceListCore<T, A, C>
606where
607    C: CacheMode<T, A>,
608{
609    fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
610        state.write_usize(self.len());
611        for val in self.iter() {
612            val.hash(state);
613        }
614    }
615}
616
617impl<T> FromIterator<T> for OnceListCore<T, Global, NoCache> {
618    fn from_iter<U: IntoIterator<Item = T>>(iter: U) -> Self {
619        let list = Self::new();
620        let mut next_cell = &list.head_slot;
621        for val in iter {
622            let new_cons = Box::new(Cons::new(val));
623            match next_cell.try_insert2(new_cons) {
624                Ok(inserted) => {
625                    next_cell = &inserted.next;
626                }
627                Err((_cur, _new_cons)) => {
628                    // This list is freshly created and not shared, so there should be no contention.
629                    unreachable!(
630                        "FromIterator: unexpected contention when inserting into a new list"
631                    );
632                }
633            }
634        }
635        list
636    }
637}
638
639impl<T, A: Allocator, C> IntoIterator for OnceListCore<T, A, C>
640where
641    C: CacheMode<T, A>,
642{
643    type Item = T;
644    type IntoIter = IntoIter<T, A>;
645
646    fn into_iter(self) -> Self::IntoIter {
647        IntoIter(self.head_slot)
648    }
649}
650
651impl<'a, T: ?Sized, A: Allocator, C> IntoIterator for &'a OnceListCore<T, A, C> {
652    type Item = &'a T;
653    type IntoIter = Iter<'a, T, A>;
654
655    fn into_iter(self) -> Self::IntoIter {
656        self.iter()
657    }
658}
659
660impl<'a, T: ?Sized, A: Allocator, C> IntoIterator for &'a mut OnceListCore<T, A, C> {
661    type Item = &'a mut T;
662    type IntoIter = IterMut<'a, T, A>;
663
664    fn into_iter(self) -> Self::IntoIter {
665        self.iter_mut()
666    }
667}
668
669impl<T, A: Allocator + Clone, C> Extend<T> for OnceListCore<T, A, C>
670where
671    C: CacheMode<T, A>,
672{
673    /// Due to the definition of the `Extend` trait, this method takes `&mut self`.
674    /// Use the [`OnceList::extend`] method instead if you want to use `&self`.
675    fn extend<U: IntoIterator<Item = T>>(&mut self, iter: U) {
676        // Call the inherent `extend(&self, ..)` method.
677        OnceListCore::<T, A, C>::extend(&*self, iter);
678    }
679}