use crate::atom::*;
use libc::{memcmp, memcpy};
use std::mem::size_of;
use std::os::raw::c_void;
#[inline]
#[must_use]
pub const fn lv2_atom_pad_size(size: u32) -> u32 {
(size + 7) & (!7)
}
#[inline]
#[must_use]
pub fn lv2_atom_total_size(atom: &LV2Atom) -> u32 {
size_of::<LV2Atom>() as u32 + atom.size
}
#[inline]
pub unsafe fn lv2_atom_is_null(atom: *const LV2Atom) -> bool {
unsafe { atom.is_null() || ((*atom).type_ == 0 && (*atom).size == 0) }
}
pub unsafe fn lv2_atom_equals(a: *const LV2Atom, b: *const LV2Atom) -> bool {
unsafe {
(a == b)
|| (((*a).type_ == (*b).type_)
&& ((*a).size == (*b).size)
&& (memcmp(
a.add(1) as *const c_void,
b.add(1) as *const c_void,
(*a).size as usize,
) == 0))
}
}
#[inline]
pub unsafe fn lv2_atom_sequence_begin(body: *const LV2AtomSequenceBody) -> *mut LV2AtomEvent {
unsafe { body.add(1) as *mut LV2AtomEvent }
}
#[inline]
pub unsafe fn lv2_atom_sequence_end(
body: *const LV2AtomSequenceBody,
size: u32,
) -> *const LV2AtomEvent {
unsafe { (body as *const u8).add(lv2_atom_pad_size(size) as usize) as *const LV2AtomEvent }
}
#[inline]
pub unsafe fn lv2_atom_sequence_is_end(
body: *const LV2AtomSequenceBody,
size: u32,
i: *const LV2AtomEvent,
) -> bool {
unsafe { i as *const u8 >= (body as *const u8).add(size as usize) }
}
#[inline]
pub unsafe fn lv2_atom_sequence_next(i: *const LV2AtomEvent) -> *mut LV2AtomEvent {
unsafe {
let off = size_of::<LV2AtomEvent>() + lv2_atom_pad_size((*i).body.size) as usize;
(i as *const u8).add(off) as *mut LV2AtomEvent
}
}
#[inline]
pub unsafe fn lv2_atom_sequence_clear(seq: *mut LV2AtomSequence) {
unsafe {
(*seq).atom.size = size_of::<LV2AtomSequenceBody>() as u32;
}
}
pub unsafe fn lv2_atom_sequence_append_event(
seq: *mut LV2AtomSequence,
capacity: u32,
event: *const LV2AtomEvent,
) -> *const LV2AtomEvent {
unsafe {
let total_size = size_of::<LV2AtomEvent>() as u32 + (*event).body.size;
if (capacity - (*seq).atom.size) < total_size {
return std::ptr::null();
}
let e = lv2_atom_sequence_end(&(*seq).body, (*seq).atom.size);
memcpy(
e as *mut c_void,
event as *const c_void,
total_size as usize,
);
(*seq).atom.size += lv2_atom_pad_size(total_size);
e
}
}
#[inline]
pub unsafe fn lv2_atom_object_begin(body: *const LV2AtomObjectBody) -> *mut LV2AtomPropertyBody {
unsafe { body.add(1) as *mut LV2AtomPropertyBody }
}
#[inline]
pub unsafe fn lv2_atom_object_is_end(
body: *const LV2AtomObjectBody,
size: u32,
i: *const LV2AtomPropertyBody,
) -> bool {
unsafe { i as *const u8 >= (body as *const u8).add(size as usize) }
}
#[inline]
pub unsafe fn lv2_atom_object_next(i: *const LV2AtomPropertyBody) -> *mut LV2AtomPropertyBody {
unsafe {
let value = (i as *const u8).add(2 * size_of::<u32>()) as *const LV2Atom;
let offset = lv2_atom_pad_size(size_of::<LV2AtomPropertyBody>() as u32 + (*value).size);
(i as *mut u8).add(offset as usize) as *mut LV2AtomPropertyBody
}
}
#[derive(Debug)]
pub struct LV2AtomObjectQuery {
pub key: u32,
pub value: *mut *mut LV2Atom,
}
pub unsafe fn lv2_atom_object_query(
obj: *mut LV2AtomObject,
query: *mut LV2AtomObjectQuery,
) -> i32 {
unsafe {
let object = &mut *obj;
let mut n_queries = 0;
let mut matches = 0;
let mut q = query;
while (*q).key != 0 {
n_queries += 1;
q = q.add(1);
}
object.foreach(|prop: *mut LV2AtomPropertyBody| -> bool {
let mut q = query;
while (*q).key != 0 {
if (*q).key == (*prop).key && !(*q).value.is_null() {
let val = &mut (*prop).value;
*(*q).value = val;
matches += 1;
if matches == n_queries {
return true;
}
break;
}
q = q.add(1);
}
false
});
matches
}
}
#[derive(Debug)]
pub struct ObjectHelper {
pub key: u32,
pub atom: *mut *mut LV2Atom,
}
pub unsafe fn lv2_atom_object_get(body: *mut LV2AtomObject, query: &[ObjectHelper]) -> i32 {
unsafe {
let mut matches = 0;
let mut n_queries = 0;
for it in query {
if it.atom.is_null() {
return -1;
}
n_queries += 1;
}
(*body).foreach(|prop: *mut LV2AtomPropertyBody| -> bool {
for it in query {
let qkey = it.key;
if qkey == (*prop).key && (*it.atom).is_null() {
*it.atom = &mut (*prop).value;
matches += 1;
if matches == n_queries {
return matches > 0;
}
break;
}
}
true
});
matches
}
}
impl LV2AtomSequenceBody {
pub unsafe fn foreach<F>(&mut self, size: u32, mut closure: F)
where
F: FnMut(*const LV2AtomEvent),
{
unsafe {
let mut it = lv2_atom_sequence_begin(self);
while !lv2_atom_sequence_is_end(self, size, it) {
closure(it);
it = lv2_atom_sequence_next(it);
}
}
}
}
pub struct LV2AtomSequenceIterator<'a> {
pub seq: &'a LV2AtomSequence,
pub current: &'a LV2AtomEvent,
}
impl<'a> Iterator for LV2AtomSequenceIterator<'a> {
type Item = &'a LV2AtomEvent;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let body = &self.seq.body;
let size = self.seq.atom.size;
if !lv2_atom_sequence_is_end(body, size, self.current) {
let out = self.current;
self.current = &*lv2_atom_sequence_next(self.current);
Some(out)
} else {
None
}
}
}
}
impl<'a> IntoIterator for &'a LV2AtomSequence {
type Item = &'a LV2AtomEvent;
type IntoIter = LV2AtomSequenceIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
unsafe {
LV2AtomSequenceIterator {
seq: self,
current: &*lv2_atom_sequence_begin(&self.body as *const LV2AtomSequenceBody),
}
}
}
}