use crate::node::{Node, Nodes};
use crate::plugin::Class;
use crate::plugin::Plugins;
use lilv_sys as lib;
use parking_lot::Mutex;
use std::ptr::NonNull;
use std::sync::Arc;
unsafe impl Send for Life {}
unsafe impl Sync for Life {}
pub struct World {
pub(crate) life: Arc<Life>,
}
#[doc(hidden)]
#[allow(clippy::non_send_fields_in_send_ty)]
pub struct Life {
pub(crate) inner: Mutex<NonNull<lib::LilvWorldImpl>>,
}
impl World {
#[must_use]
pub fn new() -> Self {
Self {
life: Arc::new(Life {
inner: Mutex::new(NonNull::new(unsafe { lib::lilv_world_new() }).unwrap()),
}),
}
}
#[must_use]
pub fn with_load_all() -> World {
let world = World::new();
world.load_all();
world
}
}
impl World {
#[must_use]
pub fn plugin_class(&self) -> Option<Class> {
let world = self.life.inner.lock();
Some({
let ptr =
NonNull::new(unsafe { lib::lilv_world_get_plugin_class(world.as_ptr()) as _ })?;
let world = self.life.clone();
Class {
inner: ptr,
life: world,
}
})
}
#[must_use]
pub fn plugins(&self) -> Plugins {
let world = self.life.inner.lock();
let ptr = unsafe { lib::lilv_world_get_all_plugins(world.as_ptr()) };
Plugins {
life: self.life.clone(),
ptr,
}
}
}
impl World {
pub fn set_option(&self, uri: &str, value: &Node) {
let world = self.life.inner.lock();
let uri = std::ffi::CString::new(uri).unwrap();
let value = value.inner.as_ptr();
unsafe { lib::lilv_world_set_option(world.as_ptr(), uri.as_ptr().cast(), value) }
}
}
impl World {
#[must_use]
pub fn new_uri(&self, uri: &str) -> Node {
let world = self.life.inner.lock();
let uri = std::ffi::CString::new(uri).unwrap();
{
let ptr =
NonNull::new(unsafe { lib::lilv_new_uri(world.as_ptr(), uri.as_ptr().cast()) })
.unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
}
}
#[must_use]
pub fn new_file_uri(&self, host: Option<&str>, path: &str) -> Node {
let world = self.life.inner.lock();
let host = host
.iter()
.find_map(|h| std::ffi::CString::new(h.as_bytes()).ok());
let path = std::ffi::CString::new(path.as_bytes()).unwrap();
let host_ptr = host.map_or(std::ptr::null(), |h| h.as_ptr());
let path_ptr = path.as_ptr();
{
let ptr =
NonNull::new(unsafe { lib::lilv_new_file_uri(world.as_ptr(), host_ptr, path_ptr) })
.unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
}
}
#[must_use]
pub fn new_string(&self, string: &str) -> Node {
let world = self.life.inner.lock();
let string = std::ffi::CString::new(string).unwrap();
{
let ptr =
NonNull::new(unsafe { lib::lilv_new_string(world.as_ptr(), string.as_ptr()) })
.unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
}
}
#[must_use]
pub fn new_int(&self, value: i32) -> Node {
let world = self.life.inner.lock();
{
let ptr = NonNull::new(unsafe { lib::lilv_new_int(world.as_ptr(), value) }).unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
}
}
#[must_use]
pub fn new_float(&self, value: f32) -> Node {
let world = self.life.inner.lock();
{
let ptr = NonNull::new(unsafe { lib::lilv_new_float(world.as_ptr(), value) }).unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
}
}
#[must_use]
pub fn new_bool(&self, value: bool) -> Node {
let world = self.life.inner.lock();
{
let ptr = NonNull::new(unsafe { lib::lilv_new_bool(world.as_ptr(), value) }).unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
}
}
}
impl World {
pub fn load_all(&self) {
let world = self.life.inner.lock();
unsafe { lib::lilv_world_load_all(world.as_ptr()) }
}
pub fn load_bundle(&self, bundle_uri: &Node) {
let world = self.life.inner.lock();
let bundle_uri = bundle_uri.inner.as_ptr();
unsafe { lib::lilv_world_load_bundle(world.as_ptr(), bundle_uri) }
}
pub fn load_specifications(&self) {
let world = self.life.inner.lock();
unsafe { lib::lilv_world_load_specifications(world.as_ptr()) }
}
pub fn load_plugin_classes(&self) {
let world = self.life.inner.lock();
unsafe { lib::lilv_world_load_plugin_classes(world.as_ptr()) }
}
#[must_use]
pub unsafe fn unload_bundle(&self, bundle_uri: &Node) -> bool {
let world = self.life.inner.lock();
let bundle_uri = bundle_uri.inner.as_ptr();
lib::lilv_world_unload_bundle(world.as_ptr(), bundle_uri) == 0
}
#[allow(clippy::cast_sign_loss)]
#[must_use]
pub fn load_resource(&self, resource: &Node) -> Option<usize> {
let world = self.life.inner.lock();
let resource = resource.inner.as_ptr();
match unsafe { lib::lilv_world_load_resource(world.as_ptr(), resource) } {
-1 => None,
n => Some(n as usize),
}
}
#[must_use]
pub unsafe fn unload_resource(&self, resource: &Node) -> bool {
let world = self.life.inner.lock();
let resource = resource.inner.as_ptr();
lib::lilv_world_unload_resource(world.as_ptr(), resource) == 0
}
}
impl World {
#[must_use]
pub fn find_nodes(
&self,
subject: Option<&Node>,
predicate: &Node,
object: Option<&Node>,
) -> Nodes {
let world = self.life.inner.lock();
let subject = subject.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
let predicate = predicate.inner.as_ptr();
let object = object.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
let inner =
unsafe { lib::lilv_world_find_nodes(world.as_ptr(), subject, predicate, object) };
let world = self.life.clone();
Nodes { inner, life: world }
}
#[must_use]
pub fn get(
&self,
subject: Option<&Node>,
predicate: Option<&Node>,
object: Option<&Node>,
) -> Option<Node> {
let world = self.life.inner.lock();
let subject = subject.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
let predicate = predicate.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
let object = object.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
Some({
let ptr = NonNull::new(unsafe {
lib::lilv_world_get(world.as_ptr(), subject, predicate, object)
})?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
})
}
#[must_use]
pub fn ask(
&self,
subject: Option<&Node>,
predicate: Option<&Node>,
object: Option<&Node>,
) -> bool {
let world = self.life.inner.lock();
let subject = subject.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
let predicate = predicate.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
let object = object.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
unsafe { lib::lilv_world_ask(world.as_ptr(), subject, predicate, object) }
}
#[must_use]
pub fn symbol(&self, subject: &Node) -> Option<Node> {
let world = self.life.inner.lock();
let subject = subject.inner.as_ptr();
Some({
let ptr = NonNull::new(unsafe { lib::lilv_world_get_symbol(world.as_ptr(), subject) })?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
})
}
}
impl Default for World {
fn default() -> World {
World::new()
}
}
impl Drop for Life {
fn drop(&mut self) {
unsafe {
let world = self.inner.lock();
lib::lilv_world_free(world.as_ptr());
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_load_all() {
let w = World::new();
w.load_all();
}
#[test]
fn test_new_node() {
let w = World::new();
assert!(w.new_bool(true).is_bool());
assert!(w.new_float(0.1).is_float());
assert!(w.new_int(1).is_int());
assert!(w.new_file_uri(None, "/some/path").is_uri());
assert!(w.new_file_uri(Some("me"), "/some/path").is_uri());
assert!(w.new_string("string").is_string());
}
}