Skip to content

Commit f554dd3

Browse files
committed
Simplify access to PacketList fields and validate layout
1 parent effc202 commit f554dd3

File tree

2 files changed

+51
-29
lines changed

2 files changed

+51
-29
lines changed

src/lib.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extern crate coremidi_sys;
4545
use core_foundation_sys::base::OSStatus;
4646

4747
use coremidi_sys::{
48-
MIDIObjectRef, MIDIFlushOutput, MIDIRestart, MIDIPacketList
48+
MIDIObjectRef, MIDIFlushOutput, MIDIRestart, MIDIPacket, MIDIPacketList
4949
};
5050

5151
/// A [MIDI Object](https://developer.apple.com/reference/coremidi/midiobjectref).
@@ -212,16 +212,29 @@ pub struct VirtualDestination {
212212
#[derive(PartialEq)]
213213
pub struct Device { object: Object }
214214

215+
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
216+
type AlignmentMarker = [u32; 0]; // ensures 4-byte alignment (on ARM)
217+
218+
219+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
220+
type AlignmentMarker = [u8; 0]; // unaligned
221+
215222
/// A [list of MIDI events](https://developer.apple.com/reference/coremidi/midipacketlist) being received from, or being sent to, one endpoint.
216223
///
217-
#[derive(PartialEq)]
218224
#[repr(C)]
219-
// This type must only exist in the form of references and always point
220-
// to a valid instance of MIDIPacketList.
221-
// `u32` is the fixed-size header (numPackages) that every instance has.
222-
// Everything after that is dynamically sized (but not in the sense of Rust DST).
223-
// This type must NOT implement `Copy`!
224-
pub struct PacketList { _do_not_construct: u32 }
225+
pub struct PacketList {
226+
// NOTE: This type must only exist in the form of immutable references
227+
// pointing to valid instances of MIDIPacketList.
228+
// This type must NOT implement `Copy`!
229+
inner: PacketListInner,
230+
_do_not_construct: AlignmentMarker
231+
}
232+
233+
#[repr(packed)]
234+
struct PacketListInner {
235+
num_packets: u32,
236+
data: [MIDIPacket; 0]
237+
}
225238

226239
impl PacketList {
227240
/// For internal usage only.

src/packets.rs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::fmt;
66
use std::ops::Deref;
77

88
use PacketList;
9+
use AlignmentMarker;
910

1011
pub type Timestamp = u64;
1112

@@ -14,11 +15,14 @@ const MAX_PACKET_DATA_LENGTH: usize = 0xffffusize;
1415
/// A collection of simultaneous MIDI events.
1516
/// See [MIDIPacket](https://developer.apple.com/reference/coremidi/midipacket).
1617
///
18+
#[repr(C)]
1719
pub struct Packet {
18-
// NOTE: At runtime this type must only be used behind references
19-
// that point to valid instances of MIDIPacket.
20+
// NOTE: At runtime this type must only be used behind immutable references
21+
// that point to valid instances of MIDIPacket (mutable references would allow mem::swap).
22+
// This type must NOT implement `Copy`!
23+
// On ARM, this must be 4-byte aligned.
2024
inner: PacketInner,
21-
_do_not_construct: [u32; 0] // u32 also guarantees at least 4-byte alignment
25+
_do_not_construct: AlignmentMarker
2226
}
2327

2428
#[repr(packed)]
@@ -56,17 +60,10 @@ impl Packet {
5660
/// 90 40 7f
5761
/// ```
5862
pub fn data(&self) -> &[u8] {
59-
let packet = self.packet();
60-
let data_ptr = packet.inner.data.as_ptr();
61-
let data_len = packet.inner.length as usize;
63+
let data_ptr = self.inner.data.as_ptr();
64+
let data_len = self.inner.length as usize;
6265
unsafe { ::std::slice::from_raw_parts(data_ptr, data_len) }
6366
}
64-
65-
#[inline]
66-
// TODO: this is wrong, a &MIDIPacket must not exist if the length is smaller than 256 bytes
67-
fn packet(&self) -> &Packet {
68-
self
69-
}
7067
}
7168

7269
impl fmt::Debug for Packet {
@@ -103,24 +100,18 @@ impl PacketList {
103100
/// Get the number of packets in the list.
104101
///
105102
pub fn length(&self) -> usize {
106-
self.packet_list().numPackets as usize
103+
self.inner.num_packets as usize
107104
}
108105

109106
/// Get an iterator for the packets in the list.
110107
///
111108
pub fn iter<'a>(&'a self) -> PacketListIterator<'a> {
112109
PacketListIterator {
113110
count: self.length(),
114-
packet_ptr: &self.packet_list().packet[0],
111+
packet_ptr: self.inner.data.as_ptr(),
115112
_phantom: ::std::marker::PhantomData::default(),
116113
}
117114
}
118-
119-
#[inline]
120-
// TODO: This must be removed
121-
fn packet_list(&self) -> &MIDIPacketList {
122-
unsafe { &*(self.as_ptr() as *const MIDIPacketList) }
123-
}
124115
}
125116

126117
impl fmt::Debug for PacketList {
@@ -140,7 +131,7 @@ impl fmt::Debug for PacketList {
140131

141132
impl fmt::Display for PacketList {
142133
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143-
let result = write!(f, "PacketList(len={})", self.packet_list().numPackets);
134+
let result = write!(f, "PacketList(len={})", self.inner.num_packets);
144135
self.iter().fold(result, |prev_result, packet| {
145136
match prev_result {
146137
Err(err) => Err(err),
@@ -274,9 +265,27 @@ impl Deref for PacketBuffer {
274265

275266
#[cfg(test)]
276267
mod tests {
268+
use std::mem;
277269
use coremidi_sys::{MIDITimeStamp, MIDIPacketList};
278270
use PacketList;
279271
use PacketBuffer;
272+
use Packet;
273+
use super::{PACKET_HEADER_SIZE, PACKET_LIST_HEADER_SIZE};
274+
275+
#[test]
276+
pub fn packet_struct_layout() {
277+
let expected_align = if cfg!(any(target_arch = "arm", target_arch = "aarch64")) { 4 } else { 1 };
278+
assert_eq!(expected_align, mem::align_of::<Packet>());
279+
assert_eq!(expected_align, mem::align_of::<PacketList>());
280+
281+
let dummy_packet: Packet = unsafe { mem::zeroed() };
282+
let ptr = &dummy_packet as *const _ as *const u8;
283+
assert_eq!(PACKET_HEADER_SIZE, dummy_packet.inner.data.as_ptr() as usize - ptr as usize);
284+
285+
let dummy_packet_list: PacketList = unsafe { mem::zeroed() };
286+
let ptr = &dummy_packet_list as *const _ as *const u8;
287+
assert_eq!(PACKET_LIST_HEADER_SIZE, dummy_packet_list.inner.data.as_ptr() as usize - ptr as usize);
288+
}
280289

281290
#[test]
282291
pub fn packet_buffer_new() {

0 commit comments

Comments
 (0)