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