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}