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