use crate::URID;
use core::{Uri, UriBuf};
use std::collections::HashMap;
use std::convert::TryInto;
use std::os::raw::*;
use std::pin::Pin;
use std::ptr::null;
use std::sync::Mutex;
pub trait URIDMapper: Unpin + Sized {
fn map(&self, uri: &Uri) -> Option<URID>;
unsafe extern "C" fn extern_map(
handle: crate::sys::LV2_URID_Map_Handle,
uri: *const c_char,
) -> crate::sys::LV2_URID {
match (*(handle as *const Self)).map(Uri::from_ptr(uri)) {
Some(urid) => urid.get(),
_ => 0,
}
}
fn make_map_interface(self: Pin<&mut Self>) -> sys::LV2_URID_Map {
sys::LV2_URID_Map {
handle: self.get_mut() as *mut Self as *mut c_void,
map: Some(Self::extern_map),
}
}
fn unmap(&self, urid: URID) -> Option<&Uri>;
unsafe extern "C" fn extern_unmap(
handle: crate::sys::LV2_URID_Map_Handle,
urid: crate::sys::LV2_URID,
) -> *const c_char {
match URID::new(urid) {
Some(urid) => match (*(handle as *const Self)).unmap(urid) {
Some(uri) => uri.as_ptr(),
None => null(),
},
None => null(),
}
}
fn make_unmap_interface(self: Pin<&mut Self>) -> sys::LV2_URID_Unmap {
sys::LV2_URID_Unmap {
handle: self.get_mut() as *mut Self as *mut c_void,
unmap: Some(Self::extern_unmap),
}
}
}
#[derive(Default)]
pub struct HashURIDMapper(Mutex<HashMap<UriBuf, URID>>);
impl URIDMapper for HashURIDMapper {
fn map(&self, uri: &Uri) -> Option<URID<()>> {
let mut map = self.0.lock().ok()?; match map.get(uri) {
Some(urid) => Some(*urid),
None => {
let map_length: u32 = map.len().try_into().ok()?; let next_urid = map_length.checked_add(1)?;
let next_urid = unsafe { URID::new_unchecked(next_urid) };
map.insert(uri.into(), next_urid);
Some(next_urid)
}
}
}
fn unmap(&self, urid: URID<()>) -> Option<&Uri> {
let map = self.0.lock().ok()?;
for (uri, contained_urid) in map.iter() {
if *contained_urid == urid {
return Some(unsafe {
let bytes = uri.as_bytes_with_nul();
Uri::from_bytes_with_nul_unchecked(std::slice::from_raw_parts(
bytes.as_ptr(),
bytes.len(),
))
});
}
}
None
}
}
impl HashURIDMapper {
pub fn new() -> Self {
Default::default()
}
}