pango/
script_iter.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{marker::PhantomData, mem, ptr};
4
5use glib::{translate::*, GStr};
6
7use crate::{ffi, Script};
8
9#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct ScriptIter<'text> {
11    ptr: ptr::NonNull<ffi::PangoScriptIter>,
12    text: PhantomData<&'text GStr>,
13}
14
15#[cfg(feature = "v1_44")]
16#[cfg_attr(docsrs, doc(cfg(feature = "v1_44")))]
17impl Clone for ScriptIter<'_> {
18    #[inline]
19    fn clone(&self) -> Self {
20        let ptr = unsafe {
21            ptr::NonNull::new_unchecked(glib::gobject_ffi::g_boxed_copy(
22                ffi::pango_script_iter_get_type(),
23                self.ptr.as_ptr() as *mut _,
24            ) as *mut _)
25        };
26        Self {
27            ptr,
28            text: PhantomData,
29        }
30    }
31}
32
33impl Drop for ScriptIter<'_> {
34    #[inline]
35    fn drop(&mut self) {
36        unsafe {
37            ffi::pango_script_iter_free(self.ptr.as_ptr());
38        }
39    }
40}
41
42#[cfg(feature = "v1_44")]
43#[cfg_attr(docsrs, doc(cfg(feature = "v1_44")))]
44impl glib::prelude::StaticType for ScriptIter<'_> {
45    #[inline]
46    fn static_type() -> glib::Type {
47        unsafe { from_glib(ffi::pango_script_iter_get_type()) }
48    }
49}
50
51impl<'text> ScriptIter<'text> {
52    #[doc(alias = "pango_script_iter_new")]
53    pub fn new(text: impl AsRef<GStr> + 'text) -> Self {
54        let text = text.as_ref();
55        let length = text.len() as i32;
56        unsafe { from_glib_full(ffi::pango_script_iter_new(text.as_ptr(), length)) }
57    }
58
59    #[doc(alias = "pango_script_iter_get_range")]
60    #[doc(alias = "get_range")]
61    pub fn range(&mut self) -> (&'text GStr, &'text GStr, Script) {
62        unsafe {
63            let mut start = ptr::null();
64            let mut end = ptr::null();
65            let mut script = mem::MaybeUninit::uninit();
66            ffi::pango_script_iter_get_range(
67                self.to_glib_none_mut().0,
68                &mut start,
69                &mut end,
70                script.as_mut_ptr(),
71            );
72            (
73                GStr::from_ptr(start),
74                GStr::from_ptr(end),
75                from_glib(script.assume_init()),
76            )
77        }
78    }
79
80    #[doc(alias = "pango_script_iter_next")]
81    #[doc(alias = "next")]
82    pub fn next_range(&mut self) -> bool {
83        unsafe { from_glib(ffi::pango_script_iter_next(self.to_glib_none_mut().0)) }
84    }
85}
86
87impl<'text> IntoIterator for ScriptIter<'text> {
88    type Item = (&'text GStr, &'text GStr, Script);
89    type IntoIter = ScriptIntoIter<'text>;
90
91    fn into_iter(self) -> Self::IntoIter {
92        ScriptIntoIter(Some(self))
93    }
94}
95
96#[cfg_attr(feature = "v1_44", derive(Clone))]
97#[derive(Debug)]
98#[repr(transparent)]
99pub struct ScriptIntoIter<'text>(Option<ScriptIter<'text>>);
100
101impl<'text> Iterator for ScriptIntoIter<'text> {
102    type Item = (&'text GStr, &'text GStr, Script);
103
104    fn next(&mut self) -> Option<Self::Item> {
105        if let Some(iter) = &mut self.0 {
106            let attrs = iter.range();
107            if !iter.next_range() {
108                self.0 = None;
109            }
110            Some(attrs)
111        } else {
112            None
113        }
114    }
115}
116
117impl std::iter::FusedIterator for ScriptIntoIter<'_> {}
118
119#[doc(hidden)]
120impl<'a, 'text> ToGlibPtr<'a, *const ffi::PangoScriptIter> for ScriptIter<'text>
121where
122    'text: 'a,
123{
124    type Storage = PhantomData<&'a Self>;
125    #[inline]
126    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::PangoScriptIter, Self> {
127        Stash(self.ptr.as_ptr() as *const _, PhantomData)
128    }
129}
130
131#[doc(hidden)]
132impl<'a, 'text> ToGlibPtrMut<'a, *mut ffi::PangoScriptIter> for ScriptIter<'text>
133where
134    'text: 'a,
135{
136    type Storage = PhantomData<&'a mut Self>;
137    #[inline]
138    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::PangoScriptIter, Self> {
139        StashMut(self.ptr.as_ptr(), PhantomData)
140    }
141}
142
143#[doc(hidden)]
144impl FromGlibPtrFull<*mut ffi::PangoScriptIter> for ScriptIter<'_> {
145    #[inline]
146    unsafe fn from_glib_full(ptr: *mut ffi::PangoScriptIter) -> Self {
147        Self {
148            ptr: ptr::NonNull::new_unchecked(ptr),
149            text: PhantomData,
150        }
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    const SCRIPTS: &glib::GStr = glib::gstr!(
157        "\u{0020}\u{0946}\u{0939}\u{093F}\u{0928}\u{094D}\u{0926}\u{0940}\u{0020}\
158         \u{0627}\u{0644}\u{0639}\u{0631}\u{0628}\u{064A}\u{0629}\u{0020}"
159    );
160
161    #[test]
162    fn script_iter() {
163        let iter = super::ScriptIter::new(SCRIPTS);
164        let scripts = iter.into_iter().collect::<Vec<_>>();
165        assert_eq!(scripts.len(), 2);
166        assert_eq!(scripts[0].0, SCRIPTS);
167        assert_eq!(scripts[0].1, &SCRIPTS[23..]);
168        assert_eq!(scripts[0].2, crate::Script::Devanagari);
169        assert_eq!(scripts[1].0, &SCRIPTS[23..]);
170        assert_eq!(scripts[1].1, &SCRIPTS[38..]);
171        assert_eq!(scripts[1].2, crate::Script::Arabic);
172    }
173}