Implement OwnedSlice
This commit is contained in:
parent
be8e5ba157
commit
689beda166
@ -27,6 +27,8 @@
|
||||
#![feature(thread_id_value)]
|
||||
#![feature(vec_into_raw_parts)]
|
||||
#![feature(get_mut_unchecked)]
|
||||
#![feature(lint_reasons)]
|
||||
#![feature(unwrap_infallible)]
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
@ -82,6 +84,7 @@ pub mod vec_linked_list;
|
||||
pub mod work_queue;
|
||||
pub use atomic_ref::AtomicRef;
|
||||
pub mod frozen;
|
||||
pub mod owned_slice;
|
||||
pub mod sso;
|
||||
pub mod steal;
|
||||
pub mod tagged_ptr;
|
||||
|
113
compiler/rustc_data_structures/src/owned_slice.rs
Normal file
113
compiler/rustc_data_structures/src/owned_slice.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use std::{borrow::Borrow, 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::{Send, Sync};
|
||||
|
||||
/// An owned slice.
|
||||
///
|
||||
/// This is similar to `Box<[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! 🌸
|
||||
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 quite |
|
||||
// +----+ +-------------------------------+
|
||||
// \/
|
||||
// ⊂(´・◡・⊂ )∘˚˳°
|
||||
#[expect(dead_code)]
|
||||
owner: Box<dyn Send + 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: Send + Sync + 'static,
|
||||
F: Fn(&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: Send + Sync + 'static,
|
||||
F: Fn(&O) -> Result<&[u8], E>,
|
||||
{
|
||||
// We box the owner of the bytes, so it doesn't move.
|
||||
//
|
||||
// Since the owner does not move and we don't access it in any way
|
||||
// before drop, 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 = Box::new(owner);
|
||||
let bytes = slicer(&*owner)?;
|
||||
|
||||
Ok(OwnedSlice { bytes, owner })
|
||||
}
|
||||
|
||||
impl Deref for OwnedSlice {
|
||||
type Target = [u8];
|
||||
|
||||
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 {
|
||||
fn borrow(&self) -> &[u8] {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
|
||||
unsafe impl Send for OwnedSlice {}
|
||||
|
||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
|
||||
unsafe impl Sync for OwnedSlice {}
|
@ -57,11 +57,8 @@ mod vec;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(not(parallel_compiler))] {
|
||||
pub auto trait Send {}
|
||||
pub auto trait Sync {}
|
||||
|
||||
impl<T> Send for T {}
|
||||
impl<T> Sync for T {}
|
||||
pub unsafe auto trait Send {}
|
||||
pub unsafe auto trait Sync {}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! rustc_erase_owner {
|
||||
@ -69,6 +66,8 @@ cfg_if! {
|
||||
$v.erase_owner()
|
||||
}
|
||||
}
|
||||
unsafe impl<T> Send for T {}
|
||||
unsafe impl<T> Sync for T {}
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user