mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-06 06:57:42 +00:00

Since it's inception a long time ago, the parallel compiler and its cfgs have been a maintenance burden. This was a necessary evil the allow iteration while not degrading performance because of synchronization overhead. But this time is over. Thanks to the amazing work by the parallel working group (and the dyn sync crimes), the parallel compiler has now been fast enough to be shipped by default in nightly for quite a while now. Stable and beta have still been on the serial compiler, because they can't use `-Zthreads` anyways. But this is quite suboptimal: - the maintenance burden still sucks - we're not testing the serial compiler in nightly Because of these reasons, it's time to end it. The serial compiler has served us well in the years since it was split from the parallel one, but it's over now. Let the knight slay one head of the two-headed dragon!
149 lines
4.6 KiB
Rust
149 lines
4.6 KiB
Rust
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`
|
|
unsafe impl sync::Send for OwnedSlice {}
|
|
|
|
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
|
|
unsafe impl sync::Sync for OwnedSlice {}
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|