pango/
attr_iterator.rs
1use std::{marker::PhantomData, mem, ptr};
4
5use glib::{translate::*, SList};
6
7use crate::{ffi, AttrType, Attribute, FontDescription, Language};
8
9#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct AttrIterator<'list> {
18 ptr: ptr::NonNull<ffi::PangoAttrIterator>,
19 list: PhantomData<&'list crate::AttrList>,
20}
21
22impl Clone for AttrIterator<'_> {
23 #[inline]
24 fn clone(&self) -> Self {
25 let ptr = unsafe {
26 ptr::NonNull::new_unchecked(ffi::pango_attr_iterator_copy(self.ptr.as_ptr()))
27 };
28 Self {
29 ptr,
30 list: PhantomData,
31 }
32 }
33}
34
35impl Drop for AttrIterator<'_> {
36 #[inline]
37 fn drop(&mut self) {
38 unsafe {
39 ffi::pango_attr_iterator_destroy(self.ptr.as_ptr());
40 }
41 }
42}
43
44#[cfg(feature = "v1_44")]
45#[cfg_attr(docsrs, doc(cfg(feature = "v1_44")))]
46impl glib::prelude::StaticType for AttrIterator<'_> {
47 #[inline]
48 fn static_type() -> glib::Type {
49 unsafe { from_glib(ffi::pango_attr_iterator_get_type()) }
50 }
51}
52
53impl AttrIterator<'_> {
54 #[doc(alias = "pango_attr_iterator_get")]
55 pub fn get(&self, type_: AttrType) -> Option<Attribute> {
56 unsafe {
57 from_glib_none(ffi::pango_attr_iterator_get(
58 mut_override(self.to_glib_none().0),
59 type_.into_glib(),
60 ))
61 }
62 }
63
64 #[doc(alias = "pango_attr_iterator_get_attrs")]
65 #[doc(alias = "get_attrs")]
66 pub fn attrs(&self) -> SList<Attribute> {
67 unsafe {
68 FromGlibPtrContainer::from_glib_full(ffi::pango_attr_iterator_get_attrs(mut_override(
69 self.to_glib_none().0,
70 )))
71 }
72 }
73
74 #[doc(alias = "pango_attr_iterator_next")]
75 pub fn next_style_change(&mut self) -> bool {
76 unsafe { from_glib(ffi::pango_attr_iterator_next(self.to_glib_none_mut().0)) }
77 }
78
79 #[doc(alias = "pango_attr_iterator_range")]
80 pub fn range(&self) -> (i32, i32) {
81 unsafe {
82 let mut start = mem::MaybeUninit::uninit();
83 let mut end = mem::MaybeUninit::uninit();
84 ffi::pango_attr_iterator_range(
85 mut_override(self.to_glib_none().0),
86 start.as_mut_ptr(),
87 end.as_mut_ptr(),
88 );
89 let start = start.assume_init();
90 let end = end.assume_init();
91 (start, end)
92 }
93 }
94 #[doc(alias = "pango_attr_iterator_get_font")]
95 #[doc(alias = "get_font")]
96 pub fn font(&self) -> (FontDescription, Option<Language>, SList<Attribute>) {
97 unsafe {
98 let desc = FontDescription::new();
99 let mut language = mem::MaybeUninit::uninit();
100 let mut extra_attrs = mem::MaybeUninit::uninit();
101
102 ffi::pango_attr_iterator_get_font(
103 mut_override(self.to_glib_none().0),
104 mut_override(desc.to_glib_none().0),
105 language.as_mut_ptr(),
106 extra_attrs.as_mut_ptr(),
107 );
108
109 (
110 desc,
111 from_glib_full(language.assume_init()),
112 FromGlibPtrContainer::from_glib_full(extra_attrs.assume_init()),
113 )
114 }
115 }
116}
117
118impl<'list> IntoIterator for AttrIterator<'list> {
119 type Item = SList<Attribute>;
120 type IntoIter = AttrIntoIter<'list>;
121 #[inline]
122 fn into_iter(self) -> Self::IntoIter {
123 AttrIntoIter(Some(self))
124 }
125}
126
127#[derive(Clone, Debug)]
128#[repr(transparent)]
129pub struct AttrIntoIter<'list>(Option<AttrIterator<'list>>);
130
131impl Iterator for AttrIntoIter<'_> {
132 type Item = SList<Attribute>;
133 #[inline]
134 fn next(&mut self) -> Option<Self::Item> {
135 if let Some(iter) = &mut self.0 {
136 let attrs = iter.attrs();
137 if !iter.next_style_change() {
138 self.0 = None;
139 }
140 Some(attrs)
141 } else {
142 None
143 }
144 }
145}
146
147impl std::iter::FusedIterator for AttrIntoIter<'_> {}
148
149#[doc(hidden)]
150impl<'a, 'list> ToGlibPtr<'a, *const ffi::PangoAttrIterator> for AttrIterator<'list>
151where
152 'list: 'a,
153{
154 type Storage = PhantomData<&'a Self>;
155 #[inline]
156 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::PangoAttrIterator, Self> {
157 Stash(self.ptr.as_ptr() as *const _, PhantomData)
158 }
159}
160
161#[doc(hidden)]
162impl<'a, 'list> ToGlibPtrMut<'a, *mut ffi::PangoAttrIterator> for AttrIterator<'list>
163where
164 'list: 'a,
165{
166 type Storage = PhantomData<&'a mut Self>;
167 #[inline]
168 fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::PangoAttrIterator, Self> {
169 StashMut(self.ptr.as_ptr(), PhantomData)
170 }
171}
172
173#[doc(hidden)]
174impl FromGlibPtrFull<*mut ffi::PangoAttrIterator> for AttrIterator<'_> {
175 #[inline]
176 unsafe fn from_glib_full(ptr: *mut ffi::PangoAttrIterator) -> Self {
177 Self {
178 ptr: ptr::NonNull::new_unchecked(ptr),
179 list: PhantomData,
180 }
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 #[test]
187 fn attr_iterator() {
188 let default_lang = crate::Language::default();
189 let attributes = crate::AttrList::new();
190 attributes.insert(crate::AttrColor::new_foreground(0x2000, 0x2000, 0x2000));
191 attributes.insert(crate::AttrSize::new(10 * crate::SCALE));
192 attributes.insert(crate::AttrLanguage::new(&default_lang));
193 let iter = attributes.iterator();
194 {
195 let mut iter = iter.clone();
196 loop {
197 let (desc, lang, attrs) = iter.font();
198 if !attrs.is_empty() {
199 assert_eq!(desc.size(), 10 * crate::SCALE);
200 assert_eq!(lang.map(|l| l.to_string()), Some(default_lang.to_string()));
201 }
202 for attr in attrs {
203 attr.downcast_ref::<crate::AttrColor>().unwrap();
204 }
205 if !iter.next_style_change() {
206 break;
207 }
208 }
209 }
210 let mut max = 0;
211 for (i, mut attrs) in iter.into_iter().enumerate() {
212 if i == 0 {
213 attrs
214 .pop_front()
215 .unwrap()
216 .downcast_ref::<crate::AttrColor>()
217 .unwrap();
218 attrs
219 .pop_front()
220 .unwrap()
221 .downcast_ref::<crate::AttrSize>()
222 .unwrap();
223 attrs
224 .pop_front()
225 .unwrap()
226 .downcast_ref::<crate::AttrLanguage>()
227 .unwrap();
228 assert!(attrs.is_empty());
229 }
230 max = i + 1;
231 }
232 assert!(max > 0);
234 }
235}