Skip to main content

cxx_qt_lib/core/qvector/
mod.rs

1// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5
6#[cfg(feature = "qt_gui")]
7use crate::QColor;
8#[cfg(not(target_os = "emscripten"))]
9use crate::QDateTime;
10use crate::{
11    QByteArray, QDate, QLine, QLineF, QMargins, QMarginsF, QPersistentModelIndex, QPoint, QPointF,
12    QRect, QRectF, QSize, QSizeF, QString, QTime, QUrl, QUuid, QVariant,
13};
14use core::{marker::PhantomData, mem::MaybeUninit};
15use cxx::{type_id, ExternType};
16use std::fmt;
17
18/// The QVector class is a template class that provides a dynamic array.
19///
20/// To use QVector with a custom type, implement the [`QVectorElement`] trait for T.
21///
22/// Qt Documentation: [QVector]("https://doc.qt.io/qt/qvector.html#details")
23#[repr(C)]
24pub struct QVector<T>
25where
26    T: QVectorElement,
27{
28    /// The layout has changed between Qt 5 and Qt 6
29    ///
30    /// Qt5 `QVector` has one pointer as a member
31    /// Qt6 `QVector`/`QList` has one member, which contains two pointers and a `size_t`
32    #[cfg(cxxqt_qt_version_major = "5")]
33    _space: MaybeUninit<usize>,
34    #[cfg(cxxqt_qt_version_major = "6")]
35    _space: MaybeUninit<[usize; 3]>,
36    _value: PhantomData<T>,
37}
38
39impl<T> Clone for QVector<T>
40where
41    T: QVectorElement,
42{
43    /// Constructs a copy of the `QVector`.
44    fn clone(&self) -> Self {
45        T::clone(self)
46    }
47}
48
49impl<T> Default for QVector<T>
50where
51    T: QVectorElement,
52{
53    /// Constructs an empty vector.
54    fn default() -> Self {
55        T::default()
56    }
57}
58
59impl<T> Drop for QVector<T>
60where
61    T: QVectorElement,
62{
63    /// Destroys the `QVector`.
64    fn drop(&mut self) {
65        T::drop(self);
66    }
67}
68
69impl<T> PartialEq for QVector<T>
70where
71    T: QVectorElement + PartialEq,
72{
73    /// Returns `true` if both vectors contain the same elements in the same order, otherwise returns `false`.
74    fn eq(&self, other: &Self) -> bool {
75        self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
76    }
77}
78
79impl<T> Eq for QVector<T> where T: QVectorElement + Eq {}
80
81impl<T> fmt::Debug for QVector<T>
82where
83    T: QVectorElement + fmt::Debug,
84{
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        f.debug_list().entries(self.iter()).finish()
87    }
88}
89
90impl<T> QVector<T>
91where
92    T: QVectorElement,
93{
94    /// Inserts `value` at the end of the vector.
95    ///
96    /// The value is a reference here so it can be opaque or trivial but
97    /// note that the value is copied when being appended into the vector.
98    pub fn append_clone(&mut self, value: &T) {
99        T::append_clone(self, value);
100    }
101
102    /// Removes all elements from the vector.
103    ///
104    /// In versions of Qt starting from 5.7, the capacity is preserved. In versions before 5.6, this also releases the memory used by the vector.
105    pub fn clear(&mut self) {
106        T::clear(self);
107    }
108
109    /// Returns `true` if the vector contains item `value`; otherwise returns `false`.
110    pub fn contains(&self, value: &T) -> bool {
111        T::contains(self, value)
112    }
113
114    /// Returns the item at index position `index` in the list, or `None` if `index` is out of bounds (i.e. `index < 0 || index >= self.len()`).
115    pub fn get(&self, index: isize) -> Option<&T> {
116        if index >= 0 && index < self.len() {
117            Some(unsafe { T::get_unchecked(self, index) })
118        } else {
119            None
120        }
121    }
122
123    /// Returns the index position of the first occurrence of `value` in the vector. Returns -1 if no item matched.
124    pub fn index_of(&self, value: &T) -> isize {
125        T::index_of(self, value)
126    }
127
128    /// Inserts item value into the vector at index position `pos`.
129    ///
130    /// The value is a reference here so it can be opaque or trivial but
131    /// note that the value is copied when being inserted into the vector.
132    pub fn insert_clone(&mut self, pos: isize, value: &T) {
133        T::insert_clone(self, pos, value);
134    }
135
136    /// Returns `true` if the vector contains no elements; otherwise returns `false`.
137    pub fn is_empty(&self) -> bool {
138        T::len(self) == 0
139    }
140
141    /// An iterator visiting all elements in arbitrary order.
142    /// The iterator element type is `&'a T`.
143    pub fn iter(&self) -> Iter<'_, T> {
144        Iter {
145            vector: self,
146            index: 0,
147        }
148    }
149
150    /// Returns the number of items in the vector.
151    pub fn len(&self) -> isize {
152        T::len(self)
153    }
154
155    /// Removes the element at index position `pos`.
156    pub fn remove(&mut self, pos: isize) {
157        T::remove(self, pos);
158    }
159
160    /// Attempts to allocate memory for at least `size` elements.
161    ///
162    /// If you know in advance how large the vector will be, you should call this function to prevent reallocations and memory fragmentation. If you resize the vector often, you are also likely to get better performance.
163    ///
164    /// If in doubt about how much space shall be needed, it is usually better to use an upper bound as `size`, or a high estimate of the most likely size, if a strict upper bound would be much bigger than this. If `size` is an underestimate, the vector will grow as needed once the reserved size is exceeded, which may lead to a larger allocation than your best overestimate would have and will slow the operation that triggers it.
165    pub fn reserve(&mut self, size: isize) {
166        T::reserve(self, size);
167    }
168
169    /// Helper function for handling Rust values.
170    pub(crate) fn reserve_usize(&mut self, size: usize) {
171        if size != 0 {
172            T::reserve(self, isize::try_from(size).unwrap_or(isize::MAX));
173        }
174    }
175}
176
177impl<T> QVector<T>
178where
179    T: QVectorElement + ExternType<Kind = cxx::kind::Trivial>,
180{
181    /// Inserts `value` at the end of the vector.
182    pub fn append(&mut self, value: T) {
183        T::append(self, value);
184    }
185
186    /// Inserts item `value` into the vector at index position `pos`.
187    pub fn insert(&mut self, pos: isize, value: T) {
188        T::insert(self, pos, value);
189    }
190}
191
192impl<T> From<&QVector<T>> for Vec<T>
193where
194    T: QVectorElement + Clone,
195{
196    /// Convert a reference to a [`QVector`] into a [`Vec`] by making a deep copy of the data.
197    /// The original `QVector` can still be used after constructing the `Vec`.
198    fn from(qvec: &QVector<T>) -> Self {
199        qvec.iter().cloned().collect()
200    }
201}
202
203impl<T, S> From<S> for QVector<T>
204where
205    T: QVectorElement + Clone,
206    S: AsRef<[T]>,
207{
208    /// Convert anything that can be cheaply converted to a slice, such as an [array] or [`Vec`], into a [`QVector`]
209    /// by making a deep copy of the data.
210    /// The original slice can still be used after constructing the `QVector`.
211    fn from(vec: S) -> Self {
212        vec.as_ref().iter().collect()
213    }
214}
215impl<'a, T> Extend<&'a T> for QVector<T>
216where
217    T: QVectorElement,
218{
219    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
220        let iter = iter.into_iter();
221        self.reserve_usize(iter.size_hint().0);
222        for element in iter {
223            self.append_clone(element);
224        }
225    }
226}
227
228impl<T> Extend<T> for QVector<T>
229where
230    T: QVectorElement + ExternType<Kind = cxx::kind::Trivial>,
231{
232    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
233        let iter = iter.into_iter();
234        self.reserve_usize(iter.size_hint().0);
235        for element in iter {
236            self.append(element);
237        }
238    }
239}
240
241impl<'a, T> FromIterator<&'a T> for QVector<T>
242where
243    T: QVectorElement,
244{
245    fn from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Self {
246        let mut qlist = Self::default();
247        qlist.extend(iter);
248        qlist
249    }
250}
251
252impl<T> FromIterator<T> for QVector<T>
253where
254    T: QVectorElement + ExternType<Kind = cxx::kind::Trivial>,
255{
256    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
257        let mut qlist = Self::default();
258        qlist.extend(iter);
259        qlist
260    }
261}
262
263unsafe impl<T> ExternType for QVector<T>
264where
265    T: ExternType + QVectorElement,
266{
267    type Id = T::TypeId;
268    type Kind = cxx::kind::Trivial;
269}
270
271pub struct Iter<'a, T>
272where
273    T: QVectorElement,
274{
275    vector: &'a QVector<T>,
276    index: isize,
277}
278
279impl<'a, T> Iterator for Iter<'a, T>
280where
281    T: QVectorElement,
282{
283    type Item = &'a T;
284
285    fn next(&mut self) -> Option<Self::Item> {
286        if self.index < self.vector.len() {
287            let next = unsafe { T::get_unchecked(self.vector, self.index) };
288            self.index += 1;
289            Some(next)
290        } else {
291            None
292        }
293    }
294
295    fn size_hint(&self) -> (usize, Option<usize>) {
296        let len = self.len();
297        (len, Some(len))
298    }
299}
300
301impl<T> ExactSizeIterator for Iter<'_, T>
302where
303    T: QVectorElement,
304{
305    fn len(&self) -> usize {
306        (self.vector.len() - self.index) as usize
307    }
308}
309
310impl<'a, T> IntoIterator for &'a QVector<T>
311where
312    T: QVectorElement,
313{
314    type Item = &'a T;
315
316    type IntoIter = Iter<'a, T>;
317
318    fn into_iter(self) -> Self::IntoIter {
319        self.iter()
320    }
321}
322
323/// Trait implementation for an element in a [`QVector`].
324pub trait QVectorElement: Sized {
325    type TypeId;
326
327    fn append(vector: &mut QVector<Self>, value: Self)
328    where
329        Self: ExternType<Kind = cxx::kind::Trivial>;
330    fn append_clone(vector: &mut QVector<Self>, value: &Self);
331    fn clear(vector: &mut QVector<Self>);
332    fn clone(vector: &QVector<Self>) -> QVector<Self>;
333    fn contains(vector: &QVector<Self>, value: &Self) -> bool;
334    fn default() -> QVector<Self>;
335    fn drop(vector: &mut QVector<Self>);
336    /// # Safety
337    ///
338    /// Calling this method with an out-of-bounds index is undefined behavior
339    /// even if the resulting reference is not used.
340    unsafe fn get_unchecked(vector: &QVector<Self>, pos: isize) -> &Self;
341    fn index_of(vector: &QVector<Self>, value: &Self) -> isize;
342    fn insert(vector: &mut QVector<Self>, pos: isize, value: Self)
343    where
344        Self: ExternType<Kind = cxx::kind::Trivial>;
345    fn insert_clone(vector: &mut QVector<Self>, pos: isize, value: &Self);
346    fn len(vector: &QVector<Self>) -> isize;
347    fn remove(vector: &mut QVector<Self>, pos: isize);
348    fn reserve(vector: &mut QVector<Self>, size: isize);
349}
350
351macro_rules! impl_qvector_element {
352    ( $typeName:ty, $module:ident, $typeId:literal ) => {
353        mod $module;
354
355        impl QVectorElement for $typeName {
356            type TypeId = type_id!($typeId);
357
358            fn append(vector: &mut QVector<Self>, value: Self) {
359                $module::append(vector, &value);
360            }
361
362            fn append_clone(vector: &mut QVector<Self>, value: &Self) {
363                $module::append(vector, value);
364            }
365
366            fn clear(vector: &mut QVector<Self>) {
367                vector.cxx_clear()
368            }
369
370            fn clone(vector: &QVector<Self>) -> QVector<Self> {
371                $module::clone(vector)
372            }
373
374            fn contains(vector: &QVector<Self>, value: &Self) -> bool {
375                vector.cxx_contains(value)
376            }
377
378            fn default() -> QVector<Self> {
379                $module::default()
380            }
381
382            fn drop(vector: &mut QVector<Self>) {
383                $module::drop(vector);
384            }
385
386            unsafe fn get_unchecked(vector: &QVector<Self>, pos: isize) -> &Self {
387                $module::get_unchecked(vector, pos)
388            }
389
390            fn index_of(vector: &QVector<Self>, value: &Self) -> isize {
391                $module::index_of(vector, value)
392            }
393
394            fn insert(vector: &mut QVector<Self>, pos: isize, value: Self) {
395                $module::insert(vector, pos, &value);
396            }
397
398            fn insert_clone(vector: &mut QVector<Self>, pos: isize, value: &Self) {
399                $module::insert(vector, pos, value);
400            }
401
402            fn len(vector: &QVector<Self>) -> isize {
403                $module::len(vector)
404            }
405
406            fn remove(vector: &mut QVector<Self>, pos: isize) {
407                $module::remove(vector, pos);
408            }
409
410            fn reserve(vector: &mut QVector<Self>, size: isize) {
411                $module::reserve(vector, size);
412            }
413        }
414    };
415}
416
417impl_qvector_element!(bool, qvector_bool, "QVector_bool");
418impl_qvector_element!(f32, qvector_f32, "QVector_f32");
419impl_qvector_element!(f64, qvector_f64, "QVector_f64");
420impl_qvector_element!(i8, qvector_i8, "QVector_i8");
421impl_qvector_element!(i16, qvector_i16, "QVector_i16");
422impl_qvector_element!(i32, qvector_i32, "QVector_i32");
423impl_qvector_element!(i64, qvector_i64, "QVector_i64");
424impl_qvector_element!(QByteArray, qvector_qbytearray, "QVector_QByteArray");
425#[cfg(feature = "qt_gui")]
426impl_qvector_element!(QColor, qvector_qcolor, "QVector_QColor");
427impl_qvector_element!(QDate, qvector_qdate, "QVector_QDate");
428#[cfg(not(target_os = "emscripten"))]
429impl_qvector_element!(QDateTime, qvector_qdatetime, "QVector_QDateTime");
430impl_qvector_element!(QLine, qvector_qline, "QVector_QLine");
431impl_qvector_element!(QLineF, qvector_qlinef, "QVector_QLineF");
432impl_qvector_element!(QMargins, qvector_qmargins, "QVector_QMargins");
433impl_qvector_element!(QMarginsF, qvector_qmarginsf, "QVector_QMarginsF");
434impl_qvector_element!(
435    QPersistentModelIndex,
436    qvector_qpersistentmodelindex,
437    "QVector_QPersistentModelIndex"
438);
439impl_qvector_element!(QPoint, qvector_qpoint, "QVector_QPoint");
440impl_qvector_element!(QPointF, qvector_qpointf, "QVector_QPointF");
441impl_qvector_element!(QRect, qvector_qrect, "QVector_QRect");
442impl_qvector_element!(QRectF, qvector_qrectf, "QVector_QRectF");
443impl_qvector_element!(QSize, qvector_qsize, "QVector_QSize");
444impl_qvector_element!(QSizeF, qvector_qsizef, "QVector_QSizeF");
445impl_qvector_element!(QString, qvector_qstring, "QVector_QString");
446impl_qvector_element!(QTime, qvector_qtime, "QVector_QTime");
447impl_qvector_element!(QUrl, qvector_qurl, "QVector_QUrl");
448impl_qvector_element!(QUuid, qvector_quuid, "QVector_QUuid");
449impl_qvector_element!(QVariant, qvector_qvariant, "QVector_QVariant");
450impl_qvector_element!(u8, qvector_u8, "QVector_u8");
451impl_qvector_element!(u16, qvector_u16, "QVector_u16");
452impl_qvector_element!(u32, qvector_u32, "QVector_u32");
453impl_qvector_element!(u64, qvector_u64, "QVector_u64");
454
455#[cfg(test)]
456mod test {
457    use super::*;
458
459    #[test]
460    fn qvec_from_array_to_vec() {
461        let array = [0, 1, 2];
462        let qvec = QVector::<u8>::from(array);
463        assert_eq!(Vec::from(&qvec), array);
464    }
465
466    #[cfg(feature = "serde")]
467    #[test]
468    fn qvec_serde() {
469        let qvec = QVector::<u8>::from([0, 1, 2]);
470        assert_eq!(crate::serde_impl::roundtrip(&qvec), qvec);
471    }
472}