From 2ca49d51e3ec52a5e4c642c2edf5b785bbf256c4 Mon Sep 17 00:00:00 2001 From: Jason Francis Date: Mon, 14 Mar 2022 09:33:53 -0400 Subject: [PATCH] gio: Add type parameter to ListModel and ListStore --- gio/Gir.toml | 30 ---- gio/src/auto/list_model.rs | 121 ---------------- gio/src/auto/list_store.rs | 138 ------------------ gio/src/auto/mod.rs | 8 - gio/src/lib.rs | 2 + gio/src/list_model.rs | 203 ++++++++++++++++++++++++-- gio/src/list_store.rs | 258 +++++++++++++++++++++++++++++---- gio/src/prelude.rs | 2 +- gio/src/subclass/list_model.rs | 49 ++++--- 9 files changed, 455 insertions(+), 356 deletions(-) delete mode 100644 gio/src/auto/list_model.rs delete mode 100644 gio/src/auto/list_store.rs diff --git a/gio/Gir.toml b/gio/Gir.toml index 9091dbe386e7..faadde9328db 100644 --- a/gio/Gir.toml +++ b/gio/Gir.toml @@ -788,36 +788,6 @@ manual_traits = ["IOStreamExtManual"] #readonly manual = true -[[object]] -name = "Gio.ListModel" -status = "generate" -manual_traits = ["ListModelExtManual"] - # Can get removed when gir shadow annotations are implemented (gtk-rs/gir#1112) - [[object.function]] - name = "get_item" - ignore = true - [[object.function]] - name = "get_object" - rename = "item" - -[[object]] -name = "Gio.ListStore" -status = "generate" -generate_builder = true - [[object.function]] - name = "insert_sorted" - manual = true - [[object.function]] - name = "sort" - manual = true - [[object.function]] - name = "splice" - # More generic arguments - manual = true - [[object.function]] - name = "find_with_equal_func" - ignore = true # See https://gitlab.gnome.org/GNOME/glib/-/issues/2447 - [[object]] name = "Gio.MemoryInputStream" status = "generate" diff --git a/gio/src/auto/list_model.rs b/gio/src/auto/list_model.rs deleted file mode 100644 index fa95dab152ea..000000000000 --- a/gio/src/auto/list_model.rs +++ /dev/null @@ -1,121 +0,0 @@ -// This file was generated by gir (https://github.com/gtk-rs/gir) -// from gir-files (https://github.com/gtk-rs/gir-files) -// DO NOT EDIT - -use glib::object::Cast; -use glib::object::IsA; -use glib::signal::connect_raw; -use glib::signal::SignalHandlerId; -use glib::translate::*; -use std::boxed::Box as Box_; -use std::fmt; -use std::mem::transmute; - -glib::wrapper! { - #[doc(alias = "GListModel")] - pub struct ListModel(Interface); - - match fn { - type_ => || ffi::g_list_model_get_type(), - } -} - -impl ListModel { - pub const NONE: Option<&'static ListModel> = None; -} - -pub trait ListModelExt: 'static { - #[doc(alias = "g_list_model_get_item_type")] - #[doc(alias = "get_item_type")] - fn item_type(&self) -> glib::types::Type; - - #[doc(alias = "g_list_model_get_n_items")] - #[doc(alias = "get_n_items")] - fn n_items(&self) -> u32; - - #[doc(alias = "g_list_model_get_object")] - #[doc(alias = "get_object")] - fn item(&self, position: u32) -> Option; - - #[doc(alias = "g_list_model_items_changed")] - fn items_changed(&self, position: u32, removed: u32, added: u32); - - #[doc(alias = "items-changed")] - fn connect_items_changed(&self, f: F) - -> SignalHandlerId; -} - -impl> ListModelExt for O { - fn item_type(&self) -> glib::types::Type { - unsafe { - from_glib(ffi::g_list_model_get_item_type( - self.as_ref().to_glib_none().0, - )) - } - } - - fn n_items(&self) -> u32 { - unsafe { ffi::g_list_model_get_n_items(self.as_ref().to_glib_none().0) } - } - - fn item(&self, position: u32) -> Option { - unsafe { - from_glib_full(ffi::g_list_model_get_object( - self.as_ref().to_glib_none().0, - position, - )) - } - } - - fn items_changed(&self, position: u32, removed: u32, added: u32) { - unsafe { - ffi::g_list_model_items_changed( - self.as_ref().to_glib_none().0, - position, - removed, - added, - ); - } - } - - fn connect_items_changed( - &self, - f: F, - ) -> SignalHandlerId { - unsafe extern "C" fn items_changed_trampoline< - P: IsA, - F: Fn(&P, u32, u32, u32) + 'static, - >( - this: *mut ffi::GListModel, - position: libc::c_uint, - removed: libc::c_uint, - added: libc::c_uint, - f: glib::ffi::gpointer, - ) { - let f: &F = &*(f as *const F); - f( - ListModel::from_glib_borrow(this).unsafe_cast_ref(), - position, - removed, - added, - ) - } - unsafe { - let f: Box_ = Box_::new(f); - connect_raw( - self.as_ptr() as *mut _, - b"items-changed\0".as_ptr() as *const _, - Some(transmute::<_, unsafe extern "C" fn()>( - items_changed_trampoline:: as *const (), - )), - Box_::into_raw(f), - ) - } - } -} - -impl fmt::Display for ListModel { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("ListModel") - } -} diff --git a/gio/src/auto/list_store.rs b/gio/src/auto/list_store.rs deleted file mode 100644 index a85a30fb112c..000000000000 --- a/gio/src/auto/list_store.rs +++ /dev/null @@ -1,138 +0,0 @@ -// This file was generated by gir (https://github.com/gtk-rs/gir) -// from gir-files (https://github.com/gtk-rs/gir-files) -// DO NOT EDIT - -use crate::ListModel; -use glib::object::Cast; -use glib::object::IsA; -use glib::translate::*; -use glib::StaticType; -use glib::ToValue; -use std::fmt; -#[cfg(any(feature = "v2_64", feature = "dox"))] -#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] -use std::mem; - -glib::wrapper! { - #[doc(alias = "GListStore")] - pub struct ListStore(Object) @implements ListModel; - - match fn { - type_ => || ffi::g_list_store_get_type(), - } -} - -impl ListStore { - #[doc(alias = "g_list_store_new")] - pub fn new(item_type: glib::types::Type) -> ListStore { - unsafe { from_glib_full(ffi::g_list_store_new(item_type.into_glib())) } - } - - // rustdoc-stripper-ignore-next - /// Creates a new builder-pattern struct instance to construct [`ListStore`] objects. - /// - /// This method returns an instance of [`ListStoreBuilder`](crate::builders::ListStoreBuilder) which can be used to create [`ListStore`] objects. - pub fn builder() -> ListStoreBuilder { - ListStoreBuilder::default() - } - - #[doc(alias = "g_list_store_append")] - pub fn append(&self, item: &impl IsA) { - unsafe { - ffi::g_list_store_append(self.to_glib_none().0, item.as_ref().to_glib_none().0); - } - } - - #[cfg(any(feature = "v2_64", feature = "dox"))] - #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] - #[doc(alias = "g_list_store_find")] - pub fn find(&self, item: &impl IsA) -> Option { - unsafe { - let mut position = mem::MaybeUninit::uninit(); - let ret = from_glib(ffi::g_list_store_find( - self.to_glib_none().0, - item.as_ref().to_glib_none().0, - position.as_mut_ptr(), - )); - let position = position.assume_init(); - if ret { - Some(position) - } else { - None - } - } - } - - #[doc(alias = "g_list_store_insert")] - pub fn insert(&self, position: u32, item: &impl IsA) { - unsafe { - ffi::g_list_store_insert( - self.to_glib_none().0, - position, - item.as_ref().to_glib_none().0, - ); - } - } - - #[doc(alias = "g_list_store_remove")] - pub fn remove(&self, position: u32) { - unsafe { - ffi::g_list_store_remove(self.to_glib_none().0, position); - } - } - - #[doc(alias = "g_list_store_remove_all")] - pub fn remove_all(&self) { - unsafe { - ffi::g_list_store_remove_all(self.to_glib_none().0); - } - } -} - -impl Default for ListStore { - fn default() -> Self { - glib::object::Object::new::(&[]) - .expect("Can't construct ListStore object with default parameters") - } -} - -#[derive(Clone, Default)] -// rustdoc-stripper-ignore-next -/// A [builder-pattern] type to construct [`ListStore`] objects. -/// -/// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html -#[must_use = "The builder must be built to be used"] -pub struct ListStoreBuilder { - item_type: Option, -} - -impl ListStoreBuilder { - // rustdoc-stripper-ignore-next - /// Create a new [`ListStoreBuilder`]. - pub fn new() -> Self { - Self::default() - } - - // rustdoc-stripper-ignore-next - /// Build the [`ListStore`]. - #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] - pub fn build(self) -> ListStore { - let mut properties: Vec<(&str, &dyn ToValue)> = vec![]; - if let Some(ref item_type) = self.item_type { - properties.push(("item-type", item_type)); - } - glib::Object::new::(&properties) - .expect("Failed to create an instance of ListStore") - } - - pub fn item_type(mut self, item_type: glib::types::Type) -> Self { - self.item_type = Some(item_type); - self - } -} - -impl fmt::Display for ListStore { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("ListStore") - } -} diff --git a/gio/src/auto/mod.rs b/gio/src/auto/mod.rs index 76b3ee08e775..be19e4fc6827 100644 --- a/gio/src/auto/mod.rs +++ b/gio/src/auto/mod.rs @@ -179,12 +179,6 @@ pub use self::initable::Initable; mod input_stream; pub use self::input_stream::InputStream; -mod list_model; -pub use self::list_model::ListModel; - -mod list_store; -pub use self::list_store::ListStore; - mod loadable_icon; pub use self::loadable_icon::LoadableIcon; @@ -723,7 +717,6 @@ pub mod traits { pub use super::initable::InitableExt; pub use super::input_stream::InputStreamExt; pub use super::io_stream::IOStreamExt; - pub use super::list_model::ListModelExt; pub use super::loadable_icon::LoadableIconExt; pub use super::memory_input_stream::MemoryInputStreamExt; #[cfg(any(feature = "v2_64", feature = "dox"))] @@ -799,5 +792,4 @@ pub mod builders { pub use super::converter_output_stream::ConverterOutputStreamBuilder; pub use super::data_input_stream::DataInputStreamBuilder; pub use super::data_output_stream::DataOutputStreamBuilder; - pub use super::list_store::ListStoreBuilder; } diff --git a/gio/src/lib.rs b/gio/src/lib.rs index 4b01c1b5091e..5ee1b2632e75 100644 --- a/gio/src/lib.rs +++ b/gio/src/lib.rs @@ -50,7 +50,9 @@ mod initable; mod input_stream; pub use crate::input_stream::{InputStreamAsyncBufRead, InputStreamRead}; mod list_model; +pub use list_model::ListModel; mod list_store; +pub use list_store::ListStore; #[cfg(test)] mod memory_input_stream; #[cfg(test)] diff --git a/gio/src/list_model.rs b/gio/src/list_model.rs index 8f86bb1d15a3..08ea13aa6418 100644 --- a/gio/src/list_model.rs +++ b/gio/src/list_model.rs @@ -1,33 +1,214 @@ // Take a look at the license at the top of the repository in the LICENSE file. use crate::prelude::*; -use crate::ListModel; +use glib::object::Cast; +use glib::object::IsA; +use glib::signal::connect_raw; +use glib::signal::SignalHandlerId; +use glib::translate::*; +use glib::Object; +use std::boxed::Box as Box_; +use std::mem::transmute; + +glib::wrapper! { + pub struct ListModel)>(Interface), + @requires_generic + ) + (IsA), Sub: (IsA) + (IsA)> ListModel for ListModel, + @default_casts false, + @checkers ListModelCastChecker, ListModelValueChecker; + + match fn { + type_ => || ffi::g_list_model_get_type(), + } +} + +#[doc(hidden)] +pub struct ListModelCastChecker(std::marker::PhantomData); + +impl> glib::object::ObjectCastChecker> for ListModelCastChecker { + fn check(obj: &U) -> bool { + if glib::object::GenericObjectCastChecker::>::check(obj) { + let item_type: glib::Type = + unsafe { from_glib(ffi::g_list_model_get_item_type(obj.as_ptr() as *mut _)) }; + if item_type.is_a(T::static_type()) { + return true; + } + } + false + } +} + +#[doc(hidden)] +pub struct ListModelValueChecker(std::marker::PhantomData); + +unsafe impl> glib::value::ValueTypeChecker for ListModelValueChecker { + type Error = glib::value::ValueTypeMismatchOrNoneError; + + fn check(value: &glib::Value) -> Result<(), Self::Error> { + glib::object::ObjectValueTypeChecker::>::check(value)?; + let model: &ListModel = unsafe { glib::value::FromValue::from_value(value) }; + let model_type = model.item_type(); + let expected = T::static_type(); + if !model_type.is_a(expected) { + return Err(glib::value::ValueTypeMismatchError::new(model_type, expected).into()); + } + + Ok(()) + } +} + +impl> ListModel { + pub const NONE: Option<&'static ListModel> = None; +} + +impl> std::fmt::Display for ListModel { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("ListModel") + } +} + +pub trait ListModelExt: 'static { + #[doc(alias = "g_list_model_get_item_type")] + #[doc(alias = "get_item_type")] + fn item_type(&self) -> glib::types::Type; + + #[doc(alias = "g_list_model_get_n_items")] + #[doc(alias = "get_n_items")] + fn n_items(&self) -> u32; + + #[doc(alias = "g_list_model_get_object")] + #[doc(alias = "get_object")] + fn object(&self, position: u32) -> Option; + + #[doc(alias = "g_list_model_get_item")] + #[doc(alias = "get_item")] + fn item>(&self, position: u32) -> Option + where + Self: IsA>; + + #[doc(alias = "g_list_model_items_changed")] + fn items_changed(&self, position: u32, removed: u32, added: u32); + + #[doc(alias = "items-changed")] + fn connect_items_changed(&self, f: F) + -> SignalHandlerId; -pub trait ListModelExtManual: Sized { // rustdoc-stripper-ignore-next /// Get an immutable snapshot of the container inside the `ListModel`. /// Any modification done to the returned container `Vec` will not be /// reflected on the `ListModel`. - fn snapshot(&self) -> Vec; + fn snapshot>(&self) -> Vec + where + Self: IsA>; } -impl> ListModelExtManual for T { - fn snapshot(&self) -> Vec { - let mut res = Vec::with_capacity(self.n_items() as usize); - for i in 0..self.n_items() { +impl>> ListModelExt for O { + #[inline] + fn item_type(&self) -> glib::types::Type { + unsafe { + from_glib(ffi::g_list_model_get_item_type( + self.as_ref().to_glib_none().0, + )) + } + } + + #[inline] + fn n_items(&self) -> u32 { + unsafe { ffi::g_list_model_get_n_items(self.as_ref().to_glib_none().0) } + } + + #[inline] + fn object(&self, position: u32) -> Option { + unsafe { + from_glib_full(ffi::g_list_model_get_object( + self.upcast_ref::>().to_glib_none().0, + position, + )) + } + } + + fn item>(&self, position: u32) -> Option + where + Self: IsA>, + { + self.object(position).map(|o| { + o.downcast().unwrap_or_else(|o| { + panic!( + "List model type mismatch. Actual {:?}, requested {:?}", + o.type_(), + U::static_type() + ); + }) + }) + } + + #[inline] + fn items_changed(&self, position: u32, removed: u32, added: u32) { + unsafe { + ffi::g_list_model_items_changed( + self.as_ref().to_glib_none().0, + position, + removed, + added, + ); + } + } + + fn connect_items_changed( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn items_changed_trampoline< + P: IsA>, + F: Fn(&P, u32, u32, u32) + 'static, + >( + this: *mut ffi::GListModel, + position: libc::c_uint, + removed: libc::c_uint, + added: libc::c_uint, + f: glib::ffi::gpointer, + ) { + let f: &F = &*(f as *const F); + f( + ListModel::::from_glib_borrow(this).unsafe_cast_ref(), + position, + removed, + added, + ) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"items-changed\0".as_ptr() as *const _, + Some(transmute::<_, unsafe extern "C" fn()>( + items_changed_trampoline:: as *const (), + )), + Box_::into_raw(f), + ) + } + } + + fn snapshot>(&self) -> Vec + where + Self: IsA>, + { + let count = self.n_items(); + let mut res = Vec::with_capacity(count as usize); + for i in 0..count { res.push(self.item(i).unwrap()) } res } } -impl std::iter::IntoIterator for ListModel { - type Item = glib::Object; - type IntoIter = std::vec::IntoIter; +impl + IsA> std::iter::IntoIterator for ListModel { + type Item = T; + type IntoIter = std::vec::IntoIter; // rustdoc-stripper-ignore-next /// Returns an iterator with the elements returned by `ListModel::snapshot` fn into_iter(self) -> Self::IntoIter { - self.snapshot().into_iter() + self.snapshot::().into_iter() } } diff --git a/gio/src/list_store.rs b/gio/src/list_store.rs index f2eb2946b152..87654885698b 100644 --- a/gio/src/list_store.rs +++ b/gio/src/list_store.rs @@ -1,27 +1,137 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use crate::auto::traits::ListModelExt; -use crate::ListStore; +use crate::prelude::ListModelExt; +use crate::ListModel; use glib::translate::*; -use glib::{IsA, Object}; +use glib::{Cast, IsA, Object}; use std::cmp::Ordering; +#[cfg(any(feature = "v2_64", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] +use std::mem; + +glib::wrapper! { + pub struct ListStore)>(Object), + @implements_generic + ) + (IsA), Sub: (IsA) + (IsA)> ListModel for ListStore, + @default_casts true, + @checkers ListStoreCastChecker, ListStoreValueChecker; + + match fn { + type_ => || ffi::g_list_store_get_type(), + } +} + +#[doc(hidden)] +pub struct ListStoreCastChecker(std::marker::PhantomData); + +impl> glib::object::ObjectCastChecker> for ListStoreCastChecker { + fn check(obj: &U) -> bool { + if glib::object::GenericObjectCastChecker::>::check(obj) { + let item_type: glib::Type = + unsafe { from_glib(ffi::g_list_model_get_item_type(obj.as_ptr() as *mut _)) }; + if item_type == T::static_type() { + return true; + } + } + false + } +} + +#[doc(hidden)] +pub struct ListStoreValueChecker(std::marker::PhantomData); + +unsafe impl> glib::value::ValueTypeChecker for ListStoreValueChecker { + type Error = glib::value::ValueTypeMismatchOrNoneError; + + fn check(value: &glib::Value) -> Result<(), Self::Error> { + glib::object::ObjectValueTypeChecker::>::check(value)?; + let store: &ListStore = unsafe { glib::value::FromValue::from_value(value) }; + let store_type = store.item_type(); + let expected = T::static_type(); + if store_type != expected { + return Err(glib::value::ValueTypeMismatchError::new(store_type, expected).into()); + } + + Ok(()) + } +} + +impl> ListStore { + #[doc(alias = "g_list_store_new")] + pub fn new() -> Self { + unsafe { from_glib_full(ffi::g_list_store_new(T::static_type().into_glib())) } + } + + #[doc(alias = "g_list_store_append")] + pub fn append(&self, item: &(impl IsA + IsA)) { + unsafe { + ffi::g_list_store_append( + self.to_glib_none().0, + item.upcast_ref::().to_glib_none().0, + ); + } + } + + #[cfg(any(feature = "v2_64", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] + #[doc(alias = "g_list_store_find")] + pub fn find(&self, item: &(impl IsA + IsA)) -> Option { + unsafe { + let mut position = mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::g_list_store_find( + self.to_glib_none().0, + item.upcast_ref::().to_glib_none().0, + position.as_mut_ptr(), + )); + let position = position.assume_init(); + if ret { + Some(position) + } else { + None + } + } + } + + #[doc(alias = "g_list_store_insert")] + pub fn insert(&self, position: u32, item: &(impl IsA + IsA)) { + unsafe { + ffi::g_list_store_insert( + self.to_glib_none().0, + position, + item.upcast_ref::().to_glib_none().0, + ); + } + } + + #[doc(alias = "g_list_store_remove")] + pub fn remove(&self, position: u32) { + unsafe { + ffi::g_list_store_remove(self.to_glib_none().0, position); + } + } + + #[doc(alias = "g_list_store_remove_all")] + pub fn remove_all(&self) { + unsafe { + ffi::g_list_store_remove_all(self.to_glib_none().0); + } + } -impl ListStore { #[doc(alias = "g_list_store_insert_sorted")] - pub fn insert_sorted, F: FnMut(&Object, &Object) -> Ordering>( + pub fn insert_sorted + IsA, F: FnMut(&T, &T) -> Ordering>( &self, item: &P, compare_func: F, ) -> u32 { unsafe { let mut func = compare_func; - let func_obj: &mut (dyn FnMut(&Object, &Object) -> Ordering) = &mut func; - let func_ptr = &func_obj as *const &mut (dyn FnMut(&Object, &Object) -> Ordering) - as glib::ffi::gpointer; + let func_obj: &mut (dyn FnMut(&T, &T) -> Ordering) = &mut func; + let func_ptr = + &func_obj as *const &mut (dyn FnMut(&T, &T) -> Ordering) as glib::ffi::gpointer; ffi::g_list_store_insert_sorted( self.to_glib_none().0, - item.as_ref().to_glib_none().0, + item.upcast_ref::().to_glib_none().0, Some(compare_func_trampoline), func_ptr, ) @@ -29,12 +139,12 @@ impl ListStore { } #[doc(alias = "g_list_store_sort")] - pub fn sort Ordering>(&self, compare_func: F) { + pub fn sort Ordering>(&self, compare_func: F) { unsafe { let mut func = compare_func; - let func_obj: &mut (dyn FnMut(&Object, &Object) -> Ordering) = &mut func; - let func_ptr = &func_obj as *const &mut (dyn FnMut(&Object, &Object) -> Ordering) - as glib::ffi::gpointer; + let func_obj: &mut (dyn FnMut(&T, &T) -> Ordering) = &mut func; + let func_ptr = + &func_obj as *const &mut (dyn FnMut(&T, &T) -> Ordering) as glib::ffi::gpointer; ffi::g_list_store_sort( self.to_glib_none().0, @@ -45,7 +155,7 @@ impl ListStore { } #[doc(alias = "g_list_store_splice")] - pub fn splice(&self, position: u32, n_removals: u32, additions: &[impl IsA]) { + pub fn splice(&self, position: u32, n_removals: u32, additions: &[impl IsA + IsA]) { let n_additions = additions.len() as u32; unsafe { let additions = additions.as_ptr() as *mut *mut glib::gobject_ffi::GObject; @@ -62,7 +172,7 @@ impl ListStore { // rustdoc-stripper-ignore-next /// Appends all elements in a slice to the `ListStore`. - pub fn extend_from_slice(&self, additions: &[impl IsA]) { + pub fn extend_from_slice(&self, additions: &[impl IsA + IsA]) { self.splice(self.n_items() - 1, 0, additions) } } @@ -80,8 +190,20 @@ unsafe extern "C" fn compare_func_trampoline( (*func)(&a, &b).into_glib() } -impl> std::iter::Extend for ListStore { - fn extend>(&mut self, iter: T) { +impl> Default for ListStore { + fn default() -> Self { + Self::new() + } +} + +impl> std::fmt::Display for ListStore { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("ListStore") + } +} + +impl + IsA, A: AsRef> std::iter::Extend for ListStore { + fn extend>(&mut self, iter: I) { let additions = iter .into_iter() .map(|o| o.as_ref().clone()) @@ -93,28 +215,106 @@ impl> std::iter::Extend for ListStore { #[cfg(test)] mod tests { use crate::prelude::*; + use crate::Application; + use crate::File; + use crate::ListModel; use crate::ListStore; + use glib::Object; + use glib::StaticType; + use glib::ToValue; + use std::path::PathBuf; + + #[test] + fn type_checking() { + let store = ListStore::::new(); + let f = File::for_path("/"); + store.append(&f); + let _: Object = store.item(0).unwrap(); + let file = store.item(0); + assert_eq!(file.as_ref(), Some(&f)); + assert_eq!(file.unwrap().path().unwrap(), PathBuf::from("/")); + + assert!(store.dynamic_cast_ref::>().is_none()); + + let object = store.upcast_ref::(); + object.downcast_ref::>().unwrap(); + object.downcast_ref::>().unwrap(); + assert!(object.downcast_ref::>().is_none()); + assert!(object.downcast_ref::>().is_none()); + assert!(object.downcast_ref::>().is_none()); + + let typed_model = store.upcast_ref::>(); + assert_eq!(typed_model.item_type(), File::static_type()); + typed_model.downcast_ref::>().unwrap(); + + let object_model = store.upcast_ref::>(); + object_model.downcast_ref::>().unwrap(); + object_model.downcast_ref::>().unwrap(); + assert!(object_model.downcast_ref::>().is_none()); + + let value = store.to_value(); + value.get::>().unwrap(); + value.get::>>().unwrap().unwrap(); + value.get::>().unwrap(); + value.get::>().unwrap(); + value.get::>>().unwrap().unwrap(); + value.get::>>().unwrap().unwrap(); + assert!(value.get::>().is_err()); + assert!(value.get::>().is_err()); + assert!(value.get::>().is_err()); + + let none = None::>; + let none_value = none.to_value(); + assert!(none_value.get::>().is_err()); + assert!(none_value.get::>().is_err()); + assert!(none_value.get::>().is_err()); + assert!(none_value.get::>().is_err()); + assert!(none_value + .get::>>() + .unwrap() + .is_none()); + assert!(none_value + .get::>>() + .unwrap() + .is_none()); + assert!(none_value + .get::>>() + .unwrap() + .is_none()); + assert!(none_value + .get::>>() + .unwrap() + .is_none()); + assert!(none_value + .get::>>() + .unwrap() + .is_none()); + assert!(none_value + .get::>>() + .unwrap() + .is_none()); + } #[test] fn splice() { - let item0 = ListStore::new(ListStore::static_type()); - let item1 = ListStore::new(ListStore::static_type()); - let list = ListStore::new(ListStore::static_type()); + let item0 = ListStore::::new(); + let item1 = ListStore::::new(); + let list = ListStore::>::new(); list.splice(0, 0, &[item0.clone(), item1.clone()]); - assert_eq!(list.item(0), Some(item0.upcast())); - assert_eq!(list.item(1), Some(item1.upcast())); + assert_eq!(list.item(0), Some(item0)); + assert_eq!(list.item(1), Some(item1)); } #[test] fn extend() { - let item0 = ListStore::new(ListStore::static_type()); - let item1 = ListStore::new(ListStore::static_type()); - let mut list = ListStore::new(ListStore::static_type()); + let item0 = ListStore::::new(); + let item1 = ListStore::::new(); + let mut list = ListStore::>::new(); list.extend(&[&item0, &item1]); - assert_eq!(list.item(0).as_ref(), Some(item0.upcast_ref())); - assert_eq!(list.item(1).as_ref(), Some(item1.upcast_ref())); + assert_eq!(list.item(0).as_ref(), Some(&item0)); + assert_eq!(list.item(1).as_ref(), Some(&item1)); list.extend(&[item0.clone(), item1.clone()]); - assert_eq!(list.item(2).as_ref(), Some(item0.upcast_ref())); - assert_eq!(list.item(3).as_ref(), Some(item1.upcast_ref())); + assert_eq!(list.item(2).as_ref(), Some(&item0)); + assert_eq!(list.item(3).as_ref(), Some(&item1)); } } diff --git a/gio/src/prelude.rs b/gio/src/prelude.rs index a59cfacca4db..f8b925b516bb 100644 --- a/gio/src/prelude.rs +++ b/gio/src/prelude.rs @@ -26,7 +26,7 @@ pub use crate::inet_address::InetAddressExtManual; pub use crate::initable::InitableError; pub use crate::input_stream::InputStreamExtManual; pub use crate::io_stream::IOStreamExtManual; -pub use crate::list_model::ListModelExtManual; +pub use crate::list_model::ListModelExt; pub use crate::output_stream::OutputStreamExtManual; pub use crate::pollable_input_stream::PollableInputStreamExtManual; pub use crate::pollable_output_stream::PollableOutputStreamExtManual; diff --git a/gio/src/subclass/list_model.rs b/gio/src/subclass/list_model.rs index 4ab34ef3f53f..5e3eae68274e 100644 --- a/gio/src/subclass/list_model.rs +++ b/gio/src/subclass/list_model.rs @@ -3,7 +3,7 @@ use crate::ListModel; use glib::subclass::prelude::*; use glib::translate::*; -use glib::{Cast, IsA, ObjectExt}; +use glib::{Cast, IsA, Object, ObjectExt}; use once_cell::sync::Lazy; pub trait ListModelImpl: ObjectImpl { @@ -12,26 +12,31 @@ pub trait ListModelImpl: ObjectImpl { #[doc(alias = "get_n_items")] fn n_items(&self, list_model: &Self::Type) -> u32; #[doc(alias = "get_item")] - fn item(&self, list_model: &Self::Type, position: u32) -> Option; + fn item(&self, list_model: &Self::Type, position: u32) -> Option; } pub trait ListModelImplExt: ObjectSubclass { fn parent_item_type(&self, list_model: &Self::Type) -> glib::Type; fn parent_n_items(&self, list_model: &Self::Type) -> u32; - fn parent_item(&self, list_model: &Self::Type, position: u32) -> Option; + fn parent_item(&self, list_model: &Self::Type, position: u32) -> Option; } impl ListModelImplExt for T { fn parent_item_type(&self, list_model: &Self::Type) -> glib::Type { unsafe { let type_data = Self::type_data(); - let parent_iface = type_data.as_ref().parent_interface::() + let parent_iface = type_data.as_ref().parent_interface::>() as *const ffi::GListModelInterface; let func = (*parent_iface) .get_item_type .expect("no parent \"item_type\" implementation"); - let ret = func(list_model.unsafe_cast_ref::().to_glib_none().0); + let ret = func( + list_model + .unsafe_cast_ref::>() + .to_glib_none() + .0, + ); from_glib(ret) } } @@ -39,27 +44,35 @@ impl ListModelImplExt for T { fn parent_n_items(&self, list_model: &Self::Type) -> u32 { unsafe { let type_data = Self::type_data(); - let parent_iface = type_data.as_ref().parent_interface::() + let parent_iface = type_data.as_ref().parent_interface::>() as *const ffi::GListModelInterface; let func = (*parent_iface) .get_n_items .expect("no parent \"n_items\" implementation"); - func(list_model.unsafe_cast_ref::().to_glib_none().0) + func( + list_model + .unsafe_cast_ref::>() + .to_glib_none() + .0, + ) } } - fn parent_item(&self, list_model: &Self::Type, position: u32) -> Option { + fn parent_item(&self, list_model: &Self::Type, position: u32) -> Option { unsafe { let type_data = Self::type_data(); - let parent_iface = type_data.as_ref().parent_interface::() + let parent_iface = type_data.as_ref().parent_interface::>() as *const ffi::GListModelInterface; let func = (*parent_iface) .get_item .expect("no parent \"get_item\" implementation"); let ret = func( - list_model.unsafe_cast_ref::().to_glib_none().0, + list_model + .unsafe_cast_ref::>() + .to_glib_none() + .0, position, ); from_glib_full(ret) @@ -67,9 +80,9 @@ impl ListModelImplExt for T { } } -unsafe impl IsImplementable for ListModel +unsafe impl> IsImplementable for ListModel where - ::Type: IsA, + ::Type: IsA, { fn interface_init(iface: &mut glib::Interface) { let iface = iface.as_mut(); @@ -87,11 +100,11 @@ unsafe extern "C" fn list_model_get_item_type( list_model: *mut ffi::GListModel, ) -> glib::ffi::GType where - ::Type: IsA, + ::Type: IsA, { let instance = &*(list_model as *mut T::Instance); let imp = instance.imp(); - let wrap = from_glib_borrow::<_, ListModel>(list_model); + let wrap = from_glib_borrow::<_, ListModel>(list_model); let type_ = imp.item_type(wrap.unsafe_cast_ref()).into_glib(); @@ -115,12 +128,12 @@ unsafe extern "C" fn list_model_get_n_items( list_model: *mut ffi::GListModel, ) -> u32 where - ::Type: IsA, + ::Type: IsA, { let instance = &*(list_model as *mut T::Instance); let imp = instance.imp(); - imp.n_items(from_glib_borrow::<_, ListModel>(list_model).unsafe_cast_ref()) + imp.n_items(from_glib_borrow::<_, ListModel>(list_model).unsafe_cast_ref()) } unsafe extern "C" fn list_model_get_item( @@ -128,11 +141,11 @@ unsafe extern "C" fn list_model_get_item( position: u32, ) -> *mut glib::gobject_ffi::GObject where - ::Type: IsA, + ::Type: IsA, { let instance = &*(list_model as *mut T::Instance); let imp = instance.imp(); - let wrap = from_glib_borrow::<_, ListModel>(list_model); + let wrap = from_glib_borrow::<_, ListModel>(list_model); let item = imp.item(wrap.unsafe_cast_ref(), position);