diff options
author | Maurice Lam <yukl@google.com> | 2023-02-09 21:51:50 +0000 |
---|---|---|
committer | Maurice Lam <yukl@google.com> | 2023-02-09 21:52:34 +0000 |
commit | 6c71cc3835a332225f80cd000480b93488908d53 (patch) | |
tree | ad37f0ccb6bc1e2e0d6ca1b305974b6b6a4914b6 | |
parent | e03c0304d7cd1620795cdf4decf1bd4e90304a8a (diff) | |
download | aliasable-6c71cc3835a332225f80cd000480b93488908d53.tar.gz |
Import aliasable crate
Bug: 267375624
Test: None, this CL doesn't add any build files yet
Change-Id: I04115d35c7bf19abba9f76bb177a3e2d19069b94
-rw-r--r-- | .cargo_vcs_info.json | 5 | ||||
-rw-r--r-- | CHANGELOG.md | 13 | ||||
-rw-r--r-- | Cargo.toml | 40 | ||||
-rw-r--r-- | Cargo.toml.orig | 26 | ||||
-rw-r--r-- | LICENSE | 21 | ||||
-rw-r--r-- | METADATA | 19 | ||||
-rw-r--r-- | MODULE_LICENSE_MIT | 0 | ||||
-rw-r--r-- | OWNERS | 1 | ||||
-rw-r--r-- | README.md | 36 | ||||
-rw-r--r-- | src/boxed.rs | 161 | ||||
-rw-r--r-- | src/lib.rs | 60 | ||||
-rw-r--r-- | src/mut_ref.rs | 160 | ||||
-rw-r--r-- | src/string.rs | 157 | ||||
-rw-r--r-- | src/vec.rs | 180 |
14 files changed, 879 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..608f0a2 --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "ddb6958345aae7fef0686f00a592ef37e944a4ad" + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..58bfeb5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.3] - 2020-01-10 + +### Added +- `prelude` module. +- `AliasableMut` (thanks [@Koxiaet](https://github.com/Koxiaet)). diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..db72cd2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "aliasable" +version = "0.1.3" +authors = ["avitex <avitex@wfxlabs.com>"] +include = ["src/**/*", "README.md", "CHANGELOG.md", "LICENSE", "Cargo.toml"] +description = "Basic aliasable (non unique pointer) types" +homepage = "https://github.com/avitex/rust-aliasable" +documentation = "https://docs.rs/aliasable" +readme = "README.md" +categories = ["no-std", "data-structures"] +license = "MIT" +repository = "https://github.com/avitex/rust-aliasable" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +[dependencies.aliasable_deref_trait] +version = "0.2" +optional = true + +[dependencies.stable_deref_trait] +version = "1.2" +optional = true + +[features] +alloc = [] +default = ["alloc"] +traits = ["stable_deref_trait", "aliasable_deref_trait"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..d845db2 --- /dev/null +++ b/Cargo.toml.orig @@ -0,0 +1,26 @@ +[package] +name = "aliasable" +version = "0.1.3" +authors = ["avitex <avitex@wfxlabs.com>"] +edition = "2018" +description = "Basic aliasable (non unique pointer) types" +categories = ["no-std", "data-structures"] +documentation = "https://docs.rs/aliasable" +homepage = "https://github.com/avitex/rust-aliasable" +repository = "https://github.com/avitex/rust-aliasable" +license = "MIT" +readme = "README.md" +include = ["src/**/*", "README.md", "CHANGELOG.md", "LICENSE", "Cargo.toml"] + +[features] +default = ["alloc"] +alloc = [] +traits = ["stable_deref_trait", "aliasable_deref_trait"] + +[dependencies] +stable_deref_trait = { version = "1.2", optional = true } +aliasable_deref_trait = { version = "0.2", optional = true } + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 James Dyson <avitex@wfxlabs.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..4dc4499 --- /dev/null +++ b/METADATA @@ -0,0 +1,19 @@ +name: "aliasable" +description: "Basic aliasable (non unique pointer) types" +third_party { + url { + type: HOMEPAGE + value: "https://crates.io/crates/aliasable" + } + url { + type: ARCHIVE + value: "https://static.crates.io/crates/aliasable/aliasable-0.1.3.crate" + } + version: "0.1.3" + license_type: NOTICE + last_upgrade_date { + year: 2023 + month: 2 + day: 9 + } +} diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_MIT @@ -0,0 +1 @@ +include platform/prebuilts/rust:master:/OWNERS diff --git a/README.md b/README.md new file mode 100644 index 0000000..c008bc9 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +[![Build Status](https://github.com/avitex/rust-aliasable/workflows/build/badge.svg)](https://github.com/avitex/rust-aliasable/actions?query=workflow:build) +[![Coverage Status](https://codecov.io/gh/avitex/rust-aliasable/branch/master/graph/badge.svg?token=X2LXHI8VYL)](https://codecov.io/gh/avitex/rust-aliasable) +[![Crate](https://img.shields.io/crates/v/aliasable.svg)](https://crates.io/crates/aliasable) +[![Docs](https://docs.rs/aliasable/badge.svg)](https://docs.rs/aliasable) + +# rust-aliasable + +**Rust library providing basic aliasable (non `core::ptr::Unique`) types** +Documentation hosted on [docs.rs](https://docs.rs/aliasable). + +```toml +aliasable = "0.1" +``` + +## Why? + +Used for escaping `noalias` when multiple raw pointers may point to the same +data. + +## Goals + +`aliasable` is not designed to provide a full interface for container types, +simply to provide aliasable (non `core::ptr::Unique`) alternatives for +dereferencing their owned data. When converting from a unique to an aliasable +alternative, no data referenced is mutated (one-to-one internal representation +aside from the non `core::ptr::Unique` pointer). + +## Usage + +```rust +use aliasable::vec::AliasableVec; + +// Re-exported via `aliasable::vec::UniqueVec` +let unique = Vec::from(&[1, 2, 3][..]); +let aliasable = AliasableVec::from(unique); +``` diff --git a/src/boxed.rs b/src/boxed.rs new file mode 100644 index 0000000..3455fbd --- /dev/null +++ b/src/boxed.rs @@ -0,0 +1,161 @@ +//! Aliasable `Box`. + +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::ptr::NonNull; +use core::{fmt, mem}; + +pub use alloc::boxed::Box as UniqueBox; + +/// Basic aliasable (non `core::ptr::Unique`) alternative to +/// [`alloc::boxed::Box`]. +pub struct AliasableBox<T: ?Sized>(NonNull<T>); + +impl<T: ?Sized> AliasableBox<T> { + /// Construct an `AliasableBox` from a [`UniqueBox`]. + pub fn from_unique(ptr: UniqueBox<T>) -> Self { + let ptr = unsafe { NonNull::new_unchecked(UniqueBox::into_raw(ptr)) }; + Self(ptr) + } + + /// Consumes `self` and converts it into a non-aliasable [`UniqueBox`]. + #[inline] + pub fn into_unique(mut ptr: AliasableBox<T>) -> UniqueBox<T> { + // As we are consuming the `Box` structure we can safely assume any + // aliasing has ended and convert the aliasable `Box` back to into an + // unaliasable `UniqueBox`. + let unique = unsafe { ptr.reclaim_as_unique_box() }; + // Forget the aliasable `Box` so the allocation behind the `UniqueBox` + // is not deallocated. + mem::forget(ptr); + // Return the `UniqueBox`. + unique + } + + /// Convert a pinned [`AliasableBox`] to a `core::ptr::Unique` backed pinned + /// [`UniqueBox`]. + pub fn into_unique_pin(pin: Pin<AliasableBox<T>>) -> Pin<UniqueBox<T>> { + // SAFETY: The pointer is not changed, just the container. + unsafe { + let aliasable = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(AliasableBox::into_unique(aliasable)) + } + } + + /// Convert a pinned `core::ptr::Unique` backed [`UniqueBox`] to a + /// pinned [`AliasableBox`]. + pub fn from_unique_pin(pin: Pin<UniqueBox<T>>) -> Pin<AliasableBox<T>> { + // SAFETY: The pointer is not changed, just the container. + unsafe { + let unique = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(AliasableBox::from(unique)) + } + } + + #[inline] + unsafe fn reclaim_as_unique_box(&mut self) -> UniqueBox<T> { + UniqueBox::from_raw(self.0.as_ptr()) + } +} + +impl<T: ?Sized> From<UniqueBox<T>> for AliasableBox<T> { + fn from(ptr: UniqueBox<T>) -> Self { + Self::from_unique(ptr) + } +} + +impl<T: ?Sized> Drop for AliasableBox<T> { + fn drop(&mut self) { + // SAFETY: As `self` is being dropped we can safely assume any aliasing + // has ended and convert the `AliasableBox` back to into an unaliasable + // `UniqueBox` to handle the deallocation. + let _ = unsafe { self.reclaim_as_unique_box() }; + } +} + +impl<T: ?Sized> Deref for AliasableBox<T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + // SAFETY: We own the data, so we can return a reference to it. + unsafe { self.0.as_ref() } + } +} + +impl<T: ?Sized> DerefMut for AliasableBox<T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + // SAFETY: We own the data, so we can return a reference to it. + unsafe { self.0.as_mut() } + } +} + +impl<T: ?Sized> AsRef<T> for AliasableBox<T> { + #[inline] + fn as_ref(&self) -> &T { + &*self + } +} + +impl<T: ?Sized> AsMut<T> for AliasableBox<T> { + fn as_mut(&mut self) -> &mut T { + &mut *self + } +} + +impl<T: ?Sized> fmt::Debug for AliasableBox<T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_ref(), f) + } +} + +unsafe impl<T: ?Sized> Send for AliasableBox<T> where T: Send {} +unsafe impl<T: ?Sized> Sync for AliasableBox<T> where T: Sync {} + +#[cfg(feature = "traits")] +unsafe impl<T: ?Sized> crate::StableDeref for AliasableBox<T> {} + +#[cfg(feature = "traits")] +unsafe impl<T: ?Sized> crate::AliasableDeref for AliasableBox<T> {} + +#[cfg(test)] +mod tests { + use super::{AliasableBox, UniqueBox}; + use alloc::format; + + #[test] + fn test_new() { + let aliasable = AliasableBox::from_unique(UniqueBox::new(10)); + assert_eq!(*aliasable, 10); + let unique = AliasableBox::into_unique(aliasable); + assert_eq!(*unique, 10); + } + + #[test] + fn test_new_pin() { + let aliasable = AliasableBox::from_unique_pin(UniqueBox::pin(10)); + assert_eq!(*aliasable, 10); + let unique = AliasableBox::into_unique_pin(aliasable); + assert_eq!(*unique, 10); + } + + #[test] + fn test_refs() { + let mut aliasable = AliasableBox::from_unique(UniqueBox::new(10)); + let ptr: *const u8 = &*aliasable; + let as_mut_ptr: *const u8 = aliasable.as_mut(); + let as_ref_ptr: *const u8 = aliasable.as_ref(); + assert_eq!(ptr, as_mut_ptr); + assert_eq!(ptr, as_ref_ptr); + } + + #[test] + fn test_debug() { + let aliasable = AliasableBox::from_unique(UniqueBox::new(10)); + assert_eq!(format!("{:?}", aliasable), "10"); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f96c25a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,60 @@ +//! Basic aliasable (non `core::ptr::Unique`) types. +//! +//! # Why? +//! +//! Used for escaping `noalias` when multiple raw pointers may point to the same +//! data. + +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![forbid( + clippy::pedantic, + rust_2018_idioms, + anonymous_parameters, + unused_qualifications, + missing_docs, + trivial_casts, + trivial_numeric_casts, + unstable_features, + unused_extern_crates, + unused_import_braces, + unused_results, + warnings +)] +#![allow( + clippy::needless_pass_by_value, + clippy::wrong_self_convention, + clippy::must_use_candidate, + clippy::module_name_repetitions +)] + +#[cfg(any(test, feature = "alloc"))] +extern crate alloc; + +mod mut_ref; + +#[cfg(feature = "alloc")] +pub mod boxed; +#[cfg(feature = "alloc")] +pub mod string; +#[cfg(feature = "alloc")] +pub mod vec; + +pub use crate::mut_ref::AliasableMut; + +/// Export of all types enabled. +pub mod prelude { + #[cfg(feature = "alloc")] + pub use crate::boxed::*; + #[cfg(feature = "alloc")] + pub use crate::string::*; + #[cfg(feature = "alloc")] + pub use crate::vec::*; + + pub use crate::mut_ref::*; +} + +#[cfg(feature = "traits")] +pub use aliasable_deref_trait::AliasableDeref; +#[cfg(feature = "traits")] +pub use stable_deref_trait::StableDeref; diff --git a/src/mut_ref.rs b/src/mut_ref.rs new file mode 100644 index 0000000..c901db3 --- /dev/null +++ b/src/mut_ref.rs @@ -0,0 +1,160 @@ +//! Aliasable `&mut`. + +use core::fmt; +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::ptr::NonNull; + +/// Basic aliasable alternative to `&mut`. +/// +/// Note that this does not circumvent the core aliasing rules of Rust; if you use this to create +/// multiple mutable references to a memory location at the same time, that is still UB. This type +/// just adds a few abilities: +/// +/// - You may hold any number of `AliasableMut`s and no references to a location. +/// - You may hold any number of `AliasableMut`s and any number of shared references to a location +/// at once. +/// - You may hold any number of `AliasableMut`s and one mutable reference to a location at once. +pub struct AliasableMut<'a, T: ?Sized> { + inner: NonNull<T>, + _lifetime: PhantomData<&'a ()>, +} + +impl<'a, T: ?Sized> AliasableMut<'a, T> { + /// Construct an `AliasableMut` from an `&mut`. + #[inline] + pub fn from_unique(ptr: &'a mut T) -> Self { + Self { + inner: NonNull::from(ptr), + _lifetime: PhantomData, + } + } + + /// Consumes `self` and converts it into a non-aliasable `&mut`. + #[inline] + pub fn into_unique(ptr: Self) -> &'a mut T { + unsafe { &mut *ptr.inner.as_ptr() } + } + + /// Convert a pinned `AliasableMut` to a pinned `&mut`. + pub fn into_unique_pin(pin: Pin<Self>) -> Pin<&'a mut T> { + // SAFETY: The pointer is not changed, just the container. + unsafe { + let aliasable = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(Self::into_unique(aliasable)) + } + } + + /// Convert a pinned `&mut` to a pinned `AliasableMut`. + pub fn from_unique_pin(pin: Pin<&'a mut T>) -> Pin<Self> { + // SAFETY: The pointer is not changed, just the container. + unsafe { + let unique = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(Self::from_unique(unique)) + } + } +} + +impl<'a, T: ?Sized> From<&'a mut T> for AliasableMut<'a, T> { + fn from(ptr: &'a mut T) -> Self { + Self::from_unique(ptr) + } +} + +impl<T: ?Sized> Deref for AliasableMut<'_, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + // SAFETY: It is the callers responsibility to make sure that there are no `&mut` + // references at this point. + unsafe { self.inner.as_ref() } + } +} + +impl<T: ?Sized> DerefMut for AliasableMut<'_, T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: It is the callers responsibility to make sure that there are no `&mut` + // references at this point. + unsafe { self.inner.as_mut() } + } +} + +impl<T: ?Sized> AsRef<T> for AliasableMut<'_, T> { + #[inline] + fn as_ref(&self) -> &T { + self + } +} + +impl<T: ?Sized> AsMut<T> for AliasableMut<'_, T> { + #[inline] + fn as_mut(&mut self) -> &mut T { + self + } +} + +impl<T: ?Sized> fmt::Debug for AliasableMut<'_, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +unsafe impl<T: ?Sized> Send for AliasableMut<'_, T> where T: Send {} +unsafe impl<T: ?Sized> Sync for AliasableMut<'_, T> where T: Sync {} + +#[cfg(feature = "traits")] +unsafe impl<T: ?Sized> crate::StableDeref for AliasableMut<'_, T> {} + +#[cfg(feature = "traits")] +unsafe impl<T: ?Sized> crate::AliasableDeref for AliasableMut<'_, T> {} + +#[cfg(test)] +mod tests { + use super::AliasableMut; + use alloc::boxed::Box; + use alloc::format; + use core::pin::Pin; + + #[test] + fn test_new() { + let mut data = Box::new(10); + let aliasable = AliasableMut::from_unique(&mut data); + assert_eq!(**aliasable, 10); + let unique = AliasableMut::into_unique(aliasable); + assert_eq!(**unique, 10); + } + + #[test] + fn test_new_pin() { + let mut data = Box::new(10); + let data = unsafe { Pin::new_unchecked(&mut data) }; + let aliasable = AliasableMut::from_unique_pin(data); + assert_eq!(**aliasable, 10); + let unique = AliasableMut::into_unique_pin(aliasable); + assert_eq!(**unique, 10); + } + + #[test] + fn test_refs() { + let mut data = Box::new(10); + let mut aliasable = AliasableMut::from_unique(&mut data); + let ptr: *const Box<u8> = &mut *aliasable; + let as_mut_ptr: *const Box<u8> = aliasable.as_mut(); + let as_ref_ptr: *const Box<u8> = aliasable.as_ref(); + assert_eq!(ptr, as_mut_ptr); + assert_eq!(ptr, as_ref_ptr); + } + + #[test] + fn test_debug() { + let mut data = 10; + let aliasable = AliasableMut::from_unique(&mut data); + assert_eq!(format!("{:?}", aliasable), "10"); + } +} diff --git a/src/string.rs b/src/string.rs new file mode 100644 index 0000000..f9864af --- /dev/null +++ b/src/string.rs @@ -0,0 +1,157 @@ +//! Aliasable `String`. + +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::{fmt, str}; + +use crate::vec::AliasableVec; + +pub use alloc::string::String as UniqueString; + +/// Basic aliasable (non `core::ptr::Unique`) alternative to +/// [`alloc::string::String`]. +pub struct AliasableString(AliasableVec<u8>); + +impl AliasableString { + /// Consumes `self` into an [`AliasableVec`] of UTF-8 bytes. + pub fn into_bytes(self) -> AliasableVec<u8> { + self.0 + } + + /// Construct an `AliasableString` from a [`UniqueString`]. + pub fn from_unique(s: UniqueString) -> Self { + Self(s.into_bytes().into()) + } + + /// Consumes `self` and converts it into a non-aliasable [`UniqueString`]. + #[inline] + pub fn into_unique(s: AliasableString) -> UniqueString { + let unique_bytes = s.into_bytes().into(); + unsafe { UniqueString::from_utf8_unchecked(unique_bytes) } + } + + /// Convert a pinned [`AliasableString`] to a `core::ptr::Unique` backed pinned + /// [`UniqueString`]. + pub fn into_unique_pin(pin: Pin<AliasableString>) -> Pin<UniqueString> { + // SAFETY: The pointer is not changed, just the container. + unsafe { + let aliasable = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(AliasableString::into_unique(aliasable)) + } + } + + /// Convert a pinned `core::ptr::Unique` backed [`UniqueString`] to a + /// pinned [`AliasableString`]. + pub fn from_unique_pin(pin: Pin<UniqueString>) -> Pin<AliasableString> { + // SAFETY: The pointer is not changed, just the container. + unsafe { + let unique = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(AliasableString::from(unique)) + } + } +} + +impl From<UniqueString> for AliasableString { + #[inline] + fn from(s: UniqueString) -> Self { + Self::from_unique(s) + } +} + +impl From<AliasableString> for UniqueString { + #[inline] + fn from(s: AliasableString) -> Self { + AliasableString::into_unique(s) + } +} + +impl Deref for AliasableString { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + // SAFETY: `AliasableString` will only ever contain UTF-8. + unsafe { str::from_utf8_unchecked(&*self.0) } + } +} + +impl DerefMut for AliasableString { + #[inline] + fn deref_mut(&mut self) -> &mut str { + // SAFETY: `AliasableString` will only ever contain UTF-8. + unsafe { str::from_utf8_unchecked_mut(&mut *self.0) } + } +} + +impl AsRef<str> for AliasableString { + #[inline] + fn as_ref(&self) -> &str { + &*self + } +} + +impl AsMut<str> for AliasableString { + fn as_mut(&mut self) -> &mut str { + &mut *self + } +} + +impl fmt::Debug for AliasableString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_ref(), f) + } +} + +#[cfg(feature = "traits")] +unsafe impl crate::StableDeref for AliasableString {} + +#[cfg(feature = "traits")] +unsafe impl crate::AliasableDeref for AliasableString {} + +#[cfg(test)] +mod tests { + use super::{AliasableString, AliasableVec, UniqueString}; + use alloc::{format, vec}; + use core::pin::Pin; + + #[test] + fn test_new() { + let aliasable = AliasableString::from_unique(UniqueString::from("hello")); + assert_eq!(&*aliasable, &"hello"[..]); + let unique = AliasableString::into_unique(aliasable); + assert_eq!(&*unique, &"hello"[..]); + } + + #[test] + fn test_new_pin() { + let aliasable = AliasableString::from_unique_pin(Pin::new(UniqueString::from("hello"))); + assert_eq!(&*aliasable, &"hello"[..]); + let unique = AliasableString::into_unique_pin(aliasable); + assert_eq!(&*unique, &"hello"[..]); + } + + #[test] + fn test_refs() { + let mut aliasable = AliasableString::from_unique(UniqueString::from("hello")); + let ptr: *const str = &*aliasable; + let as_mut_ptr: *const str = aliasable.as_mut(); + let as_ref_ptr: *const str = aliasable.as_ref(); + assert_eq!(ptr, as_mut_ptr); + assert_eq!(ptr, as_ref_ptr); + } + + #[test] + fn test_debug() { + let aliasable = AliasableString::from_unique(UniqueString::from("hello")); + assert_eq!(format!("{:?}", aliasable), "\"hello\""); + } + + #[test] + fn test_into_bytes() { + let aliasable = AliasableString::from_unique(UniqueString::from("hello")); + assert_eq!( + AliasableVec::into_unique(aliasable.into_bytes()), + vec![b'h', b'e', b'l', b'l', b'o'] + ); + } +} diff --git a/src/vec.rs b/src/vec.rs new file mode 100644 index 0000000..d6abb5d --- /dev/null +++ b/src/vec.rs @@ -0,0 +1,180 @@ +//! Aliasable `Vec`. + +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::ptr::NonNull; +use core::{fmt, mem, slice}; + +pub use alloc::vec::Vec as UniqueVec; + +/// Basic aliasable (non `core::ptr::Unique`) alternative to +/// [`alloc::vec::Vec`]. +pub struct AliasableVec<T> { + ptr: NonNull<T>, + len: usize, + cap: usize, +} + +impl<T> AliasableVec<T> { + /// Construct an `AliasableVec` from a [`UniqueVec`]. + pub fn from_unique(mut vec: UniqueVec<T>) -> Self { + let ptr = vec.as_mut_ptr(); + let len = vec.len(); + let cap = vec.capacity(); + + mem::forget(vec); + + let ptr = unsafe { NonNull::new_unchecked(ptr) }; + + Self { ptr, len, cap } + } + + /// Consumes the [`AliasableVec`] and converts it back into a + /// non-aliasable [`UniqueVec`]. + #[inline] + pub fn into_unique(mut vec: AliasableVec<T>) -> UniqueVec<T> { + // SAFETY: As we are consuming the `Vec` structure we can safely assume + // any aliasing has ended and convert the aliasable `Vec` back to into + // an unaliasable `UniqueVec`. + let unique = unsafe { vec.reclaim_as_unique_vec() }; + // Forget the aliasable `Vec` so the allocation behind the `UniqueVec` + // is not deallocated. + mem::forget(vec); + // Return the `UniqueVec`. + unique + } + + /// Convert a pinned [`AliasableVec`] to a `core::ptr::Unique` backed pinned + /// [`UniqueVec`]. + pub fn into_unique_pin(pin: Pin<AliasableVec<T>>) -> Pin<UniqueVec<T>> { + // SAFETY: The pointer is not changed, just the container. + unsafe { + let aliasable = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(AliasableVec::into_unique(aliasable)) + } + } + + /// Convert a pinned `core::ptr::Unique` backed [`UniqueVec`] to a + /// pinned [`AliasableVec`]. + pub fn from_unique_pin(pin: Pin<UniqueVec<T>>) -> Pin<AliasableVec<T>> { + unsafe { + let unique = Pin::into_inner_unchecked(pin); + Pin::new_unchecked(AliasableVec::from(unique)) + } + } + + #[inline] + unsafe fn reclaim_as_unique_vec(&mut self) -> UniqueVec<T> { + UniqueVec::from_raw_parts(self.ptr.as_mut(), self.len, self.cap) + } +} + +impl<T> From<UniqueVec<T>> for AliasableVec<T> { + #[inline] + fn from(vec: UniqueVec<T>) -> Self { + Self::from_unique(vec) + } +} + +impl<T> From<AliasableVec<T>> for UniqueVec<T> { + #[inline] + fn from(vec: AliasableVec<T>) -> Self { + AliasableVec::into_unique(vec) + } +} + +impl<T> Drop for AliasableVec<T> { + fn drop(&mut self) { + // As the `Vec` structure is being dropped we can safely assume any + // aliasing has ended and convert the aliasable `Vec` back to into an + // unaliasable `UniqueVec` to handle the deallocation. + let _ = unsafe { self.reclaim_as_unique_vec() }; + } +} + +impl<T> Deref for AliasableVec<T> { + type Target = [T]; + + #[inline] + fn deref(&self) -> &[T] { + // SAFETY: We own the data, so we can return a reference to it. + unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) } + } +} + +impl<T> DerefMut for AliasableVec<T> { + #[inline] + fn deref_mut(&mut self) -> &mut [T] { + // SAFETY: We own the data, so we can return a reference to it. + unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) } + } +} + +impl<T> AsRef<[T]> for AliasableVec<T> { + fn as_ref(&self) -> &[T] { + &*self + } +} + +impl<T> AsMut<[T]> for AliasableVec<T> { + fn as_mut(&mut self) -> &mut [T] { + &mut *self + } +} + +impl<T> fmt::Debug for AliasableVec<T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_ref(), f) + } +} + +unsafe impl<T> Send for AliasableVec<T> where T: Send {} +unsafe impl<T> Sync for AliasableVec<T> where T: Sync {} + +#[cfg(feature = "traits")] +unsafe impl<T> crate::StableDeref for AliasableVec<T> {} + +#[cfg(feature = "traits")] +unsafe impl<T> crate::AliasableDeref for AliasableVec<T> {} + +#[cfg(test)] +mod tests { + use super::AliasableVec; + use alloc::{format, vec}; + use core::pin::Pin; + + #[test] + fn test_new() { + let aliasable = AliasableVec::from_unique(vec![10]); + assert_eq!(&*aliasable, &[10]); + let unique = AliasableVec::into_unique(aliasable); + assert_eq!(&*unique, &[10]); + } + + #[test] + fn test_new_pin() { + let aliasable = AliasableVec::from_unique_pin(Pin::new(vec![10])); + assert_eq!(&*aliasable, &[10]); + let unique = AliasableVec::into_unique_pin(aliasable); + assert_eq!(&*unique, &[10]); + } + + #[test] + fn test_refs() { + let mut aliasable = AliasableVec::from_unique(vec![10]); + let ptr: *const [u8] = &*aliasable; + let as_mut_ptr: *const [u8] = aliasable.as_mut(); + let as_ref_ptr: *const [u8] = aliasable.as_ref(); + assert_eq!(ptr, as_mut_ptr); + assert_eq!(ptr, as_ref_ptr); + } + + #[test] + fn test_debug() { + let aliasable = AliasableVec::from_unique(vec![10]); + assert_eq!(format!("{:?}", aliasable), "[10]"); + } +} |