1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
#![cfg(feature = "alloc")] use crate::prelude::*; use core::cell::UnsafeCell; /// Helps overcome limitations of the lifetime system when constructing MIDI events and files. /// /// Because many events contain references to data that outlives them, it can be hard to build a /// MIDI file programatically. /// /// Consider the following code: /// /// ```rust,compile_fail /// use midly::{TrackEvent, TrackEventKind, MetaMessage}; /// /// let mut track = Vec::new(); /// for i in 0..64 { /// let marker_name = format!("Marker {}", i); /// let marker_ref = marker_name.as_bytes(); /// track.push(TrackEvent { /// delta: 0.into(), /// kind: TrackEventKind::Meta(MetaMessage::Marker(marker_ref)), /// }); /// } /// ``` /// /// Looks pretty good, but it fails to compile with /// `error[E0597]: "marker_name" does not live long enough`, with a rightful reason: `marker_name` /// is dropped before the next iteration of the `for` loop. /// /// Instead, use the [`Arena`](struct.Arena.html) type like the following code: /// /// ```rust /// use midly::{TrackEvent, TrackEventKind, MetaMessage}; /// /// let arena = midly::Arena::new(); /// let mut track = Vec::new(); /// for i in 0..64 { /// let marker_name = format!("Marker {}", i); /// let marker_ref = arena.add(marker_name.as_bytes()); /// track.push(TrackEvent { /// delta: 0.into(), /// kind: TrackEventKind::Meta(MetaMessage::Marker(marker_ref)), /// }); /// } /// ``` /// /// This type is only available with the `alloc` feature enabled. #[derive(Default)] pub struct Arena { allocations: UnsafeCell<Vec<*mut [u8]>>, } impl Arena { /// Create a new empty arena. #[inline] pub fn new() -> Arena { Self::default() } /// Empty this arena, deallocating all added bytes. /// /// This method is safe to call because it requires a mutable reference. #[inline] pub fn clear(&mut self) { // SAFETY: // Accessing the `UnsafeCell` is safe because we have a mutable reference to it. // Since we have a mutable reference to `Arena`, there are no more references into // the boxed bytes. Therefore, it is safe to drop the boxed bytes themselves. unsafe { for bytes in (*self.allocations.get()).drain(..) { drop(Box::from_raw(bytes)); } } } /// Get the amount of allocations in the arena. #[inline] pub fn len(&self) -> usize { // SAFETY: // Accessing `self.allocations` is safe as long as there are no concurrent reads or writes. // The _contents_ of `self.allocations` might have outstanding references, but reading the // length does not require derefencing the contents. unsafe { (*self.allocations.get()).len() } } /// Add a set of bytes to the arena, returning a longer-lived mutable reference to a copy of /// these same bytes. #[inline] pub fn add<'a, 'b>(&'a self, bytes: &'b [u8]) -> &'a mut [u8] { self.add_boxed(Box::from(bytes)) } /// Add a `Vec<u8>` to the arena, returning a long-lived mutable reference to its contents. /// /// This method is very similar to `add`, but avoids an allocation and a copy. #[inline] pub fn add_vec<'a>(&'a self, bytes: Vec<u8>) -> &'a mut [u8] { self.add_boxed(bytes.into_boxed_slice()) } /// Add a set of databytes to the arena, returning a longer-lived mutable reference to a copy /// of these same databytes. #[inline] pub fn add_u7<'a, 'b>(&'a self, databytes: &'b [u7]) -> &'a mut [u7] { // SAFETY: // The returned `&mut [u8]` is transformed into a `&mut [u7]` without checking its // contents, which is safe because it was originally a `&[u7]`. unsafe { u7::slice_from_int_unchecked_mut(self.add(u7::slice_as_int(databytes))) } } /// Add a `Vec<u7>` to the arena, returning a long-lived mutable reference to its contents. /// /// This method is very similar to `add_u7`, but avoids an allocation and a copy. #[inline] pub fn add_u7_vec<'a>(&'a self, databytes: Vec<u7>) -> &'a mut [u7] { // SAFETY: // Two unsafe actions are done: // First, a `Vec<u7>` is transmuted into a `Vec<u8>`. This is valid because `u7` has the // same representation as `u8` (guaranteed by `repr(transparent)`), and every `u7` bit // pattern is a valid `u8` bit pattern. // Second, the returned `&mut [u8]` is transformed into a `&mut [u7]` without checking its // contents, which is safe because it was originally a `Vec<u7>`. unsafe { u7::slice_from_int_unchecked_mut( self.add_vec(mem::transmute::<Vec<u7>, Vec<u8>>(databytes)), ) } } #[inline] fn add_boxed<'a>(&'a self, boxed_bytes: Box<[u8]>) -> &'a mut [u8] { // SAFETY: // This block moves `boxed_bytes` into `self` and returns a mutable reference to its // contents. // Further pushes to `self.allocations` may move the _pointers_ to the boxes, but not the // box contents themselves, therefore it's safe to hand out mutable references and modify // `self.allocations` at the same time. unsafe { let pointer = Box::into_raw(boxed_bytes); (*self.allocations.get()).push(pointer); &mut *pointer } } } impl Drop for Arena { #[inline] fn drop(&mut self) { self.clear(); } } // SAFETY: There is no intrinsic issue with moving the arena to another thread, since moving the // arena guarantees there are no references into it. Any buffers left inside the arena will simply // be freed from the other thread. unsafe impl Send for Arena {} impl fmt::Debug for Arena { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { //TODO: Once the `len()` method for raw pointers to slices is stabilized, add better //debug print, showing the size of each allocation. write!(f, "Arena({})", self.len())?; Ok(()) } }