Skip to main content

i_slint_core/
sharedvector.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4//! module for the SharedVector and related things
5#![allow(unsafe_code)]
6#![warn(missing_docs)]
7use core::fmt::Debug;
8use core::mem::MaybeUninit;
9use core::ops::Deref;
10use core::ptr::NonNull;
11
12use portable_atomic as atomic;
13
14#[repr(C)]
15struct SharedVectorHeader {
16    refcount: atomic::AtomicIsize,
17    size: usize,
18    capacity: usize,
19}
20
21#[repr(C)]
22struct SharedVectorInner<T> {
23    header: SharedVectorHeader,
24    data: MaybeUninit<T>,
25}
26
27fn compute_inner_layout<T>(capacity: usize) -> core::alloc::Layout {
28    core::alloc::Layout::new::<SharedVectorHeader>()
29        .extend(core::alloc::Layout::array::<T>(capacity).unwrap())
30        .unwrap()
31        .0
32}
33
34/// Returns a raw pointer to the data with full allocation provenance.
35///
36/// Must not go through `&SharedVectorInner<T>` or `&mut SharedVectorInner<T>` because
37/// the declared struct size is smaller than the actual allocation.
38fn data_ptr<T>(inner: NonNull<SharedVectorInner<T>>) -> *mut T {
39    // Safety: inner.as_ptr() is a valid raw pointer; &raw mut avoids creating a reference.
40    unsafe { &raw mut (*inner.as_ptr()).data as *mut T }
41}
42
43/// # Safety
44/// Caller must ensure refcount is 0 and no other references to `inner` exist.
45unsafe fn drop_inner<T>(inner: NonNull<SharedVectorInner<T>>) {
46    unsafe {
47        debug_assert_eq!((*inner.as_ptr()).header.refcount.load(atomic::Ordering::Relaxed), 0);
48        let data = data_ptr(inner);
49        let size = (*inner.as_ptr()).header.size;
50        for x in 0..size {
51            core::ptr::drop_in_place(data.add(x));
52        }
53        alloc::alloc::dealloc(
54            inner.as_ptr() as *mut u8,
55            compute_inner_layout::<T>((*inner.as_ptr()).header.capacity),
56        )
57    }
58}
59
60/// Allocate the memory for the SharedVector with the given capacity. Return the inner with size and refcount set to 1
61fn alloc_with_capacity<T>(capacity: usize) -> NonNull<SharedVectorInner<T>> {
62    let ptr = unsafe { ::alloc::alloc::alloc(compute_inner_layout::<T>(capacity)) };
63    assert!(!ptr.is_null(), "allocation of {capacity:?} bytes failed");
64    unsafe {
65        core::ptr::write(
66            ptr as *mut SharedVectorHeader,
67            SharedVectorHeader { refcount: 1.into(), size: 0, capacity },
68        );
69    }
70    NonNull::new(ptr).unwrap().cast()
71}
72
73/// Return a new capacity suitable for this vector
74/// Loosely based on alloc::raw_vec::RawVec::grow_amortized.
75fn capacity_for_grow(current_cap: usize, required_cap: usize, elem_size: usize) -> usize {
76    if current_cap >= required_cap {
77        return current_cap;
78    }
79    let cap = core::cmp::max(current_cap * 2, required_cap);
80    let min_non_zero_cap = if elem_size == 1 {
81        8
82    } else if elem_size <= 1024 {
83        4
84    } else {
85        1
86    };
87    core::cmp::max(min_non_zero_cap, cap)
88}
89
90#[repr(C)]
91/// SharedVector holds a reference-counted read-only copy of `[T]`.
92pub struct SharedVector<T> {
93    inner: NonNull<SharedVectorInner<T>>,
94}
95
96// Safety: We use atomic reference counting, and if T is Send and Sync, we can send the vector to another thread
97unsafe impl<T: Send + Sync> Send for SharedVector<T> {}
98// Safety: We use atomic reference counting, and if T is Send and Sync, we can access the vector from multiple threads
99unsafe impl<T: Send + Sync> Sync for SharedVector<T> {}
100
101impl<T> Drop for SharedVector<T> {
102    fn drop(&mut self) {
103        // Safety: inner is always a valid pointer (either a real allocation or SHARED_NULL).
104        unsafe {
105            let header = &raw const (*self.inner.as_ptr()).header;
106            if (*header).refcount.load(atomic::Ordering::Relaxed) < 0 {
107                return;
108            }
109            if (*header).refcount.fetch_sub(1, atomic::Ordering::SeqCst) == 1 {
110                drop_inner(self.inner)
111            }
112        }
113    }
114}
115
116impl<T> Clone for SharedVector<T> {
117    fn clone(&self) -> Self {
118        // Safety: inner is always a valid pointer (either a real allocation or SHARED_NULL).
119        unsafe {
120            let header = &raw const (*self.inner.as_ptr()).header;
121            if (*header).refcount.load(atomic::Ordering::Relaxed) > 0 {
122                (*header).refcount.fetch_add(1, atomic::Ordering::SeqCst);
123            }
124            SharedVector { inner: self.inner }
125        }
126    }
127}
128
129impl<T> SharedVector<T> {
130    /// Create a new empty array with a pre-allocated capacity in number of items
131    pub fn with_capacity(capacity: usize) -> Self {
132        Self { inner: alloc_with_capacity(capacity) }
133    }
134
135    fn as_ptr(&self) -> *const T {
136        data_ptr(self.inner)
137    }
138
139    /// Number of elements in the array
140    pub fn len(&self) -> usize {
141        // Safety: header is always fully allocated (even for SHARED_NULL).
142        unsafe { (*self.inner.as_ptr()).header.size }
143    }
144
145    /// Return true if the SharedVector is empty
146    pub fn is_empty(&self) -> bool {
147        self.len() == 0
148    }
149
150    /// Return a slice to the array
151    pub fn as_slice(&self) -> &[T] {
152        if self.is_empty() {
153            &[]
154        } else {
155            // Safety: len > 0 ensures data_ptr is valid for len elements.
156            unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len()) }
157        }
158    }
159
160    /// Returns the number of elements the vector can hold without reallocating, when not shared
161    fn capacity(&self) -> usize {
162        // Safety: header is always fully allocated (even for SHARED_NULL).
163        unsafe { (*self.inner.as_ptr()).header.capacity }
164    }
165}
166
167impl<T: Clone + PartialEq> SharedVector<T> {
168    /// Replaces `from` by `to` in `self` `count` times
169    /// `count` - number of times to do the replacements
170    pub(crate) fn replace_range(&mut self, from: &[T], to: &[T], mut count: usize) {
171        if from.is_empty() || count == 0 || from.len() != to.len() {
172            return;
173        }
174        let s = self.make_mut_slice();
175        if s.len() < from.len() {
176            return;
177        }
178
179        let mut index = 0;
180        let from_len = from.len();
181        let max_start = s.len() - from_len;
182
183        while index <= max_start && count > 0 {
184            if s[index..index + from_len] == *from {
185                for (dst, src) in s[index..index + from_len].iter_mut().zip(to.iter()) {
186                    *dst = src.clone();
187                }
188                count -= 1;
189                index += from_len;
190            } else {
191                index += 1;
192            }
193        }
194    }
195}
196
197impl<T: Clone> SharedVector<T> {
198    /// Create a SharedVector from a slice
199    pub fn from_slice(slice: &[T]) -> SharedVector<T> {
200        Self::from(slice)
201    }
202
203    /// Ensure that the reference count is 1 so the array can be changed.
204    /// If that's not the case, the array will be cloned
205    fn detach(&mut self, new_capacity: usize) {
206        // Acquire: if refcount == 1, synchronize with the Release in the last Drop to
207        // ensure prior writes to size/data are visible before we mutate.
208        let is_shared =
209            unsafe { (*self.inner.as_ptr()).header.refcount.load(atomic::Ordering::Acquire) } != 1;
210        if !is_shared && new_capacity <= self.capacity() {
211            return;
212        }
213        let mut new_array = SharedVector::with_capacity(new_capacity);
214        core::mem::swap(&mut self.inner, &mut new_array.inner);
215        let mut size = 0;
216        for x in new_array.into_iter() {
217            assert_ne!(size, new_capacity);
218            unsafe {
219                core::ptr::write(data_ptr(self.inner).add(size), x);
220                size += 1;
221                (*self.inner.as_ptr()).header.size = size;
222            }
223            if size == new_capacity {
224                break;
225            }
226        }
227    }
228
229    /// Return a mutable slice to the array. If the array was shared, this will make a copy of the array.
230    pub fn make_mut_slice(&mut self) -> &mut [T] {
231        self.detach(self.len());
232        unsafe { core::slice::from_raw_parts_mut(self.as_ptr() as *mut T, self.len()) }
233    }
234
235    /// Add an element to the array. If the array was shared, this will make a copy of the array.
236    pub fn push(&mut self, value: T) {
237        self.detach(capacity_for_grow(self.capacity(), self.len() + 1, core::mem::size_of::<T>()));
238        // Safety: detach ensures exclusive ownership and sufficient capacity.
239        unsafe {
240            let size = (*self.inner.as_ptr()).header.size;
241            core::ptr::write(data_ptr(self.inner).add(size), value);
242            (*self.inner.as_ptr()).header.size = size + 1;
243        }
244    }
245
246    /// Removes last element from the array and returns it.
247    /// If the array was shared, this will make a copy of the array.
248    pub fn pop(&mut self) -> Option<T> {
249        if self.is_empty() {
250            None
251        } else {
252            self.detach(self.len());
253            // Safety: detach ensures exclusive ownership; len > 0 guarantees an element exists.
254            unsafe {
255                let size = (*self.inner.as_ptr()).header.size - 1;
256                (*self.inner.as_ptr()).header.size = size;
257                Some(core::ptr::read(data_ptr(self.inner).add(size)))
258            }
259        }
260    }
261
262    /// Resize the array to the given size.
263    /// If the array was smaller new elements will be initialized with the value.
264    /// If the array was bigger, extra elements will be discarded
265    ///
266    /// ```
267    /// use i_slint_core::SharedVector;
268    /// let mut shared_vector = SharedVector::<u32>::from_slice(&[1, 2, 3]);
269    /// shared_vector.resize(5, 8);
270    /// assert_eq!(shared_vector.as_slice(), &[1, 2, 3, 8, 8]);
271    /// shared_vector.resize(2, 0);
272    /// assert_eq!(shared_vector.as_slice(), &[1, 2]);
273    /// ```
274    pub fn resize(&mut self, new_len: usize, value: T) {
275        if self.len() == new_len {
276            return;
277        }
278        self.detach(new_len);
279        // Safety: detach ensured that the array is not shared.
280        let header = unsafe { &mut (*self.inner.as_ptr()).header };
281
282        if header.size >= new_len {
283            self.shrink(new_len);
284        } else {
285            let data_ptr = data_ptr(self.inner);
286            while header.size < new_len {
287                // Safety: The array must have a capacity of at least new_len because of the detach call earlier
288                unsafe {
289                    core::ptr::write(data_ptr.add(header.size), value.clone());
290                }
291                header.size += 1;
292            }
293        }
294    }
295
296    fn shrink(&mut self, new_len: usize) {
297        if self.len() == new_len {
298            return;
299        }
300
301        assert!(
302            unsafe { (*self.inner.as_ptr()).header.refcount.load(atomic::Ordering::Relaxed) } == 1
303        );
304        // Safety: caller (and above assert) must ensure that the array is not shared.
305        let header = unsafe { &mut (*self.inner.as_ptr()).header };
306        let data_ptr = data_ptr(self.inner);
307
308        while header.size > new_len {
309            header.size -= 1;
310            // Safety: The array was of size header.size, so there should be an element there
311            unsafe {
312                core::ptr::drop_in_place(data_ptr.add(header.size));
313            }
314        }
315    }
316
317    /// Clears the vector and removes all elements.
318    pub fn clear(&mut self) {
319        let is_shared =
320            unsafe { (*self.inner.as_ptr()).header.refcount.load(atomic::Ordering::Acquire) } != 1;
321        if is_shared {
322            *self = SharedVector::default();
323        } else {
324            self.shrink(0)
325        }
326    }
327
328    /// Reserves capacity for at least `additional` bytes more than the current vector's length.
329    pub fn reserve(&mut self, additional: usize) {
330        self.detach((self.len() + additional).max(self.capacity()))
331    }
332}
333
334impl<T> Deref for SharedVector<T> {
335    type Target = [T];
336    fn deref(&self) -> &Self::Target {
337        self.as_slice()
338    }
339}
340
341/* FIXME: is this a good idea to implement DerefMut knowing what it might detach?
342impl<T> DerefMut for SharedVector<T> {
343    fn deref_mut(&mut self) -> &mut Self::Target {
344        self.as_mut_slice()
345    }
346}*/
347
348impl<T: Clone> From<&[T]> for SharedVector<T> {
349    fn from(slice: &[T]) -> Self {
350        let capacity = slice.len();
351        let result = Self::with_capacity(capacity);
352        for x in slice {
353            unsafe {
354                let size = (*result.inner.as_ptr()).header.size;
355                core::ptr::write(data_ptr(result.inner).add(size), x.clone());
356                (*result.inner.as_ptr()).header.size = size + 1;
357            }
358        }
359        result
360    }
361}
362
363impl<T, const N: usize> From<[T; N]> for SharedVector<T> {
364    fn from(array: [T; N]) -> Self {
365        array.into_iter().collect()
366    }
367}
368
369impl<T> FromIterator<T> for SharedVector<T> {
370    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
371        let mut iter = iter.into_iter();
372        let mut capacity = iter.size_hint().0;
373        let mut result = Self::with_capacity(capacity);
374        let mut size = 0;
375        while let Some(x) = iter.next() {
376            if size >= capacity {
377                capacity = capacity_for_grow(
378                    capacity,
379                    size + 1 + iter.size_hint().0,
380                    core::mem::size_of::<T>(),
381                );
382                unsafe {
383                    (*result.inner.as_ptr()).header.refcount.store(0, atomic::Ordering::Relaxed)
384                };
385                let mut iter = IntoIter(IntoIterInner::UnShared(result.inner, 0));
386                result.inner = alloc_with_capacity::<T>(capacity);
387                match &mut iter.0 {
388                    IntoIterInner::UnShared(old_inner, begin) => {
389                        let old_data = data_ptr(*old_inner);
390                        while *begin < size {
391                            unsafe {
392                                core::ptr::write(
393                                    data_ptr(result.inner).add(*begin),
394                                    core::ptr::read(old_data.add(*begin)),
395                                );
396                                *begin += 1;
397                                (*result.inner.as_ptr()).header.size = *begin;
398                            }
399                        }
400                    }
401                    _ => unreachable!(),
402                }
403            }
404            debug_assert_eq!(result.len(), size);
405            debug_assert!(result.capacity() > size);
406            unsafe {
407                core::ptr::write(data_ptr(result.inner).add(size), x);
408                size += 1;
409                (*result.inner.as_ptr()).header.size = size;
410            }
411        }
412        result
413    }
414}
415
416impl<T: Clone> Extend<T> for SharedVector<T> {
417    fn extend<X: IntoIterator<Item = T>>(&mut self, iter: X) {
418        let iter = iter.into_iter();
419        let hint = iter.size_hint().0;
420        if hint > 0 {
421            self.detach(capacity_for_grow(
422                self.capacity(),
423                self.len() + hint,
424                core::mem::size_of::<T>(),
425            ));
426        }
427        for item in iter {
428            self.push(item);
429        }
430    }
431}
432
433static SHARED_NULL: SharedVectorHeader =
434    SharedVectorHeader { refcount: atomic::AtomicIsize::new(-1), size: 0, capacity: 0 };
435
436impl<T> Default for SharedVector<T> {
437    fn default() -> Self {
438        SharedVector { inner: NonNull::from(&SHARED_NULL).cast() }
439    }
440}
441
442impl<T: Debug> Debug for SharedVector<T> {
443    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
444        self.as_slice().fmt(f)
445    }
446}
447
448impl<T> AsRef<[T]> for SharedVector<T> {
449    #[inline]
450    fn as_ref(&self) -> &[T] {
451        self.as_slice()
452    }
453}
454
455impl<T, U> PartialEq<U> for SharedVector<T>
456where
457    U: ?Sized + AsRef<[T]>,
458    T: PartialEq,
459{
460    fn eq(&self, other: &U) -> bool {
461        self.as_slice() == other.as_ref()
462    }
463}
464
465impl<T: Eq> Eq for SharedVector<T> {}
466
467impl<T: Clone> IntoIterator for SharedVector<T> {
468    type Item = T;
469    type IntoIter = IntoIter<T>;
470    fn into_iter(self) -> Self::IntoIter {
471        IntoIter(unsafe {
472            if (*self.inner.as_ptr()).header.refcount.load(atomic::Ordering::Acquire) == 1 {
473                let inner = self.inner;
474                core::mem::forget(self);
475                (*inner.as_ptr()).header.refcount.store(0, atomic::Ordering::Relaxed);
476                IntoIterInner::UnShared(inner, 0)
477            } else {
478                IntoIterInner::Shared(self, 0)
479            }
480        })
481    }
482}
483
484#[cfg(feature = "serde")]
485use serde::ser::SerializeSeq;
486#[cfg(feature = "serde")]
487impl<T> serde::Serialize for SharedVector<T>
488where
489    T: serde::Serialize,
490{
491    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
492    where
493        S: serde::Serializer,
494    {
495        let mut seq = serializer.serialize_seq(Some(self.len()))?;
496        for item in self.iter() {
497            seq.serialize_element(item)?;
498        }
499        seq.end()
500    }
501}
502
503#[cfg(feature = "serde")]
504impl<'de, T> serde::Deserialize<'de> for SharedVector<T>
505where
506    T: Clone + serde::Deserialize<'de>,
507{
508    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
509    where
510        D: serde::Deserializer<'de>,
511    {
512        let mut elements: alloc::vec::Vec<T> = serde::Deserialize::deserialize(deserializer)?;
513        let mut shared_vec = SharedVector::with_capacity(elements.len());
514        for elem in elements.drain(..) {
515            shared_vec.push(elem);
516        }
517        Ok(shared_vec)
518    }
519}
520
521enum IntoIterInner<T> {
522    Shared(SharedVector<T>, usize),
523    // Elements up to the usize member are already moved out
524    UnShared(NonNull<SharedVectorInner<T>>, usize),
525}
526
527impl<T> Drop for IntoIterInner<T> {
528    fn drop(&mut self) {
529        match self {
530            IntoIterInner::Shared(..) => { /* drop of SharedVector takes care of it */ }
531            IntoIterInner::UnShared(inner, begin) => unsafe {
532                debug_assert_eq!(
533                    (*inner.as_ptr()).header.refcount.load(atomic::Ordering::Relaxed),
534                    0
535                );
536                let data_ptr = data_ptr(*inner);
537                for x in (*begin)..(*inner.as_ptr()).header.size {
538                    core::ptr::drop_in_place(data_ptr.add(x));
539                }
540                ::alloc::alloc::dealloc(
541                    inner.as_ptr() as *mut u8,
542                    compute_inner_layout::<T>((*inner.as_ptr()).header.capacity),
543                )
544            },
545        }
546    }
547}
548
549/// An iterator that moves out of a SharedVector.
550///
551/// This `struct` is created by the `into_iter` method on [`SharedVector`] (provided
552/// by the [`IntoIterator`] trait).
553pub struct IntoIter<T>(IntoIterInner<T>);
554
555impl<T: Clone> Iterator for IntoIter<T> {
556    type Item = T;
557
558    fn next(&mut self) -> Option<Self::Item> {
559        match &mut self.0 {
560            IntoIterInner::Shared(array, moved) => {
561                let result = array.as_slice().get(*moved).cloned();
562                *moved += 1;
563                result
564            }
565            IntoIterInner::UnShared(inner, begin) => unsafe {
566                if *begin < (*inner.as_ptr()).header.size {
567                    let data_ptr = data_ptr(*inner);
568                    let r = core::ptr::read(data_ptr.add(*begin));
569                    *begin += 1;
570                    Some(r)
571                } else {
572                    None
573                }
574            },
575        }
576    }
577}
578
579#[test]
580fn simple_test() {
581    let x: SharedVector<i32> = SharedVector::from([1, 2, 3]);
582    let y: SharedVector<i32> = SharedVector::from([3, 2, 1]);
583    assert_eq!(x, x.clone());
584    assert_ne!(x, y);
585    let z: [i32; 3] = [1, 2, 3];
586    assert_eq!(z, x.as_slice());
587    let vec: std::vec::Vec<i32> = std::vec![1, 2, 3];
588    assert_eq!(x, vec);
589    let def: SharedVector<i32> = Default::default();
590    assert_eq!(def, SharedVector::<i32>::default());
591    assert_ne!(def, x);
592}
593
594#[test]
595fn push_test() {
596    let mut x: SharedVector<i32> = SharedVector::from([1, 2, 3]);
597    let y = x.clone();
598    x.push(4);
599    x.push(5);
600    x.push(6);
601    assert_eq!(x.as_slice(), &[1, 2, 3, 4, 5, 6]);
602    assert_eq!(y.as_slice(), &[1, 2, 3]);
603}
604
605#[test]
606#[should_panic]
607#[cfg_attr(miri, ignore)] // Miri aborts on large allocations before the panic can fire
608fn invalid_capacity_test() {
609    let _: SharedVector<u8> = SharedVector::with_capacity(usize::MAX / 2 - 1000);
610}
611
612#[test]
613fn collect_from_iter_with_no_size_hint() {
614    use std::string::{String, ToString};
615    struct NoSizeHintIter<'a> {
616        data: &'a [&'a str],
617        i: usize,
618    }
619
620    impl Iterator for NoSizeHintIter<'_> {
621        type Item = String;
622
623        fn next(&mut self) -> Option<Self::Item> {
624            if self.i >= self.data.len() {
625                return None;
626            }
627            let item = self.data[self.i];
628            self.i += 1;
629            Some(item.to_string())
630        }
631
632        fn size_hint(&self) -> (usize, Option<usize>) {
633            (0, None)
634        }
635    }
636
637    // 5 elements to be above the initial "grow"-capacity of 4 and thus require one realloc.
638    let input = NoSizeHintIter { data: &["Hello", "sweet", "world", "of", "iterators"], i: 0 };
639
640    let shared_vec: SharedVector<String> = input.collect();
641    assert_eq!(shared_vec.as_slice(), &["Hello", "sweet", "world", "of", "iterators"]);
642}
643
644#[test]
645fn test_capacity_grows_only_when_needed() {
646    let mut vec: SharedVector<u8> = SharedVector::with_capacity(2);
647    vec.push(0);
648    assert_eq!(vec.capacity(), 2);
649    vec.push(0);
650    assert_eq!(vec.capacity(), 2);
651    vec.push(0);
652    assert_eq!(vec.len(), 3);
653    assert!(vec.capacity() > 2);
654}
655
656#[test]
657fn test_vector_clear() {
658    let mut vec: SharedVector<std::string::String> = Default::default();
659    vec.clear();
660    vec.push("Hello".into());
661    vec.push("World".into());
662    vec.push("of".into());
663    vec.push("Vectors".into());
664
665    let mut copy = vec.clone();
666
667    assert_eq!(vec.len(), 4);
668    let orig_cap = vec.capacity();
669    assert!(orig_cap >= vec.len());
670    vec.clear();
671    assert_eq!(vec.len(), 0);
672    assert_eq!(vec.capacity(), 0); // vec was shared, so start with new empty vector.
673    vec.push("Welcome back".into());
674    assert_eq!(vec.len(), 1);
675    assert!(vec.capacity() >= vec.len());
676
677    assert_eq!(copy.len(), 4);
678    assert_eq!(copy.capacity(), orig_cap);
679    copy.clear(); // copy is not shared (anymore), retain capacity.
680    assert_eq!(copy.capacity(), orig_cap);
681}
682
683#[test]
684fn pop_test() {
685    let mut x: SharedVector<i32> = SharedVector::from([1, 2, 3]);
686    let y = x.clone();
687    assert_eq!(x.pop(), Some(3));
688    assert_eq!(x.pop(), Some(2));
689    assert_eq!(x.pop(), Some(1));
690    assert_eq!(x.pop(), None);
691    assert!(x.is_empty());
692    assert_eq!(y.as_slice(), &[1, 2, 3]);
693}
694
695#[cfg(feature = "ffi")]
696pub(crate) mod ffi {
697    use super::*;
698
699    #[unsafe(no_mangle)]
700    /// This function is used for the low-level C++ interface to allocate the backing vector of a SharedVector.
701    pub unsafe extern "C" fn slint_shared_vector_allocate(size: usize, align: usize) -> *mut u8 {
702        unsafe { alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, align).unwrap()) }
703    }
704
705    #[unsafe(no_mangle)]
706    /// This function is used for the low-level C++ interface to deallocate the backing vector of a SharedVector
707    pub unsafe extern "C" fn slint_shared_vector_free(ptr: *mut u8, size: usize, align: usize) {
708        unsafe {
709            alloc::alloc::dealloc(ptr, alloc::alloc::Layout::from_size_align(size, align).unwrap())
710        }
711    }
712
713    #[unsafe(no_mangle)]
714    /// This function is used for the low-level C++ interface to initialize the empty SharedVector.
715    pub unsafe extern "C" fn slint_shared_vector_empty() -> *const u8 {
716        &SHARED_NULL as *const _ as *const u8
717    }
718}
719
720#[cfg(feature = "serde")]
721#[test]
722fn test_serialize_deserialize_sharedvector() {
723    let v = SharedVector::from([1, 2, 3]);
724    let serialized = serde_json::to_string(&v).unwrap();
725    let deserialized: SharedVector<i32> = serde_json::from_str(&serialized).unwrap();
726    assert_eq!(v, deserialized);
727}
728
729#[test]
730fn test_reserve() {
731    let mut v = SharedVector::from([1, 2, 3]);
732    assert_eq!(v.capacity(), 3);
733    v.reserve(1);
734    assert_eq!(v.capacity(), 4);
735    assert_eq!(v.len(), 3);
736    v.push(4);
737    v.push(5);
738    assert_eq!(v.len(), 5);
739    assert_eq!(v.capacity(), 8);
740    v.reserve(1);
741    assert_eq!(v.capacity(), 8);
742    v.reserve(8);
743    assert_eq!(v.len(), 5);
744    assert_eq!(v.capacity(), 13);
745}
746
747#[test]
748fn test_replace_range_all_matches() {
749    let mut v = SharedVector::from([1, 2, 3, 1, 2, 3, 1, 2, 3]);
750    v.replace_range(&[1, 2, 3], &[4, 5, 6], usize::MAX);
751    assert_eq!(v.as_slice(), &[4, 5, 6, 4, 5, 6, 4, 5, 6]);
752}
753
754#[test]
755fn test_replace_range_count_limit() {
756    let mut v = SharedVector::from([1, 2, 3, 1, 2, 3, 1, 2, 3]);
757    v.replace_range(&[1, 2, 3], &[4, 5, 6], 2);
758    assert_eq!(v.as_slice(), &[4, 5, 6, 4, 5, 6, 1, 2, 3]);
759}
760
761#[test]
762fn test_replace_range_non_overlapping() {
763    let mut v = SharedVector::from([1, 1, 1]);
764    v.replace_range(&[1, 1], &[2, 2], usize::MAX);
765    assert_eq!(v.as_slice(), &[2, 2, 1]);
766}
767
768#[test]
769fn test_replace_range() {
770    let mut v = SharedVector::from([1, 2, 3, 4]);
771    v.replace_range(&[2, 3, 4, 5], &[7, 8, 9, 9], 1);
772    assert_eq!(v.as_slice(), &[1, 2, 3, 4]);
773}