ptr_meta-0.3.0/.cargo_vcs_info.json0000644000000001460000000000100126500ustar { "git": { "sha1": "3e8aed87089acfa5218465c79bcbba993e269d07" }, "path_in_vcs": "ptr_meta" }ptr_meta-0.3.0/Cargo.toml0000644000000022420000000000100106450ustar # 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 are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.81" name = "ptr_meta" version = "0.3.0" authors = ["David Koloski "] build = false autobins = false autoexamples = false autotests = false autobenches = false description = "A radioactive stabilization of the ptr_meta rfc" documentation = "https://docs.rs/ptr_meta" readme = "README.md" keywords = ["no_std"] categories = [ "no-std", "no-std::no-alloc", ] license = "MIT" repository = "https://github.com/rkyv/ptr_meta" [lib] name = "ptr_meta" path = "src/lib.rs" [dependencies.ptr_meta_derive] version = "0.3.0" optional = true default-features = false [features] default = [ "derive", "std", ] derive = ["ptr_meta_derive"] std = [] ptr_meta-0.3.0/Cargo.toml.orig000064400000000000000000000011531046102023000143260ustar 00000000000000[package] name = "ptr_meta" description = "A radioactive stabilization of the ptr_meta rfc" version.workspace = true authors.workspace = true edition.workspace = true rust-version.workspace = true license.workspace = true readme.workspace = true repository.workspace = true keywords.workspace = true categories.workspace = true documentation = "https://docs.rs/ptr_meta" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ptr_meta_derive = { workspace = true, optional = true } [features] default = ["derive", "std"] derive = ["ptr_meta_derive"] std = [] ptr_meta-0.3.0/LICENSE000064400000000000000000000020351046102023000124440ustar 00000000000000Copyright 2021 David Koloski 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. ptr_meta-0.3.0/README.md000064400000000000000000000040101046102023000127110ustar 00000000000000# `ptr_meta` [![crates.io badge]][crates.io] [![docs badge]][docs] [![license badge]][license] [crates.io badge]: https://img.shields.io/crates/v/ptr_meta.svg [crates.io]: https://crates.io/crates/ptr_meta [docs badge]: https://img.shields.io/docsrs/ptr_meta [docs]: https://docs.rs/ptr_meta [license badge]: https://img.shields.io/badge/license-MIT-blue.svg [license]: https://github.com/rkyv/ptr_meta/blob/master/LICENSE A radioactive stabilization of the [`ptr_meta` RFC]. [`ptr_meta` RFC]: https://rust-lang.github.io/rfcs/2580-ptr-meta.html ## Documentation - [ptr_meta](https://docs.rs/ptr_meta), the core library - [ptr_meta_derive](https://docs.rs/ptr_meta_derive), proc macros for implementing `Pointee` for structs and trait objects ## Example ```rust // Get the associated metadata for pointers let str = "hello world"; assert_eq!(ptr_meta::metadata(str), str.len()); let slice = &[1, 2, 3, 4, 5] as &[i32]; assert_eq!(ptr_meta::metadata(slice), slice.len()); // Make your own wide pointers from data pointers and metadata let bytes = [b'h', b'e', b'l', b'l', b'o']; let ptr = ptr_meta::from_raw_parts::(bytes.as_ptr().cast(), 5); println!("{} world!", unsafe { &*ptr }); // prints "hello world!" // Derive Pointee on your own types #[derive(ptr_meta::Pointee)] #[repr(transparent)] struct CoolStr { inner: str, } impl CoolStr { fn print_cool(&self) { println!("😎 {} 😎", &self.inner); } } let ptr = ptr_meta::from_raw_parts::(bytes.as_ptr().cast(), 5); let cool = unsafe { &*ptr }; cool.print_cool(); // prints "😎 hello 😎" // Implement Pointee for trait objects #[ptr_meta::pointee] trait Printable { fn print(&self); } impl Printable for i32 { fn print(&self) { println!("i32: {self}"); } } let i32_vtable = ptr_meta::metadata(&0i32 as &dyn Printable); let one_hundred = 100i32; let printable = ptr_meta::from_raw_parts::( (&one_hundred as *const i32).cast(), i32_vtable, ); unsafe { (*printable).print(); // prints "i32: 100" } ``` ptr_meta-0.3.0/example.md000064400000000000000000000025001046102023000134110ustar 00000000000000```rust // Get the associated metadata for pointers let str = "hello world"; assert_eq!(ptr_meta::metadata(str), str.len()); let slice = &[1, 2, 3, 4, 5] as &[i32]; assert_eq!(ptr_meta::metadata(slice), slice.len()); // Make your own wide pointers from data pointers and metadata let bytes = [b'h', b'e', b'l', b'l', b'o']; let ptr = ptr_meta::from_raw_parts::(bytes.as_ptr().cast(), 5); println!("{} world!", unsafe { &*ptr }); // prints "hello world!" // Derive Pointee on your own types #[derive(ptr_meta::Pointee)] #[repr(transparent)] struct CoolStr { inner: str, } impl CoolStr { fn print_cool(&self) { println!("😎 {} 😎", &self.inner); } } let ptr = ptr_meta::from_raw_parts::(bytes.as_ptr().cast(), 5); let cool = unsafe { &*ptr }; cool.print_cool(); // prints "😎 hello 😎" // Implement Pointee for trait objects #[ptr_meta::pointee] trait Printable { fn print(&self); } impl Printable for i32 { fn print(&self) { println!("i32: {self}"); } } let i32_vtable = ptr_meta::metadata(&0i32 as &dyn Printable); let one_hundred = 100i32; let printable = ptr_meta::from_raw_parts::( (&one_hundred as *const i32).cast(), i32_vtable, ); unsafe { (*printable).print(); // prints "i32: 100" } ``` ptr_meta-0.3.0/src/impls.rs000064400000000000000000000027721046102023000137300ustar 00000000000000use core::{any::Any, error::Error}; use crate::{DynMetadata, Pointee}; // SAFETY: The metadata type of `dyn Any` is `DynMetadata`. unsafe impl Pointee for dyn Any { type Metadata = DynMetadata; } // SAFETY: The metadata type of `dyn Any + Send` is // `DynMetadata`. unsafe impl Pointee for dyn Any + Send { type Metadata = DynMetadata; } // SAFETY: The metadata type of `dyn Any + Sync` is // `DynMetadata`. unsafe impl Pointee for dyn Any + Sync { type Metadata = DynMetadata; } // SAFETY: The metadata type of `dyn Any + Send + Sync` is // `DynMetadata`. unsafe impl Pointee for dyn Any + Send + Sync { type Metadata = DynMetadata; } // SAFETY: The metadata type of `dyn Error` is `DynMetadata`. unsafe impl Pointee for dyn Error { type Metadata = DynMetadata; } // SAFETY: The metadata type of `dyn Error + Send` is // `DynMetadata`. unsafe impl Pointee for dyn Error + Send { type Metadata = DynMetadata; } // SAFETY: The metadata type of `dyn Error + Sync` is // `DynMetadata`. unsafe impl Pointee for dyn Error + Sync { type Metadata = DynMetadata; } // SAFETY: The metadata type of `dyn Error + Send + Sync` is // `DynMetadata`. unsafe impl Pointee for dyn Error + Send + Sync { type Metadata = DynMetadata; } ptr_meta-0.3.0/src/lib.rs000064400000000000000000000377551046102023000133630ustar 00000000000000//! A radioactive stabilization of the [`ptr_meta` RFC][rfc]. //! //! This crate provides the [`Pointee`] trait, [`from_raw_parts`] and //! [`to_raw_parts`] functions, and proc macros for deriving `Pointee` for //! structs and implementing `Pointee` for trait objects. //! //! [rfc]: https://rust-lang.github.io/rfcs/2580-ptr-meta.html //! //! # Usage //! //! Raw pointers can be decomposed into the data address and metadata components //! with [`to_raw_parts`] or [`to_raw_parts_mut`]. //! //! Alternatively, metadata alone can be extracted with the [`metadata`] //! function. Although [`metadata`] accepts pointers, references can be passed //! and will be implicitly coerced. //! //! A pointer can be created from its address and metadata with //! [`from_raw_parts`] or [`from_raw_parts_mut`]. //! //! ## Provided impls //! //! `ptr_meta` provides inherent implementations for many builtin types: //! //! - All [`Sized`] types implement [`Pointee`] via a blanket implementation. //! - `slice`, `str`, and `CStr` //! - `OsStr` (requires `std`) //! - `dyn Any`, optionally with `+ Send` and/or `+ Sync` //! - `dyn Error`, optionally with `+ Send` and/or `+ Sync` //! //! ## Structs with trailing DSTs //! //! You can derive [`Pointee`] for structs with trailing DSTs: //! //! ``` //! use ptr_meta::Pointee; //! //! #[derive(Pointee)] //! struct Block { //! header: H, //! elements: [T], //! } //! ``` //! //! Note that the last field is required to be a DST. Structs with a generic //! type as the last field may have conflicting blanket implementations, as the //! generic type may be `Sized`. A collection of specific implementations may be //! required in these cases, with the generic parameter set (for example) a //! slice, `str`, or specific trait object. //! //! ## Trait objects //! //! You can generate [`Pointee`] implementations for trait objects: //! //! ``` //! use ptr_meta::pointee; //! //! // Generates Pointee for dyn Stringy //! #[ptr_meta::pointee] //! trait Stringy { //! fn as_string(&self) -> String; //! } //! ``` //! //! Note that this will not produce implementations for `Trait + Send + Sync`. //! //! ## Features //! //! - `derive`: Re-exports the macros from `ptr_meta_derive`. Enabled by //! default. //! - `std`: Enables additional impls for `std` types. Enabled by default. //! //! ## Example #![doc = include_str!("../example.md")] #![deny( future_incompatible, missing_docs, nonstandard_style, unsafe_op_in_unsafe_fn, unused, warnings, clippy::all, clippy::missing_safety_doc, clippy::undocumented_unsafe_blocks, rustdoc::broken_intra_doc_links, rustdoc::missing_crate_level_docs )] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(all(docsrs, not(doctest)), feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(miri, allow(internal_features), feature(core_intrinsics))] mod impls; use core::{ ffi::CStr, fmt, hash::{Hash, Hasher}, }; #[cfg(feature = "derive")] pub use ptr_meta_derive::{pointee, Pointee}; /// A trait which associates pointer metadata with a pointee type. /// /// # Pointer metadata /// /// Pointers and references can be thought of as having two parts: a data /// address and some extra "pointer metadata". /// /// Pointers to [statically-sized types](`Sized`) and `extern` types are /// "narrow": their pointer metadata is `()`. /// /// Pointers to [dynamically-sized types][dst] are "wide": they have pointer /// metadata with a non-zero size. There are four classes of dynamically-sized /// types currently available: /// /// * `str`s have `usize` pointer metadata equal to the length of the string /// slice in bytes. /// * Slices like `[i32]` have `usize` pointer metadata equal to the length of /// the slice in items. /// * Trait objects like `dyn SomeTrait` have [`DynMetadata`] pointer metadata, /// which point to the trait objects' virtual method tables. /// * Structs with a trailing DST have the same metadata as the trailing DST. /// /// In the future, Rust may add new kinds of types which have different pointer /// metadata. /// /// [dst]: https://doc.rust-lang.org/reference/dynamically-sized-types.html /// /// # Safety /// /// The associated `Metadata` type must be the pointer metadata type for the /// implementing type. pub unsafe trait Pointee { /// The metadata type for pointers and references to this type. type Metadata: Copy + Send + Sync + Ord + Hash + Unpin; } // SAFETY: Pointers to `Sized` types have no metadata (i.e. their metadata is // the unit type `()`). unsafe impl Pointee for T { type Metadata = (); } // SAFETY: Pointers to slices have a `usize` representing the length of the // slice in elements as their metadata. unsafe impl Pointee for [T] { type Metadata = usize; } // SAFETY: String slice pointers have a `usize` representing the length of the // string slice in bytes as their metadata. unsafe impl Pointee for str { type Metadata = usize; } // SAFETY: `CStr` pointers have a `usize` representing the length of the // C-string slice in bytes (nul included) as their metadata. unsafe impl Pointee for CStr { type Metadata = usize; } #[cfg(feature = "std")] // SAFETY: `OsStr` pointers have a `usize` representing the length of the // string in bytes as their metadata. unsafe impl Pointee for std::ffi::OsStr { type Metadata = usize; } /// Returns the metadata of the given pointer. /// /// `*mut T`, `&T`, and `&mut T` can all be passed directly to this function as /// they implicitly coerce to `*const T`. /// /// # Example /// /// ``` /// // String slices have pointer metadata equal to their size in bytes /// assert_eq!(ptr_meta::metadata("foo"), 3_usize); /// ``` #[inline] pub const fn metadata( ptr: *const T, ) -> ::Metadata { // SAFETY: Accessing the value from the `PtrRepr` union is safe since // *const T and PtrComponents have the same memory layouts. Only std can // make this guarantee. unsafe { PtrRepr { const_ptr: ptr }.components.metadata } } /// Returns the data address and metadata of the given pointer. /// /// `*mut T`, `&T`, and `&mut T` can all be passed directly to this function as /// they implicitly coerce to `*const T`. /// /// # Example /// /// ``` /// let (data_address, metadata) = ptr_meta::to_raw_parts("foo"); /// assert_ne!(data_address, core::ptr::null()); /// assert_eq!(metadata, 3); /// ``` #[inline] pub const fn to_raw_parts( ptr: *const T, ) -> (*const (), ::Metadata) { (ptr as *const (), metadata(ptr)) } /// Returns the mutable data address and metadata of the given pointer. /// /// See [`to_raw_parts`] for more details. #[inline] pub const fn to_raw_parts_mut( ptr: *mut T, ) -> (*mut (), ::Metadata) { (ptr as *mut (), metadata(ptr)) } /// Returns a raw pointer with the given data address and metadata. /// /// This function is safe, but the returned pointer is not necessarily safe to /// dereference. For slices, see the documentation of [`slice::from_raw_parts`] /// for safety requirements. For trait objects, the metadata must come from a /// a trait object with the same underlying type. /// /// [`slice::from_raw_parts`]: core::slice::from_raw_parts #[inline] pub const fn from_raw_parts( data_address: *const (), metadata: ::Metadata, ) -> *const T { // SAFETY: Accessing the value from the `PtrRepr` union is safe since // *const T and PtrComponents have the same memory layouts. Only std can // make this guarantee. unsafe { PtrRepr { components: PtrComponents { data_address, metadata, }, } .const_ptr } } /// Returns a mutable raw pointer with the given data address and metadata. /// /// See [`from_raw_parts`] for more details. #[inline] pub const fn from_raw_parts_mut( data_address: *mut (), metadata: ::Metadata, ) -> *mut T { // SAFETY: Accessing the value from the `PtrRepr` union is safe since // *const T and PtrComponents have the same memory layouts. Only std can // make this guarantee. unsafe { PtrRepr { components: PtrComponents { data_address, metadata, }, } .mut_ptr } } #[repr(C)] union PtrRepr { const_ptr: *const T, mut_ptr: *mut T, components: PtrComponents, } #[repr(C)] struct PtrComponents { data_address: *const (), metadata: ::Metadata, } // Manual impl needed to avoid `T: Copy` bound. impl Copy for PtrComponents {} // Manual impl needed to avoid `T: Clone` bound. impl Clone for PtrComponents { fn clone(&self) -> Self { *self } } /// The metadata for a trait object. /// /// This struct wraps a pointer to a vtable (virtual method table) which /// contains all of the necessary information to manipulate the concrete type /// stored inside of the trait object: /// /// * The size and alignment of the concrete type /// * A function pointer to the type's `drop_in_place` impl /// * Function pointers for each method in the concrete type's trait /// implementation /// /// Providing a type argument that is not a `dyn` trait object is possible, but /// does not correspond with a meaningful type. pub struct DynMetadata { vtable_ptr: &'static VTable, phantom: core::marker::PhantomData, } // Extern types are not stable, so we substitute a ZST. This is not a perfect // substitute but it's not exposed anywhere so it's close enough. struct VTable; impl DynMetadata { /// Returns the size of the type associated with this metadata. #[inline] pub fn size_of(self) -> usize { #[cfg(miri)] { // Note that "size stored in vtable" is *not* the same as "result of // size_of_val_raw". Consider a reference like `&(i32, // dyn Send)`: the vtable will only store the size of the // `Send` part! // SAFETY: DynMetadata always contains a valid vtable pointer return unsafe { core::intrinsics::vtable_size( self.vtable_ptr as *const VTable as *const (), ) }; } #[cfg(not(miri))] { // SAFETY: This happens to be true. It may not always be true. The // location of the size for vtables is based on the implementation // of the vtable_size intrinsic. unsafe { (self.vtable_ptr as *const VTable as *const usize) .add(1) .read() } } } /// Returns the alignment of the type associated with this metadata. #[inline] pub fn align_of(self) -> usize { #[cfg(miri)] { // SAFETY: DynMetadata always contains a valid vtable pointer return unsafe { core::intrinsics::vtable_align( self.vtable_ptr as *const VTable as *const (), ) }; } #[cfg(not(miri))] { // SAFETY: This happens to be true. It may not always be true. The // location of the alignment for vtables is based on the // implementation of the vtable_align intrinsic. unsafe { (self.vtable_ptr as *const VTable as *const usize) .add(2) .read() } } } /// Returns the layout of the type associated with this metadata. #[inline] pub fn layout(self) -> core::alloc::Layout { // SAFETY: the compiler emitted this vtable for a concrete Rust type // which is known to have a valid layout. Same rationale as in // `Layout::for_value`. unsafe { core::alloc::Layout::from_size_align_unchecked( self.size_of(), self.align_of(), ) } } } // SAFETY: References to trait object vtables are guaranteed to be `Send`. unsafe impl Send for DynMetadata {} // SAFETY: References to trait object vtables are guaranteed to be `Sync`. unsafe impl Sync for DynMetadata {} impl fmt::Debug for DynMetadata { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("DynMetadata") .field(&(self.vtable_ptr as *const VTable)) .finish() } } // Manual impls needed to avoid `Dyn: $Trait` bounds. impl Unpin for DynMetadata {} impl Copy for DynMetadata {} impl Clone for DynMetadata { #[inline] fn clone(&self) -> Self { *self } } impl Eq for DynMetadata {} impl PartialEq for DynMetadata { #[inline] fn eq(&self, other: &Self) -> bool { core::ptr::eq::(self.vtable_ptr, other.vtable_ptr) } } impl Ord for DynMetadata { #[inline] fn cmp(&self, other: &Self) -> core::cmp::Ordering { (self.vtable_ptr as *const VTable) .cmp(&(other.vtable_ptr as *const VTable)) } } impl PartialOrd for DynMetadata { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Hash for DynMetadata { #[inline] fn hash(&self, hasher: &mut H) { core::ptr::hash::(self.vtable_ptr, hasher) } } #[cfg(test)] fn test_pointee(value: &T) { let ptr = value as *const T; let (raw, meta) = to_raw_parts(ptr); let re_ptr = from_raw_parts::(raw, meta); assert_eq!(ptr, re_ptr); } #[cfg(test)] mod tests { use super::test_pointee; #[test] fn sized_types() { test_pointee(&()); test_pointee(&42); test_pointee(&true); test_pointee(&[1, 2, 3, 4]); struct TestUnit; test_pointee(&TestUnit); #[allow(dead_code)] struct TestStruct { a: (), b: i32, c: bool, } test_pointee(&TestStruct { a: (), b: 42, c: true, }); #[allow(dead_code)] struct TestTuple((), i32, bool); test_pointee(&TestTuple((), 42, true)); struct TestGeneric(T); test_pointee(&TestGeneric(42)); } #[test] fn unsized_types() { test_pointee("hello world"); test_pointee(&[1, 2, 3, 4] as &[i32]); } } #[cfg(all(test, feature = "derive"))] mod derive_tests { use core::any::Any; use super::{test_pointee, Pointee}; #[test] fn trait_objects() { #[crate::pointee(crate)] trait TestTrait { #[allow(dead_code)] fn foo(&self); } struct A; impl TestTrait for A { fn foo(&self) {} } let trait_object = &A as &dyn TestTrait; test_pointee(trait_object); #[allow(dead_code)] struct B(i32); impl TestTrait for B { fn foo(&self) {} } let b = B(42); let trait_object = &b as &dyn TestTrait; test_pointee(trait_object); } #[test] fn last_field_dst() { #[allow(dead_code)] #[derive(Pointee)] #[ptr_meta(crate)] struct Test { head: H, tail: [T], } #[allow(dead_code)] #[derive(Pointee)] #[ptr_meta(crate)] struct TestDyn { tail: dyn Any, } #[crate::pointee(crate)] trait TestTrait {} #[allow(dead_code)] #[derive(Pointee)] #[ptr_meta(crate)] struct TestCustomDyn { tail: dyn TestTrait, } } #[test] fn generic_trait() { #[allow(dead_code)] #[crate::pointee(crate)] trait TestTrait {} impl TestTrait for () {} test_pointee(&() as &dyn TestTrait); } }