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 + 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 let instance = &*(list_model as *mut T::Instance);
80 let imp = instance.imp();
81
82 let type_ = imp.item_type().into_glib();
83
84 let instance = imp.obj();
86 let type_quark = {
87 static QUARK: OnceLock<glib::Quark> = OnceLock::new();
88 *QUARK.get_or_init(|| glib::Quark::from_str("gtk-rs-subclass-list-model-item-type"))
89 };
90 match instance.qdata(type_quark) {
91 Some(old_type) => {
92 assert_eq!(
93 type_,
94 *old_type.as_ref(),
95 "ListModel's get_item_type cannot be changed"
96 );
97 }
98 None => {
99 instance.set_qdata(type_quark, type_);
100 }
101 }
102 type_
103}
104
105unsafe extern "C" fn list_model_get_n_items<T: ListModelImpl>(
106 list_model: *mut ffi::GListModel,
107) -> u32 {
108 let instance = &*(list_model as *mut T::Instance);
109 let imp = instance.imp();
110
111 imp.n_items()
112}
113
114unsafe extern "C" fn list_model_get_item<T: ListModelImpl>(
115 list_model: *mut ffi::GListModel,
116 position: u32,
117) -> *mut glib::gobject_ffi::GObject {
118 let instance = &*(list_model as *mut T::Instance);
119 let imp = instance.imp();
120
121 let item = imp.item(position);
122
123 if let Some(ref i) = item {
124 let type_ = imp.item_type();
125 assert!(
126 i.type_().is_a(type_),
127 "All ListModel items need to be of type {} or a subtype of it",
128 type_.name()
129 );
130 };
131 item.into_glib_ptr()
132}