use std::marker::PhantomData;
use vala_sys as ffi;
use crate::object::RawWrapper;
pub struct List<T> {
raw: std::ptr::NonNull<ffi::ValaList>,
_marker: PhantomData<T>,
}
impl<T: RawWrapper> List<T> {
pub(crate) unsafe fn from_raw_none(ptr: *mut ffi::ValaList) -> Option<Self> {
let raw = std::ptr::NonNull::new(ptr)?;
ffi::vala_iterable_ref(raw.as_ptr() as ffi::gpointer);
Some(List {
raw,
_marker: PhantomData,
})
}
fn as_collection(&self) -> *mut ffi::ValaCollection {
self.raw.as_ptr() as *mut ffi::ValaCollection
}
pub fn len(&self) -> usize {
unsafe { ffi::vala_collection_get_size(self.as_collection()).max(0) as usize }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, index: usize) -> Option<T> {
if index >= self.len() {
return None;
}
unsafe {
let elem = ffi::vala_list_get(self.raw.as_ptr(), index as ffi::gint);
T::from_raw_full(elem as *mut T::Ffi)
}
}
pub fn iter(&self) -> ListIter<'_, T> {
ListIter {
list: self,
index: 0,
len: self.len(),
}
}
pub fn to_vec(&self) -> Vec<T> {
self.iter().collect()
}
}
impl<T: RawWrapper> Clone for List<T> {
fn clone(&self) -> Self {
unsafe {
ffi::vala_iterable_ref(self.raw.as_ptr() as ffi::gpointer);
List {
raw: self.raw,
_marker: PhantomData,
}
}
}
}
impl<T> Drop for List<T> {
fn drop(&mut self) {
unsafe { ffi::vala_iterable_unref(self.raw.as_ptr() as ffi::gpointer) }
}
}
impl<T: RawWrapper> std::fmt::Debug for List<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("List").field("len", &self.len()).finish()
}
}
pub struct ListIter<'a, T> {
list: &'a List<T>,
index: usize,
len: usize,
}
impl<T: RawWrapper> Iterator for ListIter<'_, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.index >= self.len {
return None;
}
let item = self.list.get(self.index);
self.index += 1;
item
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.len.saturating_sub(self.index);
(remaining, Some(remaining))
}
}
impl<T: RawWrapper> ExactSizeIterator for ListIter<'_, T> {}
impl<'a, T: RawWrapper> IntoIterator for &'a List<T> {
type Item = T;
type IntoIter = ListIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}