cxx/
cxx_vector.rs

1//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
2//! itself is exposed at the crate root.
3
4use crate::extern_type::ExternType;
5use crate::kind::Trivial;
6use crate::string::CxxString;
7use crate::unique_ptr::UniquePtr;
8use core::ffi::c_void;
9use core::fmt::{self, Debug};
10use core::iter::FusedIterator;
11use core::marker::{PhantomData, PhantomPinned};
12use core::mem::{self, ManuallyDrop, MaybeUninit};
13use core::pin::Pin;
14use core::ptr;
15use core::slice;
16
17/// Binding to C++ `std::vector<T, std::allocator<T>>`.
18///
19/// # Invariants
20///
21/// As an invariant of this API and the static analysis of the cxx::bridge
22/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
23/// Rust code we will only ever look at a vector behind a reference or smart
24/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
25#[repr(C, packed)]
26pub struct CxxVector<T> {
27    // A thing, because repr(C) structs are not allowed to consist exclusively
28    // of PhantomData fields.
29    _void: [c_void; 0],
30    // The conceptual vector elements to ensure that autotraits are propagated
31    // correctly, e.g. CxxVector is UnwindSafe iff T is.
32    _elements: PhantomData<[T]>,
33    // Prevent unpin operation from Pin<&mut CxxVector<T>> to &mut CxxVector<T>.
34    _pinned: PhantomData<PhantomPinned>,
35}
36
37impl<T> CxxVector<T>
38where
39    T: VectorElement,
40{
41    /// Constructs a new heap allocated vector, wrapped by UniquePtr.
42    ///
43    /// The C++ vector is default constructed.
44    pub fn new() -> UniquePtr<Self> {
45        unsafe { UniquePtr::from_raw(T::__vector_new()) }
46    }
47
48    /// Returns the number of elements in the vector.
49    ///
50    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
51    ///
52    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
53    pub fn len(&self) -> usize {
54        T::__vector_size(self)
55    }
56
57    /// Returns the capacity of the vector.
58    ///
59    /// Matches the behavior of C++ [std::vector\<T\>::capacity][capacity].
60    ///
61    /// [capacity]: https://en.cppreference.com/w/cpp/container/vector/capacity
62    pub fn capacity(&self) -> usize {
63        T::__vector_capacity(self)
64    }
65
66    /// Returns true if the vector contains no elements.
67    ///
68    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
69    ///
70    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
71    pub fn is_empty(&self) -> bool {
72        self.len() == 0
73    }
74
75    /// Returns a reference to an element at the given position, or `None` if
76    /// out of bounds.
77    pub fn get(&self, pos: usize) -> Option<&T> {
78        if pos < self.len() {
79            Some(unsafe { self.get_unchecked(pos) })
80        } else {
81            None
82        }
83    }
84
85    /// Returns a pinned mutable reference to an element at the given position,
86    /// or `None` if out of bounds.
87    ///
88    /// This method cannot be named "get\_mut" due to a conflict with
89    /// `Pin::get_mut`.
90    #[doc(alias = "get_mut")]
91    pub fn index_mut(self: Pin<&mut Self>, pos: usize) -> Option<Pin<&mut T>> {
92        if pos < self.len() {
93            Some(unsafe { self.index_unchecked_mut(pos) })
94        } else {
95            None
96        }
97    }
98
99    /// Returns a reference to an element without doing bounds checking.
100    ///
101    /// This is generally not recommended, use with caution! Calling this method
102    /// with an out-of-bounds index is undefined behavior even if the resulting
103    /// reference is not used.
104    ///
105    /// Matches the behavior of C++
106    /// [std::vector\<T\>::operator\[\] const][operator_at].
107    ///
108    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
109    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
110        let this = ptr::from_ref::<CxxVector<T>>(self).cast_mut();
111        unsafe {
112            let ptr = T::__get_unchecked(this, pos).cast_const();
113            &*ptr
114        }
115    }
116
117    /// Returns a pinned mutable reference to an element without doing bounds
118    /// checking.
119    ///
120    /// This is generally not recommended, use with caution! Calling this method
121    /// with an out-of-bounds index is undefined behavior even if the resulting
122    /// reference is not used.
123    ///
124    /// Matches the behavior of C++
125    /// [std::vector\<T\>::operator\[\]][operator_at].
126    ///
127    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
128    ///
129    /// This method cannot be named "get\_unchecked\_mut" due to a conflict with
130    /// `Pin::get_unchecked_mut`.
131    #[doc(alias = "get_unchecked_mut")]
132    pub unsafe fn index_unchecked_mut(self: Pin<&mut Self>, pos: usize) -> Pin<&mut T> {
133        unsafe {
134            let ptr = T::__get_unchecked(self.get_unchecked_mut(), pos);
135            Pin::new_unchecked(&mut *ptr)
136        }
137    }
138
139    /// Returns a slice to the underlying contiguous array of elements.
140    pub fn as_slice(&self) -> &[T]
141    where
142        T: ExternType<Kind = Trivial>,
143    {
144        let len = self.len();
145        if len == 0 {
146            // The slice::from_raw_parts in the other branch requires a nonnull
147            // and properly aligned data ptr. C++ standard does not guarantee
148            // that data() on a vector with size 0 would return a nonnull
149            // pointer or sufficiently aligned pointer, so using it would be
150            // undefined behavior. Create our own empty slice in Rust instead
151            // which upholds the invariants.
152            &[]
153        } else {
154            let this = ptr::from_ref::<CxxVector<T>>(self).cast_mut();
155            let ptr = unsafe { T::__get_unchecked(this, 0) };
156            unsafe { slice::from_raw_parts(ptr, len) }
157        }
158    }
159
160    /// Returns a slice to the underlying contiguous array of elements by
161    /// mutable reference.
162    pub fn as_mut_slice(self: Pin<&mut Self>) -> &mut [T]
163    where
164        T: ExternType<Kind = Trivial>,
165    {
166        let len = self.len();
167        if len == 0 {
168            &mut []
169        } else {
170            let ptr = unsafe { T::__get_unchecked(self.get_unchecked_mut(), 0) };
171            unsafe { slice::from_raw_parts_mut(ptr, len) }
172        }
173    }
174
175    /// Returns an iterator over elements of type `&T`.
176    pub fn iter(&self) -> Iter<T> {
177        Iter { v: self, index: 0 }
178    }
179
180    /// Returns an iterator over elements of type `Pin<&mut T>`.
181    pub fn iter_mut(self: Pin<&mut Self>) -> IterMut<T> {
182        IterMut { v: self, index: 0 }
183    }
184
185    /// Appends an element to the back of the vector.
186    ///
187    /// Matches the behavior of C++ [std::vector\<T\>::push_back][push_back].
188    ///
189    /// [push_back]: https://en.cppreference.com/w/cpp/container/vector/push_back
190    pub fn push(self: Pin<&mut Self>, value: T)
191    where
192        T: ExternType<Kind = Trivial>,
193    {
194        let mut value = ManuallyDrop::new(value);
195        unsafe {
196            // C++ calls move constructor followed by destructor on `value`.
197            T::__push_back(self, &mut value);
198        }
199    }
200
201    /// Removes the last element from a vector and returns it, or `None` if the
202    /// vector is empty.
203    pub fn pop(self: Pin<&mut Self>) -> Option<T>
204    where
205        T: ExternType<Kind = Trivial>,
206    {
207        if self.is_empty() {
208            None
209        } else {
210            let mut value = MaybeUninit::uninit();
211            Some(unsafe {
212                T::__pop_back(self, &mut value);
213                value.assume_init()
214            })
215        }
216    }
217
218    /// Ensures that this vector's capacity is at least `additional` elements
219    /// larger than its length.
220    ///
221    /// The capacity may be increased by more than `additional` elements if the
222    /// implementation chooses, to amortize the cost of frequent reallocations.
223    ///
224    /// **The meaning of the argument is not the same as
225    /// [std::vector\<T\>::reserve][reserve] in C++.** The C++ standard library
226    /// and Rust standard library both have a `reserve` method on vectors, but
227    /// in C++ code the argument always refers to total capacity, whereas in
228    /// Rust code it always refers to additional capacity. This API on
229    /// `CxxVector` follows the Rust convention, the same way that for the
230    /// length accessor we use the Rust conventional `len()` naming and not C++
231    /// `size()`.
232    ///
233    /// # Panics
234    ///
235    /// Panics if the new capacity overflows usize, or if `T` is not
236    /// move-constructible in C++.
237    ///
238    /// [reserve]: https://en.cppreference.com/w/cpp/container/vector/reserve.html
239    pub fn reserve(self: Pin<&mut Self>, additional: usize) {
240        let new_cap = self
241            .len()
242            .checked_add(additional)
243            .expect("CxxVector capacity overflow");
244        unsafe { T::__reserve(self, new_cap) }
245    }
246}
247
248impl<T> Extend<T> for Pin<&mut CxxVector<T>>
249where
250    T: ExternType<Kind = Trivial> + VectorElement,
251{
252    fn extend<I>(&mut self, iter: I)
253    where
254        I: IntoIterator<Item = T>,
255    {
256        let iter = iter.into_iter();
257        self.as_mut().reserve(iter.size_hint().0);
258        for element in iter {
259            self.as_mut().push(element);
260        }
261    }
262}
263
264/// Iterator over elements of a `CxxVector` by shared reference.
265///
266/// The iterator element type is `&'a T`.
267pub struct Iter<'a, T> {
268    v: &'a CxxVector<T>,
269    index: usize,
270}
271
272impl<'a, T> IntoIterator for &'a CxxVector<T>
273where
274    T: VectorElement,
275{
276    type Item = &'a T;
277    type IntoIter = Iter<'a, T>;
278
279    fn into_iter(self) -> Self::IntoIter {
280        self.iter()
281    }
282}
283
284impl<'a, T> Iterator for Iter<'a, T>
285where
286    T: VectorElement,
287{
288    type Item = &'a T;
289
290    fn next(&mut self) -> Option<Self::Item> {
291        let next = self.v.get(self.index)?;
292        self.index += 1;
293        Some(next)
294    }
295
296    fn size_hint(&self) -> (usize, Option<usize>) {
297        let len = self.len();
298        (len, Some(len))
299    }
300}
301
302impl<'a, T> ExactSizeIterator for Iter<'a, T>
303where
304    T: VectorElement,
305{
306    fn len(&self) -> usize {
307        self.v.len() - self.index
308    }
309}
310
311impl<'a, T> FusedIterator for Iter<'a, T> where T: VectorElement {}
312
313/// Iterator over elements of a `CxxVector` by pinned mutable reference.
314///
315/// The iterator element type is `Pin<&'a mut T>`.
316pub struct IterMut<'a, T> {
317    v: Pin<&'a mut CxxVector<T>>,
318    index: usize,
319}
320
321impl<'a, T> IntoIterator for Pin<&'a mut CxxVector<T>>
322where
323    T: VectorElement,
324{
325    type Item = Pin<&'a mut T>;
326    type IntoIter = IterMut<'a, T>;
327
328    fn into_iter(self) -> Self::IntoIter {
329        self.iter_mut()
330    }
331}
332
333impl<'a, T> Iterator for IterMut<'a, T>
334where
335    T: VectorElement,
336{
337    type Item = Pin<&'a mut T>;
338
339    fn next(&mut self) -> Option<Self::Item> {
340        let next = self.v.as_mut().index_mut(self.index)?;
341        self.index += 1;
342        // Extend lifetime to allow simultaneous holding of nonoverlapping
343        // elements, analogous to slice::split_first_mut.
344        unsafe {
345            let ptr = ptr::from_mut::<T>(Pin::into_inner_unchecked(next));
346            Some(Pin::new_unchecked(&mut *ptr))
347        }
348    }
349
350    fn size_hint(&self) -> (usize, Option<usize>) {
351        let len = self.len();
352        (len, Some(len))
353    }
354}
355
356impl<'a, T> ExactSizeIterator for IterMut<'a, T>
357where
358    T: VectorElement,
359{
360    fn len(&self) -> usize {
361        self.v.len() - self.index
362    }
363}
364
365impl<'a, T> FusedIterator for IterMut<'a, T> where T: VectorElement {}
366
367impl<T> Debug for CxxVector<T>
368where
369    T: VectorElement + Debug,
370{
371    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
372        formatter.debug_list().entries(self).finish()
373    }
374}
375
376/// Trait bound for types which may be used as the `T` inside of a
377/// `CxxVector<T>` in generic code.
378///
379/// This trait has no publicly callable or implementable methods. Implementing
380/// it outside of the CXX codebase requires using [explicit shim trait impls],
381/// adding the line `impl CxxVector<MyType> {}` in the same `cxx::bridge` that
382/// defines `MyType`.
383///
384/// # Example
385///
386/// A bound `T: VectorElement` may be necessary when manipulating [`CxxVector`]
387/// in generic code.
388///
389/// ```
390/// use cxx::vector::{CxxVector, VectorElement};
391/// use std::fmt::Display;
392///
393/// pub fn take_generic_vector<T>(vector: &CxxVector<T>)
394/// where
395///     T: VectorElement + Display,
396/// {
397///     println!("the vector elements are:");
398///     for element in vector {
399///         println!("  • {}", element);
400///     }
401/// }
402/// ```
403///
404/// Writing the same generic function without a `VectorElement` trait bound
405/// would not compile.
406///
407/// [explicit shim trait impls]: https://cxx.rs/extern-c++.html#explicit-shim-trait-impls
408pub unsafe trait VectorElement: Sized {
409    #[doc(hidden)]
410    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
411    #[doc(hidden)]
412    fn __vector_new() -> *mut CxxVector<Self>;
413    #[doc(hidden)]
414    fn __vector_size(v: &CxxVector<Self>) -> usize;
415    #[doc(hidden)]
416    fn __vector_capacity(v: &CxxVector<Self>) -> usize;
417    #[doc(hidden)]
418    unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
419    #[doc(hidden)]
420    unsafe fn __reserve(v: Pin<&mut CxxVector<Self>>, new_cap: usize);
421    #[doc(hidden)]
422    unsafe fn __push_back(v: Pin<&mut CxxVector<Self>>, value: &mut ManuallyDrop<Self>) {
423        // Opaque C type vector elements do not get this method because they can
424        // never exist by value on the Rust side of the bridge.
425        let _ = v;
426        let _ = value;
427        unreachable!()
428    }
429    #[doc(hidden)]
430    unsafe fn __pop_back(v: Pin<&mut CxxVector<Self>>, out: &mut MaybeUninit<Self>) {
431        // Opaque C type vector elements do not get this method because they can
432        // never exist by value on the Rust side of the bridge.
433        let _ = v;
434        let _ = out;
435        unreachable!()
436    }
437    #[doc(hidden)]
438    fn __unique_ptr_null() -> MaybeUninit<*mut c_void>;
439    #[doc(hidden)]
440    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void>;
441    #[doc(hidden)]
442    unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self>;
443    #[doc(hidden)]
444    unsafe fn __unique_ptr_release(repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<Self>;
445    #[doc(hidden)]
446    unsafe fn __unique_ptr_drop(repr: MaybeUninit<*mut c_void>);
447}
448
449macro_rules! vector_element_by_value_methods {
450    (opaque, $segment:expr, $ty:ty) => {};
451    (trivial, $segment:expr, $ty:ty) => {
452        unsafe fn __push_back(v: Pin<&mut CxxVector<$ty>>, value: &mut ManuallyDrop<$ty>) {
453            extern "C" {
454                #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$push_back")]
455                fn __push_back(_: Pin<&mut CxxVector<$ty>>, _: &mut ManuallyDrop<$ty>);
456            }
457            unsafe { __push_back(v, value) }
458        }
459        unsafe fn __pop_back(v: Pin<&mut CxxVector<$ty>>, out: &mut MaybeUninit<$ty>) {
460            extern "C" {
461                #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$pop_back")]
462                fn __pop_back(_: Pin<&mut CxxVector<$ty>>, _: &mut MaybeUninit<$ty>);
463            }
464            unsafe { __pop_back(v, out) }
465        }
466    };
467}
468
469macro_rules! impl_vector_element {
470    ($kind:ident, $segment:expr, $name:expr, $ty:ty) => {
471        const_assert_eq!(0, mem::size_of::<CxxVector<$ty>>());
472        const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());
473
474        unsafe impl VectorElement for $ty {
475            fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
476                f.write_str($name)
477            }
478            fn __vector_new() -> *mut CxxVector<Self> {
479                extern "C" {
480                    #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$new")]
481                    fn __vector_new() -> *mut CxxVector<$ty>;
482                }
483                unsafe { __vector_new() }
484            }
485            fn __vector_size(v: &CxxVector<$ty>) -> usize {
486                extern "C" {
487                    #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
488                    fn __vector_size(_: &CxxVector<$ty>) -> usize;
489                }
490                unsafe { __vector_size(v) }
491            }
492            fn __vector_capacity(v: &CxxVector<$ty>) -> usize {
493                extern "C" {
494                    #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$capacity")]
495                    fn __vector_capacity(_: &CxxVector<$ty>) -> usize;
496                }
497                unsafe { __vector_capacity(v) }
498            }
499            unsafe fn __get_unchecked(v: *mut CxxVector<$ty>, pos: usize) -> *mut $ty {
500                extern "C" {
501                    #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
502                    fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
503                }
504                unsafe { __get_unchecked(v, pos) }
505            }
506            unsafe fn __reserve(v: Pin<&mut CxxVector<$ty>>, new_cap: usize) {
507                extern "C" {
508                    #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$reserve")]
509                    fn __reserve(_: Pin<&mut CxxVector<$ty>>, _: usize);
510                }
511                unsafe { __reserve(v, new_cap) }
512            }
513            vector_element_by_value_methods!($kind, $segment, $ty);
514            fn __unique_ptr_null() -> MaybeUninit<*mut c_void> {
515                extern "C" {
516                    #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
517                    fn __unique_ptr_null(this: *mut MaybeUninit<*mut c_void>);
518                }
519                let mut repr = MaybeUninit::uninit();
520                unsafe { __unique_ptr_null(&mut repr) }
521                repr
522            }
523            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> MaybeUninit<*mut c_void> {
524                extern "C" {
525                    #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
526                    fn __unique_ptr_raw(this: *mut MaybeUninit<*mut c_void>, raw: *mut CxxVector<$ty>);
527                }
528                let mut repr = MaybeUninit::uninit();
529                unsafe { __unique_ptr_raw(&mut repr, raw) }
530                repr
531            }
532            unsafe fn __unique_ptr_get(repr: MaybeUninit<*mut c_void>) -> *const CxxVector<Self> {
533                extern "C" {
534                    #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
535                    fn __unique_ptr_get(this: *const MaybeUninit<*mut c_void>) -> *const CxxVector<$ty>;
536                }
537                unsafe { __unique_ptr_get(&repr) }
538            }
539            unsafe fn __unique_ptr_release(mut repr: MaybeUninit<*mut c_void>) -> *mut CxxVector<Self> {
540                extern "C" {
541                    #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
542                    fn __unique_ptr_release(this: *mut MaybeUninit<*mut c_void>) -> *mut CxxVector<$ty>;
543                }
544                unsafe { __unique_ptr_release(&mut repr) }
545            }
546            unsafe fn __unique_ptr_drop(mut repr: MaybeUninit<*mut c_void>) {
547                extern "C" {
548                    #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
549                    fn __unique_ptr_drop(this: *mut MaybeUninit<*mut c_void>);
550                }
551                unsafe { __unique_ptr_drop(&mut repr) }
552            }
553        }
554    };
555}
556
557macro_rules! impl_vector_element_for_primitive {
558    ($ty:ident) => {
559        impl_vector_element!(trivial, stringify!($ty), stringify!($ty), $ty);
560    };
561}
562
563impl_vector_element_for_primitive!(u8);
564impl_vector_element_for_primitive!(u16);
565impl_vector_element_for_primitive!(u32);
566impl_vector_element_for_primitive!(u64);
567impl_vector_element_for_primitive!(usize);
568impl_vector_element_for_primitive!(i8);
569impl_vector_element_for_primitive!(i16);
570impl_vector_element_for_primitive!(i32);
571impl_vector_element_for_primitive!(i64);
572impl_vector_element_for_primitive!(isize);
573impl_vector_element_for_primitive!(f32);
574impl_vector_element_for_primitive!(f64);
575
576impl_vector_element!(opaque, "string", "CxxString", CxxString);