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