Backport official GLib iterator safety fix for Linux desktop
This commit is contained in:
1 parent
43c43ebdc9
commit
8ef874c609
133 files changed
+55342
-2
No files matched your search
@@ -0,0 +1,894 @@
|
||||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
use std::{iter::FusedIterator, marker::PhantomData, mem, ptr};
|
||||
|
||||
use crate::translate::*;
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A list of items of type `T`.
|
||||
///
|
||||
/// Behaves like an `Iterator<Item = T>` but allows modifications.
|
||||
#[repr(transparent)]
|
||||
pub struct List<T: TransparentPtrType> {
|
||||
ptr: Option<ptr::NonNull<ffi::GList>>,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<T: TransparentPtrType> TransparentPtrType for List<T> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T: TransparentPtrType> GlibPtrDefault for List<T> {
|
||||
type GlibType = *mut ffi::GList;
|
||||
}
|
||||
|
||||
unsafe impl<T: Send + TransparentPtrType> Send for List<T> {}
|
||||
|
||||
unsafe impl<T: Sync + TransparentPtrType> Sync for List<T> {}
|
||||
|
||||
impl<T: TransparentPtrType> List<T> {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `List` around a list.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_none(list: *const ffi::GList) -> List<T> {
|
||||
// Need to copy the whole list
|
||||
let list = if mem::needs_drop::<T>() {
|
||||
unsafe extern "C" fn copy_item<T: TransparentPtrType>(
|
||||
ptr: ffi::gconstpointer,
|
||||
_user_data: ffi::gpointer,
|
||||
) -> ffi::gpointer {
|
||||
let mut item = mem::ManuallyDrop::new(
|
||||
(*(&ptr as *const ffi::gconstpointer as *const T)).clone(),
|
||||
);
|
||||
|
||||
*(&mut *item as *mut T as *mut *mut T::GlibType) as ffi::gpointer
|
||||
}
|
||||
|
||||
ffi::g_list_copy_deep(mut_override(list), Some(copy_item::<T>), ptr::null_mut())
|
||||
} else {
|
||||
ffi::g_list_copy(mut_override(list))
|
||||
};
|
||||
|
||||
List {
|
||||
ptr: ptr::NonNull::new(list),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `List` around a list.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_container(list: *mut ffi::GList) -> List<T> {
|
||||
// Need to copy all items as we only own the container
|
||||
if mem::needs_drop::<T>() {
|
||||
unsafe extern "C" fn copy_item<T: TransparentPtrType>(
|
||||
ptr: ffi::gpointer,
|
||||
_user_data: ffi::gpointer,
|
||||
) {
|
||||
let item = (*(&ptr as *const ffi::gpointer as *const T)).clone();
|
||||
ptr::write(ptr as *mut T, item);
|
||||
}
|
||||
|
||||
ffi::g_list_foreach(list, Some(copy_item::<T>), ptr::null_mut());
|
||||
}
|
||||
|
||||
List {
|
||||
ptr: ptr::NonNull::new(list),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `List` around a list.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_full(list: *mut ffi::GList) -> List<T> {
|
||||
List {
|
||||
ptr: ptr::NonNull::new(list),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Creates a new empty list.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
List {
|
||||
ptr: None,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a non-destructive iterator over the `List`.
|
||||
#[inline]
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter::new(self)
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a non-destructive mutable iterator over the `List`.
|
||||
#[inline]
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
IterMut::new(self)
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Check if the list is empty.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.ptr.is_none()
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the length of the list.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_length")]
|
||||
pub fn len(&self) -> usize {
|
||||
self.iter().count()
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a reference to the first item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_first")]
|
||||
pub fn front(&self) -> Option<&T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(cur) => unsafe {
|
||||
let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a mutable reference to the first item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_first")]
|
||||
pub fn front_mut(&mut self) -> Option<&mut T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(mut cur) => unsafe {
|
||||
let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes the front item from the list, if any.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
pub fn pop_front(&mut self) -> Option<T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(mut cur) => unsafe {
|
||||
self.ptr = ptr::NonNull::new(cur.as_ref().next);
|
||||
if let Some(mut next) = self.ptr {
|
||||
next.as_mut().prev = ptr::null_mut();
|
||||
}
|
||||
|
||||
let item = ptr::read(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
|
||||
|
||||
ffi::g_list_free_1(cur.as_ptr());
|
||||
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Prepends the new item to the front of the list.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_prepend")]
|
||||
pub fn push_front(&mut self, item: T) {
|
||||
unsafe {
|
||||
let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_prepend(
|
||||
ptr,
|
||||
*(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType)
|
||||
as ffi::gpointer,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a reference to the last item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_last")]
|
||||
pub fn back(&self) -> Option<&T> {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return None,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
let last_ptr = ffi::g_list_last(ptr);
|
||||
let item = &*(&(*last_ptr).data as *const ffi::gpointer as *const T);
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a mutable reference to the last item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_last")]
|
||||
pub fn back_mut(&mut self) -> Option<&mut T> {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return None,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
let last_ptr = ffi::g_list_last(ptr);
|
||||
let item = &mut *(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes the back item from the list, if any.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
pub fn pop_back(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return None,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
let last_ptr = ffi::g_list_last(ptr);
|
||||
let item = ptr::read(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
|
||||
self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(ptr, last_ptr));
|
||||
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Appends the new item to the back of the list.
|
||||
///
|
||||
/// this operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_append")]
|
||||
pub fn push_back(&mut self, item: T) {
|
||||
unsafe {
|
||||
let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_append(
|
||||
ptr,
|
||||
*(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType)
|
||||
as ffi::gpointer,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Reverse the list.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_reverse")]
|
||||
pub fn reverse(&mut self) {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_reverse(ptr)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sorts the list.
|
||||
///
|
||||
/// This operation is `O(n * log n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_sort")]
|
||||
pub fn sort(&mut self)
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
self.sort_by(|a, b| a.cmp(b));
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sorts the list.
|
||||
///
|
||||
/// This operation is `O(n * log n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_list_sort")]
|
||||
pub fn sort_by<F: FnMut(&T, &T) -> std::cmp::Ordering>(&mut self, mut f: F) {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
|
||||
unsafe extern "C" fn func<
|
||||
T: TransparentPtrType,
|
||||
F: FnMut(&T, &T) -> std::cmp::Ordering,
|
||||
>(
|
||||
a: ffi::gconstpointer,
|
||||
b: ffi::gconstpointer,
|
||||
user_data: ffi::gpointer,
|
||||
) -> i32 {
|
||||
let f = &mut *(user_data as *mut F);
|
||||
let a = &*(&a as *const ffi::gconstpointer as *const T);
|
||||
let b = &*(&b as *const ffi::gconstpointer as *const T);
|
||||
f(a, b).into_glib()
|
||||
}
|
||||
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_sort_with_data(
|
||||
ptr,
|
||||
Some(func::<T, F>),
|
||||
&mut f as *mut F as ffi::gpointer,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes all items from the list.
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
*self = Self::new();
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Only keeps the item in the list for which `f` returns `true`.
|
||||
#[inline]
|
||||
pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) {
|
||||
if let Some(head) = self.ptr {
|
||||
unsafe {
|
||||
let mut ptr = head.as_ptr();
|
||||
while !ptr.is_null() {
|
||||
let item = &*((*ptr).data as *const ffi::gpointer as *const T);
|
||||
let next = (*ptr).next;
|
||||
if !f(item) {
|
||||
ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T);
|
||||
self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(head.as_ptr(), ptr));
|
||||
}
|
||||
ptr = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the underlying pointer.
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const ffi::GList {
|
||||
self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the underlying pointer.
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut ffi::GList {
|
||||
self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Consumes the list and returns the underlying pointer.
|
||||
#[inline]
|
||||
pub fn into_raw(mut self) -> *mut ffi::GList {
|
||||
self.ptr
|
||||
.take()
|
||||
.map(|p| p.as_ptr())
|
||||
.unwrap_or(ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Default for List<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Clone for List<T> {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Drop for List<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if let Some(ptr) = self.ptr {
|
||||
unsafe {
|
||||
if mem::needs_drop::<T>() {
|
||||
unsafe extern "C" fn drop_item<T: TransparentPtrType>(mut ptr: ffi::gpointer) {
|
||||
ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T);
|
||||
}
|
||||
|
||||
ffi::g_list_free_full(ptr.as_ptr(), Some(drop_item::<T>));
|
||||
} else {
|
||||
ffi::g_list_free(ptr.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> std::iter::FromIterator<T> for List<T> {
|
||||
#[inline]
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
unsafe {
|
||||
let mut iter = iter.into_iter();
|
||||
|
||||
let first = match iter.next() {
|
||||
None => return Self::new(),
|
||||
Some(first) => first,
|
||||
};
|
||||
|
||||
let list = ffi::g_list_prepend(
|
||||
ptr::null_mut(),
|
||||
*(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType)
|
||||
as ffi::gpointer,
|
||||
);
|
||||
let mut tail = list;
|
||||
for item in iter {
|
||||
let new_tail = ffi::g_list_alloc();
|
||||
|
||||
(*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T
|
||||
as *mut *mut T::GlibType) as ffi::gpointer;
|
||||
(*new_tail).prev = tail;
|
||||
(*new_tail).next = ptr::null_mut();
|
||||
(*tail).next = new_tail;
|
||||
tail = new_tail;
|
||||
}
|
||||
|
||||
Self::from_glib_full(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a List<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut List<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> std::iter::IntoIterator for List<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
|
||||
for List<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none_num(ptr: *mut ffi::GList, _num: usize) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_container_num(ptr: *mut ffi::GList, _num: usize) -> Self {
|
||||
Self::from_glib_container(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_full_num(ptr: *mut ffi::GList, _num: usize) -> Self {
|
||||
Self::from_glib_full(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
|
||||
for List<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none_num(ptr: *const ffi::GList, _num: usize) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
unsafe fn from_glib_container_num(_ptr: *const ffi::GList, _num: usize) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
unsafe fn from_glib_full_num(_ptr: *const ffi::GList, _num: usize) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
|
||||
for List<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none(ptr: *mut ffi::GList) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_container(ptr: *mut ffi::GList) -> Self {
|
||||
Self::from_glib_container(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_full(ptr: *mut ffi::GList) -> Self {
|
||||
Self::from_glib_full(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
|
||||
for List<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none(ptr: *const ffi::GList) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
unsafe fn from_glib_container(_ptr: *const ffi::GList) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
unsafe fn from_glib_full(_ptr: *const ffi::GList) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GList> for List<T> {
|
||||
type Storage = PhantomData<&'a Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
|
||||
Stash(self.as_ptr() as *mut _, PhantomData)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
|
||||
unsafe {
|
||||
let ptr = ffi::g_malloc(mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
|
||||
as *mut ffi::GList;
|
||||
ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
|
||||
Stash(ptr, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_glib_full(&self) -> *mut ffi::GList {
|
||||
self.clone().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GList> for List<T> {
|
||||
type Storage = PhantomData<&'a Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GList, Self> {
|
||||
Stash(self.as_ptr(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GList> for List<T> {
|
||||
type Storage = PhantomData<&'a mut Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GList, Self> {
|
||||
StashMut(self.as_mut_ptr(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GList> for List<T> {
|
||||
#[inline]
|
||||
unsafe fn into_glib_ptr(self) -> *mut ffi::GList {
|
||||
self.into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A non-destructive iterator over a [`List`].
|
||||
pub struct Iter<'a, T: TransparentPtrType> {
|
||||
ptr: Option<ptr::NonNull<ffi::GList>>,
|
||||
phantom: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> Iter<'a, T> {
|
||||
#[inline]
|
||||
fn new(list: &'a List<T>) -> Iter<'a, T> {
|
||||
debug_assert_eq!(
|
||||
mem::size_of::<T>(),
|
||||
mem::size_of::<<T as GlibPtrDefault>::GlibType>()
|
||||
);
|
||||
|
||||
Iter {
|
||||
ptr: list.ptr,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(cur) => unsafe {
|
||||
self.ptr = ptr::NonNull::new(cur.as_ref().next);
|
||||
|
||||
let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
|
||||
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> FusedIterator for Iter<'a, T> {}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A non-destructive iterator over a [`List`].
|
||||
pub struct IterMut<'a, T: TransparentPtrType> {
|
||||
ptr: Option<ptr::NonNull<ffi::GList>>,
|
||||
phantom: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> IterMut<'a, T> {
|
||||
#[inline]
|
||||
fn new(list: &'a mut List<T>) -> IterMut<'a, T> {
|
||||
debug_assert_eq!(
|
||||
mem::size_of::<T>(),
|
||||
mem::size_of::<<T as GlibPtrDefault>::GlibType>()
|
||||
);
|
||||
|
||||
IterMut {
|
||||
ptr: list.ptr,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> {
|
||||
type Item = &'a mut T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a mut T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(mut cur) => unsafe {
|
||||
self.ptr = ptr::NonNull::new(cur.as_ref().next);
|
||||
|
||||
let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
|
||||
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> FusedIterator for IterMut<'a, T> {}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A destructive iterator over a [`List`].
|
||||
pub struct IntoIter<T: TransparentPtrType> {
|
||||
list: List<T>,
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> IntoIter<T> {
|
||||
#[inline]
|
||||
fn new(list: List<T>) -> IntoIter<T> {
|
||||
debug_assert_eq!(
|
||||
mem::size_of::<T>(),
|
||||
mem::size_of::<<T as GlibPtrDefault>::GlibType>()
|
||||
);
|
||||
|
||||
IntoIter { list }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> {
|
||||
self.list.pop_front()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn from_glib_full() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
let mut list = unsafe {
|
||||
let mut list = ffi::g_list_append(
|
||||
ptr::null_mut(),
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer,
|
||||
);
|
||||
List::<crate::DateTime>::from_glib_full(list)
|
||||
};
|
||||
assert!(!list.is_empty());
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.into_iter().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
|
||||
assert!(list.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn from_glib_container() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
let mut list = unsafe {
|
||||
let mut list = ffi::g_list_append(
|
||||
ptr::null_mut(),
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
|
||||
);
|
||||
List::<crate::DateTime>::from_glib_container(list)
|
||||
};
|
||||
assert!(!list.is_empty());
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.into_iter().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
|
||||
assert!(list.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn from_glib_none() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
let mut list = unsafe {
|
||||
let mut list = ffi::g_list_append(
|
||||
ptr::null_mut(),
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_list_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
|
||||
);
|
||||
let res = List::<crate::DateTime>::from_glib_none(list);
|
||||
ffi::g_list_free(list);
|
||||
|
||||
res
|
||||
};
|
||||
assert!(!list.is_empty());
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.into_iter().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
|
||||
assert!(list.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn safe_api() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
|
||||
let mut list = items[1..3].iter().cloned().collect::<List<_>>();
|
||||
assert_eq!(list.len(), 2);
|
||||
list.push_front(items[0].clone());
|
||||
assert_eq!(list.len(), 3);
|
||||
list.push_back(items[3].clone());
|
||||
assert_eq!(list.len(), 4);
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
assert_eq!(list.front(), Some(&items[0]));
|
||||
assert_eq!(list.back(), Some(&items[3]));
|
||||
assert_eq!(list.pop_front().as_ref(), Some(&items[0]));
|
||||
assert_eq!(list.len(), 3);
|
||||
|
||||
list.reverse();
|
||||
let mut list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
list_items.reverse();
|
||||
assert_eq!(&items[1..], &list_items);
|
||||
|
||||
let list2 = list.clone();
|
||||
let mut list_items = list2.iter().cloned().collect::<Vec<_>>();
|
||||
list_items.reverse();
|
||||
assert_eq!(&items[1..], &list_items);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
pub mod ptr_slice;
|
||||
pub use ptr_slice::PtrSlice;
|
||||
|
||||
pub mod slice;
|
||||
pub use slice::Slice;
|
||||
|
||||
pub mod list;
|
||||
pub use list::List;
|
||||
|
||||
pub mod slist;
|
||||
pub use slist::SList;
|
||||
|
||||
pub mod strv;
|
||||
pub use strv::StrV;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,991 @@
|
||||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
use std::{fmt, marker::PhantomData, mem, ptr};
|
||||
|
||||
use crate::translate::*;
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Minimum size of the `Slice` allocation in bytes.
|
||||
const MIN_SIZE: usize = 256;
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Slice of elements of type `T` allocated by the GLib allocator.
|
||||
///
|
||||
/// This can be used like a `&[T]`, `&mut [T]` and `Vec<T>`.
|
||||
pub struct Slice<T: TransparentType> {
|
||||
ptr: ptr::NonNull<T::GlibType>,
|
||||
len: usize,
|
||||
capacity: usize,
|
||||
}
|
||||
|
||||
unsafe impl<T: TransparentType + Send> Send for Slice<T> {}
|
||||
|
||||
unsafe impl<T: TransparentType + Sync> Sync for Slice<T> {}
|
||||
|
||||
impl<T: fmt::Debug + TransparentType> fmt::Debug for Slice<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.as_slice().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + TransparentType> PartialEq for Slice<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_slice() == other.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq + TransparentType> Eq for Slice<T> {}
|
||||
|
||||
impl<T: PartialOrd + TransparentType> PartialOrd for Slice<T> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.as_slice().partial_cmp(other.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord + TransparentType> Ord for Slice<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.as_slice().cmp(other.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::hash::Hash + TransparentType> std::hash::Hash for Slice<T> {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_slice().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + TransparentType> PartialEq<[T]> for Slice<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &[T]) -> bool {
|
||||
self.as_slice() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + TransparentType> PartialEq<Slice<T>> for [T] {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Slice<T>) -> bool {
|
||||
self == other.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> Drop for Slice<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if mem::needs_drop::<T>() {
|
||||
for i in 0..self.len {
|
||||
ptr::drop_in_place::<T>(self.ptr.as_ptr().add(i) as *mut T);
|
||||
}
|
||||
}
|
||||
|
||||
if self.capacity != 0 {
|
||||
ffi::g_free(self.ptr.as_ptr() as ffi::gpointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> AsRef<[T]> for Slice<T> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[T] {
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> AsMut<[T]> for Slice<T> {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut [T] {
|
||||
self.as_mut_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> std::borrow::Borrow<[T]> for Slice<T> {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &[T] {
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> std::borrow::BorrowMut<[T]> for Slice<T> {
|
||||
#[inline]
|
||||
fn borrow_mut(&mut self) -> &mut [T] {
|
||||
self.as_mut_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> std::ops::Deref for Slice<T> {
|
||||
type Target = [T];
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &[T] {
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> std::ops::DerefMut for Slice<T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
self.as_mut_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> Default for Slice<T> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> std::iter::Extend<T> for Slice<T> {
|
||||
#[inline]
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
let iter = iter.into_iter();
|
||||
self.reserve(iter.size_hint().0);
|
||||
|
||||
for item in iter {
|
||||
self.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType + 'a> std::iter::Extend<&'a T> for Slice<T> {
|
||||
#[inline]
|
||||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
let iter = iter.into_iter();
|
||||
self.reserve(iter.size_hint().0);
|
||||
|
||||
for item in iter {
|
||||
self.push(item.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> std::iter::FromIterator<T> for Slice<T> {
|
||||
#[inline]
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
let iter = iter.into_iter();
|
||||
let mut s = Self::with_capacity(iter.size_hint().0);
|
||||
for item in iter {
|
||||
s.push(item);
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType> std::iter::IntoIterator for &'a Slice<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = std::slice::Iter<'a, T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.as_slice().iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType> std::iter::IntoIterator for &'a mut Slice<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = std::slice::IterMut<'a, T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.as_mut_slice().iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> std::iter::IntoIterator for Slice<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntoIter<T: TransparentType> {
|
||||
ptr: ptr::NonNull<T::GlibType>,
|
||||
idx: ptr::NonNull<T::GlibType>,
|
||||
len: usize,
|
||||
empty: bool,
|
||||
}
|
||||
|
||||
impl<T: TransparentType> IntoIter<T> {
|
||||
#[inline]
|
||||
fn new(slice: Slice<T>) -> Self {
|
||||
let slice = mem::ManuallyDrop::new(slice);
|
||||
IntoIter {
|
||||
ptr: slice.ptr,
|
||||
idx: slice.ptr,
|
||||
len: slice.len,
|
||||
empty: slice.capacity == 0,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the remaining items as slice.
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
unsafe {
|
||||
if self.len == 0 {
|
||||
&[]
|
||||
} else {
|
||||
std::slice::from_raw_parts(self.idx.as_ptr() as *mut T, self.len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the remaining items as mutable slice.
|
||||
#[inline]
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
unsafe {
|
||||
if self.len == 0 {
|
||||
&mut []
|
||||
} else {
|
||||
std::slice::from_raw_parts_mut(self.idx.as_ptr() as *mut T, self.len)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> Drop for IntoIter<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if mem::needs_drop::<T>() {
|
||||
for i in 0..self.len {
|
||||
ptr::drop_in_place::<T>(self.idx.as_ptr().add(i) as *mut T);
|
||||
}
|
||||
}
|
||||
|
||||
if !self.empty {
|
||||
ffi::g_free(self.ptr.as_ptr() as ffi::gpointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.len == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let p = self.idx.as_ptr();
|
||||
self.len -= 1;
|
||||
self.idx = ptr::NonNull::new_unchecked(p.add(1));
|
||||
Some(ptr::read(p as *mut T))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.len, Some(self.len))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<T> {
|
||||
if self.len == 0 {
|
||||
None
|
||||
} else {
|
||||
self.len -= 1;
|
||||
Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> DoubleEndedIterator for IntoIter<T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
if self.len == 0 {
|
||||
None
|
||||
} else {
|
||||
self.len -= 1;
|
||||
Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> ExactSizeIterator for IntoIter<T> {}
|
||||
|
||||
impl<T: TransparentType> std::iter::FusedIterator for IntoIter<T> {}
|
||||
|
||||
impl<T: TransparentType> From<Slice<T>> for Vec<T> {
|
||||
#[inline]
|
||||
fn from(mut value: Slice<T>) -> Self {
|
||||
unsafe {
|
||||
let mut s = Vec::with_capacity(value.len);
|
||||
ptr::copy_nonoverlapping(value.ptr.as_ptr() as *const T, s.as_mut_ptr(), value.len);
|
||||
s.set_len(value.len);
|
||||
value.len = 0;
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> From<Vec<T>> for Slice<T> {
|
||||
#[inline]
|
||||
fn from(mut value: Vec<T>) -> Self {
|
||||
unsafe {
|
||||
let mut s = Self::with_capacity(value.len());
|
||||
ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, value.len());
|
||||
s.len = value.len();
|
||||
value.set_len(0);
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType, const N: usize> From<[T; N]> for Slice<T> {
|
||||
#[inline]
|
||||
fn from(value: [T; N]) -> Self {
|
||||
unsafe {
|
||||
let value = mem::ManuallyDrop::new(value);
|
||||
let len = value.len();
|
||||
let mut s = Self::with_capacity(len);
|
||||
ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, len);
|
||||
s.len = len;
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType> From<&'a [T]> for Slice<T> {
|
||||
#[inline]
|
||||
fn from(value: &'a [T]) -> Self {
|
||||
unsafe {
|
||||
let mut s = Self::with_capacity(value.len());
|
||||
for (i, item) in value.iter().enumerate() {
|
||||
ptr::write(s.ptr.as_ptr().add(i) as *mut T, item.clone());
|
||||
}
|
||||
s.len = value.len();
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType> From<&'a [&'a T]> for Slice<T> {
|
||||
#[inline]
|
||||
fn from(value: &'a [&'a T]) -> Self {
|
||||
unsafe {
|
||||
let mut s = Self::with_capacity(value.len());
|
||||
for (i, item) in value.iter().enumerate() {
|
||||
ptr::write(s.ptr.as_ptr().add(i) as *mut T, (*item).clone());
|
||||
}
|
||||
s.len = value.len();
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> Clone for Slice<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Self::from(self.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType> Slice<T> {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Borrows a C array.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_borrow_num<'a>(ptr: *const T::GlibType, len: usize) -> &'a [T] {
|
||||
debug_assert!(!ptr.is_null() || len == 0);
|
||||
|
||||
if len == 0 {
|
||||
&[]
|
||||
} else {
|
||||
std::slice::from_raw_parts(ptr as *const T, len)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Borrows a mutable C array.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_borrow_num_mut<'a>(ptr: *mut T::GlibType, len: usize) -> &'a mut [T] {
|
||||
debug_assert!(!ptr.is_null() || len == 0);
|
||||
|
||||
if len == 0 {
|
||||
&mut []
|
||||
} else {
|
||||
std::slice::from_raw_parts_mut(ptr as *mut T, len)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Borrows a C array of references.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_ptr_borrow_num<'a>(
|
||||
ptr: *const *const T::GlibType,
|
||||
len: usize,
|
||||
) -> &'a [&'a T] {
|
||||
debug_assert!(!ptr.is_null() || len == 0);
|
||||
|
||||
if len == 0 {
|
||||
&[]
|
||||
} else {
|
||||
std::slice::from_raw_parts(ptr as *const &T, len)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Borrows a mutable C array.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_ptr_borrow_num_mut<'a>(
|
||||
ptr: *mut *mut T::GlibType,
|
||||
len: usize,
|
||||
) -> &'a mut [&'a mut T] {
|
||||
debug_assert!(!ptr.is_null() || len == 0);
|
||||
|
||||
if len == 0 {
|
||||
&mut []
|
||||
} else {
|
||||
std::slice::from_raw_parts_mut(ptr as *mut &mut T, len)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `Slice` around a C array.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_none_num(ptr: *const T::GlibType, len: usize) -> Self {
|
||||
debug_assert_eq!(mem::size_of::<T>(), mem::size_of::<T::GlibType>());
|
||||
debug_assert!(!ptr.is_null() || len == 0);
|
||||
|
||||
if len == 0 {
|
||||
Slice::default()
|
||||
} else {
|
||||
// Need to fully copy the array here.
|
||||
let s = Self::from_glib_borrow_num(ptr, len);
|
||||
Self::from(s)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `Slice` around a C array.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_container_num(ptr: *mut T::GlibType, len: usize) -> Self {
|
||||
debug_assert_eq!(mem::size_of::<T>(), mem::size_of::<T::GlibType>());
|
||||
debug_assert!(!ptr.is_null() || len == 0);
|
||||
|
||||
if len == 0 {
|
||||
ffi::g_free(ptr as ffi::gpointer);
|
||||
Slice::default()
|
||||
} else {
|
||||
// Need to clone every item because we don't own it here but only
|
||||
// if this type requires explicit drop.
|
||||
if mem::needs_drop::<T>() {
|
||||
for i in 0..len {
|
||||
let p = ptr.add(i) as *mut T;
|
||||
let clone: T = (*p).clone();
|
||||
ptr::write(p, clone);
|
||||
}
|
||||
}
|
||||
|
||||
// And now it can be handled exactly the same as `from_glib_full_num()`.
|
||||
Self::from_glib_full_num(ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `Slice` around a C array.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_full_num(ptr: *mut T::GlibType, len: usize) -> Self {
|
||||
debug_assert_eq!(mem::size_of::<T>(), mem::size_of::<T::GlibType>());
|
||||
debug_assert!(!ptr.is_null() || len == 0);
|
||||
|
||||
if len == 0 {
|
||||
ffi::g_free(ptr as ffi::gpointer);
|
||||
Slice::default()
|
||||
} else {
|
||||
Slice {
|
||||
ptr: ptr::NonNull::new_unchecked(ptr),
|
||||
len,
|
||||
capacity: len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Creates a new empty slice.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Slice {
|
||||
ptr: ptr::NonNull::dangling(),
|
||||
len: 0,
|
||||
capacity: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Creates a new empty slice with the given capacity.
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
let mut s = Self::new();
|
||||
s.reserve(capacity);
|
||||
s
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the underlying pointer.
|
||||
///
|
||||
/// This is guaranteed to be `NULL`-terminated.
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const T::GlibType {
|
||||
if self.len == 0 {
|
||||
ptr::null()
|
||||
} else {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the underlying pointer.
|
||||
///
|
||||
/// This is guaranteed to be `NULL`-terminated.
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut T::GlibType {
|
||||
if self.len == 0 {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Consumes the slice and returns the underlying pointer.
|
||||
///
|
||||
/// This is guaranteed to be `NULL`-terminated.
|
||||
#[inline]
|
||||
pub fn into_raw(mut self) -> *mut T::GlibType {
|
||||
if self.len == 0 {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
self.len = 0;
|
||||
self.capacity = 0;
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Gets the length of the slice.
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns `true` if the slice is empty.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the capacity of the slice.
|
||||
#[inline]
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.capacity
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sets the length of the slice to `len`.
|
||||
///
|
||||
/// # SAFETY
|
||||
///
|
||||
/// There must be at least `len` valid items.
|
||||
pub unsafe fn set_len(&mut self, len: usize) {
|
||||
self.len = len;
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Reserves at least this much additional capacity.
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
// Nothing new to reserve as there's still enough space
|
||||
if self.len + additional <= self.capacity {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_capacity = usize::next_power_of_two(std::cmp::max(
|
||||
self.len + additional,
|
||||
MIN_SIZE / mem::size_of::<T>(),
|
||||
));
|
||||
assert_ne!(new_capacity, 0);
|
||||
assert!(new_capacity > self.capacity);
|
||||
|
||||
unsafe {
|
||||
let ptr = if self.capacity == 0 {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
self.ptr.as_ptr() as *mut _
|
||||
};
|
||||
let new_ptr =
|
||||
ffi::g_realloc(ptr, mem::size_of::<T>().checked_mul(new_capacity).unwrap())
|
||||
as *mut T::GlibType;
|
||||
self.ptr = ptr::NonNull::new_unchecked(new_ptr);
|
||||
self.capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Borrows this slice as a `&[T]`.
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
unsafe {
|
||||
if self.len == 0 {
|
||||
&[]
|
||||
} else {
|
||||
std::slice::from_raw_parts(self.ptr.as_ptr() as *const T, self.len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Borrows this slice as a `&mut [T]`.
|
||||
#[inline]
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
unsafe {
|
||||
if self.len == 0 {
|
||||
&mut []
|
||||
} else {
|
||||
std::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut T, self.len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes all items from the slice.
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
unsafe {
|
||||
if mem::needs_drop::<T>() {
|
||||
for i in 0..self.len {
|
||||
ptr::drop_in_place::<T>(self.ptr.as_ptr().add(i) as *mut T);
|
||||
}
|
||||
}
|
||||
|
||||
self.len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Clones and appends all elements in `slice` to the slice.
|
||||
#[inline]
|
||||
pub fn extend_from_slice(&mut self, other: &[T]) {
|
||||
// Nothing new to reserve as there's still enough space
|
||||
if self.len + other.len() > self.capacity {
|
||||
self.reserve(other.len());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
for item in other {
|
||||
ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item.clone());
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Inserts `item` at position `index` of the slice, shifting all elements after it to the
|
||||
/// right.
|
||||
#[inline]
|
||||
#[allow(clippy::int_plus_one)]
|
||||
pub fn insert(&mut self, index: usize, item: T) {
|
||||
assert!(index <= self.len);
|
||||
|
||||
// Nothing new to reserve as there's still enough space
|
||||
if self.len + 1 > self.capacity {
|
||||
self.reserve(1);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if index == self.len {
|
||||
ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item);
|
||||
} else {
|
||||
let p = self.ptr.as_ptr().add(index);
|
||||
ptr::copy(p, p.add(1), self.len - index);
|
||||
ptr::write(self.ptr.as_ptr().add(index) as *mut T, item);
|
||||
}
|
||||
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Pushes `item` to the end of the slice.
|
||||
#[inline]
|
||||
#[allow(clippy::int_plus_one)]
|
||||
pub fn push(&mut self, item: T) {
|
||||
// Nothing new to reserve as there's still enough space
|
||||
if self.len + 1 > self.capacity {
|
||||
self.reserve(1);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item);
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes item from position `index` of the slice, shifting all elements after it to the
|
||||
/// left.
|
||||
#[inline]
|
||||
pub fn remove(&mut self, index: usize) -> T {
|
||||
assert!(index < self.len);
|
||||
|
||||
unsafe {
|
||||
let p = self.ptr.as_ptr().add(index);
|
||||
let item = ptr::read(p as *mut T);
|
||||
ptr::copy(p.add(1), p, self.len - index - 1);
|
||||
|
||||
self.len -= 1;
|
||||
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes the last item of the slice and returns it.
|
||||
#[inline]
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
if self.len == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.len -= 1;
|
||||
let p = self.ptr.as_ptr().add(self.len);
|
||||
let item = ptr::read(p as *mut T);
|
||||
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Shortens the slice by keeping the last `len` items.
|
||||
///
|
||||
/// If there are fewer than `len` items then this has no effect.
|
||||
#[inline]
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
if self.len <= len {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
while self.len > len {
|
||||
self.len -= 1;
|
||||
let p = self.ptr.as_ptr().add(self.len);
|
||||
ptr::drop_in_place::<T>(p as *mut T);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType + 'static> FromGlibContainer<T::GlibType, *mut T::GlibType> for Slice<T> {
|
||||
unsafe fn from_glib_none_num(ptr: *mut T::GlibType, num: usize) -> Self {
|
||||
Self::from_glib_none_num(ptr, num)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_container_num(ptr: *mut T::GlibType, num: usize) -> Self {
|
||||
Self::from_glib_container_num(ptr, num)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_full_num(ptr: *mut T::GlibType, num: usize) -> Self {
|
||||
Self::from_glib_full_num(ptr, num)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType + 'static> FromGlibContainer<T::GlibType, *const T::GlibType> for Slice<T> {
|
||||
unsafe fn from_glib_none_num(ptr: *const T::GlibType, num: usize) -> Self {
|
||||
Self::from_glib_none_num(ptr, num)
|
||||
}
|
||||
|
||||
unsafe fn from_glib_container_num(_ptr: *const T::GlibType, _num: usize) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
unsafe fn from_glib_full_num(_ptr: *const T::GlibType, _num: usize) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType + 'a> ToGlibPtr<'a, *mut T::GlibType> for Slice<T> {
|
||||
type Storage = PhantomData<&'a Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none(&'a self) -> Stash<'a, *mut T::GlibType, Self> {
|
||||
Stash(self.as_ptr() as *mut _, PhantomData)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_glib_container(&'a self) -> Stash<'a, *mut T::GlibType, Self> {
|
||||
unsafe {
|
||||
let ptr = ffi::g_malloc(mem::size_of::<T>().checked_mul(self.len()).unwrap())
|
||||
as *mut T::GlibType;
|
||||
ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len());
|
||||
Stash(ptr, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_glib_full(&self) -> *mut T::GlibType {
|
||||
self.clone().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType + 'a> ToGlibPtr<'a, *const T::GlibType> for Slice<T> {
|
||||
type Storage = PhantomData<&'a Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none(&'a self) -> Stash<'a, *const T::GlibType, Self> {
|
||||
Stash(self.as_ptr(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentType + 'a> ToGlibPtrMut<'a, *mut T::GlibType> for Slice<T> {
|
||||
type Storage = PhantomData<&'a mut Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T::GlibType, Self> {
|
||||
StashMut(self.as_mut_ptr(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentType + 'static> IntoGlibPtr<*mut T::GlibType> for Slice<T> {
|
||||
#[inline]
|
||||
unsafe fn into_glib_ptr(self) -> *mut T::GlibType {
|
||||
self.into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> From<super::PtrSlice<T>> for Slice<T> {
|
||||
fn from(value: super::PtrSlice<T>) -> Self {
|
||||
let len = value.len();
|
||||
let capacity = value.capacity();
|
||||
unsafe {
|
||||
let ptr = value.into_raw();
|
||||
Slice::<T> {
|
||||
ptr: ptr::NonNull::new_unchecked(ptr),
|
||||
len,
|
||||
capacity,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_from_glib_full() {
|
||||
let items = [
|
||||
crate::Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(21, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(22, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(23, crate::DateMonth::November, 2021).unwrap(),
|
||||
];
|
||||
|
||||
let slice = unsafe {
|
||||
let ptr = ffi::g_malloc(mem::size_of::<ffi::GDate>() * 4) as *mut ffi::GDate;
|
||||
ptr::write(ptr.add(0), *items[0].to_glib_none().0);
|
||||
ptr::write(ptr.add(1), *items[1].to_glib_none().0);
|
||||
ptr::write(ptr.add(2), *items[2].to_glib_none().0);
|
||||
ptr::write(ptr.add(3), *items[3].to_glib_none().0);
|
||||
|
||||
Slice::<crate::Date>::from_glib_full_num(ptr, 4)
|
||||
};
|
||||
|
||||
assert_eq!(&items[..], &*slice);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_glib_none() {
|
||||
let items = [
|
||||
crate::Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(21, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(22, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(23, crate::DateMonth::November, 2021).unwrap(),
|
||||
];
|
||||
|
||||
let slice = unsafe {
|
||||
Slice::<crate::Date>::from_glib_none_num(items.as_ptr() as *const ffi::GDate, 4)
|
||||
};
|
||||
|
||||
assert_eq!(&items[..], &*slice);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_safe_api() {
|
||||
let items = [
|
||||
crate::Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(21, crate::DateMonth::November, 2021).unwrap(),
|
||||
crate::Date::from_dmy(22, crate::DateMonth::November, 2021).unwrap(),
|
||||
];
|
||||
|
||||
let mut slice = Slice::from(&items[..]);
|
||||
assert_eq!(slice.len(), 3);
|
||||
slice.push(crate::Date::from_dmy(23, crate::DateMonth::November, 2021).unwrap());
|
||||
assert_eq!(slice.len(), 4);
|
||||
|
||||
for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
assert_eq!(
|
||||
(slice[3].day(), slice[3].month(), slice[3].year()),
|
||||
(23, crate::DateMonth::November, 2021)
|
||||
);
|
||||
|
||||
let vec = Vec::from(slice);
|
||||
assert_eq!(vec.len(), 4);
|
||||
for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
assert_eq!(
|
||||
(vec[3].day(), vec[3].month(), vec[3].year()),
|
||||
(23, crate::DateMonth::November, 2021)
|
||||
);
|
||||
|
||||
let mut slice = Slice::from(vec);
|
||||
assert_eq!(slice.len(), 4);
|
||||
let e = slice.pop().unwrap();
|
||||
assert_eq!(
|
||||
(e.day(), e.month(), e.year()),
|
||||
(23, crate::DateMonth::November, 2021)
|
||||
);
|
||||
assert_eq!(slice.len(), 3);
|
||||
slice.insert(2, e);
|
||||
assert_eq!(slice.len(), 4);
|
||||
assert_eq!(slice[0].day(), 20);
|
||||
assert_eq!(slice[1].day(), 21);
|
||||
assert_eq!(slice[2].day(), 23);
|
||||
assert_eq!(slice[3].day(), 22);
|
||||
let e = slice.remove(2);
|
||||
assert_eq!(
|
||||
(e.day(), e.month(), e.year()),
|
||||
(23, crate::DateMonth::November, 2021)
|
||||
);
|
||||
assert_eq!(slice.len(), 3);
|
||||
slice.push(e);
|
||||
assert_eq!(slice.len(), 4);
|
||||
|
||||
for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) {
|
||||
assert_eq!(a, &b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,887 @@
|
||||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
use std::{iter::FusedIterator, marker::PhantomData, mem, ptr};
|
||||
|
||||
use crate::translate::*;
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A list of items of type `T`.
|
||||
///
|
||||
/// Behaves like an `Iterator<Item = T>` but allows modifications.
|
||||
#[repr(transparent)]
|
||||
pub struct SList<T: TransparentPtrType> {
|
||||
ptr: Option<ptr::NonNull<ffi::GSList>>,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<T: TransparentPtrType> TransparentPtrType for SList<T> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T: TransparentPtrType> GlibPtrDefault for SList<T> {
|
||||
type GlibType = *mut ffi::GSList;
|
||||
}
|
||||
|
||||
unsafe impl<T: Send + TransparentPtrType> Send for SList<T> {}
|
||||
|
||||
unsafe impl<T: Sync + TransparentPtrType> Sync for SList<T> {}
|
||||
|
||||
impl<T: TransparentPtrType> SList<T> {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `SList` around a list.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_none(list: *const ffi::GSList) -> SList<T> {
|
||||
// Need to copy the whole list
|
||||
let list = if mem::needs_drop::<T>() {
|
||||
unsafe extern "C" fn copy_item<T: TransparentPtrType>(
|
||||
ptr: ffi::gconstpointer,
|
||||
_user_data: ffi::gpointer,
|
||||
) -> ffi::gpointer {
|
||||
let mut item = mem::ManuallyDrop::new(
|
||||
(*(&ptr as *const ffi::gconstpointer as *const T)).clone(),
|
||||
);
|
||||
|
||||
*(&mut *item as *mut T as *mut *mut T::GlibType) as ffi::gpointer
|
||||
}
|
||||
|
||||
ffi::g_slist_copy_deep(mut_override(list), Some(copy_item::<T>), ptr::null_mut())
|
||||
} else {
|
||||
ffi::g_slist_copy(mut_override(list))
|
||||
};
|
||||
|
||||
SList {
|
||||
ptr: ptr::NonNull::new(list),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `SList` around a list.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_container(list: *mut ffi::GSList) -> SList<T> {
|
||||
// Need to copy all items as we only own the container
|
||||
if mem::needs_drop::<T>() {
|
||||
unsafe extern "C" fn copy_item<T: TransparentPtrType>(
|
||||
ptr: ffi::gpointer,
|
||||
_user_data: ffi::gpointer,
|
||||
) {
|
||||
let item = (*(&ptr as *const ffi::gpointer as *const T)).clone();
|
||||
ptr::write(ptr as *mut T, item);
|
||||
}
|
||||
|
||||
ffi::g_slist_foreach(list, Some(copy_item::<T>), ptr::null_mut());
|
||||
}
|
||||
|
||||
SList {
|
||||
ptr: ptr::NonNull::new(list),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new `SList` around a list.
|
||||
#[inline]
|
||||
pub unsafe fn from_glib_full(list: *mut ffi::GSList) -> SList<T> {
|
||||
SList {
|
||||
ptr: ptr::NonNull::new(list),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Creates a new empty list.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
SList {
|
||||
ptr: None,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a non-destructive iterator over the `SList`.
|
||||
#[inline]
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter::new(self)
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a non-destructive mutable iterator over the `SList`.
|
||||
#[inline]
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
IterMut::new(self)
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Check if the list is empty.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.ptr.is_none()
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the length of the list.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_length")]
|
||||
pub fn len(&self) -> usize {
|
||||
self.iter().count()
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a reference to the first item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_first")]
|
||||
pub fn front(&self) -> Option<&T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(cur) => unsafe {
|
||||
let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a mutable reference to the first item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_first")]
|
||||
pub fn front_mut(&mut self) -> Option<&mut T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(mut cur) => unsafe {
|
||||
let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes the front item from the list, if any.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
pub fn pop_front(&mut self) -> Option<T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(mut cur) => unsafe {
|
||||
self.ptr = ptr::NonNull::new(cur.as_ref().next);
|
||||
let item = ptr::read(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
|
||||
ffi::g_slist_free_1(cur.as_ptr());
|
||||
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Prepends the new item to the front of the list.
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_prepend")]
|
||||
pub fn push_front(&mut self, item: T) {
|
||||
unsafe {
|
||||
let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_prepend(
|
||||
ptr,
|
||||
*(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType)
|
||||
as ffi::gpointer,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a reference to the last item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_last")]
|
||||
pub fn back(&self) -> Option<&T> {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return None,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
let last_ptr = ffi::g_slist_last(ptr);
|
||||
let item = &*(&(*last_ptr).data as *const ffi::gpointer as *const T);
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns a mutable reference to the last item of the list, if any.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_last")]
|
||||
pub fn back_mut(&mut self) -> Option<&mut T> {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return None,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
let last_ptr = ffi::g_slist_last(ptr);
|
||||
let item = &mut *(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes the back item from the list, if any.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
pub fn pop_back(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return None,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
let last_ptr = ffi::g_slist_last(ptr);
|
||||
let item = ptr::read(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
|
||||
self.ptr = ptr::NonNull::new(ffi::g_slist_delete_link(ptr, last_ptr));
|
||||
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Appends the new item to the back of the list.
|
||||
///
|
||||
/// this operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_append")]
|
||||
pub fn push_back(&mut self, item: T) {
|
||||
unsafe {
|
||||
let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_append(
|
||||
ptr,
|
||||
*(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType)
|
||||
as ffi::gpointer,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Reverse the list.
|
||||
///
|
||||
/// This operation is `O(n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_reverse")]
|
||||
pub fn reverse(&mut self) {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_reverse(ptr)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sorts the list.
|
||||
///
|
||||
/// This operation is `O(n * log n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_sort")]
|
||||
pub fn sort(&mut self)
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
self.sort_by(|a, b| a.cmp(b));
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sorts the list.
|
||||
///
|
||||
/// This operation is `O(n * log n)`.
|
||||
#[inline]
|
||||
#[doc(alias = "g_slist_sort")]
|
||||
pub fn sort_by<F: FnMut(&T, &T) -> std::cmp::Ordering>(&mut self, mut f: F) {
|
||||
unsafe {
|
||||
let ptr = match self.ptr {
|
||||
None => return,
|
||||
Some(ptr) => ptr.as_ptr(),
|
||||
};
|
||||
|
||||
unsafe extern "C" fn func<
|
||||
T: TransparentPtrType,
|
||||
F: FnMut(&T, &T) -> std::cmp::Ordering,
|
||||
>(
|
||||
a: ffi::gconstpointer,
|
||||
b: ffi::gconstpointer,
|
||||
user_data: ffi::gpointer,
|
||||
) -> i32 {
|
||||
let f = &mut *(user_data as *mut F);
|
||||
let a = &*(&a as *const ffi::gconstpointer as *const T);
|
||||
let b = &*(&b as *const ffi::gconstpointer as *const T);
|
||||
f(a, b).into_glib()
|
||||
}
|
||||
|
||||
self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_sort_with_data(
|
||||
ptr,
|
||||
Some(func::<T, F>),
|
||||
&mut f as *mut F as ffi::gpointer,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Removes all items from the list.
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
*self = Self::new();
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Only keeps the item in the list for which `f` returns `true`.
|
||||
#[inline]
|
||||
pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) {
|
||||
if let Some(head) = self.ptr {
|
||||
unsafe {
|
||||
let mut ptr = head.as_ptr();
|
||||
while !ptr.is_null() {
|
||||
let item = &*((*ptr).data as *const ffi::gpointer as *const T);
|
||||
let next = (*ptr).next;
|
||||
if !f(item) {
|
||||
ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T);
|
||||
self.ptr = ptr::NonNull::new(ffi::g_slist_delete_link(head.as_ptr(), ptr));
|
||||
}
|
||||
ptr = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the underlying pointer.
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const ffi::GSList {
|
||||
self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the underlying pointer.
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut ffi::GSList {
|
||||
self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Consumes the list and returns the underlying pointer.
|
||||
#[inline]
|
||||
pub fn into_raw(mut self) -> *mut ffi::GSList {
|
||||
self.ptr
|
||||
.take()
|
||||
.map(|p| p.as_ptr())
|
||||
.unwrap_or(ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Default for SList<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Clone for SList<T> {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Drop for SList<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if let Some(ptr) = self.ptr {
|
||||
unsafe {
|
||||
if mem::needs_drop::<T>() {
|
||||
unsafe extern "C" fn drop_item<T: TransparentPtrType>(mut ptr: ffi::gpointer) {
|
||||
ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T);
|
||||
}
|
||||
|
||||
ffi::g_slist_free_full(ptr.as_ptr(), Some(drop_item::<T>));
|
||||
} else {
|
||||
ffi::g_slist_free(ptr.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> std::iter::FromIterator<T> for SList<T> {
|
||||
#[inline]
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
unsafe {
|
||||
let mut iter = iter.into_iter();
|
||||
|
||||
let first = match iter.next() {
|
||||
None => return Self::new(),
|
||||
Some(first) => first,
|
||||
};
|
||||
|
||||
let list = ffi::g_slist_prepend(
|
||||
ptr::null_mut(),
|
||||
*(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType)
|
||||
as ffi::gpointer,
|
||||
);
|
||||
let mut tail = list;
|
||||
for item in iter {
|
||||
let new_tail = ffi::g_slist_alloc();
|
||||
|
||||
(*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T
|
||||
as *mut *mut T::GlibType) as ffi::gpointer;
|
||||
(*new_tail).next = ptr::null_mut();
|
||||
(*tail).next = new_tail;
|
||||
tail = new_tail;
|
||||
}
|
||||
|
||||
Self::from_glib_full(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a SList<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut SList<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> std::iter::IntoIterator for SList<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList>
|
||||
for SList<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none_num(ptr: *mut ffi::GSList, _num: usize) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_container_num(ptr: *mut ffi::GSList, _num: usize) -> Self {
|
||||
Self::from_glib_container(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_full_num(ptr: *mut ffi::GSList, _num: usize) -> Self {
|
||||
Self::from_glib_full(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GSList>
|
||||
for SList<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none_num(ptr: *const ffi::GSList, _num: usize) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
unsafe fn from_glib_container_num(_ptr: *const ffi::GSList, _num: usize) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
unsafe fn from_glib_full_num(_ptr: *const ffi::GSList, _num: usize) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList>
|
||||
for SList<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none(ptr: *mut ffi::GSList) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_container(ptr: *mut ffi::GSList) -> Self {
|
||||
Self::from_glib_container(ptr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_glib_full(ptr: *mut ffi::GSList) -> Self {
|
||||
Self::from_glib_full(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType>
|
||||
FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for SList<T>
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn from_glib_none(ptr: *const ffi::GSList) -> Self {
|
||||
Self::from_glib_none(ptr)
|
||||
}
|
||||
|
||||
unsafe fn from_glib_container(_ptr: *const ffi::GSList) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
unsafe fn from_glib_full(_ptr: *const ffi::GSList) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GSList> for SList<T> {
|
||||
type Storage = PhantomData<&'a Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GSList, Self> {
|
||||
Stash(self.as_ptr() as *mut _, PhantomData)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GSList, Self> {
|
||||
unsafe {
|
||||
let ptr = ffi::g_malloc(mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
|
||||
as *mut ffi::GSList;
|
||||
ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
|
||||
Stash(ptr, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_glib_full(&self) -> *mut ffi::GSList {
|
||||
self.clone().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GSList> for SList<T> {
|
||||
type Storage = PhantomData<&'a Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GSList, Self> {
|
||||
Stash(self.as_ptr(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GSList> for SList<T> {
|
||||
type Storage = PhantomData<&'a mut Self>;
|
||||
|
||||
#[inline]
|
||||
fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GSList, Self> {
|
||||
StashMut(self.as_mut_ptr(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GSList> for SList<T> {
|
||||
#[inline]
|
||||
unsafe fn into_glib_ptr(self) -> *mut ffi::GSList {
|
||||
self.into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A non-destructive iterator over a [`SList`].
|
||||
pub struct Iter<'a, T: TransparentPtrType> {
|
||||
ptr: Option<ptr::NonNull<ffi::GSList>>,
|
||||
phantom: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> Iter<'a, T> {
|
||||
#[inline]
|
||||
fn new(list: &'a SList<T>) -> Iter<'a, T> {
|
||||
debug_assert_eq!(
|
||||
mem::size_of::<T>(),
|
||||
mem::size_of::<<T as GlibPtrDefault>::GlibType>()
|
||||
);
|
||||
|
||||
Iter {
|
||||
ptr: list.ptr,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(cur) => unsafe {
|
||||
self.ptr = ptr::NonNull::new(cur.as_ref().next);
|
||||
|
||||
let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
|
||||
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> FusedIterator for Iter<'a, T> {}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A non-destructive iterator over a [`SList`].
|
||||
pub struct IterMut<'a, T: TransparentPtrType> {
|
||||
ptr: Option<ptr::NonNull<ffi::GSList>>,
|
||||
phantom: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> IterMut<'a, T> {
|
||||
#[inline]
|
||||
fn new(list: &'a mut SList<T>) -> IterMut<'a, T> {
|
||||
debug_assert_eq!(
|
||||
mem::size_of::<T>(),
|
||||
mem::size_of::<<T as GlibPtrDefault>::GlibType>()
|
||||
);
|
||||
|
||||
IterMut {
|
||||
ptr: list.ptr,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> {
|
||||
type Item = &'a mut T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a mut T> {
|
||||
match self.ptr {
|
||||
None => None,
|
||||
Some(mut cur) => unsafe {
|
||||
self.ptr = ptr::NonNull::new(cur.as_ref().next);
|
||||
|
||||
let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
|
||||
|
||||
Some(item)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TransparentPtrType> FusedIterator for IterMut<'a, T> {}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// A destructive iterator over a [`SList`].
|
||||
pub struct IntoIter<T: TransparentPtrType> {
|
||||
list: SList<T>,
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> IntoIter<T> {
|
||||
#[inline]
|
||||
fn new(list: SList<T>) -> IntoIter<T> {
|
||||
debug_assert_eq!(
|
||||
mem::size_of::<T>(),
|
||||
mem::size_of::<<T as GlibPtrDefault>::GlibType>()
|
||||
);
|
||||
|
||||
IntoIter { list }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> {
|
||||
self.list.pop_front()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn from_glib_full() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
let mut list = unsafe {
|
||||
let mut list = ffi::g_slist_append(
|
||||
ptr::null_mut(),
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer,
|
||||
);
|
||||
SList::<crate::DateTime>::from_glib_full(list)
|
||||
};
|
||||
assert!(!list.is_empty());
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.into_iter().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list = unsafe { SList::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
|
||||
assert!(list.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn from_glib_container() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
let mut list = unsafe {
|
||||
let mut list = ffi::g_slist_append(
|
||||
ptr::null_mut(),
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
|
||||
);
|
||||
SList::<crate::DateTime>::from_glib_container(list)
|
||||
};
|
||||
assert!(!list.is_empty());
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.into_iter().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list = unsafe { SList::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
|
||||
assert!(list.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn from_glib_none() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
let mut list = unsafe {
|
||||
let mut list = ffi::g_slist_append(
|
||||
ptr::null_mut(),
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
|
||||
);
|
||||
list = ffi::g_slist_append(
|
||||
list,
|
||||
ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
|
||||
);
|
||||
let res = SList::<crate::DateTime>::from_glib_none(list);
|
||||
ffi::g_slist_free(list);
|
||||
res
|
||||
};
|
||||
assert!(!list.is_empty());
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list_items = list.into_iter().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
let list = unsafe { SList::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
|
||||
assert!(list.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// checker-ignore-item
|
||||
fn safe_api() {
|
||||
let items = [
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
|
||||
crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
|
||||
];
|
||||
|
||||
let mut list = items[1..3].iter().cloned().collect::<SList<_>>();
|
||||
assert_eq!(list.len(), 2);
|
||||
list.push_front(items[0].clone());
|
||||
assert_eq!(list.len(), 3);
|
||||
list.push_back(items[3].clone());
|
||||
assert_eq!(list.len(), 4);
|
||||
|
||||
let list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
assert_eq!(&items[..], &list_items);
|
||||
|
||||
assert_eq!(list.front(), Some(&items[0]));
|
||||
assert_eq!(list.back(), Some(&items[3]));
|
||||
assert_eq!(list.pop_front().as_ref(), Some(&items[0]));
|
||||
assert_eq!(list.len(), 3);
|
||||
|
||||
list.reverse();
|
||||
let mut list_items = list.iter().cloned().collect::<Vec<_>>();
|
||||
list_items.reverse();
|
||||
assert_eq!(&items[1..], &list_items);
|
||||
|
||||
let list2 = list.clone();
|
||||
let mut list_items = list2.iter().cloned().collect::<Vec<_>>();
|
||||
list_items.reverse();
|
||||
assert_eq!(&items[1..], &list_items);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user