rustc_data_structures/
owned_slice.rs

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
use std::borrow::Borrow;
use std::ops::Deref;

// Use our fake Send/Sync traits when on not parallel compiler,
// so that `OwnedSlice` only implements/requires Send/Sync
// for parallel compiler builds.
use crate::sync;
use crate::sync::Lrc;

/// An owned slice.
///
/// This is similar to `Lrc<[u8]>` but allows slicing and using anything as the
/// backing buffer.
///
/// See [`slice_owned`] for `OwnedSlice` construction and examples.
///
/// ---------------------------------------------------------------------------
///
/// This is essentially a replacement for `owning_ref` which is a lot simpler
/// and even sound! 🌸
#[derive(Clone)]
pub struct OwnedSlice {
    /// This is conceptually a `&'self.owner [u8]`.
    bytes: *const [u8],

    // +---------------------------------------+
    // | We expect `dead_code` lint here,      |
    // | because we don't want to accidentally |
    // | touch the owner — otherwise the owner |
    // | could invalidate out `bytes` pointer  |
    // |                                       |
    // | so be quiet                           |
    // +----+  +-------------------------------+
    //       \/
    //      ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
    #[expect(dead_code)]
    owner: Lrc<dyn sync::Send + sync::Sync>,
}

/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
///
/// ## Examples
///
/// ```rust
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
/// let vec = vec![1, 2, 3, 4];
///
/// // Identical to slicing via `&v[1..3]` but produces an owned slice
/// let slice: OwnedSlice = slice_owned(vec, |v| &v[1..3]);
/// assert_eq!(&*slice, [2, 3]);
/// ```
///
/// ```rust
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
/// # use std::ops::Deref;
/// let vec = vec![1, 2, 3, 4];
///
/// // Identical to slicing via `&v[..]` but produces an owned slice
/// let slice: OwnedSlice = slice_owned(vec, Deref::deref);
/// assert_eq!(&*slice, [1, 2, 3, 4]);
/// ```
pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
where
    O: sync::Send + sync::Sync + 'static,
    F: FnOnce(&O) -> &[u8],
{
    try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
}

/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function that can fail.
///
/// See [`slice_owned`] for the infallible version.
pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
where
    O: sync::Send + sync::Sync + 'static,
    F: FnOnce(&O) -> Result<&[u8], E>,
{
    // We wrap the owner of the bytes in, so it doesn't move.
    //
    // Since the owner does not move and we don't access it in any way
    // before dropping, there is nothing that can invalidate the bytes pointer.
    //
    // Thus, "extending" the lifetime of the reference returned from `F` is fine.
    // We pretend that we pass it a reference that lives as long as the returned slice.
    //
    // N.B. the HRTB on the `slicer` is important — without it the caller could provide
    // a short lived slice, unrelated to the owner.

    let owner = Lrc::new(owner);
    let bytes = slicer(&*owner)?;

    Ok(OwnedSlice { bytes, owner })
}

impl OwnedSlice {
    /// Slice this slice by `slicer`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
    /// let vec = vec![1, 2, 3, 4];
    ///
    /// // Identical to slicing via `&v[1..3]` but produces an owned slice
    /// let slice: OwnedSlice = slice_owned(vec, |v| &v[..]);
    /// assert_eq!(&*slice, [1, 2, 3, 4]);
    ///
    /// let slice = slice.slice(|slice| &slice[1..][..2]);
    /// assert_eq!(&*slice, [2, 3]);
    /// ```
    ///
    pub fn slice(self, slicer: impl FnOnce(&[u8]) -> &[u8]) -> OwnedSlice {
        // This is basically identical to `try_slice_owned`,
        // `slicer` can only return slices of its argument or some static data,
        // both of which are valid while `owner` is alive.

        let bytes = slicer(&self);
        OwnedSlice { bytes, ..self }
    }
}

impl Deref for OwnedSlice {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        // Safety:
        // `self.bytes` is valid per the construction in `slice_owned`
        // (which is the only constructor)
        unsafe { &*self.bytes }
    }
}

impl Borrow<[u8]> for OwnedSlice {
    #[inline]
    fn borrow(&self) -> &[u8] {
        self
    }
}

// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
#[cfg(parallel_compiler)]
unsafe impl sync::Send for OwnedSlice {}

// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
#[cfg(parallel_compiler)]
unsafe impl sync::Sync for OwnedSlice {}

#[cfg(test)]
mod tests;