gio/subclass/
list_model.rs
1use std::sync::OnceLock;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{ffi, ListModel};
8
9pub trait ListModelImpl: ObjectImpl {
10 #[doc(alias = "get_item_type")]
11 fn item_type(&self) -> glib::Type;
12 #[doc(alias = "get_n_items")]
13 fn n_items(&self) -> u32;
14 #[doc(alias = "get_item")]
15 fn item(&self, position: u32) -> Option<glib::Object>;
16}
17
18mod sealed {
19 pub trait Sealed {}
20 impl<T: super::ListModelImplExt> Sealed for T {}
21}
22
23pub trait ListModelImplExt: sealed::Sealed + ObjectSubclass {
24 fn parent_item_type(&self) -> glib::Type {
25 unsafe {
26 let type_data = Self::type_data();
27 let parent_iface = type_data.as_ref().parent_interface::<ListModel>()
28 as *const ffi::GListModelInterface;
29
30 let func = (*parent_iface)
31 .get_item_type
32 .expect("no parent \"item_type\" implementation");
33 let ret = func(self.obj().unsafe_cast_ref::<ListModel>().to_glib_none().0);
34 from_glib(ret)
35 }
36 }
37
38 fn parent_n_items(&self) -> u32 {
39 unsafe {
40 let type_data = Self::type_data();
41 let parent_iface = type_data.as_ref().parent_interface::<ListModel>()
42 as *const ffi::GListModelInterface;
43
44 let func = (*parent_iface)
45 .get_n_items
46 .expect("no parent \"n_items\" implementation");
47 func(self.obj().unsafe_cast_ref::<ListModel>().to_glib_none().0)
48 }
49 }
50
51 fn parent_item(&self, position: u32) -> Option<glib::Object> {
52 unsafe {
53 let type_data = Self::type_data();
54 let parent_iface = type_data.as_ref().parent_interface::<ListModel>()
55 as *const ffi::GListModelInterface;
56
57 let func = (*parent_iface)
58 .get_item
59 .expect("no parent \"get_item\" implementation");
60 let ret = func(
61 self.obj().unsafe_cast_ref::<ListModel>().to_glib_none().0,
62 position,
63 );
64 from_glib_full(ret)
65 }
66 }
67}
68
69impl<T: ListModelImpl> ListModelImplExt for T {}
70
71unsafe impl<T: ListModelImpl> IsImplementable<T> for ListModel
72where
73 <T as ObjectSubclass>::Type: IsA<glib::Object>,
74{
75 fn interface_init(iface: &mut glib::Interface<Self>) {
76 let iface = iface.as_mut();
77
78 iface.get_item_type = Some(list_model_get_item_type::<T>);
79 iface.get_n_items = Some(list_model_get_n_items::<T>);
80 iface.get_item = Some(list_model_get_item::<T>);
81 }
82}
83
84unsafe extern "C" fn list_model_get_item_type<T: ListModelImpl>(
85 list_model: *mut ffi::GListModel,
86) -> glib::ffi::GType
87where
88 <T as ObjectSubclass>::Type: IsA<glib::Object>,
89{
90 let instance = &*(list_model as *mut T::Instance);
91 let imp = instance.imp();
92
93 let type_ = imp.item_type().into_glib();
94
95 let instance = imp.obj();
97 let type_quark = {
98 static QUARK: OnceLock<glib::Quark> = OnceLock::new();
99 *QUARK.get_or_init(|| glib::Quark::from_str("gtk-rs-subclass-list-model-item-type"))
100 };
101 match instance.qdata(type_quark) {
102 Some(old_type) => {
103 assert_eq!(
104 type_,
105 *old_type.as_ref(),
106 "ListModel's get_item_type cannot be changed"
107 );
108 }
109 None => {
110 instance.set_qdata(type_quark, type_);
111 }
112 }
113 type_
114}
115
116unsafe extern "C" fn list_model_get_n_items<T: ListModelImpl>(
117 list_model: *mut ffi::GListModel,
118) -> u32
119where
120 <T as ObjectSubclass>::Type: IsA<glib::Object>,
121{
122 let instance = &*(list_model as *mut T::Instance);
123 let imp = instance.imp();
124
125 imp.n_items()
126}
127
128unsafe extern "C" fn list_model_get_item<T: ListModelImpl>(
129 list_model: *mut ffi::GListModel,
130 position: u32,
131) -> *mut glib::gobject_ffi::GObject
132where
133 <T as ObjectSubclass>::Type: IsA<glib::Object>,
134{
135 let instance = &*(list_model as *mut T::Instance);
136 let imp = instance.imp();
137
138 let item = imp.item(position);
139
140 if let Some(ref i) = item {
141 let type_ = imp.item_type();
142 assert!(
143 i.type_().is_a(type_),
144 "All ListModel items need to be of type {} or a subtype of it",
145 type_.name()
146 );
147 };
148 item.into_glib_ptr()
149}