Implement OwnedSlice
This commit is contained in:
parent
be8e5ba157
commit
689beda166
3 changed files with 120 additions and 5 deletions
|
@ -27,6 +27,8 @@
|
||||||
#![feature(thread_id_value)]
|
#![feature(thread_id_value)]
|
||||||
#![feature(vec_into_raw_parts)]
|
#![feature(vec_into_raw_parts)]
|
||||||
#![feature(get_mut_unchecked)]
|
#![feature(get_mut_unchecked)]
|
||||||
|
#![feature(lint_reasons)]
|
||||||
|
#![feature(unwrap_infallible)]
|
||||||
#![allow(rustc::default_hash_types)]
|
#![allow(rustc::default_hash_types)]
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
#![deny(rustc::untranslatable_diagnostic)]
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
|
@ -82,6 +84,7 @@ pub mod vec_linked_list;
|
||||||
pub mod work_queue;
|
pub mod work_queue;
|
||||||
pub use atomic_ref::AtomicRef;
|
pub use atomic_ref::AtomicRef;
|
||||||
pub mod frozen;
|
pub mod frozen;
|
||||||
|
pub mod owned_slice;
|
||||||
pub mod sso;
|
pub mod sso;
|
||||||
pub mod steal;
|
pub mod steal;
|
||||||
pub mod tagged_ptr;
|
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! {
|
cfg_if! {
|
||||||
if #[cfg(not(parallel_compiler))] {
|
if #[cfg(not(parallel_compiler))] {
|
||||||
pub auto trait Send {}
|
pub unsafe auto trait Send {}
|
||||||
pub auto trait Sync {}
|
pub unsafe auto trait Sync {}
|
||||||
|
|
||||||
impl<T> Send for T {}
|
|
||||||
impl<T> Sync for T {}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! rustc_erase_owner {
|
macro_rules! rustc_erase_owner {
|
||||||
|
@ -69,6 +66,8 @@ cfg_if! {
|
||||||
$v.erase_owner()
|
$v.erase_owner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unsafe impl<T> Send for T {}
|
||||||
|
unsafe impl<T> Sync for T {}
|
||||||
|
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue