gtk4/subclass/
buildable_parser.rs1use crate::ffi;
4use glib::{GString, translate::*};
5use std::{collections::HashMap, mem, ptr::NonNull};
6
7#[doc(alias = "GtkBuildableParseContext")]
8pub struct BuildableParseContext(NonNull<ffi::GtkBuildableParseContext>);
9
10impl BuildableParseContext {
11 pub(crate) fn from_raw(ctx: *mut ffi::GtkBuildableParseContext) -> Self {
12 Self(NonNull::new(ctx).expect("Null ParseContext"))
13 }
14
15 #[doc(alias = "gtk_buildable_parse_context_get_element")]
16 pub fn element(&self) -> Option<GString> {
17 unsafe {
18 from_glib_none(ffi::gtk_buildable_parse_context_get_element(
19 self.0.as_ptr(),
20 ))
21 }
22 }
23
24 #[doc(alias = "gtk_buildable_parse_context_get_element_stack")]
25 pub fn element_stack(&self) -> Vec<GString> {
28 unsafe {
29 let stack = ffi::gtk_buildable_parse_context_get_element_stack(self.0.as_ptr());
30 FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(stack)
31 }
32 }
33
34 pub fn position(&self) -> (i32, i32) {
35 unsafe {
36 let mut line_number = mem::MaybeUninit::uninit();
37 let mut char_number = mem::MaybeUninit::uninit();
38 ffi::gtk_buildable_parse_context_get_position(
39 self.0.as_ptr(),
40 line_number.as_mut_ptr(),
41 char_number.as_mut_ptr(),
42 );
43 (line_number.assume_init(), char_number.assume_init())
44 }
45 }
46}
47
48#[doc(alias = "GtkBuildableParser")]
49pub struct BuildableParser {
50 parser: ffi::GtkBuildableParser,
51 data: glib::ffi::gpointer,
52}
53
54impl BuildableParser {
55 pub(crate) unsafe fn from_raw_parts(
56 parser: ffi::GtkBuildableParser,
57 data: glib::ffi::gpointer,
58 ) -> Self {
59 Self { parser, data }
60 }
61
62 pub(crate) fn into_raw_parts(self) -> (ffi::GtkBuildableParser, glib::ffi::gpointer) {
63 (self.parser, self.data)
64 }
65
66 pub fn new<T: BuildableParserImpl>(data: T) -> Self {
67 Self {
68 parser: ffi::GtkBuildableParser {
69 start_element: Some(start_element_trampoline::<T>),
70 end_element: Some(end_element_trampoline::<T>),
71 text: Some(text_trampoline::<T>),
72 error: Some(error_trampoline::<T>),
73 padding: [
74 std::ptr::null_mut(),
75 std::ptr::null_mut(),
76 std::ptr::null_mut(),
77 std::ptr::null_mut(),
78 ],
79 },
80 data: Box::into_raw(Box::new(data)) as glib::ffi::gpointer,
81 }
82 }
83
84 pub unsafe fn take_data<T: BuildableParserImpl>(data: glib::ffi::gpointer) -> Box<T> {
92 unsafe { Box::from_raw(data as *mut T) }
93 }
94}
95
96pub unsafe trait BuildableParserImpl: Sized + 'static {
102 fn start_element(
103 &mut self,
104 ctx: &BuildableParseContext,
105 element_name: &str,
106 attributes: HashMap<String, String>,
107 ) -> Result<(), glib::Error>;
108 fn end_element(
109 &mut self,
110 ctx: &BuildableParseContext,
111 element_name: &str,
112 ) -> Result<(), glib::Error>;
113 fn text(&mut self, ctx: &BuildableParseContext, text: &str) -> Result<(), glib::Error>;
114 fn error(&mut self, _ctx: &BuildableParseContext, _error: glib::Error) {}
115}
116
117unsafe extern "C" fn start_element_trampoline<T: BuildableParserImpl>(
118 ctx: *mut ffi::GtkBuildableParseContext,
119 element_name: *const libc::c_char,
120 attributes_names: *mut *const libc::c_char,
121 attributes_values: *mut *const libc::c_char,
122 user_data: glib::ffi::gpointer,
123 errorptr: *mut *mut glib::ffi::GError,
124) {
125 unsafe {
126 let ctx = BuildableParseContext::from_raw(ctx);
127 let name = from_glib_borrow::<_, GString>(element_name);
128 let attributes_names =
129 FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(attributes_names);
130 let attributes_values =
131 FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(attributes_values);
132 let attributes = attributes_names
133 .into_iter()
134 .zip(attributes_values)
135 .collect::<HashMap<String, String>>();
136 let parser_data = &mut *(user_data as *mut T);
137 match parser_data.start_element(&ctx, &name, attributes) {
138 Ok(_) => {
139 *errorptr = std::ptr::null_mut();
140 }
141 Err(err) => {
142 *errorptr = err.into_glib_ptr();
143 }
144 };
145 }
146}
147
148unsafe extern "C" fn end_element_trampoline<T: BuildableParserImpl>(
149 ctx: *mut ffi::GtkBuildableParseContext,
150 element_name: *const libc::c_char,
151 user_data: glib::ffi::gpointer,
152 errorptr: *mut *mut glib::ffi::GError,
153) {
154 unsafe {
155 let ctx = BuildableParseContext::from_raw(ctx);
156 let element_name = from_glib_borrow::<_, GString>(element_name);
157 let parser_data = &mut *(user_data as *mut T);
158 match parser_data.end_element(&ctx, &element_name) {
159 Ok(_) => {
160 *errorptr = std::ptr::null_mut();
161 }
162 Err(err) => {
163 *errorptr = err.into_glib_ptr();
164 }
165 }
166 }
167}
168
169unsafe extern "C" fn text_trampoline<T: BuildableParserImpl>(
170 ctx: *mut ffi::GtkBuildableParseContext,
171 text: *const libc::c_char,
172 _length: usize,
173 user_data: glib::ffi::gpointer,
174 errorptr: *mut *mut glib::ffi::GError,
175) {
176 unsafe {
177 let ctx = BuildableParseContext::from_raw(ctx);
178 let text = from_glib_borrow::<_, GString>(text);
179
180 let parser_data = &mut *(user_data as *mut T);
181 match parser_data.text(&ctx, &text) {
182 Ok(_) => {
183 *errorptr = std::ptr::null_mut();
184 }
185 Err(err) => {
186 *errorptr = err.into_glib_ptr();
187 }
188 }
189 }
190}
191
192unsafe extern "C" fn error_trampoline<T: BuildableParserImpl>(
193 ctx: *mut ffi::GtkBuildableParseContext,
194 errorptr: *mut glib::ffi::GError,
195 user_data: glib::ffi::gpointer,
196) {
197 unsafe {
198 let ctx = BuildableParseContext::from_raw(ctx);
199
200 let parser_data = &mut *(user_data as *mut T);
201 parser_data.error(&ctx, from_glib_full(errorptr));
202 }
203}