1use crate::node::{Node, Nodes};
2use crate::plugin::Plugin;
3use crate::world::Life;
4use lilv_sys as lib;
5use std::ffi::CStr;
6use std::ptr::NonNull;
7use std::sync::Arc;
8
9pub struct UI {
10    pub(crate) inner: NonNull<lib::LilvUI>,
11    pub(crate) plugin: Plugin,
12    pub(crate) life: Arc<Life>,
13}
14
15impl UI {
16    #[must_use]
21    pub fn uri(&self) -> Node {
22        let _life = self.life.inner.lock();
23        let ui = self.inner.as_ptr();
24
25        {
26            let ptr = NonNull::new(unsafe { lib::lilv_ui_get_uri(ui) as _ }).unwrap();
27            let world = self.plugin.life.clone();
28            Node {
29                inner: ptr,
30                borrowed: true,
31                life: world,
32            }
33        }
34    }
35
36    #[must_use]
38    pub fn classes(&self) -> Nodes {
39        let _life = self.life.inner.lock();
40        let ui = self.inner.as_ptr();
41
42        let inner = unsafe { lib::lilv_ui_get_classes(ui) };
43        let world = self.plugin.life.clone();
44        Nodes { inner, life: world }
45    }
46
47    #[must_use]
49    pub fn is_a(&self, class_uri: &Node) -> bool {
50        let _life = self.life.inner.lock();
51        let ui = self.inner.as_ptr();
52        let class_uri = class_uri.inner.as_ptr();
53
54        unsafe { lib::lilv_ui_is_a(ui, class_uri) }
55    }
56
57    #[must_use]
58    pub fn is_supported<S>(
59        &self,
60        container_type: &Node,
61        ui_type: Option<&mut Option<Node>>,
62    ) -> UISupportQuality
63    where
64        S: UISupport,
65    {
66        let ui = self.inner.as_ptr();
67        let container_type = container_type.inner.as_ptr();
68
69        let mut ui_type_ptr = std::ptr::null();
70
71        let quality = UISupportQuality(unsafe {
72            let _life = self.life.inner.lock();
73            lib::lilv_ui_is_supported(
74                ui,
75                Some(supported_func::<S>),
76                container_type,
77                ui_type
78                    .as_ref()
79                    .map_or(std::ptr::null_mut(), |_| &mut ui_type_ptr as _),
80            )
81        });
82
83        if let Some(ui_type) = ui_type {
84            let ptr = match NonNull::new(ui_type_ptr as _) {
85                Some(ptr) => ptr,
86                None => return UISupportQuality(0),
87            };
88            *ui_type = Some({
89                let world = self.plugin.life.clone();
90                Node {
91                    inner: ptr,
92                    borrowed: true,
93                    life: world,
94                }
95            });
96        }
97
98        quality
99    }
100
101    #[must_use]
102    pub fn bundle_uri(&self) -> Option<Node> {
103        let ui = self.inner.as_ptr();
104        let _life = self.life.inner.lock();
105
106        Some({
107            let ptr = NonNull::new(unsafe { lib::lilv_ui_get_bundle_uri(ui) as _ })?;
108            let world = self.plugin.life.clone();
109            Node {
110                inner: ptr,
111                borrowed: true,
112                life: world,
113            }
114        })
115    }
116
117    #[must_use]
119    pub fn binary_uri(&self) -> Option<Node> {
120        let _life = self.life.inner.lock();
121        let ui = self.inner.as_ptr();
122
123        Some({
124            let ptr = NonNull::new(unsafe { lib::lilv_ui_get_binary_uri(ui) as _ })?;
125            let world = self.plugin.life.clone();
126            Node {
127                inner: ptr,
128                borrowed: true,
129                life: world,
130            }
131        })
132    }
133}
134
135#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
136pub struct UISupportQuality(pub u32);
137
138pub trait UISupport {
139    fn supported(container: &str, ui: &str) -> UISupportQuality;
140}
141
142unsafe extern "C" fn supported_func<S: UISupport>(
143    container_type_uri: *const i8,
144    ui_type_uri: *const i8,
145) -> u32 {
146    S::supported(
147        CStr::from_ptr(container_type_uri).to_str().unwrap(),
148        CStr::from_ptr(ui_type_uri).to_str().unwrap(),
149    )
150    .0
151}
152
153#[derive(Clone)]
155pub struct Uis {
156    pub(crate) inner: NonNull<lib::LilvUIs>,
157    pub(crate) plugin: Plugin,
158    pub(crate) life: Arc<Life>,
159}
160
161impl Uis {
162    #[must_use]
163    pub fn count(&self) -> usize {
164        let _life = self.life.inner.lock();
165        unsafe { lib::lilv_uis_size(self.inner.as_ptr()) as _ }
166    }
167
168    #[must_use]
169    pub fn get_by_uri(&self, uri: &Node) -> Option<UI> {
170        let _life = self.life.inner.lock();
171        let inner = self.inner.as_ptr();
172        let uri = uri.inner.as_ptr();
173
174        Some(UI {
175            inner: NonNull::new(unsafe { lib::lilv_plugins_get_by_uri(inner, uri) as _ })?,
176            plugin: self.plugin.clone(),
177            life: self.life.clone(),
178        })
179    }
180
181    pub fn iter(&self) -> impl Iterator<Item = UI> {
182        self.clone().into_iter()
183    }
184}
185
186impl IntoIterator for Uis {
187    type Item = UI;
188
189    type IntoIter = Iter;
190
191    fn into_iter(self) -> Self::IntoIter {
192        let iter = unsafe {
193            let _life = self.life.inner.lock();
194            lib::lilv_uis_begin(self.inner.as_ptr()).cast()
195        };
196        Iter { uis: self, iter }
197    }
198}
199
200pub struct Iter {
202    uis: Uis,
203    iter: *mut lib::LilvIter,
204}
205
206impl Iterator for Iter {
207    type Item = UI;
208
209    fn next(&mut self) -> Option<UI> {
210        let _life = self.uis.life.inner.lock();
211        let next =
212            unsafe { lib::lilv_uis_get(self.uis.inner.as_ptr(), self.iter) } as *mut lib::LilvUI;
213        let ret = Some(UI {
214            inner: NonNull::new(next)?,
215            plugin: self.uis.plugin.clone(),
216            life: self.uis.life.clone(),
217        });
218        self.iter = unsafe { lib::lilv_uis_next(self.uis.inner.as_ptr(), self.iter) };
219        ret
220    }
221}