Skip to content

Commit 44aac00

Browse files
authored
Atom soundness and usability fixes (#100)
Mark atom-reading methods as unsafe. Renamed Space into AlignedSpace, and made it a Dynamically Sized Type. Removed all of the use_padding parameters in atom writing methods. Added a SpaceReader struct. Removed all the odd split_* methods on Space. Added VecSpace, replacing SpaceList. Renamed FramedMutSpace into AtomSpaceWriter Renamed RootMutSpace into SpaceCursor. Renamed the MutSpace trait into SpaceWriter. Added the Terminated struct. Made UnidentifiedAtom a Dynamically Sized Type. Added the AtomHeader struct. Removed lifetimes from the Atom types (and removed many extra lifetimes accordingly). Removed ReadParameter and WriteParameter associated types. Moved all base atom types to a sub-module. Removed lifetimes in the Atom type. Removed Vector type parameter. Moved Sequence unit type reading into a type parameter for its reader. Added an AtomError error type, as well as sub-error types AtomReadError, AtomWriteError, and AlignmentError. Added a special prelude for the atom-implementing side. Added lots of extra documentation, especially in AlignedSpace.
1 parent b6d02f3 commit 44aac00

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+4995
-2646
lines changed

atom/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ maintenance = { status = "passively-maintained" }
1616
[dependencies]
1717
lv2-sys = "2.0.0"
1818
lv2-units = "0.1.3"
19-
urid = "0.1.0"
19+
urid = { version = "0.1.0", default-features = false }
2020

2121
[dependencies.lv2-core]
2222
version = "3.0.0"
2323
optional = true
24+
default-features = false
2425

2526
[dev-dependencies]
2627
lv2-urid = "2.1.0"

atom/src/atoms.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
pub mod chunk;
2+
pub mod object;
3+
pub mod scalar;
4+
pub mod sequence;
5+
pub mod string;
6+
pub mod tuple;
7+
pub mod vector;
8+
9+
use urid::*;
10+
11+
/// An URID collection of all standard atom types, provided for convenience.
12+
#[derive(Clone)]
13+
pub struct AtomURIDCollection {
14+
pub blank: URID<object::Blank>,
15+
pub double: URID<scalar::Double>,
16+
pub float: URID<scalar::Float>,
17+
pub int: URID<scalar::Int>,
18+
pub long: URID<scalar::Long>,
19+
pub urid: URID<scalar::AtomURID>,
20+
pub bool: URID<scalar::Bool>,
21+
pub vector: URID<vector::Vector>,
22+
pub chunk: URID<chunk::Chunk>,
23+
pub literal: URID<string::Literal>,
24+
pub object: URID<object::Object>,
25+
pub property: URID<object::Property>,
26+
pub string: URID<string::String>,
27+
pub tuple: URID<tuple::Tuple>,
28+
pub sequence: URID<sequence::Sequence>,
29+
}
30+
31+
impl URIDCollection for AtomURIDCollection {
32+
fn from_map<M: Map + ?Sized>(map: &M) -> Option<Self> {
33+
Some(Self {
34+
blank: map.map_type()?,
35+
double: map.map_type()?,
36+
float: map.map_type()?,
37+
int: map.map_type()?,
38+
long: map.map_type()?,
39+
urid: map.map_type()?,
40+
bool: map.map_type()?,
41+
vector: map.map_type()?,
42+
chunk: map.map_type()?,
43+
literal: map.map_type()?,
44+
object: map.map_type()?,
45+
property: map.map_type()?,
46+
string: map.map_type()?,
47+
tuple: map.map_type()?,
48+
sequence: map.map_type()?,
49+
})
50+
}
51+
}

atom/src/atoms/chunk.rs

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//! An atom containing memory of undefined type.
2+
//!
3+
//! This contents of this atom is considered as a simple blob of data. It used, for example, by the host to transmit the size of a writable atom port. Since it is so simple, it does not need a reading or writing parameter.
4+
//!
5+
//! # Example
6+
//! ```
7+
//! use lv2_core::prelude::*;
8+
//! use lv2_atom::prelude::*;
9+
//!
10+
//! use lv2_atom::space::{AtomSpace, AtomWriter, SpaceWriter};
11+
//!
12+
//! #[derive(PortCollection)]
13+
//! struct MyPorts {
14+
//! input: InputPort<AtomPort>,
15+
//! output: OutputPort<AtomPort>,
16+
//! }
17+
//!
18+
//! fn run(ports: &mut MyPorts, urids: &AtomURIDCollection) {
19+
//! let in_chunk: &AtomSpace = ports.input.read(urids.chunk).unwrap();
20+
//! let mut out_chunk: AtomWriter = ports.output.write(urids.chunk).unwrap();
21+
//!
22+
//! let bytes = in_chunk.as_bytes();
23+
//! out_chunk.write_bytes(bytes).unwrap();
24+
//! }
25+
//! ```
26+
//!
27+
//! # Specification
28+
//!
29+
//! [http://lv2plug.in/ns/ext/atom/atom.html#Chunk](http://lv2plug.in/ns/ext/atom/atom.html#Chunk)
30+
use crate::space::error::{AtomReadError, AtomWriteError};
31+
use crate::space::*;
32+
use crate::AtomWriter;
33+
use crate::{Atom, AtomHandle};
34+
use urid::UriBound;
35+
36+
/// An atom containing an arbitrary byte buffer.
37+
///
38+
/// [See also the module documentation.](index.html)
39+
pub struct Chunk;
40+
41+
unsafe impl UriBound for Chunk {
42+
const URI: &'static [u8] = sys::LV2_ATOM__Chunk;
43+
}
44+
45+
pub struct ChunkReaderHandle;
46+
impl<'a> AtomHandle<'a> for ChunkReaderHandle {
47+
type Handle = &'a AtomSpace;
48+
}
49+
50+
pub struct ChunkWriterHandle;
51+
impl<'a> AtomHandle<'a> for ChunkWriterHandle {
52+
type Handle = AtomWriter<'a>;
53+
}
54+
55+
impl Atom for Chunk {
56+
type ReadHandle = ChunkReaderHandle;
57+
type WriteHandle = ChunkWriterHandle;
58+
59+
#[inline]
60+
unsafe fn read(
61+
body: &AtomSpace,
62+
) -> Result<<Self::ReadHandle as AtomHandle>::Handle, AtomReadError> {
63+
Ok(body)
64+
}
65+
66+
#[inline]
67+
fn write(
68+
frame: AtomWriter,
69+
) -> Result<<Self::WriteHandle as AtomHandle>::Handle, AtomWriteError> {
70+
Ok(frame)
71+
}
72+
}
73+
74+
#[cfg(test)]
75+
mod tests {
76+
use crate::atoms::chunk::*;
77+
use crate::*;
78+
79+
#[test]
80+
fn test_chunk_and_slice_writer() {
81+
const SLICE_LENGTH: usize = 42;
82+
83+
let map = HashURIDMapper::new();
84+
let urids = crate::atoms::AtomURIDCollection::from_map(&map).unwrap();
85+
86+
let mut raw_space = AlignedVec::<AtomHeader>::new_with_capacity(64);
87+
let raw_space = raw_space.as_space_mut();
88+
89+
// writing
90+
{
91+
let mut space = SpaceCursor::new(raw_space.as_bytes_mut());
92+
let mut writer = space.write_atom(urids.chunk).unwrap();
93+
let data = writer.allocate(SLICE_LENGTH).unwrap();
94+
95+
for (i, value) in data.iter_mut().enumerate() {
96+
*value = i as u8;
97+
}
98+
99+
space.write_value(41u8).unwrap();
100+
}
101+
102+
// verifying
103+
{
104+
let atom = unsafe { raw_space.read().next_atom() }.unwrap();
105+
assert_eq!(atom.header().size_of_body(), SLICE_LENGTH);
106+
assert_eq!(atom.header().urid(), urids.chunk.get());
107+
108+
let data = atom.body().as_bytes();
109+
for (i, value) in data.iter().enumerate() {
110+
assert_eq!(*value as usize, i);
111+
}
112+
}
113+
114+
// reading
115+
{
116+
let data =
117+
unsafe { Chunk::read(raw_space.read().next_atom().unwrap().body()) }.unwrap();
118+
assert_eq!(data.bytes_len(), SLICE_LENGTH);
119+
120+
for (i, value) in data.as_bytes().iter().enumerate() {
121+
assert_eq!(*value as usize, i);
122+
}
123+
}
124+
}
125+
}

0 commit comments

Comments
 (0)