use crate::space::*;
use crate::*;
use std::marker::Unpin;
use urid::UriBound;
use urid::URID;
pub trait ScalarAtom: UriBound {
type InternalType: Unpin + Copy + Send + Sync + Sized + 'static;
fn read_scalar(body: Space) -> Option<Self::InternalType> {
body.split_type::<Self::InternalType>()
.map(|(value, _)| *value)
}
fn write_scalar<'a, 'b>(
mut frame: FramedMutSpace<'a, 'b>,
value: Self::InternalType,
) -> Option<&'a mut Self::InternalType> {
(&mut frame as &mut dyn MutSpace).write(&value, true)
}
}
impl<'a, 'b, A: ScalarAtom> Atom<'a, 'b> for A
where
'a: 'b,
{
type ReadParameter = ();
type ReadHandle = A::InternalType;
type WriteParameter = A::InternalType;
type WriteHandle = &'a mut A::InternalType;
fn read(body: Space<'a>, _: ()) -> Option<A::InternalType> {
<A as ScalarAtom>::read_scalar(body)
}
fn init(
frame: FramedMutSpace<'a, 'b>,
value: A::InternalType,
) -> Option<&'a mut A::InternalType> {
<A as ScalarAtom>::write_scalar(frame, value)
}
}
macro_rules! make_scalar_atom {
($atom:ty, $internal:ty, $uri:expr, $urid:expr) => {
unsafe impl UriBound for $atom {
const URI: &'static [u8] = $uri;
}
impl ScalarAtom for $atom {
type InternalType = $internal;
}
};
}
pub struct Double;
make_scalar_atom!(
Double,
f64,
sys::LV2_ATOM__Double,
|urids: &AtomURIDCollection| urids.double
);
pub struct Float;
make_scalar_atom!(
Float,
f32,
sys::LV2_ATOM__Float,
|urids: &AtomURIDCollection| { urids.float }
);
pub struct Long;
make_scalar_atom!(
Long,
i64,
sys::LV2_ATOM__Long,
|urids: &AtomURIDCollection| { urids.long }
);
pub struct Int;
make_scalar_atom!(
Int,
i32,
sys::LV2_ATOM__Int,
|urids: &AtomURIDCollection| { urids.int }
);
pub struct Bool;
make_scalar_atom!(
Bool,
i32,
sys::LV2_ATOM__Bool,
|urids: &AtomURIDCollection| { urids.bool }
);
pub struct AtomURID;
make_scalar_atom!(
AtomURID,
URID,
sys::LV2_ATOM__URID,
|urids: &AtomURIDCollection| urids.urid
);
#[cfg(test)]
mod tests {
use crate::prelude::*;
use crate::scalar::ScalarAtom;
use crate::space::*;
use std::convert::TryFrom;
use std::mem::size_of;
use urid::*;
fn test_scalar<A: ScalarAtom>(value: A::InternalType)
where
A::InternalType: PartialEq<A::InternalType>,
A::InternalType: std::fmt::Debug,
{
let map = HashURIDMapper::new();
let urid: URID<A> = map.map_type().unwrap();
let mut raw_space: Box<[u8]> = Box::new([0; 256]);
{
let mut space = RootMutSpace::new(raw_space.as_mut());
(&mut space as &mut dyn MutSpace).init(urid, value).unwrap();
}
{
#[repr(C)]
struct Scalar<B: Sized> {
atom: sys::LV2_Atom,
body: B,
}
let (scalar, _) = raw_space.split_at(size_of::<sys::LV2_Atom>());
let scalar = unsafe { &*(scalar.as_ptr() as *const Scalar<A::InternalType>) };
assert_eq!(scalar.atom.type_, urid);
assert_eq!(scalar.atom.size as usize, size_of::<A::InternalType>());
assert_eq!(scalar.body, value);
}
{
let space = Space::from_slice(raw_space.as_ref());
let (body, _) = space.split_atom_body(urid).unwrap();
assert_eq!(A::read(body, ()).unwrap(), value);
}
}
#[test]
fn test_scalars() {
test_scalar::<Double>(42.0);
test_scalar::<Float>(42.0);
test_scalar::<Long>(42);
test_scalar::<Int>(42);
test_scalar::<Bool>(1);
test_scalar::<AtomURID>(URID::try_from(1).unwrap());
}
}