use lv2_raw::{LV2Feature, LV2Urid};
use lv2_sys::LV2_Options_Option;
use std::convert::TryFrom;
use std::{collections::HashMap, ffi::CStr};
static OPTIONS_FEATURE_URI: &[u8] = b"http://lv2plug.in/ns/ext/options#options\0";
const EMPTY_OPTION: LV2_Options_Option = LV2_Options_Option {
context: 0,
subject: 0,
key: 0,
size: 0,
type_: 0,
value: std::ptr::null(),
};
pub struct Options {
data: Vec<lv2_sys::LV2_Options_Option>,
values: HashMap<LV2Urid, Box<i32>>,
feature: LV2Feature,
}
unsafe impl Send for Options {}
impl Options {
pub fn new() -> Options {
let mut options = Options {
data: vec![EMPTY_OPTION],
values: HashMap::new(),
feature: LV2Feature {
uri: OPTIONS_FEATURE_URI.as_ptr().cast(),
data: std::ptr::null_mut(),
},
};
options.feature.data = options.data.as_mut_ptr().cast();
options
}
pub fn as_feature(&self) -> &LV2Feature {
&self.feature
}
pub fn set_int_option(
&mut self,
urid_map: &crate::features::urid_map::UridMap,
key: LV2Urid,
value: i32,
) {
if let Some(v) = self.values.get_mut(&key) {
*v.as_mut() = value;
return;
}
let value = Box::new(value);
let value_ptr = value.as_ref() as *const i32;
self.values.insert(key, value);
self.push_option(LV2_Options_Option {
context: 0,
subject: 0,
key,
size: u32::try_from(std::mem::size_of::<i32>())
.expect("Size exceeded capacity of u32."),
type_: urid_map
.map(CStr::from_bytes_with_nul(b"http://lv2plug.in/ns/ext/atom#Int\0").unwrap()),
value: value_ptr.cast(),
});
}
fn push_option(&mut self, option: LV2_Options_Option) {
self.data.pop(); self.data.push(option);
self.data.push(EMPTY_OPTION);
self.feature.data = self.data.as_mut_ptr().cast();
}
}
impl std::fmt::Debug for Options {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Options")
.field("data", &self.data)
.field("values", &self.values)
.field("feature", &"__feature__")
.finish()
}
}