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(())
    }
}