1use crate::space::*;
71use crate::*;
72use std::convert::TryFrom;
73use std::iter::Iterator;
74use urid::UriBound;
75use urid::URID;
76
77pub struct Object;
81
82unsafe impl UriBound for Object {
83 const URI: &'static [u8] = sys::LV2_ATOM__Object;
84}
85
86pub struct ObjectHeader {
88 pub id: Option<URID>,
92 pub otype: URID,
94}
95
96impl<'a, 'b> Atom<'a, 'b> for Object
97where
98 'a: 'b,
99{
100 type ReadParameter = ();
101 type ReadHandle = (ObjectHeader, ObjectReader<'a>);
102 type WriteParameter = ObjectHeader;
103 type WriteHandle = ObjectWriter<'a, 'b>;
104
105 fn read(body: Space<'a>, _: ()) -> Option<(ObjectHeader, ObjectReader<'a>)> {
106 let (header, body) = body.split_type::<sys::LV2_Atom_Object_Body>()?;
107 let header = ObjectHeader {
108 id: URID::try_from(header.id).ok(),
109 otype: URID::try_from(header.otype).ok()?,
110 };
111
112 let reader = ObjectReader { space: body };
113
114 Some((header, reader))
115 }
116
117 fn init(
118 mut frame: FramedMutSpace<'a, 'b>,
119 header: ObjectHeader,
120 ) -> Option<ObjectWriter<'a, 'b>> {
121 {
122 let frame = &mut frame as &mut dyn MutSpace;
123 frame.write(
124 &sys::LV2_Atom_Object_Body {
125 id: header.id.map(|urid| urid.get()).unwrap_or(0),
126 otype: header.otype.get(),
127 },
128 true,
129 );
130 }
131 Some(ObjectWriter { frame })
132 }
133}
134
135pub struct Blank;
141
142unsafe impl UriBound for Blank {
143 const URI: &'static [u8] = sys::LV2_ATOM__Blank;
144}
145
146impl<'a, 'b> Atom<'a, 'b> for Blank
147where
148 'a: 'b,
149{
150 type ReadParameter = <Object as Atom<'a, 'b>>::ReadParameter;
151 type ReadHandle = <Object as Atom<'a, 'b>>::ReadHandle;
152 type WriteParameter = <Object as Atom<'a, 'b>>::WriteParameter;
153 type WriteHandle = <Object as Atom<'a, 'b>>::WriteHandle;
154
155 #[allow(clippy::unit_arg)]
156 fn read(body: Space<'a>, parameter: Self::ReadParameter) -> Option<Self::ReadHandle> {
157 Object::read(body, parameter)
158 }
159
160 fn init(
161 frame: FramedMutSpace<'a, 'b>,
162 parameter: Self::WriteParameter,
163 ) -> Option<Self::WriteHandle> {
164 Object::init(frame, parameter)
165 }
166}
167
168pub struct ObjectReader<'a> {
172 space: Space<'a>,
173}
174
175impl<'a> Iterator for ObjectReader<'a> {
176 type Item = (PropertyHeader, UnidentifiedAtom<'a>);
177
178 fn next(&mut self) -> Option<(PropertyHeader, UnidentifiedAtom<'a>)> {
179 let (header, value, space) = Property::read_body(self.space)?;
180 self.space = space;
181 Some((header, UnidentifiedAtom::new(value)))
182 }
183}
184
185pub struct ObjectWriter<'a, 'b> {
189 frame: FramedMutSpace<'a, 'b>,
190}
191
192impl<'a, 'b> ObjectWriter<'a, 'b> {
193 pub fn init_with_context<'c, K: ?Sized, T: ?Sized, A: Atom<'a, 'c>>(
197 &'c mut self,
198 key: URID<K>,
199 context: URID<T>,
200 child_urid: URID<A>,
201 parameter: A::WriteParameter,
202 ) -> Option<A::WriteHandle> {
203 Property::write_header(&mut self.frame, key.into_general(), Some(context))?;
204 (&mut self.frame as &mut dyn MutSpace).init(child_urid, parameter)
205 }
206
207 pub fn init<'c, K: ?Sized, A: Atom<'a, 'c>>(
213 &'c mut self,
214 key: URID<K>,
215 child_urid: URID<A>,
216 parameter: A::WriteParameter,
217 ) -> Option<A::WriteHandle> {
218 Property::write_header::<K, ()>(&mut self.frame, key, None)?;
219 (&mut self.frame as &mut dyn MutSpace).init(child_urid, parameter)
220 }
221}
222
223pub struct Property;
229
230unsafe impl UriBound for Property {
231 const URI: &'static [u8] = sys::LV2_ATOM__Property;
232}
233
234#[derive(Clone, Copy)]
236pub struct PropertyHeader {
237 pub key: URID,
239 pub context: Option<URID>,
241}
242
243impl Property {
244 fn read_body(space: Space) -> Option<(PropertyHeader, Space, Space)> {
248 #[repr(C)]
249 #[derive(Clone, Copy)]
250 struct StrippedPropertyBody {
254 key: u32,
255 context: u32,
256 }
257
258 let (header, space) = space.split_type::<StrippedPropertyBody>()?;
259
260 let header = PropertyHeader {
261 key: URID::try_from(header.key).ok()?,
262 context: URID::try_from(header.context).ok(),
263 };
264
265 let (atom, space) = space.split_atom()?;
266 Some((header, atom, space))
267 }
268
269 fn write_header<K: ?Sized, C: ?Sized>(
273 space: &mut dyn MutSpace,
274 key: URID<K>,
275 context: Option<URID<C>>,
276 ) -> Option<()> {
277 space.write(&key.get(), true)?;
278 space.write(&context.map(|urid| urid.get()).unwrap_or(0), false)?;
279 Some(())
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use crate::prelude::*;
286 use crate::space::*;
287 use std::mem::size_of;
288 use urid::*;
289
290 #[test]
291 fn test_object() {
292 let map = HashURIDMapper::new();
293 let urids = AtomURIDCollection::from_map(&map).unwrap();
294
295 let object_type = map
296 .map_uri(Uri::from_bytes_with_nul(b"urn:my-type\0").unwrap())
297 .unwrap();
298
299 let first_key = map
300 .map_uri(Uri::from_bytes_with_nul(b"urn:value-a\0").unwrap())
301 .unwrap();
302 let first_value: i32 = 17;
303
304 let second_key = map
305 .map_uri(Uri::from_bytes_with_nul(b"urn:value-b\0").unwrap())
306 .unwrap();
307 let second_value: f32 = 42.0;
308
309 let mut raw_space: Box<[u8]> = Box::new([0; 256]);
310
311 {
313 let mut space = RootMutSpace::new(raw_space.as_mut());
314 let frame = FramedMutSpace::new(&mut space as &mut dyn MutSpace, urids.object).unwrap();
315 let mut writer = Object::init(
316 frame,
317 ObjectHeader {
318 id: None,
319 otype: object_type,
320 },
321 )
322 .unwrap();
323 {
324 writer.init(first_key, urids.int, first_value).unwrap();
325 }
326 {
327 writer.init(second_key, urids.float, second_value).unwrap();
328 }
329 }
330
331 {
333 let (atom, space) = raw_space.split_at(size_of::<sys::LV2_Atom>());
335 let atom = unsafe { &*(atom.as_ptr() as *const sys::LV2_Atom) };
336 assert_eq!(atom.type_, urids.object);
337 assert_eq!(
338 atom.size as usize,
339 size_of::<sys::LV2_Atom_Object_Body>()
340 + size_of::<sys::LV2_Atom_Property_Body>()
341 + 2 * size_of::<i32>()
342 + size_of::<sys::LV2_Atom_Property_Body>()
343 + size_of::<f32>()
344 );
345
346 let (object, space) = space.split_at(size_of::<sys::LV2_Atom_Object_Body>());
348 let object = unsafe { &*(object.as_ptr() as *const sys::LV2_Atom_Object_Body) };
349 assert_eq!(object.id, 0);
350 assert_eq!(object.otype, object_type);
351
352 let (property, space) = space.split_at(size_of::<sys::LV2_Atom_Property_Body>());
354 let property = unsafe { &*(property.as_ptr() as *const sys::LV2_Atom_Property_Body) };
355 assert_eq!(property.key, first_key);
356 assert_eq!(property.context, 0);
357 assert_eq!(property.value.type_, urids.int);
358 assert_eq!(property.value.size as usize, size_of::<i32>());
359
360 let (value, space) = space.split_at(size_of::<i32>());
361 let value = unsafe { *(value.as_ptr() as *const i32) };
362 assert_eq!(value, first_value);
363 let (_, space) = space.split_at(size_of::<i32>());
364
365 let (property, space) = space.split_at(size_of::<sys::LV2_Atom_Property_Body>());
367 let property = unsafe { &*(property.as_ptr() as *const sys::LV2_Atom_Property_Body) };
368 assert_eq!(property.key, second_key);
369 assert_eq!(property.context, 0);
370 assert_eq!(property.value.type_, urids.float);
371 assert_eq!(property.value.size as usize, size_of::<f32>());
372
373 let (value, _) = space.split_at(size_of::<f32>());
374 let value = unsafe { *(value.as_ptr() as *const f32) };
375 assert_eq!(value, second_value);
376 }
377
378 {
380 let space = Space::from_slice(raw_space.as_ref());
381 let (body, _) = space.split_atom_body(urids.object).unwrap();
382
383 let (header, iter) = Object::read(body, ()).unwrap();
384 assert_eq!(header.otype, object_type);
385 assert_eq!(header.id, None);
386
387 let properties: Vec<(PropertyHeader, UnidentifiedAtom)> = iter.collect();
388 let (header, atom) = properties[0];
389 assert_eq!(header.key, first_key);
390 assert_eq!(atom.read::<Int>(urids.int, ()).unwrap(), first_value);
391 let (header, atom) = properties[1];
392 assert_eq!(header.key, second_key);
393 assert_eq!(atom.read::<Float>(urids.float, ()).unwrap(), second_value);
394 }
395 }
396}