├── .github ├── FUNDING.yml └── workflows │ └── gh-pages.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── TODO.md ├── book.toml ├── book ├── SUMMARY.md └── rel.md ├── heresy ├── Cargo.toml └── src │ ├── alloc.rs │ ├── boxed.rs │ └── lib.rs ├── macroix ├── Cargo.toml └── src │ ├── attr_value.rs │ ├── case.rs │ ├── lib.rs │ └── repr.rs ├── media ├── logo.png ├── logo.svg ├── logo_color.png ├── logo_color.svg ├── logo_text.png ├── logo_text.svg ├── logo_text_color.png └── logo_text_color.svg ├── mischief ├── Cargo.toml └── src │ ├── frame.rs │ ├── in.rs │ ├── lib.rs │ ├── metadata.rs │ ├── pointer.rs │ ├── region.rs │ ├── slot.rs │ └── unique │ ├── ghost_ref.rs │ ├── mod.rs │ ├── static_ref.rs │ └── token.rs ├── mischief_derive ├── Cargo.toml └── src │ ├── lib.rs │ ├── singleton.rs │ └── unique.rs ├── raw_enum ├── Cargo.toml └── src │ └── lib.rs ├── raw_enum_macro ├── Cargo.toml └── src │ └── lib.rs ├── rel_alloc ├── Cargo.toml ├── bench_tests │ ├── bench.rs │ ├── from_data.rs │ ├── gen.rs │ ├── log │ │ ├── data.rs │ │ └── mod.rs │ ├── mc_savedata │ │ ├── data.rs │ │ └── mod.rs │ ├── mesh │ │ ├── data.rs │ │ └── mod.rs │ └── test.rs └── src │ ├── alloc.rs │ ├── boxed.rs │ ├── emplace_in.rs │ ├── lib.rs │ ├── string.rs │ └── vec.rs ├── rel_core ├── Cargo.toml └── src │ ├── basis.rs │ ├── emplace │ ├── impls.rs │ └── mod.rs │ ├── export.rs │ ├── lib.rs │ ├── move │ ├── impls.rs │ └── mod.rs │ ├── option.rs │ ├── portable.rs │ ├── primitive.rs │ ├── rel_mem.rs │ ├── rel_ptr.rs │ ├── rel_ref.rs │ └── rel_tuple.rs ├── rel_core_derive ├── Cargo.toml └── src │ ├── lib.rs │ ├── move.rs │ └── portable.rs ├── rel_example ├── Cargo.toml └── src │ └── main.rs ├── rel_slab_allocator ├── Cargo.toml └── src │ └── lib.rs ├── rel_util ├── Cargo.toml └── src │ └── lib.rs ├── rustfmt.toml ├── situ ├── Cargo.toml └── src │ ├── alloc │ ├── allocator.rs │ ├── mod.rs │ └── regional.rs │ ├── drop │ ├── impls.rs │ └── mod.rs │ ├── fmt.rs │ ├── lib.rs │ ├── mut.rs │ ├── ops.rs │ ├── owned_val.rs │ ├── pinned.rs │ ├── ref.rs │ ├── str.rs │ └── val.rs └── situ_derive ├── Cargo.toml └── src ├── drop_raw.rs └── lib.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: rkyv -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: GitHub pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | update: 13 | name: Update 14 | if: github.repository == 'rkyv/rel' 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - uses: peaceiris/actions-mdbook@v1 20 | with: 21 | mdbook-version: 'latest' 22 | 23 | - name: Build book 24 | run: mdbook build -d public 25 | 26 | - uses: actions-rs/toolchain@v1 27 | with: 28 | toolchain: stable 29 | 30 | - name: Build crate docs 31 | run: cargo doc --target-dir crate_docs 32 | 33 | - run: mv crate_docs/doc public/docs 34 | 35 | - name: Deploy 36 | uses: peaceiris/actions-gh-pages@v3 37 | with: 38 | github_token: ${{ secrets.GITHUB_TOKEN }} 39 | force_orphan: true 40 | cname: rel.rkyv.org 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "heresy", 4 | "macroix", 5 | "mischief", 6 | "mischief_derive", 7 | "raw_enum", 8 | "raw_enum_macro", 9 | "rel_alloc", 10 | "rel_core", 11 | "rel_core_derive", 12 | "rel_example", 13 | "rel_slab_allocator", 14 | "rel_util", 15 | "situ", 16 | ] 17 | 18 | [profile.bench] 19 | # Uncomment to profile 20 | # debug = true 21 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | rel 3 |

4 |

5 | rel is an object system based on relative pointers 6 |

7 | 8 | _This project is still in its early stages. Development is being done in the open._ 9 | 10 | ## Resources 11 | 12 | - [The book](https://rel.rkyv.org) contains information about the project and its direction. 13 | - [Crate docs](https://rel.rkyv.org/docs/rel_core) are available for all crates in the project and 14 | built continuously from the `main` branch. 15 | 16 | ## What is rel? 17 | 18 | rel is the future object model for [rkyv](https://github.com/rkyv/rkyv) and will enable fully 19 | mutable containers and zero-work serialization and deserialization. It achieves this by providing 20 | value emplacement semantics and a full allocator API for immovable data structures. To that end, rel 21 | also encompasses some relatively novel libraries that may be applicable beyond itself. 22 | 23 | ## What does this mean for rkyv? 24 | 25 | Once development on rel is far enough along, rkyv will be replacing its object model (structures 26 | like `ArchivedVec`, `ArchivedBTreeMap`, and more) with rel. rkyv will become focused on providing 27 | users its familiar derive macros and serialization system for easy entry and exit points from rel's 28 | object system. By formally separating the derive system from the object system, it will be easier 29 | for existing users to migrate from rkyv + rel to a fully rel-based project if they want to. 30 | 31 | ## How can I help? 32 | 33 | rel is currently in the experimental phase and needs more thought and scrutiny to help it mature 34 | into a library that rkyv can move on top of. If you're interested in helping shape the future of 35 | rel, [join rkyv's Discord][discord] to discuss the library. Issues are always welcome as well, and 36 | we'll be using them mostly to track feature development as the project moves towards feature 37 | completeness and stability. 38 | 39 | If you're already an rkyv user, then you may recognize rel as a core component of rkyv's vision for 40 | the 0.8 release. If you want to know more about how your project may be able to leverage rel, then 41 | [visit the Discord][discord] to discuss the future of rkyv and rel. 42 | 43 | [discord]: https://discord.gg/65F6MdnbQh 44 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - [ ] Extension methods for boxy types (e.g. `Box`, `OwnedVal`) that return an `In` (e.g. `deref_in`) 2 | - [ ] Write a rel version of the `rust_serialization_benchmark` benchmarks 3 | - [x] `mesh` first because it is very simple 4 | - [x] `log` 5 | - [*] `minecraft_savedata` for stress testing 6 | - [ ] Intern `RelString` with a custom implementation (instead of using `RelVec`) to speed up serialization 7 | - [ ] Should `In: DerefMut where P: DerefMut, P::Target: Unpin`? 8 | - [ ] Provide some allocators from a crate like `rel_allocator` 9 | - [ ] Extension methods for `RegionalAllocator` and `RawRegionalAllocator` that return an `In` from `Allocate` 10 | - [ ] Add CI checks that: 11 | - [ ] Check formatting 12 | - [ ] Run clippy 13 | - [ ] Run the example 14 | - [ ] Run the example under MIRI with MIRIFLAGS="-Zmiri-strict-provenance" 15 | - [ ] Build docs 16 | 17 | Backlog 18 | - [ ] Write derive macro for `DebugRaw` 19 | - [ ] Make `RegionalAllocator`/`RawRegionalAllocator` less wordy 20 | - [ ] Add `RelMut` to parallel `RefRef` 21 | - [ ] Add support for subslicing in `IndexRaw` and `IndexMutRaw` by adding a `SliceIndex` type 22 | - [ ] Add support for runtime regions by creating a fresh `Unique` value and associating it with an allocated object. Then dynamically check whether a memory segment is located in that region and create an `In` to carry that invariant. 23 | - [ ] Make derive macros optional for all crates? 24 | - [ ] Add more robust testing for `no_std` compatibility 25 | - [ ] Figure out how to provide an `Emplace` derive 26 | - [ ] Maybe `#[derive(Emplace)] #[emplace(RelFoo, RelBar, ...)]` 27 | - [ ] This is supposed to be rkyv's job? 28 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["David Koloski"] 3 | language = "en" 4 | multilingual = false 5 | src = "book" 6 | title = "rel" 7 | 8 | [output.html] 9 | cname = "rel.rkyv.org" 10 | edit-url-template = "https://github.com/rkyv/rel/edit/main/{path}" 11 | -------------------------------------------------------------------------------- /book/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [rel](./rel.md) 4 | -------------------------------------------------------------------------------- /book/rel.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | [rel](https://github.com/rkyv/rel) is an object system for Rust based on relative pointers. 6 | 7 | This book covers the motivation, architecture, and major features of rel and its constituent crates. 8 | 9 | ## Documentation 10 | 11 | ### rel 12 | 13 | - [`rel_core`](https://rel.rkyv.org/docs/rel_core) 14 | - [`rel_alloc`](https://rel.rkyv.org/docs/rel_alloc) 15 | 16 | ### Other crates 17 | 18 | - [`heresy`](https://rel.rkyv.org/docs/heresy) 19 | - [`macroix`](https://rel.rkyv.org/docs/macroix) 20 | - [`mischief`](https://rel.rkyv.org/docs/mischief) 21 | - [`situ`](https://rel.rkyv.org/docs/situ) 22 | -------------------------------------------------------------------------------- /heresy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "heresy" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies.ptr_meta] 7 | version = "0.2" 8 | default-features = false 9 | 10 | [features] 11 | default = ["alloc"] 12 | alloc = [] 13 | -------------------------------------------------------------------------------- /heresy/src/boxed.rs: -------------------------------------------------------------------------------- 1 | //! A pointer type for memory allocation. 2 | 3 | use ::core::{ 4 | alloc::Layout, 5 | fmt::{Debug, Display}, 6 | mem::ManuallyDrop, 7 | ops::{Deref, DerefMut}, 8 | ptr::{read, NonNull}, 9 | }; 10 | 11 | use crate::alloc::Allocator; 12 | #[cfg(feature = "alloc")] 13 | use crate::alloc::Global; 14 | 15 | /// A pointer type for memory allocation. 16 | pub struct Box< 17 | T: ?Sized, 18 | #[cfg(feature = "alloc")] A: Allocator = Global, 19 | #[cfg(not(feature = "alloc"))] A: Allocator, 20 | > { 21 | ptr: NonNull, 22 | alloc: A, 23 | } 24 | 25 | impl Drop for Box { 26 | fn drop(&mut self) { 27 | let layout = Layout::for_value(&**self); 28 | // SAFETY: `self.ptr` is always valid for reads and writes, properly 29 | // aligned, and valid for dropping. 30 | unsafe { 31 | self.ptr.as_ptr().drop_in_place(); 32 | } 33 | // SAFETY: `self.ptr` is always allocated via `self.alloc` and `layout` 34 | // is guaranteed to fit it. 35 | unsafe { 36 | self.alloc.deallocate(self.ptr.cast(), layout); 37 | } 38 | } 39 | } 40 | 41 | impl Box { 42 | /// Constructs a box from a raw pointer in the given allocator. 43 | /// 44 | /// After calling this function, the raw pointer is owned by the resulting 45 | /// `Box`. Specifically, the `Box` destructor will call the destructor of 46 | /// `T` and free the allocated memory. For this to be safe, the memory must 47 | /// have been allocated in accordance with the memory layout used by `Box`. 48 | /// 49 | /// # Safety 50 | /// 51 | /// - `ptr` must point to a memory block currently allocated by `alloc`. 52 | /// - The layout used to allocate `ptr` must exactly match the return value 53 | /// of `Layout::for_value`. 54 | /// - `ptr` must point to an initialized `T`. 55 | pub unsafe fn from_raw_in(ptr: *mut T, alloc: A) -> Self { 56 | Self { 57 | // SAFETY: `ptr` is allocated by `alloc`, and so must not be null. 58 | ptr: unsafe { NonNull::new_unchecked(ptr) }, 59 | alloc, 60 | } 61 | } 62 | 63 | /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. 64 | /// 65 | /// The pointer will be properly aligned and non-null. 66 | /// 67 | /// After calling this function, the caller is responsible for the memory 68 | /// previously managed by the `Box`. In particular, the caller should 69 | /// properly destroy `T` and release the memory, taking into account the 70 | /// memory layout used by `Box`. The easiest way to do this is to convert 71 | /// the raw pointer back into a `Box` with the `Box::from_raw_in` function, 72 | /// allowing the `Box` destructor to perform the cleanup. 73 | /// 74 | /// Note: this is an associated function, which means that you have to call 75 | /// it as `Box::into_raw_with_allocator(b)` instead of 76 | /// `b.into_raw_with_allocator()`. This is so that there is no conflict with 77 | /// a method on the inner type. 78 | pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { 79 | let b = ManuallyDrop::new(b); 80 | // SAFETY: Because it is a reference, `b.alloc` is valid for reads, 81 | // properly aligned, and points to a properly initialized `A`. The 82 | // original will never be accessed or dropped. 83 | (b.ptr.as_ptr(), unsafe { read(&b.alloc) }) 84 | } 85 | } 86 | 87 | impl Box { 88 | /// Allocates memory in the given allocator then places `x` into it. 89 | pub fn new_in(x: T, alloc: A) -> Box { 90 | let ptr = alloc 91 | .allocate(Layout::new::()) 92 | .unwrap() 93 | .as_ptr() 94 | .cast::(); 95 | // SAFETY: `ptr` is guaranteed to be properly aligned for a `T` and 96 | // valid for writes because we just allocated it. 97 | unsafe { 98 | ptr.write(x); 99 | } 100 | // SAFETY: We allocated `ptr` in `alloc` with the layout of `T` and 101 | // initialized it by writing `x`. 102 | unsafe { Self::from_raw_in(ptr, alloc) } 103 | } 104 | } 105 | 106 | #[cfg(feature = "alloc")] 107 | impl Box { 108 | /// Allocates memory in the `Global` allocator and then places `x` into it. 109 | pub fn new(x: T) -> Self { 110 | Self::new_in(x, Global) 111 | } 112 | } 113 | 114 | impl Debug for Box { 115 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 116 | T::fmt(self, f) 117 | } 118 | } 119 | 120 | impl Display for Box { 121 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 122 | T::fmt(self, f) 123 | } 124 | } 125 | 126 | impl Deref for Box { 127 | type Target = T; 128 | 129 | #[inline] 130 | fn deref(&self) -> &Self::Target { 131 | // SAFETY: 132 | // - `self.ptr` is always valid for reads, properly aligned, and always 133 | // points to an initialized `T`. 134 | // - The underlying `T` has the same aliasing as `self`. 135 | unsafe { &*self.ptr.as_ptr() } 136 | } 137 | } 138 | 139 | impl DerefMut for Box { 140 | #[inline] 141 | fn deref_mut(&mut self) -> &mut Self::Target { 142 | // SAFETY: 143 | // - `self.ptr` is always valid for reads, properly aligned, and always 144 | // points to an intialized `T`. 145 | // - The underlying `T` has the same aliasing as `self`. 146 | unsafe { &mut *self.ptr.as_ptr() } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /heresy/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A reformulation of the allocator API for more general-purpose use. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | #![no_std] 13 | 14 | #[cfg(feature = "alloc")] 15 | extern crate alloc as builtin_alloc; 16 | 17 | pub mod alloc; 18 | pub mod boxed; 19 | 20 | pub use self::boxed::*; 21 | -------------------------------------------------------------------------------- /macroix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "macroix" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | proc-macro2 = "1.0" 8 | quote = "1.0" 9 | syn = "1.0" 10 | -------------------------------------------------------------------------------- /macroix/src/attr_value.rs: -------------------------------------------------------------------------------- 1 | use ::syn::{parse, token::Eq, LitStr}; 2 | 3 | /// The value of an attribute like `#[key = "value"]`. 4 | pub struct AttrValue { 5 | /// The `=` token between the key and value. 6 | pub eq_token: Eq, 7 | /// The value parsed from a string literal. 8 | pub value: T, 9 | } 10 | 11 | impl parse::Parse for AttrValue { 12 | fn parse(input: parse::ParseStream) -> parse::Result { 13 | Ok(AttrValue { 14 | eq_token: input.parse::()?, 15 | value: input.parse::()?.parse::()?, 16 | }) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /macroix/src/case.rs: -------------------------------------------------------------------------------- 1 | //! Case conversion functions. 2 | 3 | /// Converts a name from `PascalCase` to `snake_case`. 4 | pub fn pascal_to_snake(s: &str) -> String { 5 | let mut result = String::new(); 6 | for c in s.chars() { 7 | if c.is_ascii_uppercase() && !result.is_empty() { 8 | result.push('_'); 9 | } 10 | result.push(c.to_ascii_lowercase()); 11 | } 12 | result 13 | } 14 | -------------------------------------------------------------------------------- /macroix/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Common parsers and code generation for proc macros. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | 13 | mod attr_value; 14 | pub mod case; 15 | pub mod repr; 16 | 17 | use ::syn::{Data, Field, Fields, GenericParam, Generics, TypeParam}; 18 | 19 | pub use self::attr_value::*; 20 | 21 | /// Visits each field of the given struct, enum, or union and calls a function 22 | /// on each one. 23 | pub fn visit_fields(data: &Data, mut f: F) { 24 | match data { 25 | Data::Struct(data) => { 26 | visit_fields_inner(&data.fields, f); 27 | } 28 | Data::Enum(data) => { 29 | for variant in &data.variants { 30 | visit_fields_inner(&variant.fields, &mut f); 31 | } 32 | } 33 | Data::Union(data) => { 34 | for field in data.fields.named.iter() { 35 | f(field); 36 | } 37 | } 38 | } 39 | } 40 | 41 | fn visit_fields_inner(fields: &Fields, mut f: F) { 42 | match fields { 43 | Fields::Named(fields) => { 44 | for field in fields.named.iter() { 45 | f(field); 46 | } 47 | } 48 | Fields::Unnamed(fields) => { 49 | for field in fields.unnamed.iter() { 50 | f(field); 51 | } 52 | } 53 | Fields::Unit => (), 54 | } 55 | } 56 | 57 | /// Inserts a type parameter at the correct position in some `Generics`. 58 | pub fn insert_type_param(generics: &mut Generics, param: TypeParam) { 59 | let first_non_lifetime = generics 60 | .params 61 | .iter() 62 | .position(|p| !matches!(p, GenericParam::Lifetime(_))) 63 | .unwrap_or(generics.params.len()); 64 | generics 65 | .params 66 | .insert(first_non_lifetime, GenericParam::Type(param)); 67 | } 68 | -------------------------------------------------------------------------------- /media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rkyv/rel/e0880d31c9b5c0be5574f4333c8d6a240d0ba0da/media/logo.png -------------------------------------------------------------------------------- /media/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 40 | 45 | 46 | 48 | 53 | 58 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /media/logo_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rkyv/rel/e0880d31c9b5c0be5574f4333c8d6a240d0ba0da/media/logo_color.png -------------------------------------------------------------------------------- /media/logo_color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 38 | 43 | 44 | 46 | 49 | 53 | 57 | 58 | 67 | 68 | 73 | 78 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /media/logo_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rkyv/rel/e0880d31c9b5c0be5574f4333c8d6a240d0ba0da/media/logo_text.png -------------------------------------------------------------------------------- /media/logo_text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 37 | 42 | 43 | 45 | 50 | 55 | 57 | 61 | 65 | 69 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /media/logo_text_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rkyv/rel/e0880d31c9b5c0be5574f4333c8d6a240d0ba0da/media/logo_text_color.png -------------------------------------------------------------------------------- /mischief/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mischief" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies.heresy] 7 | version = "0.1" 8 | path = "../heresy" 9 | default-features = false 10 | 11 | [dependencies.mischief_derive] 12 | version = "0.1" 13 | path = "../mischief_derive" 14 | optional = true 15 | 16 | [dependencies.munge] 17 | version = "0.4" 18 | git = "https://github.com/djkoloski/munge" 19 | 20 | [dependencies.ptr_meta] 21 | version = "0.2" 22 | default-features = false 23 | 24 | [features] 25 | default = ["alloc", "derive"] 26 | alloc = ["heresy/alloc"] 27 | derive = ["mischief_derive"] 28 | -------------------------------------------------------------------------------- /mischief/src/in.rs: -------------------------------------------------------------------------------- 1 | use ::core::{ 2 | marker::PhantomData, 3 | ops::{Deref, DerefMut}, 4 | }; 5 | use ::munge::{Destructure, Restructure}; 6 | use ::ptr_meta::Pointee; 7 | 8 | use crate::{Frame, Metadata, Pointer, Region, RegionalAllocator, Slot}; 9 | 10 | /// A pointer which has its pointee in a specific memory region. 11 | #[derive(Clone, Copy)] 12 | pub struct In { 13 | ptr: P, 14 | region: PhantomData, 15 | } 16 | 17 | impl In 18 | where 19 | P::Target: Pointee, 20 | { 21 | /// Creates a new `In` from a pointer. 22 | pub fn new(ptr: P) -> Self 23 | where 24 | P: Within, 25 | { 26 | // SAFETY: The pointee of `ptr` is must be located in `R` because `P` 27 | // implements `Within`. 28 | unsafe { Self::new_unchecked(ptr) } 29 | } 30 | 31 | /// Creates a new `In` from a pointer. 32 | /// 33 | /// # Safety 34 | /// 35 | /// The pointee of `ptr` must be contained in `R`. 36 | pub unsafe fn new_unchecked(ptr: P) -> Self { 37 | Self { 38 | ptr, 39 | region: PhantomData, 40 | } 41 | } 42 | 43 | /// Maps this `In` to another pointer in its region. 44 | pub fn map(self, f: F) -> In 45 | where 46 | F: FnOnce(P) -> Q, 47 | Q: Pointer + Within, 48 | Q::Target: Pointee, 49 | { 50 | In::new(f(Self::into_inner(self))) 51 | } 52 | 53 | /// Maps this `In` to another pointer in its region. 54 | /// 55 | /// # Safety 56 | /// 57 | /// The pointer returned by `f` must be completely contained in `R`. 58 | pub unsafe fn map_unchecked(self, f: F) -> In 59 | where 60 | F: FnOnce(P) -> Q, 61 | Q: Pointer, 62 | Q::Target: Pointee, 63 | { 64 | let ptr = Self::into_inner(self); 65 | // SAFETY: The caller has gauranteed that `R` completely contains the 66 | // mapped pointer. 67 | unsafe { In::new_unchecked(f(ptr)) } 68 | } 69 | 70 | /// Gets a raw `In` from this pointer. 71 | pub fn as_raw(&self) -> In<*mut P::Target, R> { 72 | // SAFETY: `self.ptr.deref_raw()` returns a pointer located in `R`. 73 | // Calling `deref_raw` on that returned `*mut P::Target` returns the 74 | // same pointer again because raw pointers `deref_raw` to themselves. So 75 | // `self.ptr.deref_raw()` also returns a pointer in `R` when `deref_raw` 76 | // is called on it. 77 | unsafe { In::new_unchecked(self.ptr.target()) } 78 | } 79 | } 80 | 81 | impl In { 82 | /// Unwraps an `In`, returning the underlying pointer. 83 | pub fn into_inner(this: Self) -> P { 84 | this.ptr 85 | } 86 | 87 | /// Returns a reference to the pointer of this `In`. 88 | pub fn ptr(&self) -> &P { 89 | &self.ptr 90 | } 91 | 92 | /// Returns a mutable reference to the pointer of this `In`. 93 | /// 94 | /// # Safety 95 | /// 96 | /// The pointer must not be mutated to point outside of `R`. 97 | pub unsafe fn ptr_mut(&mut self) -> &mut P { 98 | &mut self.ptr 99 | } 100 | } 101 | 102 | impl In, A::Region> 103 | where 104 | ::Metadata: Metadata, 105 | { 106 | /// Returns a [`Slot`] of the internal contents. 107 | pub fn slot(&'_ mut self) -> In, A::Region> { 108 | // SAFETY: `slot` is wrapped in an `In` before being returned to prevent 109 | // it from being pointed outside of `R`, and we don't mutate it to point 110 | // elsewhere. 111 | let slot = unsafe { self.ptr_mut().slot() }; 112 | // SAFETY: `slot` points to the same location as `self`, which points to 113 | // a slot located in `R`. Therefore, `slot` must also point to a a slot 114 | // located in `R`. 115 | unsafe { In::new_unchecked(slot) } 116 | } 117 | } 118 | 119 | impl<'a, T: Pointee + ?Sized, R: Region> In, R> { 120 | /// Gets a mutable borrow from this slot. 121 | pub fn as_mut<'b>(&'b mut self) -> In, R> 122 | where 123 | 'a: 'b, 124 | { 125 | // SAFETY: The original and reborrowed slots are guaranteed to both 126 | // point to the same memory. Since the original slot is guaranteed to be 127 | // located in `R`, the reborrowed slot must also be located in `R`. 128 | unsafe { In::new_unchecked(self.ptr.as_mut()) } 129 | } 130 | } 131 | 132 | impl Deref for In { 133 | type Target = P::Target; 134 | 135 | fn deref(&self) -> &Self::Target { 136 | self.ptr().deref() 137 | } 138 | } 139 | 140 | impl DerefMut for In { 141 | fn deref_mut(&mut self) -> &mut Self::Target { 142 | self.ptr.deref_mut() 143 | } 144 | } 145 | 146 | /// A `Pointer` that may be restructured with `munge`. 147 | /// 148 | /// # Safety 149 | /// 150 | /// This type's `Destructure::underlying` implementation must return the same 151 | /// pointer as `Pointer::target`. 152 | pub unsafe trait RestructurablePointer: Destructure {} 153 | 154 | // SAFETY: 155 | // - `In` is destructured in the same way as its inner pointer is, so its 156 | // `Destructuring` type is `P::Underlying`. 157 | // - `underlying` returns the underlying of the inner pointer, which is also 158 | // guaranteed to be non-null, properly-aligned, and valid for reads. 159 | unsafe impl Destructure for In { 160 | type Underlying = P::Underlying; 161 | type Destructuring = P::Destructuring; 162 | 163 | fn underlying(&mut self) -> *mut Self::Underlying { 164 | self.ptr.underlying() 165 | } 166 | } 167 | 168 | type RsTarget = <>::Restructured as Pointer>::Target; 169 | 170 | // SAFETY: `restructure` returns a valid `In` created by restructuring using the 171 | // inner pointer's restructuring. Because the inner pointer upholds its 172 | // destructuring invariants, `In` does too. 173 | unsafe impl Restructure for In 174 | where 175 | P: RestructurablePointer + Restructure, 176 |

>::Restructured: Pointer, 177 | RsTarget: Pointee, 178 | { 179 | type Restructured = In<

>::Restructured, R>; 180 | 181 | unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured { 182 | // SAFETY: The caller has guaranteed that `ptr` is a properly aligned 183 | // pointer to a subfield of the pointer underlying `self`, which is the 184 | // pointer underlying `self.ptr`. 185 | let restructured = unsafe { self.ptr.restructure(ptr) }; 186 | // SAFETY: The restructured pointer must be a subfield of the original 187 | // pointer's pointee, so it's necessarily located in the same region as 188 | // the original as well. The safety requirements for 189 | // `RestructurablePointer` require that the pointer returned from 190 | // `Destructure::underlying` must be the same as the pointer returned 191 | // from `deref_raw`, so it's not possible to return different pointers 192 | // from each. 193 | unsafe { In::new_unchecked(restructured) } 194 | } 195 | } 196 | 197 | /// A pointer that knows where its target is located 198 | /// 199 | /// # Safety 200 | /// 201 | /// The `target` of the type must be located in `R`. 202 | pub unsafe trait Within: Pointer {} 203 | -------------------------------------------------------------------------------- /mischief/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Some extra mischief compatible with the standard library or `heresy`. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | #![no_std] 13 | 14 | mod frame; 15 | mod r#in; 16 | mod metadata; 17 | mod pointer; 18 | mod region; 19 | mod slot; 20 | mod unique; 21 | 22 | pub use self::{ 23 | frame::*, 24 | metadata::*, 25 | pointer::*, 26 | r#in::*, 27 | region::*, 28 | slot::*, 29 | unique::*, 30 | }; 31 | -------------------------------------------------------------------------------- /mischief/src/metadata.rs: -------------------------------------------------------------------------------- 1 | use ::core::{alloc::Layout, hash::Hash}; 2 | use ::ptr_meta::{metadata, DynMetadata, Pointee}; 3 | 4 | /// Pointer metadata that can determine the memory layout of its pointee. 5 | /// 6 | /// # Safety 7 | /// 8 | /// `pointee_layout` must return the correct layout of a `T` pointee with this 9 | /// metadata. 10 | pub unsafe trait Metadata + ?Sized>: 11 | Copy + Send + Sync + Ord + Hash + Unpin 12 | { 13 | /// Returns the layout of a `T` pointee with the this metadata. 14 | /// 15 | /// # Safety 16 | /// 17 | /// `self` must be valid metadata for `T`. 18 | unsafe fn pointee_layout(self) -> Layout; 19 | } 20 | 21 | // SAFETY: `Layout::new` returns the correct layout for `T`. 22 | unsafe impl Metadata for () { 23 | unsafe fn pointee_layout(self) -> Layout { 24 | Layout::new::() 25 | } 26 | } 27 | 28 | // SAFETY: `Layout::array` returns the correct layout for `[T]` because slices 29 | // have the same layouts as arrays of the same length. 30 | unsafe impl Metadata<[T]> for usize { 31 | unsafe fn pointee_layout(self) -> Layout { 32 | // SAFETY: `Layout::array` cannot fail because `self` is valid metadata 33 | // for `[T]`. 34 | unsafe { Layout::array::(self).unwrap_unchecked() } 35 | } 36 | } 37 | 38 | // SAFETY: `Layout::array` returns the correct layout for `str` because string 39 | // slices have the same layouts as byte arrays of the same length. 40 | unsafe impl Metadata for usize { 41 | unsafe fn pointee_layout(self) -> Layout { 42 | // SAFETY: `Layout::array` cannot fail because `self` is valid metadata 43 | // for `str`. 44 | unsafe { Layout::array::(self).unwrap_unchecked() } 45 | } 46 | } 47 | 48 | // SAFETY: `DynMetadata::layout` returns the layout of the corresponding value. 49 | unsafe impl Metadata for DynMetadata 50 | where 51 | T: Pointee> + ?Sized, 52 | { 53 | unsafe fn pointee_layout(self) -> Layout { 54 | self.layout() 55 | } 56 | } 57 | 58 | /// Returns the layout of the value pointed to by the given pointer. 59 | pub fn layout_of_val_raw(ptr: *const T) -> Layout 60 | where 61 | T::Metadata: Metadata, 62 | { 63 | let metadata = metadata(ptr); 64 | // SAFETY: `metadata` is the metadata of a pointer, and all pointers must 65 | // have valid metadata. So the metadata is guaranteed to be valid. 66 | unsafe { metadata.pointee_layout() } 67 | } 68 | -------------------------------------------------------------------------------- /mischief/src/pointer.rs: -------------------------------------------------------------------------------- 1 | /// A type that points to a single location in memory. 2 | /// 3 | /// # Safety 4 | /// 5 | /// If the type implementing `Pointer` also implements `Deref` or `DerefMut`, 6 | /// the pointer returned by `Target` must be equal to the references returned 7 | /// from `deref` and `deref_mut`. 8 | pub unsafe trait Pointer { 9 | /// The target value of this type. 10 | type Target: ?Sized; 11 | 12 | /// Returns a pointer to this type's target. 13 | fn target(&self) -> *mut Self::Target; 14 | } 15 | 16 | // SAFETY: `*const T` does not implement `Deref` or `DerefMut` and never will 17 | // because `*const T` is a fundamental type. 18 | unsafe impl Pointer for *const T { 19 | type Target = T; 20 | 21 | fn target(&self) -> *mut Self::Target { 22 | self.cast_mut() 23 | } 24 | } 25 | 26 | // SAFETY: `*mut T` does not implement `Deref` or `DerefMut` and never will 27 | // because `*mut T` is a fundamental type. 28 | unsafe impl Pointer for *mut T { 29 | type Target = T; 30 | 31 | fn target(&self) -> *mut Self::Target { 32 | *self 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mischief/src/region.rs: -------------------------------------------------------------------------------- 1 | use ::heresy::alloc::Allocator; 2 | 3 | /// A contiguous memory region. 4 | /// 5 | /// Each type that implements `Region` corresponds to a single allocated object 6 | /// at runtime. That `Region` type is said to "contain" some memory segment if 7 | /// the segment is completely contained within the bounds of the allocated 8 | /// object. While each region must correspond to a single allocated object, each 9 | /// allocated object may correspond with multiple `Region` types. 10 | /// 11 | /// If memory segments are contained in the same region type, then computing the 12 | /// the offset between them is guaranteed to be safe. However, because different 13 | /// `Region` types may correspond with the same allocated object, computing the 14 | /// offset betwewen memory segments in different regions may or may not be safe. 15 | /// 16 | /// Note that while a type implementing `Region` must correspond with a single 17 | /// allocated object, it does not need to know anything about that allocated 18 | /// object. 19 | /// 20 | /// # Safety 21 | /// 22 | /// This type must correspond to a single unique allocated object. 23 | pub unsafe trait Region {} 24 | 25 | /// An `Allocator` that allocates inside a single contiguous memory region. 26 | /// 27 | /// # Safety 28 | /// 29 | /// The pointers returned from a `RegionalAllocator`'s `Allocator` 30 | /// implementation must always be contained in its associated `Region`. 31 | pub unsafe trait RegionalAllocator: Allocator { 32 | /// The region type for this allocator. 33 | type Region: Region; 34 | } 35 | -------------------------------------------------------------------------------- /mischief/src/unique/ghost_ref.rs: -------------------------------------------------------------------------------- 1 | use ::core::{marker::PhantomData, mem::forget}; 2 | 3 | use crate::unique::{Singleton, Unique}; 4 | 5 | /// A "ghost" reference that is guaranteed to be zero-sized and obey borrowing 6 | /// and ownership semantics 7 | pub struct GhostRef(PhantomData); 8 | 9 | impl Clone for GhostRef { 10 | fn clone(&self) -> Self { 11 | Self(self.0) 12 | } 13 | } 14 | 15 | impl Copy for GhostRef {} 16 | 17 | impl GhostRef { 18 | /// Returns a new `GhostRef` from the given value. 19 | /// 20 | /// Note that the given value will be leaked forever. Leaking types that 21 | /// have a meaningful `Drop` implementation can cause system resources to 22 | /// leak. 23 | pub fn leak(value: T) -> Self { 24 | forget(value); 25 | Self(PhantomData) 26 | } 27 | } 28 | 29 | // SAFETY: Because `GhostRef` can only be constructed by leaking a `T`, and `T` 30 | // is guaranteed to be `Unique`, the `GhostRef` is also `Unique`. 31 | unsafe impl Unique for GhostRef {} 32 | 33 | // SAFETY: Because `GhostRef` can only be constructed by leaking a `T`, and `T` 34 | // is guaranteed to be a `Singleton`, the `GhostRef` is also a `Singleton`. 35 | unsafe impl Singleton for GhostRef {} 36 | -------------------------------------------------------------------------------- /mischief/src/unique/mod.rs: -------------------------------------------------------------------------------- 1 | //! Unique and singleton types and tools for constructing them. 2 | 3 | mod ghost_ref; 4 | mod static_ref; 5 | mod token; 6 | 7 | pub use ::mischief_derive::{Singleton, Unique}; 8 | 9 | pub use self::{ghost_ref::*, static_ref::*, token::*}; 10 | 11 | /// A type which guarantees that only one value can ever exist at a time. 12 | /// 13 | /// # Safety 14 | /// 15 | /// Only one value of this type may ever exist simultaneously. 16 | pub unsafe trait Unique {} 17 | 18 | // SAFETY: Mutable references may not alias, so a mutable reference of a unique 19 | // type must also be unique. 20 | unsafe impl Unique for &mut T {} 21 | 22 | /// A type which guarantees that all simultaneous values share the same state. 23 | /// 24 | /// # Safety 25 | /// 26 | /// Any two simultaneous instances of this type must be interchangeable and 27 | /// share the same state. A `Singleton` type might fulfill this obligation by 28 | /// referencing shared state, referencing a [`Unique`], or requiring the 29 | /// precondition to be checked manually. 30 | pub unsafe trait Singleton {} 31 | 32 | // SAFETY: All simultaneous shared references to a `Unique` type must be to the 33 | // same value. 34 | unsafe impl Singleton for &T {} 35 | 36 | #[cfg(feature = "alloc")] 37 | // SAFETY: Every `Global` is guaranteed to share the same state. 38 | unsafe impl Singleton for ::heresy::alloc::Global {} 39 | 40 | /// Splits a unique value into several others. 41 | #[macro_export] 42 | macro_rules! split_unique { 43 | (fn $fn:ident($in:ty) -> $out:ident) => { 44 | $crate::split_unique!(@define $in => ($out,)); 45 | $crate::split_unique!(@impl $fn($in) -> $out); 46 | }; 47 | (fn $fn:ident($in:ty) -> ($($out:tt)*)) => { 48 | $crate::split_unique!(@define $in => ($($out)*)); 49 | $crate::split_unique!(@impl $fn($in) -> ($($out)*)); 50 | }; 51 | (pub fn $fn:ident($in:ty) -> $out:ident) => { 52 | $crate::split_unique!(@define $in => ($out,) $($vis)*); 53 | $crate::split_unique!(@impl $fn($in) -> $out pub); 54 | }; 55 | (pub fn $fn:ident($in:ty) -> ($($out:tt)*)) => { 56 | $crate::split_unique!(@define $in => ($($out)*) $($vis)*); 57 | $crate::split_unique!(@impl $fn($in) -> ($($out)*) pub); 58 | }; 59 | (pub($($vis:tt)*) fn $fn:ident($in:ty) -> $out:ident) => { 60 | $crate::split_unique!(@define $in => ($out,) $($vis)*); 61 | $crate::split_unique!(@impl $fn($in) -> $out pub($($vis)*)); 62 | }; 63 | (pub($($vis:tt)*) fn $fn:ident($in:ty) -> ($($out:tt)*)) => { 64 | $crate::split_unique!(@define $in => ($($out)*) $($vis)*); 65 | $crate::split_unique!(@impl $fn($in) -> ($($out)*) pub($($vis)*)); 66 | }; 67 | 68 | (@impl $fn:ident($in:ty) -> $out:ident $($vis:tt)*) => { 69 | #[inline] 70 | $($vis)* fn $fn(unique: $in) -> $out { 71 | // Forgetting is semantically equivalent to moving into static 72 | // variable permanently. 73 | ::core::mem::forget(unique); 74 | $out(::core::marker::PhantomData) 75 | } 76 | }; 77 | (@impl $fn:ident($in:ty) -> ($($out:ident),*) $($vis:tt)*) => { 78 | #[inline] 79 | $($vis)* fn $fn(unique: $in) -> ($($out),*) { 80 | // Forgetting is semantically equivalent to moving into static 81 | // variable permanently. 82 | ::core::mem::forget(unique); 83 | ($( 84 | $out(::core::marker::PhantomData) 85 | ),*) 86 | } 87 | }; 88 | (@impl $fn:ident($in:ty) -> ($($out:ident,)*) $($vis:tt)*) => { 89 | #[inline] 90 | $($vis)* fn $fn(unique: $in) -> ($($out,)*) { 91 | // Forgetting is semantically equivalent to moving into static 92 | // variable permanently. 93 | ::core::mem::forget(unique); 94 | ($( 95 | $out(::core::marker::PhantomData), 96 | )*) 97 | } 98 | }; 99 | 100 | (@define $in:ty => () $($vis:tt)*) => {}; 101 | (@define 102 | $in:ty => ($out_first:ident $(, $out_rest:ident)* $(,)?) $($vis:tt)* 103 | ) => { 104 | $($vis)* struct $out_first( 105 | ::core::marker::PhantomData<&'static mut $in>, 106 | ); 107 | 108 | // SAFETY: `$out` can only be acquired by exchanging another `Unique` 109 | // for it. That unique value is retained indefinitely, so the exchange 110 | // can only ever be performed once. 111 | unsafe impl $crate::Unique for $out_first {} 112 | 113 | $crate::split_unique!(@define $in => ($($out_rest,)*) $($vis:tt)*); 114 | }; 115 | } 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | #[test] 120 | fn split_unique() { 121 | use crate::{runtime_token, Unique}; 122 | 123 | #[inline] 124 | fn assert_unique() {} 125 | 126 | runtime_token!(Foo); 127 | split_unique!(fn barify(Foo) -> (Bar, Baz, Bat)); 128 | 129 | assert_unique::(); 130 | assert_unique::(); 131 | assert_unique::(); 132 | assert_unique::(); 133 | 134 | let (bar, baz, bat): (Bar, Baz, Bat) = barify(Foo::acquire()); 135 | assert!(matches!(Foo::try_acquire(), Err(_))); 136 | 137 | let _ = (bar, baz, bat); 138 | 139 | assert!(matches!(Foo::try_acquire(), Err(_))); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /mischief/src/unique/static_ref.rs: -------------------------------------------------------------------------------- 1 | use ::core::ops::{Deref, DerefMut}; 2 | 3 | use crate::{GhostRef, Singleton, Slot, Unique}; 4 | 5 | /// A type that can lease access to a type without any context. 6 | pub trait Static { 7 | /// The unique type that can be used to lease this static memory location. 8 | type Unique: Unique; 9 | /// The type that a reference can be created to. 10 | type Target: 'static; 11 | 12 | /// Returns a mutable reference to a slot of the target type. 13 | /// 14 | /// # Safety 15 | /// 16 | /// The caller must hold a mutable borrow of the `Unique`. 17 | unsafe fn slot() -> Slot<'static, Self::Target>; 18 | } 19 | 20 | /// A lease on a static memory location for a statically-checked lifetime. 21 | #[repr(transparent)] 22 | pub struct Lease<'scope, S: Static>(GhostRef<&'scope mut S::Unique>); 23 | 24 | // SAFETY: `Lease<'scope, S>` contains a `GhostRef<&'scope mut S::Unique>`, so 25 | // if that field is `Unique` then the `Lease` is also `Unique`. 26 | unsafe impl<'scope, S: Static> Unique for Lease<'scope, S> where 27 | GhostRef<&'scope mut S::Unique>: Unique 28 | { 29 | } 30 | 31 | impl<'scope, S: Static> Drop for Lease<'scope, S> { 32 | fn drop(&mut self) { 33 | // SAFETY: 34 | // - We hold a mutable borrow of `S::Unique`. 35 | // - Because the `Lease` is being dropped, there are no other references 36 | // to the value in the static variable. Therefore, we may consume the 37 | // value by dropping it. 38 | unsafe { S::slot().assume_init_drop() } 39 | } 40 | } 41 | 42 | impl<'scope, S: Static> Lease<'scope, S> { 43 | /// Creates a new scope from a unique borrow and an initial value. 44 | pub fn new(x: &'scope mut S::Unique, value: S::Target) -> Self { 45 | // SAFETY: 46 | // - We hold a mutable borrow of `S::Unique`. 47 | // - Because we are the only holders of the mutable borrow, we may treat 48 | // the slot as owned. 49 | let mut slot = unsafe { S::slot() }; 50 | slot.write(value); 51 | Self(GhostRef::leak(x)) 52 | } 53 | 54 | /// Creates a shared borrow of this scoped static. 55 | pub fn borrow(&self) -> StaticRef<&Self> { 56 | StaticRef::leak(self) 57 | } 58 | 59 | /// Creates a mutable borrow of this scoped static. 60 | pub fn borrow_mut(&mut self) -> StaticRef<&mut Self> { 61 | StaticRef::leak(self) 62 | } 63 | } 64 | 65 | /// A reference to some static value. 66 | #[derive(Clone, Copy)] 67 | #[repr(transparent)] 68 | pub struct StaticRef(GhostRef); 69 | 70 | // SAFETY: `StaticRef` contains a `GhostRef<&'scope mut S::Unique>`, so if 71 | // that field is `Unique` then the `StaticRef` is also `Singleton`. 72 | unsafe impl Unique for StaticRef where GhostRef: Unique {} 73 | 74 | // SAFETY: `StaticRef` contains only a `GhostRef`, so if that field is 75 | // `Singleton` then the `StaticRef` is also `Singleton`. 76 | unsafe impl Singleton for StaticRef where GhostRef: Singleton {} 77 | 78 | impl StaticRef { 79 | /// Creates a new `StaticRef`. 80 | pub fn leak(x: T) -> Self { 81 | StaticRef(GhostRef::leak(x)) 82 | } 83 | } 84 | 85 | impl<'borrow, 'scope, S> Deref for StaticRef<&'borrow Lease<'scope, S>> 86 | where 87 | 'scope: 'borrow, 88 | S: Static, 89 | { 90 | type Target = S::Target; 91 | 92 | fn deref(&self) -> &Self::Target { 93 | // SAFETY: 94 | // - `StaticRef` transitively holds a mutable borrow of `S::Unique`. 95 | // - The borrowed `Lease` initialized the slot when it was created. 96 | // - Because the borrow of `Lease` is shared, we treat the slot as 97 | // shared. 98 | unsafe { S::slot().assume_init_ref() } 99 | } 100 | } 101 | 102 | impl<'borrow, 'scope, S> Deref for StaticRef<&'borrow mut Lease<'scope, S>> 103 | where 104 | 'scope: 'borrow, 105 | S: Static, 106 | { 107 | type Target = S::Target; 108 | 109 | fn deref(&self) -> &Self::Target { 110 | // SAFETY: 111 | // - `StaticRef` transitively holds a mutable borrow of `S::Unique`. 112 | // - The borrowed `Lease` initialized the slot when it was created. 113 | // - Because the borrow of `Lease` is unique, we may treat the slot as 114 | // shared or mutable. 115 | unsafe { S::slot().assume_init_ref() } 116 | } 117 | } 118 | 119 | impl<'borrow, 'scope, S> DerefMut for StaticRef<&'borrow mut Lease<'scope, S>> 120 | where 121 | 'scope: 'borrow, 122 | S: Static, 123 | { 124 | fn deref_mut(&mut self) -> &mut Self::Target { 125 | // SAFETY: 126 | // - `StaticRef` transitively holds a mutable borrow of `S::Unique`. 127 | // - The borrowed `Lease` initialized the slot when it was created. 128 | // - Because the borrow of `Lease` is unique, we may treat the slot as 129 | // shared or mutable. 130 | unsafe { S::slot().assume_init_mut() } 131 | } 132 | } 133 | 134 | /// Creates a type that provides safe access to a static variable using a unique 135 | /// value. 136 | #[macro_export] 137 | macro_rules! lease_static { 138 | ($unique:ty => $name:ident: $ty:ty) => { 139 | $crate::lease_static!(@declare $name); 140 | $crate::lease_static!(@impl $unique => $name: $ty) 141 | }; 142 | ($unique:ty => pub $name:ident: $ty:ty) => { 143 | $crate::lease_static!(@declare $name pub); 144 | $crate::lease_static!(@impl $unique => $name: $ty) 145 | }; 146 | ($unique:ty => pub ($($vis:tt)*) $name:ident: $ty:ty) => { 147 | $crate::lease_static!(@declare $name pub($($vis)*)); 148 | $crate::lease_static!(@impl $unique => $name: $ty) 149 | }; 150 | (@declare $name:ident $($vis:tt)*) => { 151 | $($vis)* struct $name(::core::marker::PhantomData<()>); 152 | }; 153 | (@impl $unique:ty => $name:ident: $target:ty) => { 154 | const _: () = { 155 | use ::core::mem::MaybeUninit; 156 | static mut VALUE: MaybeUninit<$target> = MaybeUninit::uninit(); 157 | 158 | impl $crate::Static for $name { 159 | type Unique = $unique; 160 | type Target = $target; 161 | 162 | unsafe fn slot() -> $crate::Slot<'static, Self::Target> { 163 | // SAFETY: Only one `Lease` can have access to the slot at a 164 | // time. 165 | unsafe { $crate::Slot::new(&mut VALUE) } 166 | } 167 | } 168 | }; 169 | }; 170 | } 171 | 172 | #[cfg(test)] 173 | mod tests { 174 | #[test] 175 | fn vend() { 176 | use crate::{runtime_token, Lease}; 177 | 178 | struct Gumball { 179 | size: i32, 180 | } 181 | 182 | runtime_token!(Quarter); 183 | lease_static!(Quarter => Vend: Gumball); 184 | 185 | let mut quarter = Quarter::acquire(); 186 | let mut vend = Lease::::new(&mut quarter, Gumball { size: 100 }); 187 | 188 | assert_eq!(::core::mem::size_of_val(&vend.borrow()), 0); 189 | 190 | let mut gumball = vend.borrow_mut(); 191 | gumball.size = 6; 192 | 193 | assert_eq!(vend.borrow().size, 6); 194 | 195 | let mut gumball_2 = vend.borrow_mut(); 196 | gumball_2.size = 4; 197 | 198 | assert_eq!(vend.borrow().size, 4); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /mischief/src/unique/token.rs: -------------------------------------------------------------------------------- 1 | use ::core::marker::PhantomData; 2 | 3 | use crate::Unique; 4 | 5 | /// A type of which there can only ever exist one value. 6 | #[repr(transparent)] 7 | pub struct StaticToken<'id>(PhantomData &'id ()>); 8 | 9 | impl<'id> StaticToken<'id> { 10 | /// Calls the given function with a fresh, unique token that will never be 11 | /// used again. 12 | #[inline] 13 | pub fn acquire(f: F) -> R 14 | where 15 | F: for<'new_id> FnOnce(StaticToken<'new_id>) -> R, 16 | { 17 | f(StaticToken(PhantomData)) 18 | } 19 | } 20 | 21 | // SAFETY: All `StaticToken`s have fresh, unused lifetimes and so are unique 22 | // types. 23 | unsafe impl<'id> Unique for StaticToken<'id> {} 24 | 25 | /// The runtime token is simultaneously acquired elsewhere. 26 | #[derive(Debug)] 27 | pub struct RuntimeTokenError; 28 | 29 | /// Creates a token with a fresh type that is checked for uniqueness at runtime. 30 | #[macro_export] 31 | macro_rules! runtime_token { 32 | ($name:ident) => { 33 | $crate::runtime_token!(@impl $name); 34 | }; 35 | (pub $name:ident) => { 36 | $crate::runtime_token!(@impl $name pub); 37 | }; 38 | (pub ($($vis:tt)*) $name:ident) => { 39 | $crate::runtime_token!(@impl $name pub($($vis)*)); 40 | }; 41 | (@impl $name:ident $($vis:tt)*) => { 42 | #[repr(transparent)] 43 | $($vis)* struct $name(::core::marker::PhantomData<()>); 44 | 45 | const _: () = { 46 | static ALIVE: ::core::sync::atomic::AtomicBool = 47 | ::core::sync::atomic::AtomicBool::new(false); 48 | 49 | impl Drop for $name { 50 | #[inline] 51 | fn drop(&mut self) { 52 | ALIVE.compare_exchange( 53 | true, 54 | false, 55 | ::core::sync::atomic::Ordering::AcqRel, 56 | ::core::sync::atomic::Ordering::Acquire, 57 | ).unwrap(); 58 | } 59 | } 60 | 61 | impl $name { 62 | /// Acquires the token. 63 | /// 64 | /// # Panics 65 | /// 66 | /// Panics if the token is still acquired elsewhere. 67 | #[inline] 68 | pub fn acquire() -> Self { 69 | Self::try_acquire().unwrap() 70 | } 71 | 72 | /// Attempts to acquire the token. 73 | /// 74 | /// Returns an error if the token is still acquired elsewhere. 75 | #[inline] 76 | pub fn try_acquire() -> 77 | ::core::result::Result 78 | { 79 | let result = ALIVE.compare_exchange( 80 | false, 81 | true, 82 | ::core::sync::atomic::Ordering::AcqRel, 83 | ::core::sync::atomic::Ordering::Acquire, 84 | ); 85 | 86 | match result { 87 | Ok(_) => ::core::result::Result::Ok( 88 | $name(::core::marker::PhantomData), 89 | ), 90 | Err(_) => ::core::result::Result::Err( 91 | $crate::RuntimeTokenError, 92 | ), 93 | } 94 | } 95 | } 96 | 97 | // SAFETY: `$name` can only be constructed by flipping `ALIVE` from 98 | // `false` to `true`, which can only happen one at a time. 99 | // Therefore, only one `$name` can exist at a time. The token will 100 | // flip it back to `false` when it is dropped, which destroys the 101 | // unique value. 102 | unsafe impl $crate::Unique for $name {} 103 | }; 104 | }; 105 | } 106 | 107 | #[cfg(test)] 108 | mod tests { 109 | use crate::Unique; 110 | 111 | #[inline] 112 | fn assert_unique() {} 113 | 114 | #[test] 115 | fn static_token() { 116 | use crate::StaticToken; 117 | 118 | StaticToken::acquire(|_: StaticToken| { 119 | assert_unique::(); 120 | }); 121 | } 122 | 123 | #[test] 124 | fn runtime_token() { 125 | runtime_token!(Foo); 126 | assert_unique::(); 127 | 128 | let foo: Foo = Foo::acquire(); 129 | assert!(matches!(Foo::try_acquire(), Err(_))); 130 | drop(foo); 131 | assert!(matches!(Foo::try_acquire(), Ok(_))); 132 | } 133 | 134 | #[test] 135 | #[should_panic] 136 | fn runtime_token_duplicate() { 137 | runtime_token!(Foo); 138 | assert_unique::(); 139 | 140 | let foo: Foo = Foo::acquire(); 141 | let bar: Foo = Foo::acquire(); 142 | drop(foo); 143 | drop(bar); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /mischief_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mischief_derive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | proc-macro = true 8 | 9 | [dependencies] 10 | proc-macro2 = "1.0" 11 | quote = "1.0" 12 | syn = "1.0" 13 | 14 | [dependencies.macroix] 15 | version = "0.1" 16 | path = "../macroix" 17 | -------------------------------------------------------------------------------- /mischief_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Procedural macros for `mischief`. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | 13 | mod singleton; 14 | mod unique; 15 | 16 | use ::proc_macro::TokenStream; 17 | use ::syn::{parse_macro_input, DeriveInput}; 18 | 19 | /// Derives `Singleton` on the annotated type. 20 | #[proc_macro_derive(Singleton, attributes(mischief))] 21 | pub fn derive_singleton(input: TokenStream) -> TokenStream { 22 | let derive_input = parse_macro_input!(input as DeriveInput); 23 | singleton::derive(derive_input) 24 | .unwrap_or_else(|e| e.to_compile_error()) 25 | .into() 26 | } 27 | 28 | /// Derives `Unique` on the annotated type. 29 | #[proc_macro_derive(Unique, attributes(mischief, unique))] 30 | pub fn derive_unique(input: TokenStream) -> TokenStream { 31 | let derive_input = parse_macro_input!(input as DeriveInput); 32 | unique::derive(derive_input) 33 | .unwrap_or_else(|e| e.to_compile_error()) 34 | .into() 35 | } 36 | -------------------------------------------------------------------------------- /mischief_derive/src/singleton.rs: -------------------------------------------------------------------------------- 1 | use ::macroix::{visit_fields, AttrValue}; 2 | use ::proc_macro2::TokenStream; 3 | use ::quote::quote; 4 | use ::syn::{parse2, parse_quote, DeriveInput, Error, Path}; 5 | 6 | pub fn derive(mut input: DeriveInput) -> Result { 7 | let mut mischief = None; 8 | for attr in input.attrs.iter() { 9 | if attr.path.is_ident("mischief") { 10 | mischief = 11 | Some(parse2::>(attr.tokens.clone())?.value); 12 | } 13 | } 14 | 15 | let mischief = mischief.unwrap_or_else(|| parse_quote! { ::mischief }); 16 | 17 | let where_clause = input.generics.make_where_clause(); 18 | visit_fields(&input.data, |f| { 19 | let ty = &f.ty; 20 | where_clause 21 | .predicates 22 | .push(parse_quote! { #ty: #mischief::Singleton }); 23 | }); 24 | 25 | let (impl_generics, ty_generics, where_clause) = 26 | input.generics.split_for_impl(); 27 | let ty_name = &input.ident; 28 | Ok(quote! { 29 | unsafe impl #impl_generics #mischief::Singleton 30 | for #ty_name #ty_generics #where_clause {} 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /mischief_derive/src/unique.rs: -------------------------------------------------------------------------------- 1 | use ::macroix::{visit_fields, AttrValue}; 2 | use ::proc_macro2::{Span, TokenStream}; 3 | use ::quote::quote; 4 | use ::syn::{parse2, parse_quote, DeriveInput, Error, Path}; 5 | 6 | pub fn derive(mut input: DeriveInput) -> Result { 7 | let mut mischief = None; 8 | for attr in input.attrs.iter() { 9 | if attr.path.is_ident("mischief") { 10 | mischief = 11 | Some(parse2::>(attr.tokens.clone())?.value); 12 | } 13 | } 14 | 15 | let mischief = mischief.unwrap_or_else(|| parse_quote! { ::mischief }); 16 | 17 | let where_clause = input.generics.make_where_clause(); 18 | let mut has_unique = false; 19 | visit_fields(&input.data, |f| { 20 | if f.attrs.iter().any(|a| a.path.is_ident("unique")) { 21 | has_unique = true; 22 | let ty = &f.ty; 23 | where_clause 24 | .predicates 25 | .push(parse_quote! { #ty: #mischief::Unique }); 26 | } 27 | }); 28 | if !has_unique { 29 | return Err(Error::new( 30 | Span::call_site(), 31 | "expected a field to be annotated with `#[unique]`", 32 | )); 33 | } 34 | 35 | let (impl_generics, ty_generics, where_clause) = 36 | input.generics.split_for_impl(); 37 | let ty_name = &input.ident; 38 | Ok(quote! { 39 | unsafe impl #impl_generics #mischief::Unique 40 | for #ty_name #ty_generics #where_clause {} 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /raw_enum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "raw_enum" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | proc-macro2 = "1.0" 8 | quote = "1.0" 9 | syn = "1.0" 10 | 11 | [dependencies.macroix] 12 | version = "0.1" 13 | path = "../macroix" 14 | -------------------------------------------------------------------------------- /raw_enum_macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "raw_enum_macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | proc-macro = true 8 | 9 | [dependencies] 10 | proc-macro2 = "1.0" 11 | quote = "1.0" 12 | syn = "1.0" 13 | 14 | [dependencies.raw_enum] 15 | version = "0.1" 16 | path = "../raw_enum" 17 | -------------------------------------------------------------------------------- /raw_enum_macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An attribute proc macro that generates the output from `raw_enum` into the 2 | //! scope of the annotated enum. 3 | 4 | #![deny( 5 | missing_docs, 6 | unsafe_op_in_unsafe_fn, 7 | clippy::as_conversions, 8 | clippy::missing_safety_doc, 9 | clippy::undocumented_unsafe_blocks, 10 | rustdoc::broken_intra_doc_links, 11 | rustdoc::missing_crate_level_docs 12 | )] 13 | 14 | use ::proc_macro2::TokenStream; 15 | use ::quote::ToTokens; 16 | use ::raw_enum::RawEnum; 17 | use ::syn::{parse_macro_input, DeriveInput, Error}; 18 | 19 | /// Generates a raw version of an enum. 20 | #[proc_macro_attribute] 21 | pub fn raw_enum( 22 | _attr: proc_macro::TokenStream, 23 | input: proc_macro::TokenStream, 24 | ) -> proc_macro::TokenStream { 25 | let input = parse_macro_input!(input as DeriveInput); 26 | generate_raw_enum(&input) 27 | .unwrap_or_else(|e| e.to_compile_error()) 28 | .into() 29 | } 30 | 31 | fn generate_raw_enum(input: &DeriveInput) -> Result { 32 | let raw_enum = RawEnum::for_derive(input)?; 33 | 34 | let mut result = input.to_token_stream(); 35 | result.extend(raw_enum.tokens); 36 | Ok(result) 37 | } 38 | -------------------------------------------------------------------------------- /rel_alloc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rel_alloc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies.heresy] 7 | version = "0.1" 8 | path = "../heresy" 9 | default-features = false 10 | 11 | [dependencies.mischief] 12 | version = "0.1" 13 | path = "../mischief" 14 | default-features = false 15 | 16 | [dependencies.munge] 17 | version = "0.4" 18 | git = "https://github.com/djkoloski/munge" 19 | 20 | [dependencies.ptr_meta] 21 | version = "0.2" 22 | default-features = false 23 | 24 | [dependencies.rel_core] 25 | version = "0.1" 26 | path = "../rel_core" 27 | default-features = false 28 | 29 | [dependencies.situ] 30 | version = "0.1" 31 | path = "../situ" 32 | 33 | [features] 34 | default = ["alloc"] 35 | alloc = ["heresy/alloc"] 36 | 37 | [dev-dependencies] 38 | criterion = "0.4" 39 | rand = "0.8" 40 | rand_pcg = "0.3" 41 | 42 | [dev-dependencies.rel_slab_allocator] 43 | version = "0.1" 44 | path = "../rel_slab_allocator" 45 | 46 | [dev-dependencies.rel_util] 47 | version = "0.1" 48 | path = "../rel_util" 49 | 50 | [[test]] 51 | name = "test" 52 | path = "bench_tests/test.rs" 53 | 54 | [[bench]] 55 | name = "bench" 56 | path = "bench_tests/bench.rs" 57 | harness = false 58 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/bench.rs: -------------------------------------------------------------------------------- 1 | pub mod from_data; 2 | pub mod gen; 3 | mod log; 4 | mod mc_savedata; 5 | mod mesh; 6 | 7 | use ::criterion::{criterion_group, criterion_main, Criterion}; 8 | 9 | fn criterion_benchmark(c: &mut Criterion) { 10 | let mut bench = mesh::make_bench(&mut gen::default_rng(), 125_000); 11 | println!("populate_mesh size: {} bytes", bench()); 12 | c.bench_function("populate_mesh", |b| { 13 | b.iter(&mut bench); 14 | }); 15 | 16 | let mut bench = log::make_bench(&mut gen::default_rng(), 10_000); 17 | println!("populate_log size: {} bytes", bench()); 18 | c.bench_function("populate_log", |b| { 19 | b.iter(&mut bench); 20 | }); 21 | 22 | let mut bench = mc_savedata::make_bench(&mut gen::default_rng(), 500); 23 | println!("populate_mc_savedata size: {} bytes", bench()); 24 | c.bench_function("populate_mc_savedata", |b| { 25 | b.iter(&mut bench); 26 | }); 27 | } 28 | 29 | criterion_group!(benches, criterion_benchmark); 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/from_data.rs: -------------------------------------------------------------------------------- 1 | pub struct FromData<'a, R, T> { 2 | pub alloc: R, 3 | pub data: &'a T, 4 | } 5 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/gen.rs: -------------------------------------------------------------------------------- 1 | use ::core::mem; 2 | use ::rand::Rng; 3 | 4 | pub trait Generate { 5 | fn generate(rng: &mut R) -> Self; 6 | } 7 | 8 | impl Generate for () { 9 | fn generate(_: &mut R) -> Self {} 10 | } 11 | 12 | impl Generate for bool { 13 | fn generate(rng: &mut R) -> Self { 14 | rng.gen_bool(0.5) 15 | } 16 | } 17 | 18 | macro_rules! impl_generate { 19 | ($ty:ty) => { 20 | impl Generate for $ty { 21 | fn generate(rng: &mut R) -> Self { 22 | rng.gen() 23 | } 24 | } 25 | }; 26 | } 27 | 28 | impl_generate!(u8); 29 | impl_generate!(u16); 30 | impl_generate!(u32); 31 | impl_generate!(u64); 32 | impl_generate!(u128); 33 | impl_generate!(usize); 34 | impl_generate!(i8); 35 | impl_generate!(i16); 36 | impl_generate!(i32); 37 | impl_generate!(i64); 38 | impl_generate!(i128); 39 | impl_generate!(isize); 40 | impl_generate!(f32); 41 | impl_generate!(f64); 42 | 43 | macro_rules! impl_tuple { 44 | () => {}; 45 | ($first:ident, $($rest:ident,)*) => { 46 | impl<$first: Generate, $($rest: Generate,)*> Generate for ($first, $($rest,)*) { 47 | fn generate(rng: &mut R) -> Self { 48 | ($first::generate(rng), $($rest::generate(rng),)*) 49 | } 50 | } 51 | 52 | impl_tuple!($($rest,)*); 53 | }; 54 | } 55 | 56 | impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,); 57 | 58 | macro_rules! impl_array { 59 | () => {}; 60 | ($len:literal, $($rest:literal,)*) => { 61 | impl Generate for [T; $len] { 62 | fn generate(rng: &mut R) -> Self { 63 | let mut result = mem::MaybeUninit::::uninit(); 64 | let result_ptr = result.as_mut_ptr().cast::(); 65 | for i in 0..$len { 66 | unsafe { 67 | result_ptr.add(i).write(Generate::generate(rng)); 68 | } 69 | } 70 | unsafe { 71 | result.assume_init() 72 | } 73 | } 74 | } 75 | 76 | impl_array!($($rest,)*); 77 | } 78 | } 79 | 80 | impl_array!( 81 | 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 82 | 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 83 | ); 84 | 85 | impl Generate for Option { 86 | fn generate(rng: &mut R) -> Self { 87 | if rng.gen_bool(0.5) { 88 | Some(Generate::generate(rng)) 89 | } else { 90 | None 91 | } 92 | } 93 | } 94 | 95 | pub fn generate_vec(rng: &mut R, len: usize) -> Vec { 96 | let mut result = Vec::with_capacity(len); 97 | for _ in 0..len { 98 | result.push(Generate::generate(rng)); 99 | } 100 | result 101 | } 102 | 103 | pub fn default_rng() -> impl Rng { 104 | use ::rand_pcg::Lcg64Xsh32; 105 | 106 | // Nothing up our sleeves; state and stream are first 20 digits of pi. 107 | const STATE: u64 = 3141592653; 108 | const STREAM: u64 = 5897932384; 109 | 110 | Lcg64Xsh32::new(STATE, STREAM) 111 | } 112 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/log/data.rs: -------------------------------------------------------------------------------- 1 | use ::rand::Rng; 2 | 3 | use crate::gen::Generate; 4 | 5 | pub struct Address { 6 | pub x0: u8, 7 | pub x1: u8, 8 | pub x2: u8, 9 | pub x3: u8, 10 | } 11 | 12 | impl Generate for Address { 13 | fn generate(rand: &mut R) -> Self { 14 | Self { 15 | x0: rand.gen_range(0..=255), 16 | x1: rand.gen_range(0..=255), 17 | x2: rand.gen_range(0..=255), 18 | x3: rand.gen_range(0..=255), 19 | } 20 | } 21 | } 22 | 23 | pub struct Entry { 24 | pub address: Address, 25 | pub identity: String, 26 | pub userid: String, 27 | pub date: String, 28 | pub request: String, 29 | pub code: u16, 30 | pub size: u64, 31 | } 32 | 33 | impl Generate for Entry { 34 | fn generate(rand: &mut R) -> Self { 35 | const USERID: [&str; 9] = [ 36 | "-", "alice", "bob", "carmen", "david", "eric", "frank", "george", 37 | "harry", 38 | ]; 39 | const MONTHS: [&str; 12] = [ 40 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 41 | "Oct", "Nov", "Dec", 42 | ]; 43 | const TIMEZONE: [&str; 25] = [ 44 | "-1200", "-1100", "-1000", "-0900", "-0800", "-0700", "-0600", 45 | "-0500", "-0400", "-0300", "-0200", "-0100", "+0000", "+0100", 46 | "+0200", "+0300", "+0400", "+0500", "+0600", "+0700", "+0800", 47 | "+0900", "+1000", "+1100", "+1200", 48 | ]; 49 | let date = format!( 50 | "{}/{}/{}:{}:{}:{} {}", 51 | rand.gen_range(1..=28), 52 | MONTHS[rand.gen_range(0..12)], 53 | rand.gen_range(1970..=2021), 54 | rand.gen_range(0..24), 55 | rand.gen_range(0..60), 56 | rand.gen_range(0..60), 57 | TIMEZONE[rand.gen_range(0..25)], 58 | ); 59 | const CODES: [u16; 63] = [ 60 | 100, 101, 102, 103, 200, 201, 202, 203, 204, 205, 206, 207, 208, 61 | 226, 300, 301, 302, 303, 304, 305, 306, 307, 308, 400, 401, 402, 62 | 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 63 | 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451, 64 | 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511, 65 | ]; 66 | const METHODS: [&str; 5] = ["GET", "POST", "PUT", "UPDATE", "DELETE"]; 67 | const ROUTES: [&str; 7] = [ 68 | "/favicon.ico", 69 | "/css/index.css", 70 | "/css/font-awesome.min.css", 71 | "/img/logo-full.svg", 72 | "/img/splash.jpg", 73 | "/api/login", 74 | "/api/logout", 75 | ]; 76 | const PROTOCOLS: [&str; 4] = 77 | ["HTTP/1.0", "HTTP/1.1", "HTTP/2", "HTTP/3"]; 78 | let request = format!( 79 | "{} {} {}", 80 | METHODS[rand.gen_range(0..5)], 81 | ROUTES[rand.gen_range(0..7)], 82 | PROTOCOLS[rand.gen_range(0..4)], 83 | ); 84 | Self { 85 | address: Generate::generate(rand), 86 | identity: "-".into(), 87 | userid: USERID[rand.gen_range(0..USERID.len())].into(), 88 | date, 89 | request, 90 | code: CODES[rand.gen_range(0..CODES.len())], 91 | size: rand.gen_range(0..100_000_000), 92 | } 93 | } 94 | } 95 | 96 | pub struct Log { 97 | pub entries: Vec, 98 | } 99 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/log/mod.rs: -------------------------------------------------------------------------------- 1 | mod data; 2 | 3 | use ::criterion::black_box; 4 | use ::mischief::{GhostRef, In, Region, Slot, StaticToken}; 5 | use ::munge::munge; 6 | use ::rand::Rng; 7 | use ::rel_alloc::{alloc::RelAllocator, EmplaceIn, RelString, RelVec}; 8 | use ::rel_core::{Emplace, EmplaceExt, Move, Portable, U16, U64}; 9 | use ::rel_slab_allocator::{RelSlabAllocator, SlabAllocator}; 10 | use ::rel_util::Align16; 11 | use ::situ::{alloc::RawRegionalAllocator, DropRaw}; 12 | 13 | use crate::{from_data::FromData, gen::generate_vec}; 14 | 15 | #[derive(DropRaw, Move, Portable)] 16 | #[repr(C)] 17 | pub struct RelAddress { 18 | pub x0: u8, 19 | pub x1: u8, 20 | pub x2: u8, 21 | pub x3: u8, 22 | } 23 | 24 | unsafe impl Emplace for &'_ data::Address { 25 | fn emplaced_meta(&self) -> ::Metadata {} 26 | 27 | unsafe fn emplace_unsized_unchecked( 28 | self, 29 | out: In, R>, 30 | ) { 31 | munge!( 32 | let RelAddress { 33 | x0, 34 | x1, 35 | x2, 36 | x3, 37 | } = out; 38 | ); 39 | 40 | self.x0.emplace(x0); 41 | self.x1.emplace(x1); 42 | self.x2.emplace(x2); 43 | self.x3.emplace(x3); 44 | } 45 | } 46 | 47 | #[derive(DropRaw, Move, Portable)] 48 | #[repr(C)] 49 | pub struct RelEntry { 50 | pub address: RelAddress, 51 | pub identity: RelString, 52 | pub userid: RelString, 53 | pub date: RelString, 54 | pub request: RelString, 55 | pub code: U16, 56 | pub size: U64, 57 | } 58 | 59 | unsafe impl Emplace, R::Region> 60 | for FromData<'_, R, data::Entry> 61 | where 62 | A: DropRaw + RawRegionalAllocator, 63 | R: Clone + RelAllocator, 64 | { 65 | fn emplaced_meta(&self) -> as ptr_meta::Pointee>::Metadata {} 66 | 67 | unsafe fn emplace_unsized_unchecked( 68 | self, 69 | out: In>, A::Region>, 70 | ) { 71 | use ::rel_alloc::string; 72 | 73 | munge!( 74 | let RelEntry { 75 | address, 76 | identity, 77 | userid, 78 | date, 79 | request, 80 | code, 81 | size, 82 | } = out; 83 | ); 84 | 85 | let Self { alloc, data } = self; 86 | 87 | data.address.emplace(address); 88 | string::Clone(alloc.clone(), &data.identity).emplace(identity); 89 | string::Clone(alloc.clone(), &data.userid).emplace(userid); 90 | string::Clone(alloc.clone(), &data.date).emplace(date); 91 | string::Clone(alloc.clone(), &data.request).emplace(request); 92 | data.code.emplace(code); 93 | data.size.emplace(size); 94 | } 95 | } 96 | 97 | #[derive(DropRaw, Move, Portable)] 98 | #[repr(C)] 99 | pub struct RelLog { 100 | pub entries: RelVec, A>, 101 | } 102 | 103 | unsafe impl Emplace, R::Region> for FromData<'_, R, data::Log> 104 | where 105 | A: DropRaw + Move + RawRegionalAllocator, 106 | R: Clone + RelAllocator, 107 | { 108 | fn emplaced_meta(&self) -> as ptr_meta::Pointee>::Metadata {} 109 | 110 | unsafe fn emplace_unsized_unchecked( 111 | self, 112 | out: In>, A::Region>, 113 | ) { 114 | use ::rel_alloc::vec; 115 | 116 | munge!(let RelLog { entries } = out); 117 | 118 | let entries = 119 | vec::WithCapacity(self.alloc.clone(), self.data.entries.len()) 120 | .emplace_mut(entries); 121 | 122 | RelVec::extend( 123 | In::into_inner(entries), 124 | self.data.entries.iter().map(|data| FromData { 125 | alloc: self.alloc.clone(), 126 | data, 127 | }), 128 | ); 129 | } 130 | } 131 | 132 | fn populate_buffer(data: &data::Log, buffer: Slot<'_, [u8]>) -> usize { 133 | StaticToken::acquire(|mut token| { 134 | let alloc = 135 | SlabAllocator::<_>::try_new_in(buffer, GhostRef::leak(&mut token)) 136 | .unwrap(); 137 | 138 | let log = FromData { alloc, data } 139 | .emplace_in::>>(alloc); 140 | 141 | alloc.deposit(log); 142 | alloc.shrink_to_fit() 143 | }) 144 | } 145 | 146 | pub fn make_bench( 147 | rng: &mut impl Rng, 148 | input_size: usize, 149 | ) -> impl FnMut() -> usize { 150 | let input = data::Log { 151 | entries: generate_vec(rng, input_size), 152 | }; 153 | 154 | let mut bytes = Align16::frame(10_000_000); 155 | 156 | move || { 157 | black_box(populate_buffer( 158 | black_box(&input), 159 | black_box(bytes.slot().as_bytes()), 160 | )) 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/mc_savedata/data.rs: -------------------------------------------------------------------------------- 1 | use ::rand::Rng; 2 | 3 | use crate::gen::{generate_vec, Generate}; 4 | 5 | pub enum GameType { 6 | Survival, 7 | Creative, 8 | Adventure, 9 | Spectator, 10 | } 11 | 12 | impl Generate for GameType { 13 | fn generate(rand: &mut R) -> Self { 14 | match rand.gen_range(0..4) { 15 | 0 => GameType::Survival, 16 | 1 => GameType::Creative, 17 | 2 => GameType::Adventure, 18 | 3 => GameType::Spectator, 19 | _ => unreachable!(), 20 | } 21 | } 22 | } 23 | 24 | pub struct Item { 25 | pub count: i8, 26 | pub slot: u8, 27 | pub id: String, 28 | } 29 | 30 | impl Generate for Item { 31 | fn generate(rng: &mut R) -> Self { 32 | const IDS: [&str; 8] = [ 33 | "dirt", 34 | "stone", 35 | "pickaxe", 36 | "sand", 37 | "gravel", 38 | "shovel", 39 | "chestplate", 40 | "steak", 41 | ]; 42 | Self { 43 | count: rng.gen(), 44 | slot: rng.gen(), 45 | id: IDS[rng.gen_range(0..IDS.len())].to_string(), 46 | } 47 | } 48 | } 49 | 50 | pub struct Abilities { 51 | pub walk_speed: f32, 52 | pub fly_speed: f32, 53 | pub may_fly: bool, 54 | pub flying: bool, 55 | pub invulnerable: bool, 56 | pub may_build: bool, 57 | pub instabuild: bool, 58 | } 59 | 60 | impl Generate for Abilities { 61 | fn generate(rng: &mut R) -> Self { 62 | Self { 63 | walk_speed: rng.gen(), 64 | fly_speed: rng.gen(), 65 | may_fly: rng.gen_bool(0.5), 66 | flying: rng.gen_bool(0.5), 67 | invulnerable: rng.gen_bool(0.5), 68 | may_build: rng.gen_bool(0.5), 69 | instabuild: rng.gen_bool(0.5), 70 | } 71 | } 72 | } 73 | 74 | pub struct Entity { 75 | pub id: String, 76 | pub pos: (f64, f64, f64), 77 | pub motion: (f64, f64, f64), 78 | pub rotation: (f32, f32), 79 | pub fall_distance: f32, 80 | pub fire: u16, 81 | pub air: u16, 82 | pub on_ground: bool, 83 | pub no_gravity: bool, 84 | pub invulnerable: bool, 85 | pub portal_cooldown: i32, 86 | pub uuid: [u32; 4], 87 | pub custom_name: Option, 88 | pub custom_name_visible: bool, 89 | pub silent: bool, 90 | pub glowing: bool, 91 | } 92 | 93 | impl Generate for Entity { 94 | fn generate(rng: &mut R) -> Self { 95 | const IDS: [&str; 8] = [ 96 | "cow", "sheep", "zombie", "skeleton", "spider", "creeper", 97 | "parrot", "bee", 98 | ]; 99 | const CUSTOM_NAMES: [&str; 8] = [ 100 | "rainbow", "princess", "steve", "johnny", "missy", "coward", 101 | "fairy", "howard", 102 | ]; 103 | 104 | Self { 105 | id: IDS[rng.gen_range(0..IDS.len())].to_string(), 106 | pos: Generate::generate(rng), 107 | motion: Generate::generate(rng), 108 | rotation: Generate::generate(rng), 109 | fall_distance: rng.gen(), 110 | fire: rng.gen(), 111 | air: rng.gen(), 112 | on_ground: rng.gen_bool(0.5), 113 | no_gravity: rng.gen_bool(0.5), 114 | invulnerable: rng.gen_bool(0.5), 115 | portal_cooldown: rng.gen(), 116 | uuid: Generate::generate(rng), 117 | custom_name: rng.gen_bool(0.5).then(|| { 118 | CUSTOM_NAMES[rng.gen_range(0..CUSTOM_NAMES.len())].to_string() 119 | }), 120 | custom_name_visible: rng.gen_bool(0.5), 121 | silent: rng.gen_bool(0.5), 122 | glowing: rng.gen_bool(0.5), 123 | } 124 | } 125 | } 126 | 127 | pub struct RecipeBook { 128 | pub recipes: Vec, 129 | pub to_be_displayed: Vec, 130 | pub is_filtering_craftable: bool, 131 | pub is_gui_open: bool, 132 | pub is_furnace_filtering_craftable: bool, 133 | pub is_furnace_gui_open: bool, 134 | pub is_blasting_furnace_filtering_craftable: bool, 135 | pub is_blasting_furnace_gui_open: bool, 136 | pub is_smoker_filtering_craftable: bool, 137 | pub is_smoker_gui_open: bool, 138 | } 139 | 140 | impl Generate for RecipeBook { 141 | fn generate(rng: &mut R) -> Self { 142 | const RECIPES: [&str; 8] = [ 143 | "pickaxe", 144 | "torch", 145 | "bow", 146 | "crafting table", 147 | "furnace", 148 | "shears", 149 | "arrow", 150 | "tnt", 151 | ]; 152 | const MAX_RECIPES: usize = 30; 153 | const MAX_DISPLAYED_RECIPES: usize = 10; 154 | 155 | let recipes_count = rng.gen_range(0..MAX_RECIPES); 156 | let to_be_displayed_count = rng.gen_range(0..MAX_DISPLAYED_RECIPES); 157 | 158 | Self { 159 | recipes: generate_vec::<_, ()>(rng, recipes_count) 160 | .iter() 161 | .map(|_| RECIPES[rng.gen_range(0..RECIPES.len())].to_string()) 162 | .collect(), 163 | to_be_displayed: generate_vec::<_, ()>(rng, to_be_displayed_count) 164 | .iter() 165 | .map(|_| RECIPES[rng.gen_range(0..RECIPES.len())].to_string()) 166 | .collect(), 167 | is_filtering_craftable: rng.gen_bool(0.5), 168 | is_gui_open: rng.gen_bool(0.5), 169 | is_furnace_filtering_craftable: rng.gen_bool(0.5), 170 | is_furnace_gui_open: rng.gen_bool(0.5), 171 | is_blasting_furnace_filtering_craftable: rng.gen_bool(0.5), 172 | is_blasting_furnace_gui_open: rng.gen_bool(0.5), 173 | is_smoker_filtering_craftable: rng.gen_bool(0.5), 174 | is_smoker_gui_open: rng.gen_bool(0.5), 175 | } 176 | } 177 | } 178 | 179 | pub struct Player { 180 | pub game_type: GameType, 181 | pub previous_game_type: GameType, 182 | pub score: i64, 183 | pub dimension: String, 184 | pub selected_item_slot: u32, 185 | pub selected_item: Item, 186 | pub spawn_dimension: Option, 187 | pub spawn_x: i64, 188 | pub spawn_y: i64, 189 | pub spawn_z: i64, 190 | pub spawn_forced: Option, 191 | pub sleep_timer: u16, 192 | pub food_exhaustion_level: f32, 193 | pub food_saturation_level: f32, 194 | pub food_tick_timer: u32, 195 | pub xp_level: u32, 196 | pub xp_p: f32, 197 | pub xp_total: i32, 198 | pub xp_seed: i32, 199 | pub inventory: Vec, 200 | pub ender_items: Vec, 201 | pub abilities: Abilities, 202 | pub entered_nether_position: Option<(f64, f64, f64)>, 203 | pub root_vehicle: Option<([u32; 4], Entity)>, 204 | pub shoulder_entity_left: Option, 205 | pub shoulder_entity_right: Option, 206 | pub seen_credits: bool, 207 | pub recipe_book: RecipeBook, 208 | } 209 | 210 | impl Generate for Player { 211 | fn generate(rng: &mut R) -> Self { 212 | const DIMENSIONS: [&str; 3] = ["overworld", "nether", "end"]; 213 | const MAX_ITEMS: usize = 40; 214 | const MAX_ENDER_ITEMS: usize = 27; 215 | 216 | let inventory_count = rng.gen_range(0..MAX_ITEMS); 217 | let ender_items_count = rng.gen_range(0..MAX_ENDER_ITEMS); 218 | 219 | Self { 220 | game_type: Generate::generate(rng), 221 | previous_game_type: Generate::generate(rng), 222 | score: rng.gen(), 223 | dimension: DIMENSIONS[rng.gen_range(0..DIMENSIONS.len())] 224 | .to_string(), 225 | selected_item_slot: rng.gen(), 226 | selected_item: Generate::generate(rng), 227 | spawn_dimension: rng.gen_bool(0.5).then(|| { 228 | DIMENSIONS[rng.gen_range(0..DIMENSIONS.len())].to_string() 229 | }), 230 | spawn_x: rng.gen(), 231 | spawn_y: rng.gen(), 232 | spawn_z: rng.gen(), 233 | spawn_forced: Generate::generate(rng), 234 | sleep_timer: rng.gen(), 235 | food_exhaustion_level: rng.gen(), 236 | food_saturation_level: rng.gen(), 237 | food_tick_timer: rng.gen(), 238 | xp_level: rng.gen(), 239 | xp_p: rng.gen(), 240 | xp_total: rng.gen(), 241 | xp_seed: rng.gen(), 242 | inventory: generate_vec(rng, inventory_count), 243 | ender_items: generate_vec(rng, ender_items_count), 244 | abilities: Generate::generate(rng), 245 | entered_nether_position: Generate::generate(rng), 246 | root_vehicle: Generate::generate(rng), 247 | shoulder_entity_left: Generate::generate(rng), 248 | shoulder_entity_right: Generate::generate(rng), 249 | seen_credits: rng.gen_bool(0.5), 250 | recipe_book: Generate::generate(rng), 251 | } 252 | } 253 | } 254 | 255 | pub struct SaveData { 256 | pub players: Vec, 257 | } 258 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/mesh/data.rs: -------------------------------------------------------------------------------- 1 | use ::rand::Rng; 2 | 3 | use crate::gen::Generate; 4 | 5 | pub struct Vector3 { 6 | pub x: f32, 7 | pub y: f32, 8 | pub z: f32, 9 | } 10 | 11 | impl Generate for Vector3 { 12 | fn generate(rand: &mut R) -> Self { 13 | Self { 14 | x: rand.gen(), 15 | y: rand.gen(), 16 | z: rand.gen(), 17 | } 18 | } 19 | } 20 | 21 | pub struct Triangle { 22 | pub v0: Vector3, 23 | pub v1: Vector3, 24 | pub v2: Vector3, 25 | pub normal: Vector3, 26 | } 27 | 28 | impl Generate for Triangle { 29 | fn generate(rand: &mut R) -> Self { 30 | Self { 31 | v0: Generate::generate(rand), 32 | v1: Generate::generate(rand), 33 | v2: Generate::generate(rand), 34 | normal: Generate::generate(rand), 35 | } 36 | } 37 | } 38 | 39 | pub struct Mesh { 40 | pub triangles: Vec, 41 | } 42 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/mesh/mod.rs: -------------------------------------------------------------------------------- 1 | mod data; 2 | 3 | use ::criterion::black_box; 4 | use ::mischief::{GhostRef, In, Region, Slot, StaticToken}; 5 | use ::munge::munge; 6 | use ::rand::Rng; 7 | use ::rel_alloc::{alloc::RelAllocator, EmplaceIn, RelVec}; 8 | use ::rel_core::{Emplace, EmplaceExt, Move, Portable, F32}; 9 | use ::rel_slab_allocator::{RelSlabAllocator, SlabAllocator}; 10 | use ::rel_util::Align16; 11 | use ::situ::{alloc::RawRegionalAllocator, DropRaw}; 12 | 13 | use crate::{from_data::FromData, gen::generate_vec}; 14 | 15 | #[derive(DropRaw, Move, Portable)] 16 | #[repr(C)] 17 | pub struct RelVector3 { 18 | pub x: F32, 19 | pub y: F32, 20 | pub z: F32, 21 | } 22 | 23 | unsafe impl Emplace for &'_ data::Vector3 { 24 | fn emplaced_meta(&self) -> ::Metadata {} 25 | 26 | unsafe fn emplace_unsized_unchecked( 27 | self, 28 | out: In, R>, 29 | ) { 30 | munge!( 31 | let RelVector3 { 32 | x, 33 | y, 34 | z, 35 | } = out; 36 | ); 37 | 38 | self.x.emplace(x); 39 | self.y.emplace(y); 40 | self.z.emplace(z); 41 | } 42 | } 43 | 44 | #[derive(DropRaw, Move, Portable)] 45 | #[repr(C)] 46 | pub struct RelTriangle { 47 | pub v0: RelVector3, 48 | pub v1: RelVector3, 49 | pub v2: RelVector3, 50 | pub normal: RelVector3, 51 | } 52 | 53 | unsafe impl Emplace for &'_ data::Triangle { 54 | fn emplaced_meta(&self) -> ::Metadata {} 55 | 56 | unsafe fn emplace_unsized_unchecked( 57 | self, 58 | out: In, R>, 59 | ) { 60 | munge!( 61 | let RelTriangle { 62 | v0, 63 | v1, 64 | v2, 65 | normal, 66 | } = out; 67 | ); 68 | 69 | self.v0.emplace(v0); 70 | self.v1.emplace(v1); 71 | self.v2.emplace(v2); 72 | self.normal.emplace(normal); 73 | } 74 | } 75 | 76 | #[derive(DropRaw, Move, Portable)] 77 | #[repr(C)] 78 | pub struct RelMesh { 79 | pub triangles: RelVec, 80 | } 81 | 82 | unsafe impl Emplace, R::Region> for FromData<'_, R, data::Mesh> 83 | where 84 | A: DropRaw + RawRegionalAllocator, 85 | R: RelAllocator, 86 | { 87 | fn emplaced_meta(&self) -> as ptr_meta::Pointee>::Metadata {} 88 | 89 | unsafe fn emplace_unsized_unchecked( 90 | self, 91 | out: In>, A::Region>, 92 | ) { 93 | use ::rel_alloc::vec; 94 | 95 | munge!(let RelMesh { triangles } = out); 96 | 97 | let triangles = 98 | vec::WithCapacity(self.alloc, self.data.triangles.len()) 99 | .emplace_mut(triangles); 100 | 101 | RelVec::extend(In::into_inner(triangles), self.data.triangles.iter()); 102 | } 103 | } 104 | 105 | fn populate_buffer(data: &data::Mesh, buffer: Slot<'_, [u8]>) -> usize { 106 | StaticToken::acquire(|mut token| { 107 | let alloc = 108 | SlabAllocator::<_>::try_new_in(buffer, GhostRef::leak(&mut token)) 109 | .unwrap(); 110 | 111 | let mesh = FromData { alloc, data } 112 | .emplace_in::>>(alloc); 113 | 114 | alloc.deposit(mesh); 115 | alloc.shrink_to_fit() 116 | }) 117 | } 118 | 119 | pub fn make_bench( 120 | rng: &mut impl Rng, 121 | input_size: usize, 122 | ) -> impl FnMut() -> usize { 123 | let input = data::Mesh { 124 | triangles: generate_vec(rng, input_size), 125 | }; 126 | 127 | let mut bytes = Align16::frame(10_000_000); 128 | move || { 129 | black_box(populate_buffer( 130 | black_box(&input), 131 | black_box(bytes.slot().as_bytes()), 132 | )) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /rel_alloc/bench_tests/test.rs: -------------------------------------------------------------------------------- 1 | pub mod from_data; 2 | pub mod gen; 3 | mod log; 4 | mod mc_savedata; 5 | mod mesh; 6 | 7 | #[test] 8 | fn test_log_bench() { 9 | log::make_bench(&mut gen::default_rng(), 10)(); 10 | } 11 | 12 | #[test] 13 | fn test_mesh_bench() { 14 | mesh::make_bench(&mut gen::default_rng(), 10)(); 15 | } 16 | 17 | #[test] 18 | fn test_mc_savedata_bench() { 19 | mc_savedata::make_bench(&mut gen::default_rng(), 10)(); 20 | } 21 | -------------------------------------------------------------------------------- /rel_alloc/src/alloc.rs: -------------------------------------------------------------------------------- 1 | //! Memory allocation APIs. 2 | 3 | use ::mischief::RegionalAllocator; 4 | use ::rel_core::Emplace; 5 | use ::situ::{alloc::RawRegionalAllocator, DropRaw}; 6 | 7 | /// An `Allocator` that is suitable for allocating relative types. 8 | /// 9 | /// # Safety 10 | /// 11 | /// When emplaced as an `E`, the emplaced `E` must function analogously to the 12 | /// original allocator. Specifically, it must return the same results when 13 | /// calling the analogous allocator methods from `RawAllocator` and share the 14 | /// same state between the two (e.g. allocating with one and freeing with the 15 | /// other must be safe and function properly). 16 | pub unsafe trait RelAllocator: 17 | RegionalAllocator + Emplace + Sized 18 | where 19 | E: DropRaw + RawRegionalAllocator, 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /rel_alloc/src/boxed.rs: -------------------------------------------------------------------------------- 1 | //! A pointer type for heap allocation. 2 | 3 | use ::core::{alloc::Layout, fmt, mem::MaybeUninit}; 4 | use ::mischief::{In, Slot}; 5 | use ::munge::munge; 6 | use ::ptr_meta::Pointee; 7 | use ::rel_core::{ 8 | Basis, 9 | BasisPointee, 10 | DefaultBasis, 11 | Emplace, 12 | EmplaceExt, 13 | Move, 14 | Portable, 15 | RelPtr, 16 | }; 17 | use ::situ::{ 18 | alloc::RawRegionalAllocator, 19 | fmt::{DebugRaw, DisplayRaw}, 20 | ops::{DerefMutRaw, DerefRaw, IndexMutRaw, IndexRaw}, 21 | DropRaw, 22 | Mut, 23 | OwnedVal, 24 | Ref, 25 | Val, 26 | }; 27 | 28 | use crate::alloc::RelAllocator; 29 | 30 | /// A relative counterpart to `Box`. 31 | #[derive(Move, Portable)] 32 | #[repr(C)] 33 | pub struct RelBox< 34 | T: BasisPointee + ?Sized, 35 | A: RawRegionalAllocator, 36 | B: Basis = DefaultBasis, 37 | > { 38 | ptr: RelPtr, 39 | alloc: A, 40 | } 41 | 42 | impl DropRaw for RelBox 43 | where 44 | T: BasisPointee + DropRaw + ?Sized, 45 | A: RawRegionalAllocator + DropRaw, 46 | B: Basis, 47 | { 48 | #[inline] 49 | unsafe fn drop_raw(mut this: Mut<'_, Self>) { 50 | let inner = Self::deref_mut_raw(this.as_mut()); 51 | let layout = Layout::for_value(&*inner); 52 | 53 | let inner_ptr = inner.as_non_null(); 54 | // SAFETY: `inner` is valid for dropping because we own it. It will 55 | // never be accessed again because `this` will never be accessed again. 56 | unsafe { 57 | DropRaw::drop_raw(inner); 58 | } 59 | 60 | munge!(let RelBox { ptr, alloc } = this); 61 | 62 | // SAFETY: `ptr` is never null and always allocated in `alloc` with a 63 | // layout of `layout`. 64 | unsafe { 65 | A::raw_deallocate(alloc.as_ref(), inner_ptr.cast(), layout); 66 | } 67 | 68 | // SAFETY: `ptr` and `alloc` are always valid for dropping and are not 69 | // accessed again. 70 | unsafe { 71 | DropRaw::drop_raw(ptr); 72 | DropRaw::drop_raw(alloc); 73 | } 74 | } 75 | } 76 | 77 | impl RelBox 78 | where 79 | T: BasisPointee + ?Sized, 80 | A: RawRegionalAllocator, 81 | B: Basis, 82 | { 83 | /// Returns a reference to the underlying allocator. 84 | #[inline] 85 | pub fn allocator(this: Ref<'_, Self>) -> Ref<'_, A> { 86 | munge!(let RelBox { alloc, .. } = this); 87 | alloc 88 | } 89 | } 90 | 91 | impl DerefRaw for RelBox 92 | where 93 | T: BasisPointee + ?Sized, 94 | A: RawRegionalAllocator, 95 | B: Basis, 96 | { 97 | type Target = T; 98 | 99 | fn deref_raw(this: Ref<'_, Self>) -> Ref<'_, T> { 100 | munge!(let RelBox { ptr, .. } = this); 101 | // SAFETY: 102 | // - The value pointed to by a `RelBox` is always non-null, 103 | // properly-aligned, and valid for reads. 104 | // - Because `this` is a shared reference and `ptr` is borrowed from it, 105 | // `ptr` cannot alias any other mutable references for `'_`. 106 | // - The value pointed to by a `RelBox` is always initialized. 107 | unsafe { RelPtr::as_ref(ptr) } 108 | } 109 | } 110 | 111 | impl DerefMutRaw for RelBox 112 | where 113 | T: BasisPointee + ?Sized, 114 | A: RawRegionalAllocator, 115 | B: Basis, 116 | { 117 | fn deref_mut_raw(this: Mut<'_, Self>) -> Mut<'_, T> { 118 | munge!(let RelBox { ptr, .. } = this); 119 | // SAFETY: 120 | // - The value pointed to by a `RelBox` is always non-null, 121 | // properly-aligned, and valid for reads and writes. 122 | // - Because `this` is a shared reference and `ptr` is borrowed from it, 123 | // `ptr` cannot alias any other accessible references for `'_`. 124 | // - The value pointed to by a `RelBox` is always initialized and 125 | // treated as immovable. 126 | unsafe { RelPtr::as_mut(ptr) } 127 | } 128 | } 129 | 130 | impl DebugRaw for RelBox 131 | where 132 | T: BasisPointee + DebugRaw + ?Sized, 133 | A: RawRegionalAllocator, 134 | B: Basis, 135 | { 136 | fn fmt_raw( 137 | this: Ref<'_, Self>, 138 | f: &mut fmt::Formatter<'_>, 139 | ) -> Result<(), fmt::Error> { 140 | DebugRaw::fmt_raw(DerefRaw::deref_raw(this), f) 141 | } 142 | } 143 | 144 | impl DisplayRaw for RelBox 145 | where 146 | T: BasisPointee + DisplayRaw + ?Sized, 147 | A: RawRegionalAllocator, 148 | B: Basis, 149 | { 150 | fn fmt_raw( 151 | this: Ref<'_, Self>, 152 | f: &mut fmt::Formatter<'_>, 153 | ) -> Result<(), fmt::Error> { 154 | DisplayRaw::fmt_raw(DerefRaw::deref_raw(this), f) 155 | } 156 | } 157 | 158 | impl IndexRaw for RelBox 159 | where 160 | T: BasisPointee + IndexRaw + ?Sized, 161 | A: RawRegionalAllocator, 162 | B: Basis, 163 | { 164 | type Output = >::Output; 165 | 166 | fn index_raw(this: Ref<'_, Self>, index: Idx) -> Ref<'_, Self::Output> { 167 | IndexRaw::index_raw(DerefRaw::deref_raw(this), index) 168 | } 169 | 170 | unsafe fn index_raw_unchecked( 171 | this: Ref<'_, Self>, 172 | index: Idx, 173 | ) -> Ref<'_, Self::Output> { 174 | // SAFETY: The caller has guaranteed that `index` is in bounds for 175 | // indexing. 176 | unsafe { 177 | IndexRaw::index_raw_unchecked(DerefRaw::deref_raw(this), index) 178 | } 179 | } 180 | } 181 | 182 | impl IndexMutRaw for RelBox 183 | where 184 | T: BasisPointee + IndexMutRaw + ?Sized, 185 | A: RawRegionalAllocator, 186 | B: Basis, 187 | { 188 | fn index_mut_raw(this: Mut<'_, Self>, index: Idx) -> Mut<'_, Self::Output> { 189 | IndexMutRaw::index_mut_raw(DerefMutRaw::deref_mut_raw(this), index) 190 | } 191 | 192 | unsafe fn index_mut_raw_unchecked( 193 | this: Mut<'_, Self>, 194 | index: Idx, 195 | ) -> Mut<'_, Self::Output> { 196 | // SAFETY: The caller has guaranteed that `index` is in bounds for 197 | // indexing. 198 | unsafe { 199 | IndexMutRaw::index_mut_raw_unchecked( 200 | DerefMutRaw::deref_mut_raw(this), 201 | index, 202 | ) 203 | } 204 | } 205 | } 206 | 207 | impl RelBox, A, B> 208 | where 209 | T: DropRaw, 210 | A: RawRegionalAllocator + DropRaw, 211 | B: Basis, 212 | { 213 | /// Converts to a `RelBox`. 214 | /// 215 | /// # Safety 216 | /// 217 | /// The value in this `RelBox` must be initialized. 218 | pub unsafe fn assume_init(b: Val) -> Val> { 219 | // SAFETY: The caller has guaranteed that the underlying `MaybeUninit` 220 | // has been properly initialized, and `MaybeUninit` has the same 221 | // layout as the `T` it wraps. 222 | unsafe { b.cast() } 223 | } 224 | } 225 | 226 | // SAFETY: 227 | // - `RelBox` is `Sized` and always has metadata `()`, so `emplaced_meta` always 228 | // returns valid metadata for it. 229 | // - `emplace_unsized_unchecked` initializes its `out` parameter. 230 | unsafe impl Emplace, R::Region> for OwnedVal 231 | where 232 | T: BasisPointee + DropRaw + ?Sized, 233 | A: DropRaw + RawRegionalAllocator, 234 | B: Basis, 235 | R: RelAllocator, 236 | { 237 | #[inline] 238 | fn emplaced_meta(&self) -> as Pointee>::Metadata {} 239 | 240 | unsafe fn emplace_unsized_unchecked( 241 | self, 242 | mut out: In>, R::Region>, 243 | ) { 244 | let this = In::new(self); 245 | let ptr = this.as_raw(); 246 | let (_, alloc) = OwnedVal::into_raw_parts(In::into_inner(this)); 247 | 248 | munge!(let RelBox { ptr: out_ptr, alloc: out_alloc } = out.as_mut()); 249 | 250 | ptr.emplace(out_ptr); 251 | alloc.emplace(out_alloc); 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /rel_alloc/src/emplace_in.rs: -------------------------------------------------------------------------------- 1 | use ::mischief::{Frame, In, Metadata, RegionalAllocator}; 2 | use ::ptr_meta::Pointee; 3 | use ::rel_core::Emplace; 4 | use ::situ::{DropRaw, OwnedVal}; 5 | 6 | /// An extension trait for `Emplace` that provides an allocating emplacement 7 | /// function. 8 | pub trait EmplaceIn { 9 | /// Emplaces a value into a new `OwnedVal` allocated from the given 10 | /// allocator and returns it. 11 | #[must_use] 12 | fn emplace_in(self, alloc: A) -> OwnedVal 13 | where 14 | T: DropRaw + Pointee + ?Sized, 15 | ::Metadata: Metadata, 16 | Self: Emplace; 17 | } 18 | 19 | impl EmplaceIn for E 20 | where 21 | A: RegionalAllocator, 22 | { 23 | #[must_use] 24 | fn emplace_in(self, alloc: A) -> OwnedVal 25 | where 26 | T: DropRaw + Pointee + ?Sized, 27 | ::Metadata: Metadata, 28 | Self: Emplace, 29 | { 30 | let frame = 31 | // SAFETY: The pointer metadata is from `emplaced_meta`, which is 32 | // guaranteed to be valid for a pointer to `T`. 33 | unsafe { Frame::new_unsized_in(self.emplaced_meta(), alloc) }; 34 | 35 | let mut frame = In::new(frame); 36 | let slot = frame.slot(); 37 | 38 | // SAFETY: We just allocated the slot in a frame with the metadata from 39 | // `emplaced_meta`. 40 | unsafe { 41 | self.emplace_unsized_unchecked(slot); 42 | } 43 | // SAFETY: `emplace` is guaranteed to initialize the slot. That slot is 44 | // from the frame, so the frame is initialized. 45 | unsafe { OwnedVal::assume_init(In::into_inner(frame)) } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rel_alloc/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `rel_alloc` is a set of portable, relative-pointer based replacements for 2 | //! alloc library types. 3 | 4 | #![deny( 5 | missing_docs, 6 | unsafe_op_in_unsafe_fn, 7 | clippy::as_conversions, 8 | clippy::missing_safety_doc, 9 | clippy::undocumented_unsafe_blocks, 10 | rustdoc::broken_intra_doc_links, 11 | rustdoc::missing_crate_level_docs 12 | )] 13 | #![no_std] 14 | 15 | pub mod alloc; 16 | pub mod boxed; 17 | mod emplace_in; 18 | pub mod string; 19 | pub mod vec; 20 | 21 | pub use self::{ 22 | boxed::RelBox, 23 | emplace_in::EmplaceIn, 24 | string::RelString, 25 | vec::RelVec, 26 | }; 27 | -------------------------------------------------------------------------------- /rel_alloc/src/string.rs: -------------------------------------------------------------------------------- 1 | //! A UTF-8 encoded, growable string. 2 | 3 | use ::core::{fmt, ptr::copy_nonoverlapping}; 4 | use ::mischief::{In, Slot}; 5 | use ::munge::munge; 6 | use ::ptr_meta::Pointee; 7 | use ::rel_core::{Basis, DefaultBasis, Emplace, EmplaceExt, Move, Portable}; 8 | use ::situ::{ 9 | alloc::RawRegionalAllocator, 10 | fmt::{DebugRaw, DisplayRaw}, 11 | ops::{DerefMutRaw, DerefRaw}, 12 | str::{from_raw_utf8_unchecked, from_raw_utf8_unchecked_mut}, 13 | DropRaw, 14 | Mut, 15 | Ref, 16 | }; 17 | 18 | use crate::{alloc::RelAllocator, vec, RelVec}; 19 | 20 | /// A relative counterpart to `String`. 21 | #[derive(DropRaw, Move, Portable)] 22 | #[repr(C)] 23 | pub struct RelString { 24 | vec: RelVec, 25 | } 26 | 27 | impl RelString { 28 | /// Returns a reference to the underlying allocator. 29 | #[inline] 30 | pub fn allocator(this: Ref<'_, Self>) -> Ref<'_, A> { 31 | munge!(let RelString { vec } = this); 32 | RelVec::allocator(vec) 33 | } 34 | 35 | /// Returns a bytes slice of this `RelString`'s contents. 36 | #[inline] 37 | pub fn as_bytes(this: Ref<'_, Self>) -> Ref<'_, [u8]> { 38 | munge!(let RelString { vec } = this); 39 | DerefRaw::deref_raw(vec) 40 | } 41 | 42 | /// Returns a string slice of the `RelString`'s contents. 43 | #[inline] 44 | pub fn as_str(this: Ref<'_, Self>) -> Ref<'_, str> { 45 | // SAFETY: The bytes of a `RelString` are always valid UTF-8. 46 | unsafe { from_raw_utf8_unchecked(Self::as_bytes(this)) } 47 | } 48 | 49 | /// Returns a mutable reference to the contents of this `RelString`. 50 | /// 51 | /// # Safety 52 | /// 53 | /// The returned `Mut<'_, RelVec>` allows writing bytes which are 54 | /// not valid UTF-8. If this constraint is violated, using the original 55 | /// `RelString` after dropping the `Mut` may violate memory safety, as other 56 | /// code may assume that `RelStrings` only contain valid UTF-8. 57 | #[inline] 58 | pub unsafe fn as_mut_vec(this: Mut<'_, Self>) -> Mut<'_, RelVec> { 59 | munge!(let RelString { vec } = this); 60 | vec 61 | } 62 | 63 | /// Returns a mutable string slice of the `RelString`'s contents. 64 | #[inline] 65 | pub fn as_mut_str(this: Mut<'_, Self>) -> Mut<'_, str> { 66 | // SAFETY: The contents of the `RelVec` are returned as a mutable `str`, 67 | // which cannot be mutated into invalid UTF-8. 68 | let vec = unsafe { Self::as_mut_vec(this) }; 69 | let bytes = DerefMutRaw::deref_mut_raw(vec); 70 | // SAFETY: The bytes of a `RelString` are always valid UTF-8. 71 | unsafe { from_raw_utf8_unchecked_mut(bytes) } 72 | } 73 | 74 | /// Returns this `RelString`'s capacity, in bytes. 75 | #[inline] 76 | pub fn capacity(&self) -> usize { 77 | self.vec.capacity() 78 | } 79 | 80 | /// Truncates this `RelString`, removing all contents. 81 | /// 82 | /// While this means the `String` will have a length of zero, it does not 83 | /// affect its capacity. 84 | #[inline] 85 | pub fn clear(this: Mut<'_, Self>) { 86 | munge!(let RelString { vec } = this); 87 | RelVec::clear(vec) 88 | } 89 | 90 | /// Returns the length of this `RelString`, in bytes, not `char`s or 91 | /// graphemes. In other words, it might not be what a human considers the 92 | /// length of the string. 93 | #[inline] 94 | pub fn len(&self) -> usize { 95 | self.vec.len() 96 | } 97 | 98 | /// Returns whether this `RelString` is empty. 99 | #[inline] 100 | pub fn is_empty(&self) -> bool { 101 | self.vec.is_empty() 102 | } 103 | } 104 | 105 | impl DerefRaw for RelString { 106 | type Target = str; 107 | 108 | fn deref_raw(this: Ref<'_, Self>) -> Ref<'_, Self::Target> { 109 | Self::as_str(this) 110 | } 111 | } 112 | 113 | /// An emplacer for a `RelString` that copies its bytes from a `str`. 114 | pub struct Clone<'a, R>(pub R, pub &'a str); 115 | 116 | // SAFETY: 117 | // - `RelString` is `Sized` and always has metadata `()`, so `emplaced_meta` 118 | // always returns valid metadata for it. 119 | // - `emplace_unsized_unchecked` initializes its `out` parameter by emplacing to 120 | // each field. 121 | unsafe impl Emplace, R::Region> for Clone<'_, R> 122 | where 123 | A: DropRaw + RawRegionalAllocator, 124 | B: Basis, 125 | R: RelAllocator, 126 | { 127 | fn emplaced_meta(&self) -> as Pointee>::Metadata {} 128 | 129 | unsafe fn emplace_unsized_unchecked( 130 | self, 131 | out: In>, A::Region>, 132 | ) { 133 | let len = self.1.len(); 134 | 135 | munge!(let RelString { vec: out_vec } = out); 136 | let mut vec = 137 | In::into_inner(vec::WithCapacity(self.0, len).emplace_mut(out_vec)); 138 | // SAFETY: 139 | // - `src.1.as_ptr()` is valid for reads of `len` bytes because it is a 140 | // pointer to a `&str` of length `len`. 141 | // - `RelVec::as_mut_ptr` is valid for writes of `len` bytes because it 142 | // was emplaced with capacity `len`. 143 | // - Both `str` and `RelVec` are allocated with the proper alignment 144 | // for `u8`. 145 | // - The two regions of memory cannot overlap because `vec` is newly 146 | // allocated and points to unaliased memory. 147 | unsafe { 148 | copy_nonoverlapping( 149 | self.1.as_ptr(), 150 | RelVec::as_mut_ptr(vec.as_mut()), 151 | len, 152 | ); 153 | } 154 | // SAFETY: 155 | // - `len` is exactly equal to capacity. 156 | // - We initialized all of the bytes of the `RelVec` by copying the 157 | // bytes of the emplaced string to them. 158 | unsafe { 159 | RelVec::set_len(vec, len); 160 | } 161 | } 162 | } 163 | 164 | impl DebugRaw for RelString { 165 | fn fmt_raw( 166 | this: Ref<'_, Self>, 167 | f: &mut fmt::Formatter<'_>, 168 | ) -> Result<(), fmt::Error> { 169 | fmt::Debug::fmt(&*Self::as_str(this), f) 170 | } 171 | } 172 | 173 | impl DisplayRaw for RelString { 174 | fn fmt_raw( 175 | this: Ref<'_, Self>, 176 | f: &mut fmt::Formatter<'_>, 177 | ) -> Result<(), fmt::Error> { 178 | fmt::Display::fmt(&*Self::as_str(this), f) 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /rel_core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rel_core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies.mischief] 7 | version = "0.1" 8 | path = "../mischief" 9 | default-features = false 10 | 11 | [dependencies.munge] 12 | version = "0.4" 13 | git = "https://github.com/djkoloski/munge" 14 | 15 | [dependencies.ptr_meta] 16 | version = "0.2" 17 | default-features = false 18 | 19 | [dependencies.raw_enum_macro] 20 | version = "0.1" 21 | path = "../raw_enum_macro" 22 | 23 | [dependencies.rel_core_derive] 24 | version = "0.1" 25 | path = "../rel_core_derive" 26 | 27 | [dependencies.situ] 28 | version = "0.1" 29 | path = "../situ" 30 | 31 | [features] 32 | default = ["little_endian", "basis_32"] 33 | little_endian = [] 34 | big_endian = [] 35 | basis_16 = [] 36 | basis_32 = [] 37 | basis_64 = [] 38 | -------------------------------------------------------------------------------- /rel_core/src/emplace/impls.rs: -------------------------------------------------------------------------------- 1 | use ::core::{mem::ManuallyDrop, ptr}; 2 | use ::mischief::{In, Region, Slot}; 3 | use ::ptr_meta::Pointee; 4 | use ::situ::DropRaw; 5 | 6 | use crate::{Emplace, EmplaceExt}; 7 | 8 | macro_rules! impl_builtin { 9 | ($($ty:ty),*) => { 10 | $( 11 | // SAFETY: 12 | // - `emplaced_meta` returns `()`, the only valid metadata for 13 | // `Sized` types. 14 | // - `emplace_unsized_unchecked` initializes its `out` parameter by 15 | // writing to it. 16 | unsafe impl Emplace<$ty, R> for $ty { 17 | fn emplaced_meta(&self) -> ::Metadata {} 18 | 19 | unsafe fn emplace_unsized_unchecked( 20 | self, 21 | out: In, R>, 22 | ) { 23 | In::into_inner(out).write(self); 24 | } 25 | } 26 | )* 27 | } 28 | } 29 | 30 | impl_builtin!(i8, u8, bool, ()); 31 | 32 | // SAFETY: 33 | // - `emplaced_meta` returns `()`, the only valid metadata for `Sized` types. 34 | // - `emplace_unsized_unchecked` emplaces to every element of the `out` slot, 35 | // which initializes it. 36 | unsafe impl Emplace<[T; N], R> for [E; N] 37 | where 38 | E: Emplace, 39 | T: DropRaw, 40 | { 41 | fn emplaced_meta(&self) -> ::Metadata {} 42 | 43 | unsafe fn emplace_unsized_unchecked(self, out: In, R>) { 44 | let emplacers = ManuallyDrop::new(self); 45 | let mut out = In::into_inner(out); 46 | for i in 0..N { 47 | // SAFETY: `i` is in bounds because it must be less than the length 48 | // of the array, `N`. 49 | let out_i = unsafe { out.as_mut().get_unchecked(i) }; 50 | // SAFETY: `out_i` is located in `R` because `out` is located in `R` 51 | // and `out_i` is an element of `out`. 52 | let out_i = unsafe { In::new_unchecked(out_i) }; 53 | // SAFETY: The pointer being read is from a reference, so it must be 54 | // valid for reads, properly aligned, and point to an initialized 55 | // value. 56 | let emplacer_i = unsafe { ptr::read(&emplacers[i]) }; 57 | emplacer_i.emplace(out_i); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /rel_core/src/emplace/mod.rs: -------------------------------------------------------------------------------- 1 | mod impls; 2 | 3 | use ::mischief::{In, Region, Slot}; 4 | use ::ptr_meta::{metadata, Pointee}; 5 | use ::situ::{DropRaw, Mut, Val}; 6 | 7 | /// A value emplacer. 8 | /// 9 | /// # Safety 10 | /// 11 | /// - `emplaced_meta` must return valid metadata for the value emplaced with 12 | /// `emplace_unsized_unchecked`. 13 | /// - `emplace_unsized_unchecked` must initialize its `out` parameter. 14 | pub unsafe trait Emplace { 15 | /// Returns the metadata of the `T` that this emplaces. 16 | /// 17 | /// For sized `T`, this is always `()`. 18 | fn emplaced_meta(&self) -> ::Metadata; 19 | 20 | /// Emplaces a value into a given slot within some memory region. 21 | /// 22 | /// # Safety 23 | /// 24 | /// `out` must have the metadata returned by `emplaced_meta`. 25 | unsafe fn emplace_unsized_unchecked(self, out: In, R>); 26 | } 27 | 28 | /// An extension trait for `Emplace` that provides a variety of convenient 29 | /// emplacement methods. 30 | /// 31 | /// # Safety 32 | /// 33 | /// `emplace_val_unsized` and `emplace_val` must initialize `out` and return it 34 | /// as a `Val`. 35 | pub unsafe trait EmplaceExt: Emplace 36 | where 37 | T: DropRaw + Pointee + ?Sized, 38 | { 39 | /// Emplaces a value into a given slot within some memory region. 40 | /// 41 | /// # Panics 42 | /// 43 | /// Panics if `out` does not have the metadata returned by `emplaced_meta`. 44 | fn emplace_unsized(self, out: In, R>); 45 | 46 | /// Emplaces a sized value into a given slot within some memory region. 47 | /// 48 | /// This simply wraps a call to `emplace_unsized_unchecked`. Because `T` is 49 | /// `Sized`, the metadata of the slot's pointer must always match the 50 | /// metadata returned from `emplaced_meta`, and so it is safe. 51 | fn emplace(self, out: In, R>) 52 | where 53 | T: Sized; 54 | 55 | /// Emplaces a value into a given slot within some memory region and returns 56 | /// a mutable reference. 57 | /// 58 | /// # Safety 59 | /// 60 | /// `out` must have the metadata returned by `emplaced_meta`. 61 | unsafe fn emplace_mut_unsized( 62 | self, 63 | out: In, R>, 64 | ) -> In, R>; 65 | 66 | /// Emplaces a sized value into a given slot within some memory region and 67 | /// returns a mutable reference. 68 | fn emplace_mut(self, out: In, R>) -> In, R>; 69 | 70 | /// Emplaces a value into a given slot within some memory region and returns 71 | /// an initialized value. 72 | /// 73 | /// # Safety 74 | /// 75 | /// `out` must have the metadata returned by `emplaced_meta`. 76 | #[must_use] 77 | unsafe fn emplace_val_unsized( 78 | self, 79 | out: In, R>, 80 | ) -> In, R>; 81 | 82 | /// Emplaces a sized value into a given slot within some memory region and 83 | /// returns an initialized value. 84 | /// 85 | /// This simply wraps a call to `emplace_val_unsized`. Because `T` is sized, 86 | /// the metadata of the slot's pointer must always match the metadata 87 | /// returned from `emplaced_meta`, and so it is safe. 88 | #[must_use] 89 | fn emplace_val(self, out: In, R>) -> In, R> 90 | where 91 | T: Sized; 92 | } 93 | 94 | // SAFETY: `emplace_val` initializes `out` and returns it as a `Val`. 95 | unsafe impl EmplaceExt for E 96 | where 97 | E: Emplace, 98 | T: DropRaw + Pointee + ?Sized, 99 | R: Region, 100 | { 101 | fn emplace_unsized(self, out: In, R>) { 102 | assert!(self.emplaced_meta() == metadata::(out.ptr().as_ptr())); 103 | // SAFETY: We have asserted that the metadata of `self` and `out` are 104 | // equal. 105 | unsafe { 106 | self.emplace_unsized_unchecked(out); 107 | } 108 | } 109 | 110 | #[inline] 111 | fn emplace(self, out: In, R>) 112 | where 113 | T: Sized, 114 | { 115 | // SAFETY: `out` can only have the metadata `()` and so it must be the 116 | // same as the metadata returned from `emplaced_meta`. 117 | unsafe { self.emplace_unsized_unchecked(out) } 118 | } 119 | 120 | unsafe fn emplace_mut_unsized( 121 | self, 122 | out: In, R>, 123 | ) -> In, R> { 124 | // SAFETY: The caller has guaranteed that `out` has the metadata 125 | // returned by `emplaced_meta`. 126 | let val = unsafe { self.emplace_val_unsized(out) }; 127 | // SAFETY: `Val::leak` returns a mutable reference to its contained 128 | // value. Since the value is allocated in `R`, its contained value must 129 | // also be. 130 | unsafe { In::map_unchecked(val, Val::leak) } 131 | } 132 | 133 | #[inline] 134 | fn emplace_mut(self, out: In, R>) -> In, R> { 135 | // SAFETY: `out` can only have the metadata `()` and so it must be the 136 | // same as the metadata returned from `emplaced_meta`. 137 | unsafe { self.emplace_mut_unsized(out) } 138 | } 139 | 140 | #[must_use] 141 | unsafe fn emplace_val_unsized( 142 | self, 143 | mut out: In, R>, 144 | ) -> In, R> { 145 | // SAFETY: The caller has guaranteed that `out` has the metadata 146 | // returned by `emplaced_meta`. 147 | unsafe { 148 | self.emplace_unsized_unchecked(out.as_mut()); 149 | } 150 | // SAFETY: `emplace` is guaranteed to initialize `out`. 151 | let initialize = |s| unsafe { Val::from_slot_unchecked(s) }; 152 | // SAFETY: the `Val` created from `out` points to the same memory and so 153 | // must be located in the same region. 154 | unsafe { out.map_unchecked(initialize) } 155 | } 156 | 157 | #[inline] 158 | #[must_use] 159 | fn emplace_val(self, out: In, R>) -> In, R> 160 | where 161 | T: Sized, 162 | { 163 | // SAFETY: `out` can only have the metadata `()` and so it must be the 164 | // same as the metadata returned from `emplaced_meta`. 165 | unsafe { self.emplace_val_unsized(out) } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /rel_core/src/export.rs: -------------------------------------------------------------------------------- 1 | //! Public re-exports of dependencies. 2 | 3 | pub use ::mischief; 4 | pub use ::situ; 5 | -------------------------------------------------------------------------------- /rel_core/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `rel_core` is a set of portable, relative-pointer based replacements for 2 | //! core library types. 3 | 4 | #![deny( 5 | missing_docs, 6 | unsafe_op_in_unsafe_fn, 7 | clippy::as_conversions, 8 | clippy::missing_safety_doc, 9 | clippy::undocumented_unsafe_blocks, 10 | rustdoc::broken_intra_doc_links, 11 | rustdoc::missing_crate_level_docs 12 | )] 13 | #![no_std] 14 | 15 | mod basis; 16 | mod emplace; 17 | pub mod export; 18 | mod r#move; 19 | pub mod option; 20 | mod portable; 21 | mod primitive; 22 | pub mod rel_mem; 23 | pub mod rel_ptr; 24 | pub mod rel_ref; 25 | pub mod rel_tuple; 26 | 27 | pub use self::{ 28 | basis::*, 29 | emplace::*, 30 | portable::*, 31 | primitive::*, 32 | r#move::*, 33 | rel_ptr::RelPtr, 34 | rel_ref::RelRef, 35 | }; 36 | -------------------------------------------------------------------------------- /rel_core/src/move/impls.rs: -------------------------------------------------------------------------------- 1 | use ::core::marker::PhantomData; 2 | use ::mischief::{In, Region, Slot}; 3 | use ::situ::{ops::IndexMutRaw, Mut, Val}; 4 | 5 | use crate::{Move, MoveExt}; 6 | 7 | macro_rules! impl_builtin { 8 | ($($ty:ty),*) => { 9 | $( 10 | // SAFETY: `move_unsized_unchecked` initializes `out` by emplacing 11 | // to it. 12 | unsafe impl Move for $ty { 13 | unsafe fn move_unsized_unchecked( 14 | this: In, R>, 15 | out: In, R>, 16 | ) { 17 | // SAFETY: `$ty` is `Sized`, so it has metadata `()` and 18 | // `out` must have the same metadata as it. 19 | unsafe { 20 | Val::read_unsized_unchecked( 21 | In::into_inner(this), 22 | In::into_inner(out), 23 | ); 24 | } 25 | } 26 | } 27 | )* 28 | }; 29 | } 30 | 31 | impl_builtin!(i8, u8, bool, ()); 32 | 33 | // SAFETY: `move_unsized_unchecked` initializes its `out` parameter by emplacing 34 | // to every element in it. 35 | unsafe impl Move for [T; N] 36 | where 37 | T: Move, 38 | { 39 | unsafe fn move_unsized_unchecked( 40 | this: In, R>, 41 | out: In, R>, 42 | ) { 43 | let mut this = Val::leak(In::into_inner(this)); 44 | let mut out = In::into_inner(out); 45 | 46 | for i in 0..N { 47 | // SAFETY: `i` is in bounds because it must be less than the length 48 | // of the array, `N`. 49 | let this_i = unsafe { 50 | IndexMutRaw::index_mut_raw_unchecked(this.as_mut(), i) 51 | }; 52 | // SAFETY: 53 | // - `this_i` is an element of `this`, which we own and may drop. 54 | // - `this_i` is only taken once, and `this` is leaked so its 55 | // elements will not be accessed again. 56 | let this_i = unsafe { Mut::take(this_i) }; 57 | // SAFETY: `this_i` is an element of `this`, which is located in 58 | // `R`, so `this_i` must also be located in `R`. 59 | let this_i = unsafe { In::new_unchecked(this_i) }; 60 | // SAFETY: `i` is in bounds because it must be less than the length 61 | // of the array, `N`. 62 | let out_i = unsafe { out.as_mut().get_unchecked(i) }; 63 | // SAFETY: `out_i` is an element of `out`, which is located in `R`, 64 | // so `out_i` must also be located in `R`. 65 | let out_i = unsafe { In::new_unchecked(out_i) }; 66 | T::r#move(this_i, out_i); 67 | } 68 | } 69 | } 70 | 71 | // SAFETY: `move_unsized_unchecked` initializes its `out` parameter by emplacing 72 | // to every element in it. 73 | unsafe impl Move for [T] 74 | where 75 | T: Move, 76 | { 77 | unsafe fn move_unsized_unchecked( 78 | this: In, R>, 79 | out: In, R>, 80 | ) { 81 | let len = this.len(); 82 | let mut this = Val::leak(In::into_inner(this)); 83 | let mut out = In::into_inner(out); 84 | 85 | for i in 0..len { 86 | // SAFETY: `i` is in bounds because it must be less than the length 87 | // of the array, `len`. 88 | let this_i = unsafe { 89 | IndexMutRaw::index_mut_raw_unchecked(this.as_mut(), i) 90 | }; 91 | // SAFETY: 92 | // - `this_i` is an element of `this`, which we own and may drop. 93 | // - `this_i` is only taken once, and `this` is leaked so its 94 | // elements will not be accessed again. 95 | let this_i = unsafe { Mut::take(this_i) }; 96 | // SAFETY: `this_i` is an element of `this`, which is located in 97 | // `R`, so `this_i` must also be located in `R`. 98 | let this_i = unsafe { In::new_unchecked(this_i) }; 99 | // SAFETY: `i` is in bounds because it must be less than the length 100 | // of the array, `len`. 101 | let out_i = unsafe { out.as_mut().get_unchecked(i) }; 102 | // SAFETY: `out_i` is an element of `out`, which is located in `R`, 103 | // so `out_i` must also be located in `R`. 104 | let out_i = unsafe { In::new_unchecked(out_i) }; 105 | T::r#move(this_i, out_i); 106 | } 107 | } 108 | } 109 | 110 | // SAFETY: `move_unsized_unchecked` does not have to initialize `out` because 111 | // `PhantomData` is zero-sized and so always initialized. 112 | unsafe impl Move for PhantomData { 113 | unsafe fn move_unsized_unchecked( 114 | _: In, R>, 115 | _: In, R>, 116 | ) { 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /rel_core/src/move/mod.rs: -------------------------------------------------------------------------------- 1 | mod impls; 2 | 3 | use ::mischief::{In, Region, Slot}; 4 | use ::ptr_meta::{metadata, Pointee}; 5 | pub use ::rel_core_derive::Move; 6 | use ::situ::{DropRaw, Val}; 7 | 8 | /// An emplaced value that can be moved. 9 | /// 10 | /// # Safety 11 | /// 12 | /// `move_unsized_unchecked` must initialize its `out` parameter. 13 | pub unsafe trait Move: DropRaw { 14 | /// Moves a value into a given slot within some memory region. 15 | /// 16 | /// # Safety 17 | /// 18 | /// `out` must have the same metadata as `this`. 19 | unsafe fn move_unsized_unchecked( 20 | this: In, R>, 21 | out: In, R>, 22 | ); 23 | } 24 | 25 | /// An extension trait for `Move` that provides a variety of convenient movement 26 | /// methods. 27 | /// 28 | /// # Safety 29 | /// 30 | /// `move_unsized` and `r#move`/`move_` must initialize their `out` parameters. 31 | pub unsafe trait MoveExt: Move { 32 | /// Moves a value into a given slot within some memory region. 33 | /// 34 | /// # Panics 35 | /// 36 | /// Panics if `out` does not have the same metadata as `this`. 37 | fn move_unsized(this: In, R>, out: In, R>); 38 | 39 | /// Moves a `Sized` value into a given slot within some memory region. 40 | fn r#move(this: In, R>, out: In, R>) 41 | where 42 | Self: Sized; 43 | 44 | /// Moves a `Sized` value into a given slot within some memory region. 45 | /// 46 | /// This is an alternate name for [`move`](MoveExt::move), which uses a 47 | /// raw identifier in the name. 48 | fn move_(this: In, R>, out: In, R>) 49 | where 50 | Self: Sized; 51 | } 52 | 53 | // SAFETY: `move_unsized` and `r#move`/`move_` initialize their `out` paramters 54 | // by calling `move_unsized_unchecked`. 55 | unsafe impl + Pointee + ?Sized, R: Region> MoveExt for T { 56 | fn move_unsized(this: In, R>, out: In, R>) { 57 | assert!(metadata(this.ptr().as_ptr()) == metadata(out.ptr().as_ptr())); 58 | // SAFETY: We have asserted that `out` has the same metadata as `this`. 59 | unsafe { 60 | Move::move_unsized_unchecked(this, out); 61 | } 62 | } 63 | 64 | fn r#move(this: In, R>, out: In, R>) 65 | where 66 | Self: Sized, 67 | { 68 | // SAFETY: Because `Self: Sized`, its pointer metadata is `()` and so 69 | // the metadata of `this` and `out` must be the same because there is 70 | // only one possible value of `()`. 71 | unsafe { 72 | Move::move_unsized_unchecked(this, out); 73 | } 74 | } 75 | 76 | fn move_(this: In, R>, out: In, R>) 77 | where 78 | Self: Sized, 79 | { 80 | Self::r#move(this, out); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /rel_core/src/option.rs: -------------------------------------------------------------------------------- 1 | //! A value that may or may not exist. 2 | 3 | use ::core::{hint::unreachable_unchecked, ptr::addr_of_mut}; 4 | use ::mischief::{In, Region, Slot}; 5 | use ::ptr_meta::Pointee; 6 | use ::raw_enum_macro::raw_enum; 7 | use ::situ::DropRaw; 8 | 9 | use crate::{Emplace, EmplaceExt, Move, Portable}; 10 | 11 | /// A relative counterpart to `Option`. 12 | #[derive(DropRaw, Move, Portable)] 13 | #[rel_core = "crate"] 14 | #[repr(u8)] 15 | #[raw_enum] 16 | pub enum RelOption { 17 | /// No value. 18 | None, 19 | /// Some value of type `T`. 20 | Some(T), 21 | } 22 | 23 | // SAFETY: 24 | // - `emplaced_meta` returns `()`, the only valid metadata for `Sized` types. 25 | // - `emplace_unsized_unchecked` initializes its `out` parameter by always 26 | // setting the discriminant and additionally emplacing a value for the `Some` 27 | // variant. 28 | unsafe impl Emplace, R> for Option 29 | where 30 | E: Emplace, 31 | { 32 | fn emplaced_meta(&self) -> as Pointee>::Metadata {} 33 | 34 | unsafe fn emplace_unsized_unchecked( 35 | self, 36 | out: In>, R>, 37 | ) { 38 | let raw_out = raw_rel_option(out.ptr().as_ptr()); 39 | let out_discriminant = raw_rel_option_discriminant(raw_out); 40 | 41 | match self { 42 | // SAFETY: `raw_rel_option_discriminant` guarantees that the pointer 43 | // it returns is properly aligned and valid for writes. 44 | None => unsafe { 45 | out_discriminant.write(RawRelOptionDiscriminant::None); 46 | }, 47 | Some(emplacer) => { 48 | // SAFETY: `raw_rel_option_discriminant` guarantees that the 49 | // pointer it returns is properly aligned and valid for writes. 50 | unsafe { 51 | out_discriminant.write(RawRelOptionDiscriminant::Some); 52 | } 53 | match raw_rel_option_variant(raw_out) { 54 | RawRelOptionVariants::Some(out_ptr) => { 55 | let value_ptr = addr_of_mut!((*out_ptr).1); 56 | // SAFETY: 57 | // - `value_ptr` is a pointer into `out`, so it is 58 | // non-null, properly aligned, and valid for reads and 59 | // writes. 60 | // - `value_ptr` is a disjoint borrow of `out`, which is 61 | // guaranteed not to alias any other accessible 62 | // references, so the returned `Slot` will not either. 63 | let slot = unsafe { Slot::new_unchecked(value_ptr) }; 64 | // SAFETY: `value_ptr` is a pointer into `out`, which is 65 | // contained in `R`, so `value_ptr` must be contained in 66 | // `R` as well. 67 | let slot = unsafe { In::new_unchecked(slot) }; 68 | emplacer.emplace(slot); 69 | } 70 | // SAFETY: We wrote the `Some` discriminant to 71 | // `out_discriminant` so it must be the `Some` variant. 72 | _ => unsafe { unreachable_unchecked() }, 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /rel_core/src/portable.rs: -------------------------------------------------------------------------------- 1 | use ::core::{ 2 | cell::Cell, 3 | marker::{PhantomData, PhantomPinned}, 4 | mem::MaybeUninit, 5 | }; 6 | use ::mischief::{GhostRef, StaticToken}; 7 | pub use ::rel_core_derive::Portable; 8 | 9 | /// A type that has the same representation on all targets. 10 | /// 11 | /// # Safety 12 | /// 13 | /// `Portable` types must have the same layout and bytewise representation on 14 | /// all targets. 15 | pub unsafe trait Portable {} 16 | 17 | // Sources: 18 | // https://doc.rust-lang.org/reference/types/boolean.html 19 | // https://doc.rust-lang.org/reference/types/numeric.html 20 | // https://doc.rust-lang.org/reference/type-layout.html 21 | 22 | // SAFETY: `bool` has a size and alignment of 1 each. `false` has the bit 23 | // pattern `0x00` and `true` has the bit pattern `0x01`. 24 | unsafe impl Portable for bool {} 25 | 26 | // SAFETY: `u8` has a size and alignment of 1 each. Values are represented as 27 | // unsigned integers. 28 | unsafe impl Portable for u8 {} 29 | 30 | // SAFETY: `i8` has a size and alignment of 1 each. Values are represented as 31 | // signed two's complement integers. 32 | unsafe impl Portable for i8 {} 33 | 34 | // SAFETY: `()` has a size of 0 and an alignment of 1. It has no bit patterns. 35 | unsafe impl Portable for () {} 36 | 37 | // SAFETY: `[T; N]` has a size of `size_of::() * N`, an alignment of 38 | // `align_of::()`, and contains its `Portable` elements in order. 39 | unsafe impl Portable for [T; N] {} 40 | 41 | // SAFETY: `[T]` has a size of `size_of::() * len`, an alignment of 42 | // `align_of::()`, and contains its `Portable` elements in order. 43 | unsafe impl Portable for [T] {} 44 | 45 | // SAFETY: `str` is `Portable` because `[u8]` is `Portable`. 46 | unsafe impl Portable for str {} 47 | 48 | // SAFETY: `PhantomData` has a size of 0 and an alignment of 1. It has no bit 49 | // patterns. 50 | unsafe impl Portable for PhantomData {} 51 | 52 | // SAFETY: `PhantomPinned` has a size of 0 and an alignment of 1. It has no bit 53 | // patterns. 54 | unsafe impl Portable for PhantomPinned {} 55 | 56 | // SAFETY: `MaybeUninit` has the same size, alignment, and bit patterns as 57 | // `T`. 58 | unsafe impl Portable for MaybeUninit {} 59 | 60 | // SAFETY: `Cell` is `Portable` if `T` is `Portable` because it is 61 | // `repr(transparent)`. 62 | unsafe impl Portable for Cell {} 63 | 64 | // SAFETY: `GhostRef` has a size of 0 and an alignment of 1. It has no bit 65 | // patterns. 66 | unsafe impl Portable for GhostRef {} 67 | 68 | // SAFETY: `StaticToken` has a size of 0 and an alignment of 1. It has no bit 69 | // patterns. 70 | unsafe impl Portable for StaticToken<'_> {} 71 | -------------------------------------------------------------------------------- /rel_core/src/primitive.rs: -------------------------------------------------------------------------------- 1 | use ::core::{ 2 | cmp::Ordering, 3 | fmt, 4 | hash::{Hash, Hasher}, 5 | }; 6 | use ::mischief::{In, Region, Slot}; 7 | use ::ptr_meta::Pointee; 8 | use ::situ::{DropRaw, Mut, Val}; 9 | 10 | use crate::{Emplace, Move, Portable}; 11 | 12 | /// Alias for `i8`. 13 | pub type I8 = i8; 14 | 15 | /// Alias for `u8`. 16 | pub type U8 = u8; 17 | 18 | /// Alias for `bool`. 19 | pub type Bool = bool; 20 | 21 | /// Alias for `()`. 22 | pub type Unit = (); 23 | 24 | macro_rules! impl_primitive { 25 | (@base $portable:ty, $native:ty) => { 26 | impl From<$native> for $portable { 27 | #[inline] 28 | fn from(value: $native) -> Self { 29 | <$portable>::from_ne(value) 30 | } 31 | } 32 | 33 | impl From<$portable> for $native { 34 | #[inline] 35 | fn from(value: $portable) -> Self { 36 | value.to_ne() 37 | } 38 | } 39 | 40 | impl PartialEq for $portable 41 | where 42 | $native: PartialEq, 43 | { 44 | #[inline] 45 | fn eq(&self, other: &Self) -> bool { 46 | self.to_ne().eq(&other.to_ne()) 47 | } 48 | } 49 | 50 | impl PartialOrd for $portable 51 | where 52 | $native: PartialOrd, 53 | { 54 | #[inline] 55 | fn partial_cmp(&self, other: &Self) -> Option { 56 | self.to_ne().partial_cmp(&other.to_ne()) 57 | } 58 | } 59 | 60 | impl fmt::Debug for $portable 61 | where 62 | $native: fmt::Debug, 63 | { 64 | #[inline] 65 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 66 | self.to_ne().fmt(f) 67 | } 68 | } 69 | 70 | impl fmt::Display for $portable 71 | where 72 | $native: fmt::Display, 73 | { 74 | #[inline] 75 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 | self.to_ne().fmt(f) 77 | } 78 | } 79 | 80 | impl DropRaw for $portable { 81 | #[inline] 82 | unsafe fn drop_raw(_: Mut<'_, Self>) {} 83 | } 84 | 85 | // SAFETY: 86 | // - All primitives are `Sized` and always have metadata `()`, so 87 | // `emplaced_meta` always returns valid metadata for them. 88 | // - `emplace_unsized_unchecked` initializes `out` by writing to it. 89 | unsafe impl Emplace<$portable, R> for $native { 90 | fn emplaced_meta(&self) -> <$portable as Pointee>::Metadata {} 91 | 92 | unsafe fn emplace_unsized_unchecked( 93 | self, 94 | out: In, R>, 95 | ) { 96 | In::into_inner(out).write(<$portable>::from_ne(self)); 97 | } 98 | } 99 | 100 | // SAFETY: `move_unsized_unchecked` initializes its `out` parameter by 101 | // writing to it. 102 | unsafe impl Move for $portable { 103 | unsafe fn move_unsized_unchecked( 104 | this: In, R>, 105 | out: In, R>, 106 | ) { 107 | In::into_inner(out).write(Val::read(In::into_inner(this))); 108 | } 109 | } 110 | }; 111 | ($portable:ty, $native:ty) => { 112 | impl_primitive!(@base $portable, $native); 113 | 114 | impl Eq for $portable 115 | where 116 | $native: Eq, 117 | {} 118 | 119 | impl Ord for $portable 120 | where 121 | $native: Ord, 122 | { 123 | #[inline] 124 | fn cmp(&self, other: &Self) -> Ordering { 125 | self.to_ne().cmp(&other.to_ne()) 126 | } 127 | } 128 | 129 | impl Hash for $portable 130 | where 131 | $native: Hash, 132 | { 133 | #[inline] 134 | fn hash(&self, state: &mut H) { 135 | self.to_ne().hash(state) 136 | } 137 | } 138 | } 139 | } 140 | 141 | macro_rules! impl_multibyte_integer { 142 | ($portable:ident, $align:expr, $native:ty) => { 143 | #[doc = concat!("A portable `", stringify!($native), "`.")] 144 | #[derive(Clone, Copy)] 145 | #[repr(C, align($align))] 146 | pub struct $portable { 147 | value: $native, 148 | } 149 | 150 | // SAFETY: Multibyte integers have a well-defined size, an alignment 151 | // equal to their size, and their bit patterns are adjusted for 152 | // endianness. 153 | unsafe impl Portable for $portable {} 154 | 155 | impl $portable { 156 | #[doc = "Returns the `"] 157 | #[doc = stringify!($portable)] 158 | #[doc = "` corresponding to the given `"] 159 | #[doc = stringify!($native)] 160 | #[doc = "`."] 161 | #[inline] 162 | pub const fn from_ne(value: $native) -> Self { 163 | Self { 164 | value: { 165 | #[cfg(feature = "little_endian")] 166 | { 167 | value.to_le() 168 | } 169 | #[cfg(feature = "big_endian")] 170 | { 171 | value.to_be() 172 | } 173 | }, 174 | } 175 | } 176 | 177 | #[doc = "Returns the `"] 178 | #[doc = stringify!($native)] 179 | #[doc = "` corresponding to this `"] 180 | #[doc = stringify!($portable)] 181 | #[doc = "`."] 182 | #[inline] 183 | pub const fn to_ne(self) -> $native { 184 | #[cfg(feature = "little_endian")] 185 | { 186 | <$native>::from_le(self.value) 187 | } 188 | #[cfg(feature = "big_endian")] 189 | { 190 | <$native>::from_be(self.value) 191 | } 192 | } 193 | } 194 | 195 | impl_primitive!($portable, $native); 196 | }; 197 | } 198 | 199 | impl_multibyte_integer!(I16, 2, i16); 200 | impl_multibyte_integer!(I32, 4, i32); 201 | impl_multibyte_integer!(I64, 8, i64); 202 | impl_multibyte_integer!(I128, 16, i128); 203 | impl_multibyte_integer!(U16, 2, u16); 204 | impl_multibyte_integer!(U32, 4, u32); 205 | impl_multibyte_integer!(U64, 8, u64); 206 | impl_multibyte_integer!(U128, 16, u128); 207 | 208 | /// A portable `f32`. 209 | #[derive(Clone, Copy)] 210 | #[repr(transparent)] 211 | pub struct F32 { 212 | int_repr: U32, 213 | } 214 | 215 | // SAFETY: `U32` is `Portable` and `F32` is `repr(transparent)`, so `F32` has 216 | // the same layout and bytewise representation guarantees as `U32`. 217 | unsafe impl Portable for F32 where U32: Portable {} 218 | 219 | impl F32 { 220 | /// Returns the `F32` corresponding to the given `f32`. 221 | #[inline] 222 | pub fn from_ne(value: f32) -> Self { 223 | Self { 224 | int_repr: U32::from_ne(value.to_bits()), 225 | } 226 | } 227 | 228 | /// Returns the `f32` corresponding to this `F32`. 229 | #[inline] 230 | pub fn to_ne(self) -> f32 { 231 | f32::from_bits(self.int_repr.to_ne()) 232 | } 233 | } 234 | 235 | impl_primitive!(@base F32, f32); 236 | 237 | /// A portable `f64`. 238 | #[derive(Clone, Copy)] 239 | #[repr(transparent)] 240 | pub struct F64 { 241 | int_repr: U64, 242 | } 243 | 244 | // SAFETY: `U64` is `Portable` and `F64` is `repr(transparent)`, so `F64` has 245 | // the same layout and bytewise representation guarantees as `U64`. 246 | unsafe impl Portable for F64 where U64: Portable {} 247 | 248 | impl F64 { 249 | /// Returns the `F64` corresponding to the given `f64`. 250 | #[inline] 251 | pub fn from_ne(value: f64) -> Self { 252 | Self { 253 | int_repr: U64::from_ne(value.to_bits()), 254 | } 255 | } 256 | 257 | /// Returns the `f64` corresponding to this `F64`. 258 | #[inline] 259 | pub fn to_ne(self) -> f64 { 260 | f64::from_bits(self.int_repr.to_ne()) 261 | } 262 | } 263 | 264 | impl_primitive!(@base F64, f64); 265 | 266 | /// A portable `char`. 267 | #[derive(Clone, Copy)] 268 | #[repr(transparent)] 269 | pub struct Char { 270 | int_repr: U32, 271 | } 272 | 273 | // SAFETY: `U32` is `Portable` and `Char` is `repr(transparent)` so `Char` has 274 | // the same layout and bytewise representation guarantees as `U32`. 275 | unsafe impl Portable for Char where U32: Portable {} 276 | 277 | impl Char { 278 | /// Returns the `Char` corresponding to the given `char`. 279 | #[inline] 280 | pub fn from_ne(value: char) -> Self { 281 | Self { 282 | int_repr: U32::from_ne(u32::from(value)), 283 | } 284 | } 285 | 286 | /// Returns the `char` corresponding to this `Char`. 287 | #[inline] 288 | pub fn to_ne(self) -> char { 289 | // SAFETY: `int_repr` always contains a `u32` that is a valid `char`. 290 | unsafe { char::from_u32_unchecked(self.int_repr.to_ne()) } 291 | } 292 | } 293 | 294 | impl_primitive!(Char, char); 295 | -------------------------------------------------------------------------------- /rel_core/src/rel_mem.rs: -------------------------------------------------------------------------------- 1 | //! Basic functions for dealing with relative values in memory. 2 | //! 3 | //! This module contains functions for initializing and manipulating relative 4 | //! values in memory. 5 | 6 | use ::mischief::{In, Region}; 7 | use ::ptr_meta::{metadata, Pointee}; 8 | use ::situ::{DropRaw, Mut, Val}; 9 | 10 | use crate::Emplace; 11 | 12 | /// Replaces the unsized value in `dest` by emplacing `src` into it. 13 | /// 14 | /// # Safety 15 | /// 16 | /// The caller must guarantee that `dest` must have the metadata returned from 17 | /// `src.emplaced_meta`. 18 | pub unsafe fn replace_unsized_unchecked( 19 | dest: In, R>, 20 | src: E, 21 | ) where 22 | T: DropRaw + Pointee + ?Sized, 23 | R: Region, 24 | E: Emplace, 25 | { 26 | // SAFETY: 27 | // - We are taking ownership of the value in `dest`, so it is valid for 28 | // dropping. 29 | // - The `Val` is dropped and emplaced over, so nothing can access the `Mut` 30 | // between dropping and emplacement. 31 | let drop_into_slot = |m| unsafe { Val::drop(Mut::take(m)) }; 32 | // SAFETY: `drop_into_slot` returns a slot of the same location as the given 33 | // `Mut`, so it must be located in the same region. 34 | let dest = unsafe { In::map_unchecked(dest, drop_into_slot) }; 35 | // SAFETY: The caller has guaranteed that `dest` has the metadata returned 36 | // by `emplaced_meta`. 37 | unsafe { 38 | src.emplace_unsized_unchecked(dest); 39 | } 40 | } 41 | 42 | /// Replaces the unsized value in `dest` by emplacing `src` into it. 43 | pub fn replace_unsized(dest: In, R>, src: E) 44 | where 45 | T: DropRaw + Pointee + ?Sized, 46 | R: Region, 47 | E: Emplace, 48 | { 49 | assert!(metadata(dest.ptr().as_ptr()) == src.emplaced_meta()); 50 | // SAFETY: We have asserted that the `dest` has the metadata returned from 51 | // `src.emplaced_meta`. 52 | unsafe { 53 | replace_unsized_unchecked(dest, src); 54 | } 55 | } 56 | 57 | /// Replaces the value in `dest` by emplacing `src` into it. 58 | pub fn replace(dest: In, R>, src: E) 59 | where 60 | T: DropRaw, 61 | R: Region, 62 | E: Emplace, 63 | { 64 | // SAFETY: `T` is sized, so `dest` must have the metadata returned from 65 | // `src.emplaced_meta`. 66 | unsafe { 67 | replace_unsized_unchecked(dest, src); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /rel_core/src/rel_ref.rs: -------------------------------------------------------------------------------- 1 | //! Relative pointers and related types. 2 | 3 | use ::core::{fmt, marker::PhantomData}; 4 | use ::mischief::{In, Region, Slot}; 5 | use ::munge::munge; 6 | use ::ptr_meta::Pointee; 7 | use ::situ::{ 8 | fmt::{DebugRaw, DisplayRaw}, 9 | DropRaw, 10 | Ref, 11 | }; 12 | 13 | use crate::{ 14 | Basis, 15 | BasisPointee, 16 | DefaultBasis, 17 | Emplace, 18 | EmplaceExt, 19 | Move, 20 | Portable, 21 | RelPtr, 22 | }; 23 | 24 | /// A reference stored using a relative pointer. 25 | #[repr(C)] 26 | #[derive(DropRaw, Move, Portable)] 27 | #[rel_core = "crate"] 28 | pub struct RelRef<'a, T, R, B = DefaultBasis> 29 | where 30 | T: BasisPointee + ?Sized, 31 | R: Region, 32 | B: Basis, 33 | { 34 | inner: RelPtr, 35 | _phantom: PhantomData<&'a T>, 36 | } 37 | 38 | impl<'a, T: BasisPointee + ?Sized, R: Region, B: Basis> RelRef<'a, T, R, B> { 39 | /// Returns a `Ref` to the underlying value. 40 | pub fn deref(this: Ref<'_, Self>) -> Ref<'a, T> { 41 | munge!(let RelRef { inner, .. } = this); 42 | // SAFETY: The `RelPtr` in a `RelRef` is always non-null, properly 43 | // aligned, and valid for reads. It also never aliases any mutable 44 | // references, and is guaranteed to point to an initialized value. 45 | unsafe { RelPtr::as_ref(inner) } 46 | } 47 | } 48 | 49 | // SAFETY: 50 | // - `RelRef` is `Sized` and always has metadata `()`, so `emplaced_meta` always 51 | // returns valid metadata for it. 52 | // - `emplace_unsized_unchecked` initializes its `out` parameter. 53 | unsafe impl<'a, T, R, B> Emplace, R> for In, R> 54 | where 55 | T: BasisPointee + ?Sized, 56 | R: Region, 57 | B: Basis, 58 | { 59 | #[inline] 60 | fn emplaced_meta(&self) -> as Pointee>::Metadata {} 61 | 62 | unsafe fn emplace_unsized_unchecked( 63 | self, 64 | out: In>, R>, 65 | ) { 66 | munge!(let RelRef { inner: out_inner, .. } = out); 67 | 68 | self.as_raw().emplace(out_inner); 69 | } 70 | } 71 | 72 | impl<'a, T, R, B> DebugRaw for RelRef<'a, T, R, B> 73 | where 74 | T: BasisPointee + DebugRaw + ?Sized, 75 | R: Region, 76 | B: Basis, 77 | { 78 | fn fmt_raw( 79 | this: Ref<'_, Self>, 80 | f: &mut fmt::Formatter<'_>, 81 | ) -> Result<(), fmt::Error> { 82 | DebugRaw::fmt_raw(RelRef::deref(this), f) 83 | } 84 | } 85 | 86 | impl<'a, T, R, B> DisplayRaw for RelRef<'a, T, R, B> 87 | where 88 | T: BasisPointee + DisplayRaw + ?Sized, 89 | R: Region, 90 | B: Basis, 91 | { 92 | fn fmt_raw( 93 | this: Ref<'_, Self>, 94 | f: &mut fmt::Formatter<'_>, 95 | ) -> Result<(), fmt::Error> { 96 | DisplayRaw::fmt_raw(RelRef::deref(this), f) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /rel_core/src/rel_tuple.rs: -------------------------------------------------------------------------------- 1 | //! Relative versions of tuples. 2 | 3 | use ::mischief::{In, Region, Slot}; 4 | use ::munge::munge; 5 | use ::ptr_meta::Pointee; 6 | use ::situ::DropRaw; 7 | 8 | use crate::{Emplace, EmplaceExt, Move, Portable}; 9 | 10 | macro_rules! define_tuple { 11 | ( 12 | $n:expr, 13 | $ident:ident<$($types:ident),*>, 14 | ($($emplace_types:ident),*), 15 | $($indices:tt,)* 16 | ) => { 17 | #[doc = concat!("A relative ", stringify!($n), "-tuple")] 18 | #[derive(DropRaw, Move, Portable)] 19 | #[rel_core = "crate"] 20 | #[repr(C)] 21 | pub struct $ident<$($types),*>($($types),*); 22 | 23 | // SAFETY: 24 | // - `emplaced_meta` returns `()`, the only valid metadata for `Sized` 25 | // types. 26 | // - `emplace_unsized_unchecked` initializes its `out` parameter by 27 | // emplacing to each of its fields. 28 | unsafe impl<$($types,)* $($emplace_types,)* R: Region> 29 | Emplace<$ident<$($types),*>, R> for ($($emplace_types,)*) 30 | where 31 | $( 32 | $types: DropRaw, 33 | $emplace_types: Emplace<$types, R>, 34 | )* 35 | { 36 | fn emplaced_meta( 37 | &self, 38 | ) -> <$ident<$($types),*> as Pointee>::Metadata {} 39 | 40 | #[allow(non_snake_case)] 41 | unsafe fn emplace_unsized_unchecked( 42 | self, 43 | out: In>, R>, 44 | ) { 45 | munge!(let $ident($($types,)*) = out); 46 | $( 47 | self.$indices.emplace($types); 48 | )* 49 | } 50 | } 51 | } 52 | } 53 | 54 | /// A type alias for the unit type. 55 | pub type RelTuple0 = (); 56 | 57 | define_tuple!(1, RelTuple1, (EA), 0,); 58 | define_tuple!( 59 | 2, 60 | RelTuple2, 61 | (EA, EB), 62 | 0, 1, 63 | ); 64 | define_tuple!( 65 | 3, 66 | RelTuple3, 67 | (EA, EB, EC), 68 | 0, 1, 2, 69 | ); 70 | define_tuple!( 71 | 4, 72 | RelTuple4, 73 | (EA, EB, EC, ED), 74 | 0, 1, 2, 3, 75 | ); 76 | define_tuple!( 77 | 5, 78 | RelTuple5, 79 | (EA, EB, EC, ED, EE), 80 | 0, 1, 2, 3, 4, 81 | ); 82 | define_tuple!( 83 | 6, 84 | RelTuple6, 85 | (EA, EB, EC, ED, EE, EF), 86 | 0, 1, 2, 3, 4, 5, 87 | ); 88 | define_tuple!( 89 | 7, 90 | RelTuple7, 91 | (EA, EB, EC, ED, EE, EF, EG), 92 | 0, 1, 2, 3, 4, 5, 6, 93 | ); 94 | define_tuple!( 95 | 8, 96 | RelTuple8, 97 | (EA, EB, EC, ED, EE, EF, EG, EH), 98 | 0, 1, 2, 3, 4, 5, 6, 7, 99 | ); 100 | define_tuple!( 101 | 9, 102 | RelTuple9, 103 | (EA, EB, EC, ED, EE, EF, EG, EH, EI), 104 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 105 | ); 106 | define_tuple!( 107 | 10, 108 | RelTuple10, 109 | (EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ), 110 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 111 | ); 112 | define_tuple!( 113 | 11, 114 | RelTuple11, 115 | (EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ, EK), 116 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 117 | ); 118 | define_tuple!( 119 | 12, 120 | RelTuple12, 121 | (EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ, EK, EL), 122 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 123 | ); 124 | define_tuple!( 125 | 13, 126 | RelTuple13, 127 | (EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ, EK, EL, EM), 128 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 129 | ); 130 | define_tuple!( 131 | 14, 132 | RelTuple14, 133 | (EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ, EK, EL, EM, EN), 134 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 135 | ); 136 | define_tuple!( 137 | 15, 138 | RelTuple15, 139 | (EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ, EK, EL, EM, EN, EO), 140 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 141 | ); 142 | define_tuple!( 143 | 16, 144 | RelTuple16, 145 | (EA, EB, EC, ED, EE, EF, EG, EH, EI, EJ, EK, EL, EM, EN, EO, EP), 146 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 147 | ); 148 | -------------------------------------------------------------------------------- /rel_core_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rel_core_derive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | proc-macro = true 8 | 9 | [dependencies] 10 | proc-macro2 = "1.0" 11 | quote = "1.0" 12 | syn = "1.0" 13 | 14 | [dependencies.macroix] 15 | version = "0.1" 16 | path = "../macroix" 17 | 18 | [dependencies.raw_enum] 19 | version = "0.1" 20 | path = "../raw_enum" 21 | -------------------------------------------------------------------------------- /rel_core_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Procedural macros for `rel_core`. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | 13 | mod r#move; 14 | mod portable; 15 | 16 | use ::proc_macro::TokenStream; 17 | use ::syn::{parse_macro_input, DeriveInput}; 18 | 19 | /// Derives `Move` on the annotated type. 20 | #[proc_macro_derive(Move, attributes(rel_core))] 21 | pub fn derive_move(input: TokenStream) -> TokenStream { 22 | let derive_input = parse_macro_input!(input as DeriveInput); 23 | r#move::derive(derive_input) 24 | .unwrap_or_else(|e| e.to_compile_error()) 25 | .into() 26 | } 27 | 28 | /// Derives `Portable` on the annotated type. 29 | #[proc_macro_derive(Portable, attributes(rel_core))] 30 | pub fn derive_portable(input: TokenStream) -> TokenStream { 31 | let derive_input = parse_macro_input!(input as DeriveInput); 32 | portable::derive(derive_input) 33 | .unwrap_or_else(|e| e.to_compile_error()) 34 | .into() 35 | } 36 | -------------------------------------------------------------------------------- /rel_core_derive/src/portable.rs: -------------------------------------------------------------------------------- 1 | use ::macroix::{ 2 | repr::{BaseKind, Int, PrimitiveType, Repr}, 3 | visit_fields, 4 | AttrValue, 5 | }; 6 | use ::proc_macro2::{Span, TokenStream}; 7 | use ::quote::quote; 8 | use ::syn::{parse2, parse_quote, Data, DeriveInput, Error, Path}; 9 | 10 | pub fn derive(mut input: DeriveInput) -> Result { 11 | let mut repr = None; 12 | let mut rel_core = None; 13 | for attr in input.attrs.iter() { 14 | if attr.path.is_ident("repr") { 15 | Repr::merge_attr(&mut repr, attr.tokens.clone())?; 16 | } else if attr.path.is_ident("rel_core") { 17 | rel_core = 18 | Some(parse2::>(attr.tokens.clone())?.value); 19 | } 20 | } 21 | let rel_core = rel_core.unwrap_or_else(|| parse_quote! { ::rel_core }); 22 | 23 | let repr = repr.ok_or_else(|| { 24 | Error::new( 25 | Span::call_site(), 26 | "`Portable` types require an explicit `repr` attribute", 27 | ) 28 | })?; 29 | let repr_base = repr.base.ok_or_else(|| { 30 | Error::new( 31 | Span::call_site(), 32 | "`Portable` types require a base `repr` kind", 33 | ) 34 | })?; 35 | 36 | match input.data { 37 | Data::Struct(_) => { 38 | if !matches!(repr_base.kind, BaseKind::C | BaseKind::Transparent) { 39 | return Err(Error::new_spanned( 40 | repr_base.kind_token, 41 | "`Portable` structs must be `repr(C)` or \ 42 | `repr(transparent)`", 43 | )); 44 | } 45 | } 46 | Data::Enum(_) => match repr_base.kind { 47 | BaseKind::Primitive(Int::I8 | Int::U8) => (), 48 | BaseKind::C => match repr.primitive_type { 49 | Some(PrimitiveType { 50 | int: Int::I8 | Int::U8, 51 | .. 52 | }) => (), 53 | Some(PrimitiveType { int_token, .. }) => { 54 | return Err(Error::new_spanned( 55 | int_token, 56 | "`Portable` enums that are `repr(C)` must have a \ 57 | primitive type of `i8` or `u8`", 58 | )) 59 | } 60 | None => { 61 | return Err(Error::new_spanned( 62 | repr_base.kind_token, 63 | "`Portable` enums that are `repr(C)` must specify \ 64 | a primitive type with `repr(C, i8)` or \ 65 | `repr(C, u8)`", 66 | )) 67 | } 68 | }, 69 | _ => { 70 | return Err(Error::new_spanned( 71 | repr_base.kind_token, 72 | "`Portable` enums must be `repr(i8)`, `repr(u8)`, \ 73 | `repr(C, i8)`, or `repr(C, u8)`", 74 | )); 75 | } 76 | }, 77 | Data::Union(_) => { 78 | if !matches!(repr_base.kind, BaseKind::C | BaseKind::Transparent) { 79 | return Err(Error::new_spanned( 80 | repr_base.kind_token, 81 | "`Portable` unions must be `repr(C)` or \ 82 | `repr(transparent)`", 83 | )); 84 | } 85 | } 86 | } 87 | 88 | let where_clause = input.generics.make_where_clause(); 89 | visit_fields(&input.data, |f| { 90 | let ty = &f.ty; 91 | where_clause 92 | .predicates 93 | .push(parse_quote! { #ty: #rel_core::Portable }); 94 | }); 95 | 96 | let (impl_generics, ty_generics, where_clause) = 97 | input.generics.split_for_impl(); 98 | let ty_name = &input.ident; 99 | Ok(quote! { 100 | // SAFETY: This type has a valid `repr` and contains only `Portable` 101 | // fields. 102 | unsafe impl #impl_generics #rel_core::Portable 103 | for #ty_name #ty_generics #where_clause {} 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /rel_example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rel_example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | ptr_meta = "0.2" 9 | 10 | [dependencies.heresy] 11 | version = "0.1" 12 | path = "../heresy" 13 | 14 | [dependencies.mischief] 15 | version = "0.1" 16 | path = "../mischief" 17 | 18 | [dependencies.munge] 19 | version = "0.4" 20 | git = "https://github.com/djkoloski/munge" 21 | 22 | [dependencies.rel_alloc] 23 | version = "0.1" 24 | path = "../rel_alloc" 25 | 26 | [dependencies.rel_core] 27 | version = "0.1" 28 | path = "../rel_core" 29 | 30 | [dependencies.rel_slab_allocator] 31 | version = "0.1" 32 | path = "../rel_slab_allocator" 33 | 34 | [dependencies.rel_util] 35 | version = "0.1" 36 | path = "../rel_util" 37 | 38 | [dependencies.situ] 39 | version = "0.1" 40 | path = "../situ" 41 | -------------------------------------------------------------------------------- /rel_example/src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(unsafe_op_in_unsafe_fn)] 2 | 3 | use ::core::mem::MaybeUninit; 4 | use ::mischief::{GhostRef, Slot, StaticToken}; 5 | use ::rel_slab_allocator::*; 6 | use ::rel_util::Align16; 7 | use ::situ::ops::DerefMutRaw; 8 | 9 | fn rel_box() { 10 | use rel_alloc::{EmplaceIn, RelBox}; 11 | use rel_core::I32; 12 | 13 | let mut backing = Align16(MaybeUninit::<[u8; 128]>::zeroed()); 14 | 15 | let size = StaticToken::acquire(|mut token| { 16 | let bytes = Slot::new(&mut backing.0).unsize(); 17 | let alloc = 18 | SlabAllocator::<_>::try_new_in(bytes, GhostRef::leak(&mut token)) 19 | .unwrap(); 20 | 21 | let int = 42.emplace_in::(alloc); 22 | println!("{int}"); 23 | let emplaced_int = 24 | int.emplace_in::>>(alloc); 25 | println!("{emplaced_int}"); 26 | 27 | assert!(alloc.deposit(emplaced_int).is_none()); 28 | 29 | alloc.shrink_to_fit() 30 | }); 31 | 32 | let mut backing_2 = Align16::frame(size); 33 | backing_2.slot().zero(); 34 | unsafe { 35 | ::core::ptr::copy_nonoverlapping( 36 | backing.0.as_mut_ptr().cast::(), 37 | backing_2.as_mut_ptr().cast::(), 38 | size, 39 | ); 40 | } 41 | 42 | StaticToken::acquire(|token| { 43 | let bytes = backing_2.slot().as_bytes(); 44 | let alloc = SlabAllocator::<_>::try_from_bytes(bytes, token).unwrap(); 45 | 46 | let mut emplaced_int = unsafe { 47 | alloc.withdraw_unchecked::>>().unwrap() 48 | }; 49 | *RelBox::deref_mut_raw(emplaced_int.as_mut()) = I32::from(10); 50 | println!("{emplaced_int}"); 51 | }); 52 | 53 | println!("bytes: {:?}", unsafe { backing_2.assume_init() }); 54 | } 55 | 56 | fn rel_vec() { 57 | use ::rel_alloc::{vec, EmplaceIn, RelVec}; 58 | use ::rel_core::I32; 59 | 60 | let mut backing = Align16(MaybeUninit::<[u8; 512]>::zeroed()); 61 | 62 | StaticToken::acquire(|token| { 63 | let bytes = Slot::new(&mut backing.0).unsize(); 64 | let alloc = SlabAllocator::<_>::try_new_in(bytes, token).unwrap(); 65 | 66 | let mut vec = vec::New(alloc) 67 | .emplace_in::>>(alloc); 68 | 69 | for i in 0..10 { 70 | RelVec::push(vec.as_mut(), i * i); 71 | } 72 | 73 | println!("initial ints: {vec:?}"); 74 | 75 | assert!(alloc.deposit(vec).is_none()); 76 | }); 77 | 78 | StaticToken::acquire(|token| { 79 | let bytes = Slot::new(&mut backing.0).unsize(); 80 | let alloc = SlabAllocator::<_>::try_from_bytes(bytes, token).unwrap(); 81 | 82 | let mut vec = unsafe { 83 | alloc.withdraw_unchecked::>>().unwrap() 84 | }; 85 | 86 | println!("ints before: {vec:?}"); 87 | 88 | for i in 10..20 { 89 | RelVec::push(vec.as_mut(), i * i); 90 | } 91 | 92 | println!("ints after: {vec:?}"); 93 | }); 94 | } 95 | 96 | fn rel_vec_rel_box() { 97 | use ::rel_alloc::{vec, EmplaceIn, RelBox, RelVec}; 98 | use ::rel_core::I32; 99 | 100 | let mut backing = Align16(MaybeUninit::<[u8; 1024]>::zeroed()); 101 | 102 | StaticToken::acquire(|token| { 103 | let bytes = Slot::new(&mut backing.0).unsize(); 104 | let alloc = SlabAllocator::<_>::try_new_in(bytes, token).unwrap(); 105 | 106 | let mut vec = vec::New(alloc).emplace_in::>, 108 | RelSlabAllocator, 109 | >>(alloc); 110 | 111 | for i in 0..10 { 112 | let int = (i * i).emplace_in::(alloc); 113 | RelVec::push(vec.as_mut(), int); 114 | } 115 | 116 | println!("initial ints: {vec:?}"); 117 | 118 | assert!(alloc.deposit(vec).is_none()); 119 | }); 120 | 121 | StaticToken::acquire(|token| { 122 | let bytes = Slot::new(&mut backing.0).unsize(); 123 | let alloc = SlabAllocator::<_>::try_from_bytes(bytes, token).unwrap(); 124 | 125 | let mut vec = unsafe { 126 | alloc 127 | .withdraw_unchecked::>, 129 | RelSlabAllocator, 130 | >>() 131 | .unwrap() 132 | }; 133 | 134 | println!("ints before: {vec:?}"); 135 | 136 | for i in 10..20 { 137 | let int = (i * i).emplace_in::(alloc); 138 | RelVec::push(vec.as_mut(), int); 139 | } 140 | println!("ints after: {vec:?}"); 141 | }); 142 | } 143 | 144 | fn rel_string() { 145 | use ::rel_alloc::{string, EmplaceIn, RelString}; 146 | 147 | let mut backing = Align16(MaybeUninit::<[u8; 1024]>::zeroed()); 148 | 149 | StaticToken::acquire(|token| { 150 | let bytes = Slot::new(&mut backing.0).unsize(); 151 | let alloc = SlabAllocator::<_>::try_new_in(bytes, token).unwrap(); 152 | 153 | let s = string::Clone(alloc, "Hello world!") 154 | .emplace_in::>>(alloc); 155 | 156 | println!("string: '{s}'"); 157 | }); 158 | } 159 | 160 | fn main() { 161 | rel_box(); 162 | rel_vec(); 163 | rel_vec_rel_box(); 164 | rel_string(); 165 | } 166 | -------------------------------------------------------------------------------- /rel_slab_allocator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rel_slab_allocator" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | ptr_meta = "0.2" 9 | 10 | [dependencies.heresy] 11 | version = "0.1" 12 | path = "../heresy" 13 | 14 | [dependencies.mischief] 15 | version = "0.1" 16 | path = "../mischief" 17 | 18 | [dependencies.munge] 19 | version = "0.4" 20 | git = "https://github.com/djkoloski/munge" 21 | 22 | [dependencies.rel_alloc] 23 | version = "0.1" 24 | path = "../rel_alloc" 25 | 26 | [dependencies.rel_core] 27 | version = "0.1" 28 | path = "../rel_core" 29 | 30 | [dependencies.situ] 31 | version = "0.1" 32 | path = "../situ" 33 | -------------------------------------------------------------------------------- /rel_util/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rel_util" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies.mischief] 7 | version = "0.1" 8 | path = "../mischief" 9 | default-features = false 10 | 11 | [dependencies.ptr_meta] 12 | version = "0.2" 13 | default-features = false 14 | -------------------------------------------------------------------------------- /rel_util/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Common utilities for working with `rel` types. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | #![no_std] 13 | 14 | use ::core::alloc::Layout; 15 | use ::mischief::{Frame, Metadata}; 16 | use ::ptr_meta::Pointee; 17 | 18 | /// A type that aligns its contents to 16-byte boundaries. 19 | #[derive(Debug)] 20 | #[repr(C, align(16))] 21 | pub struct Align16(pub T); 22 | 23 | impl Align16<[u8]> { 24 | /// Returns a new [`Frame`] of at least the given size. 25 | pub fn frame(size: usize) -> Frame { 26 | let metadata = size.checked_add(15).unwrap() & !15; 27 | // SAFETY: `metadata` is the size of the slice contained in this 28 | // `Align16`, and is guaranteed to be a multiple of 16. 29 | unsafe { Frame::new_unsized(metadata) } 30 | } 31 | } 32 | 33 | impl Pointee for Align16<[u8]> { 34 | type Metadata = <[u8] as Pointee>::Metadata; 35 | } 36 | 37 | // SAFETY: `pointee_layout` returns the layout for a `u8` slice of length `self` 38 | // aligned to 16 bytes. 39 | unsafe impl Metadata> for usize { 40 | unsafe fn pointee_layout(self) -> Layout { 41 | // SAFETY: The caller has guaranteed that `self` is a valid length for 42 | // `Align16<[u8]>`, which always has an alignment of 16. 43 | unsafe { Layout::from_size_align_unchecked(self, 16) } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | group_imports = "StdExternalCrate" 2 | imports_granularity = "Crate" 3 | imports_layout = "HorizontalVertical" 4 | max_width = 80 5 | unstable_features = true 6 | -------------------------------------------------------------------------------- /situ/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "situ" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies.heresy] 9 | version = "0.1" 10 | path = "../heresy" 11 | default-features = false 12 | 13 | [dependencies.mischief] 14 | version = "0.1" 15 | path = "../mischief" 16 | 17 | [dependencies.munge] 18 | version = "0.4" 19 | git = "https://github.com/djkoloski/munge" 20 | 21 | [dependencies.ptr_meta] 22 | version = "0.2" 23 | default-features = false 24 | 25 | [dependencies.situ_derive] 26 | version = "0.1" 27 | path = "../situ_derive" 28 | 29 | [features] 30 | default = ["alloc"] 31 | alloc = ["heresy/alloc"] 32 | -------------------------------------------------------------------------------- /situ/src/alloc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Memory alocation APIs. 2 | 3 | mod allocator; 4 | mod regional; 5 | 6 | pub use self::{allocator::*, regional::*}; 7 | -------------------------------------------------------------------------------- /situ/src/alloc/regional.rs: -------------------------------------------------------------------------------- 1 | use ::mischief::Region; 2 | 3 | use crate::alloc::RawAllocator; 4 | 5 | /// A `RawAllocator` that allocates inside a single contiguous memory region. 6 | /// 7 | /// # Safety 8 | /// 9 | /// The pointers returned from a `RawRegionalAllocator`'s `RawAllocator` 10 | /// implementation must always be contained in its associated `Region`. 11 | pub unsafe trait RawRegionalAllocator: RawAllocator { 12 | /// The region type for this allocator. 13 | type Region: Region; 14 | } 15 | -------------------------------------------------------------------------------- /situ/src/drop/impls.rs: -------------------------------------------------------------------------------- 1 | use ::core::{ 2 | marker::{PhantomData, PhantomPinned}, 3 | mem::MaybeUninit, 4 | }; 5 | 6 | use crate::{ops::IndexMutRaw, DropRaw, Mut}; 7 | 8 | macro_rules! impl_builtin { 9 | ($($ty:ty),*) => { 10 | $( 11 | // SAFETY: 12 | // - `emplaced_meta` returns `()`, the only valid metadata for 13 | // `$ty`. 14 | // - `emplace_unsized_unchecked` initializes `out` by writing to it. 15 | impl DropRaw for $ty { 16 | #[inline] 17 | unsafe fn drop_raw(_: Mut<'_, Self>) {} 18 | } 19 | )* 20 | }; 21 | } 22 | 23 | impl_builtin!(i8, u8, bool, (), PhantomPinned); 24 | 25 | impl DropRaw for [T; N] { 26 | #[inline] 27 | unsafe fn drop_raw(mut this: Mut<'_, Self>) { 28 | for i in 0..N { 29 | // SAFETY: The caller has guaranteed that `this` (and therefore all 30 | // of its elements) are valid for dropping. We drop each one exactly 31 | // once and never access them again. 32 | unsafe { 33 | DropRaw::drop_raw(IndexMutRaw::index_mut_raw(this.as_mut(), i)); 34 | } 35 | } 36 | } 37 | } 38 | 39 | impl DropRaw for [T] { 40 | #[inline] 41 | unsafe fn drop_raw(mut this: Mut<'_, Self>) { 42 | for i in 0..this.len() { 43 | // SAFETY: The caller has guaranteed that `this` (and therefore all 44 | // of its elements) are valid for dropping. We drop each one exactly 45 | // once and never access them again. 46 | unsafe { 47 | DropRaw::drop_raw(IndexMutRaw::index_mut_raw(this.as_mut(), i)); 48 | } 49 | } 50 | } 51 | } 52 | 53 | impl DropRaw for PhantomData { 54 | #[inline] 55 | unsafe fn drop_raw(_: Mut<'_, Self>) {} 56 | } 57 | 58 | impl DropRaw for MaybeUninit { 59 | #[inline] 60 | unsafe fn drop_raw(_: Mut<'_, Self>) {} 61 | } 62 | -------------------------------------------------------------------------------- /situ/src/drop/mod.rs: -------------------------------------------------------------------------------- 1 | mod impls; 2 | 3 | pub use ::situ_derive::DropRaw; 4 | 5 | use crate::Mut; 6 | 7 | /// A type that can be dropped through a raw pointer, without creating an 8 | /// intermediary reference. 9 | /// 10 | /// This is different from `ptr::drop_in_place` because it does not invoke 11 | /// `Drop::drop` with a mutable reference. `DropRaw::drop_raw` is the last 12 | /// method called with access to the value; effectively a raw version of `Drop`. 13 | /// This is to avoid creating an intermediate reference, which narrows 14 | /// provenance for the dropped value. 15 | /// 16 | /// Types that implement `Copy` may have their raw drops elided. 17 | pub trait DropRaw { 18 | /// Drops the value pointed to by `this`. 19 | /// 20 | /// # Safety 21 | /// 22 | /// - The value pointed to by `this` must be valid for dropping. 23 | /// - After calling `drop_raw`, the value pointed to by `this` must never be 24 | /// accessed again. 25 | unsafe fn drop_raw(this: Mut<'_, Self>); 26 | } 27 | -------------------------------------------------------------------------------- /situ/src/fmt.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for formatting and printing raw values. 2 | 3 | use ::core::fmt::{Debug, Display, Error, Formatter}; 4 | 5 | use crate::Ref; 6 | 7 | /// `?` formatting for raw references. 8 | pub trait DebugRaw { 9 | /// Formats the value using the given formatter. 10 | fn fmt_raw(this: Ref<'_, Self>, f: &mut Formatter<'_>) 11 | -> Result<(), Error>; 12 | } 13 | 14 | impl DebugRaw for T { 15 | fn fmt_raw( 16 | this: Ref<'_, Self>, 17 | f: &mut Formatter<'_>, 18 | ) -> Result<(), Error> { 19 | Debug::fmt(&*this, f) 20 | } 21 | } 22 | 23 | /// Format trait for an empty format, `{}`. 24 | pub trait DisplayRaw { 25 | /// Formats the value using the given formatter. 26 | fn fmt_raw(this: Ref<'_, Self>, f: &mut Formatter<'_>) 27 | -> Result<(), Error>; 28 | } 29 | 30 | impl DisplayRaw for T { 31 | fn fmt_raw( 32 | this: Ref<'_, Self>, 33 | f: &mut Formatter<'_>, 34 | ) -> Result<(), Error> { 35 | Display::fmt(&*this, f) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /situ/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `situ` is a set of types and traits for handling types that cannot be moved. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | #![no_std] 13 | 14 | pub mod alloc; 15 | mod drop; 16 | pub mod fmt; 17 | mod r#mut; 18 | pub mod ops; 19 | mod owned_val; 20 | mod pinned; 21 | mod r#ref; 22 | pub mod str; 23 | mod val; 24 | 25 | pub use self::{drop::*, owned_val::*, pinned::*, r#mut::*, r#ref::*, val::*}; 26 | -------------------------------------------------------------------------------- /situ/src/mut.rs: -------------------------------------------------------------------------------- 1 | use ::core::{ 2 | fmt, 3 | marker::PhantomData, 4 | ops::{Deref, DerefMut}, 5 | ptr::NonNull, 6 | }; 7 | use ::mischief::{Pointer, Region, RestructurablePointer, Unique, Within}; 8 | use ::munge::{Destructure, Restructure}; 9 | 10 | use crate::{ 11 | fmt::{DebugRaw, DisplayRaw}, 12 | DropRaw, 13 | Pinned, 14 | Ref, 15 | Val, 16 | }; 17 | 18 | /// An immovable mutable reference, like `&mut T` that cannot be relocated. 19 | pub struct Mut<'a, T: ?Sized> { 20 | ptr: NonNull, 21 | _phantom: PhantomData<&'a mut T>, 22 | } 23 | 24 | impl<'a, T: ?Sized> Mut<'a, T> { 25 | /// Creates a new `Mut` from an exclusively borrowed pointer. 26 | /// 27 | /// # Safety 28 | /// 29 | /// - `ptr` must be non-null, properly aligned, and valid for reads and 30 | /// writes. 31 | /// - `ptr` must not alias any other accessible references for `'a`. 32 | /// - The value pointed to by `ptr` must be initialized and immovable. 33 | pub unsafe fn new_unchecked(ptr: *mut T) -> Self { 34 | Self { 35 | // SAFETY: The caller has guaranteed that `ptr` is non-null. 36 | ptr: unsafe { NonNull::new_unchecked(ptr) }, 37 | _phantom: PhantomData, 38 | } 39 | } 40 | 41 | /// Constructs a new `Mut` by mapping the interior pointer. 42 | /// 43 | /// # Safety 44 | /// 45 | /// - The pointer returned by `f` must be non-null, properly aligned, and 46 | /// valid for reads and writes. 47 | /// - The pointer returned by `f` must not alias any other accessible 48 | /// references for `'a`. 49 | /// - The value pointed to by the pointer returned by `f` must be 50 | /// initialized and immutable. 51 | pub unsafe fn map_unchecked(self, f: F) -> Mut<'a, U> 52 | where 53 | F: FnOnce(*mut T) -> *mut U, 54 | { 55 | // SAFETY: The caller has guaranteed that pointer returned by `f` meets 56 | // all of the safety requirements of `new_unchecked`. 57 | unsafe { Mut::new_unchecked(f(self.as_ptr())) } 58 | } 59 | 60 | /// Returns a pointer to the referenced value. 61 | pub fn as_ptr(&self) -> *mut T { 62 | self.ptr.as_ptr() 63 | } 64 | 65 | /// Returns a `NonNull` to the referenced value. 66 | pub fn as_non_null(&self) -> NonNull { 67 | self.ptr 68 | } 69 | 70 | /// Returns a `Ref` of the referenced value. 71 | pub fn as_ref(&self) -> Ref<'_, T> { 72 | // SAFETY: The requirements for `Ref` are a subset of those for `Mut`. 73 | unsafe { Ref::new_unchecked(self.as_ptr()) } 74 | } 75 | 76 | /// Returns a reborrowed `Mut` of the referenced value. 77 | pub fn as_mut(&mut self) -> Mut<'_, T> { 78 | // SAFETY: The reborrowed `Mut` lives shorter than `self` and satisfies 79 | // all of the same requirements. 80 | unsafe { Mut::new_unchecked(self.as_ptr()) } 81 | } 82 | 83 | /// Assumes ownership of the value in the `Mut`. 84 | /// 85 | /// # Safety 86 | /// 87 | /// - The value pointed to by the `Mut` must be valid for dropping. 88 | /// - The caller must ensure that the value pointed to by the `Mut` is never 89 | /// accessed in an illegal state. Because `Val` may drop the value, care 90 | /// must be taken to forget the `Val` or replace the value after dropping 91 | /// it. 92 | pub unsafe fn take(self) -> Val<'a, T> 93 | where 94 | T: DropRaw, 95 | { 96 | // SAFETY: `Mut` upholds all of the invariants required for `Val`, 97 | // except that the caller has guaranteed that the value pointed to by 98 | // `self` is valid for dropping. 99 | unsafe { Val::new_unchecked(self.as_ptr()) } 100 | } 101 | } 102 | 103 | // SAFETY: `Mut` returns the same value from `target`, `deref`, and `deref_mut`. 104 | unsafe impl Pointer for Mut<'_, T> { 105 | type Target = T; 106 | 107 | fn target(&self) -> *mut Self::Target { 108 | self.ptr.as_ptr() 109 | } 110 | } 111 | 112 | // SAFETY: `T` is only located in `R`, so the targets of all `Mut<'_, T>` must 113 | // be located in `R`. 114 | unsafe impl + ?Sized, R: Region> Within for Mut<'_, T> {} 115 | 116 | impl Deref for Mut<'_, T> { 117 | type Target = T; 118 | 119 | fn deref(&self) -> &Self::Target { 120 | // SAFETY: 121 | // - `self.ptr` is always properly aligned and dereferenceable. 122 | // - `self.ptr` always points to an initialized value of `T`. 123 | // - Because `Mut<'a, T>` lives for `'a` at most, the lifetime of 124 | // `&self` must be shorter than `'a`. That lifetime is used for the 125 | // returned reference, so the returned reference is valid for `'a` and 126 | // has shared read-only aliasing. 127 | unsafe { self.ptr.as_ref() } 128 | } 129 | } 130 | 131 | // Note that `T` must be `Unpin` to avoid violating the immovability invariant 132 | // of `Mut`. 133 | impl DerefMut for Mut<'_, T> { 134 | fn deref_mut(&mut self) -> &mut Self::Target { 135 | // SAFETY: 136 | // - `self.ptr` is always properly aligned and dereferenceable. 137 | // - `self.ptr` always points to an initialized value of `T`. 138 | // - Because `Mut<'a, T>` lives for `'a` at most, the lifetime of 139 | // `&mut self` must be shorter than `'a`. That lifetime is used for 140 | // the returned reference, so the returned reference is valid for `'a` 141 | // and has unique read-write aliasing. 142 | unsafe { self.ptr.as_mut() } 143 | } 144 | } 145 | 146 | impl fmt::Debug for Mut<'_, T> { 147 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 148 | DebugRaw::fmt_raw(self.as_ref(), f) 149 | } 150 | } 151 | 152 | impl fmt::Display for Mut<'_, T> { 153 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 154 | DisplayRaw::fmt_raw(self.as_ref(), f) 155 | } 156 | } 157 | 158 | // SAFETY: `Destructure::underlying` for `Mut` returns the same pointer as 159 | // `Pointer::target`. 160 | unsafe impl RestructurablePointer for Mut<'_, T> {} 161 | 162 | // SAFETY: 163 | // - `Mut<'a, T>` is destructured by reference, so its `Destructuring` type is 164 | // `Ref`. 165 | // - `underlying` returns the pointer inside the `Mut<'a, T>`, which is 166 | // guaranteed to be non-null, properly-aligned, and valid for reads. 167 | unsafe impl<'a, T: ?Sized> Destructure for Mut<'a, T> { 168 | type Underlying = T; 169 | type Destructuring = ::munge::Ref; 170 | 171 | fn underlying(&mut self) -> *mut Self::Underlying { 172 | self.as_ptr() 173 | } 174 | } 175 | 176 | // SAFETY: `restructure` returns a `Mut<'a, U>` that borrows the restructured 177 | // field because `Mut<'a, T>` is destructured by reference. 178 | unsafe impl<'a, T, U: 'a> Restructure for Mut<'a, T> { 179 | type Restructured = Mut<'a, U>; 180 | 181 | unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured { 182 | // SAFETY: 183 | // - A pointer to a subfield of a `Mut` is also non-null, properly 184 | // aligned, and valid for reads and writes. 185 | // - `munge` enforces that the field pointer cannot alias another 186 | // accessible reference to the field. Because `Mut` is an exclusive 187 | // borrow of the entire object, there cannot be another reference to 188 | // one of its fields. 189 | // - All of the fields of a `Mut` must be initialized and immovable 190 | // because the overall `Mut` is initialized and immovable. 191 | unsafe { Mut::new_unchecked(ptr) } 192 | } 193 | } 194 | 195 | // SAFETY: Because the borrowed `T` is unique and mutable references are 196 | // exclusive, there can only ever be one `Mut` to each unique `T` at any time. 197 | unsafe impl Unique for Mut<'_, T> {} 198 | -------------------------------------------------------------------------------- /situ/src/ops.rs: -------------------------------------------------------------------------------- 1 | //! Variants of `ops` traits that work with raw references. 2 | 3 | use ::ptr_meta::metadata; 4 | 5 | use crate::{Mut, Ref}; 6 | 7 | /// A variant of `Deref` that works with raw references. 8 | pub trait DerefRaw { 9 | /// The resulting type after dereferencing. 10 | type Target: ?Sized; 11 | 12 | /// Dereferences the value. 13 | fn deref_raw(this: Ref<'_, Self>) -> Ref<'_, Self::Target>; 14 | } 15 | 16 | /// A variant of `DerefMut` that works with raw references. 17 | pub trait DerefMutRaw: DerefRaw { 18 | /// Mutably dereferences the value. 19 | fn deref_mut_raw(this: Mut<'_, Self>) -> Mut<'_, Self::Target>; 20 | } 21 | 22 | /// A variant of `Index` that works with raw references. 23 | pub trait IndexRaw { 24 | /// The returned type after indexing. 25 | type Output: ?Sized; 26 | 27 | /// Performs the indexing (`container[index]`) operation. 28 | /// 29 | /// # Panics 30 | /// 31 | /// May panic if the index is out of bounds. 32 | fn index_raw(this: Ref<'_, Self>, index: Idx) -> Ref<'_, Self::Output>; 33 | 34 | /// Performs the indexing (`container[index]`) operation without performing 35 | /// bounds checking 36 | /// 37 | /// # Safety 38 | /// 39 | /// `index` must be in bounds for `this`. 40 | unsafe fn index_raw_unchecked( 41 | this: Ref<'_, Self>, 42 | index: Idx, 43 | ) -> Ref<'_, Self::Output>; 44 | } 45 | 46 | /// A variant of `IndexMut` that works with raw references. 47 | pub trait IndexMutRaw: IndexRaw { 48 | /// Performs the mutable indexing (`container[index]`) operation. 49 | /// 50 | /// # Panics 51 | /// 52 | /// May panic if the index is out of bounds. 53 | fn index_mut_raw(this: Mut<'_, Self>, index: Idx) -> Mut<'_, Self::Output>; 54 | 55 | /// Performs the mutable indexing (`container[index]`) operation without 56 | /// performing bounds checking 57 | /// 58 | /// # Safety 59 | /// 60 | /// `index` must be in bounds for `this`. 61 | unsafe fn index_mut_raw_unchecked( 62 | this: Mut<'_, Self>, 63 | index: Idx, 64 | ) -> Mut<'_, Self::Output>; 65 | } 66 | 67 | impl IndexRaw for [T; N] { 68 | type Output = T; 69 | 70 | fn index_raw(this: Ref<'_, Self>, index: usize) -> Ref<'_, Self::Output> { 71 | assert!(index < N); 72 | // SAFETY: We asserted that `index` is less than `N` and so it in 73 | // bounds. 74 | unsafe { Self::index_raw_unchecked(this, index) } 75 | } 76 | 77 | unsafe fn index_raw_unchecked( 78 | this: Ref<'_, Self>, 79 | index: usize, 80 | ) -> Ref<'_, Self::Output> { 81 | // SAFETY: This pointer add is safe because the pointer is guaranteed to 82 | // be to the first `T` in an array of `N` consecutive `T`, and the 83 | // resulting pointer must be in-bounds because the caller has guaranteed 84 | // that `index` is less than `N`. 85 | let ptr = unsafe { this.as_ptr().cast::().add(index) }; 86 | // SAFETY: The offset pointer is to an element of the original array, 87 | // and so must be non-null, properly aligned, valid for reads, and 88 | // initialized. It has the same shared aliasing as the `Ref` it is 89 | // derived from, and so must not alias any other mutable references for 90 | // `'_`. 91 | unsafe { Ref::new_unchecked(ptr) } 92 | } 93 | } 94 | 95 | impl IndexMutRaw for [T; N] { 96 | fn index_mut_raw( 97 | this: Mut<'_, Self>, 98 | index: usize, 99 | ) -> Mut<'_, Self::Output> { 100 | assert!(index < N); 101 | // SAFETY: We asserted that `index` is less than `N` and so is in 102 | // bounds. 103 | unsafe { Self::index_mut_raw_unchecked(this, index) } 104 | } 105 | 106 | unsafe fn index_mut_raw_unchecked( 107 | this: Mut<'_, Self>, 108 | index: usize, 109 | ) -> Mut<'_, Self::Output> { 110 | // SAFETY: This pointer add is safe because the pointer is guaranteed to 111 | // be to the first `T` in an array of `N` consecutive `T`, and the 112 | // resulting pointer must be in-bounds because the caller has guaranteed 113 | // that `index` is less than `N`. 114 | let ptr = unsafe { this.as_ptr().cast::().add(index) }; 115 | // SAFETY: The offset pointer is to an element of the original array, 116 | // and so must be non-null, properly aligned, valid for reads, and 117 | // initialized. It has the same mutable aliasing as the `Mut` it is 118 | // derived from, and so must not alias any other accessible references 119 | // for `'_`. 120 | unsafe { Mut::new_unchecked(ptr) } 121 | } 122 | } 123 | 124 | impl IndexRaw for [T] { 125 | type Output = T; 126 | 127 | fn index_raw(this: Ref<'_, Self>, index: usize) -> Ref<'_, Self::Output> { 128 | let slice_ptr = this.as_ptr(); 129 | let len = metadata(slice_ptr); 130 | assert!(index < len, "index out of bounds"); 131 | // SAFETY: We asserted that `index` is less than `len` and so it in 132 | // bounds. 133 | unsafe { Self::index_raw_unchecked(this, index) } 134 | } 135 | 136 | unsafe fn index_raw_unchecked( 137 | this: Ref<'_, Self>, 138 | index: usize, 139 | ) -> Ref<'_, Self::Output> { 140 | let slice_ptr = this.as_ptr(); 141 | // SAFETY: This pointer add is safe because the pointer is guaranteed to 142 | // be to the first `T` in a slice of `len` consecutive `T`, and the 143 | // resulting pointer must be in-bounds because the caller has guaranteed 144 | // that `index` is less than `len`. 145 | let ptr = unsafe { slice_ptr.cast::().add(index) }; 146 | // SAFETY: The offset pointer is to an element of the original slice, 147 | // and so must be non-null, properly aligned, valid for reads, and 148 | // initialized. It has the same shared aliasing as the `Ref` it is 149 | // derived from, and so must not alias any other mutable references for 150 | // `'_`. 151 | unsafe { Ref::new_unchecked(ptr) } 152 | } 153 | } 154 | 155 | impl IndexMutRaw for [T] { 156 | fn index_mut_raw( 157 | this: Mut<'_, Self>, 158 | index: usize, 159 | ) -> Mut<'_, Self::Output> { 160 | let slice_ptr = this.as_ptr(); 161 | let len = metadata(slice_ptr); 162 | assert!(index < len, "index out of bounds"); 163 | // SAFETY: We asserted that `index` is less than `len` and so is in 164 | // bounds. 165 | unsafe { Self::index_mut_raw_unchecked(this, index) } 166 | } 167 | 168 | unsafe fn index_mut_raw_unchecked( 169 | this: Mut<'_, Self>, 170 | index: usize, 171 | ) -> Mut<'_, Self::Output> { 172 | let slice_ptr = this.as_ptr(); 173 | // SAFETY: This pointer add is safe because the pointer is guaranteed to 174 | // be to the first `T` in a slice of `len` consecutive `T`, and the 175 | // resulting pointer must be in-bounds because the caller has guaranteed 176 | // that `index` is less than `len`. 177 | let ptr = unsafe { slice_ptr.cast::().add(index) }; 178 | // SAFETY: The offset pointer is to an element of the original slice, 179 | // and so must be non-null, properly aligned, valid for reads, and 180 | // initialized. It has the same mutable aliasing as the `Mut` it is 181 | // derived from, and so must not alias any other accessible references 182 | // for `'_`. 183 | unsafe { Mut::new_unchecked(ptr) } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /situ/src/owned_val.rs: -------------------------------------------------------------------------------- 1 | //! A pointer type for memory allocation. 2 | 3 | use ::core::{ 4 | alloc::Layout, 5 | fmt, 6 | mem::ManuallyDrop, 7 | ops::{Deref, DerefMut}, 8 | ptr::NonNull, 9 | }; 10 | use ::heresy::alloc::Allocator; 11 | #[cfg(feature = "alloc")] 12 | use ::heresy::alloc::Global; 13 | use ::mischief::{Frame, Metadata, Pointer, RegionalAllocator, Within}; 14 | use ::ptr_meta::Pointee; 15 | 16 | use crate::{ 17 | fmt::{DebugRaw, DisplayRaw}, 18 | DropRaw, 19 | Mut, 20 | Ref, 21 | }; 22 | 23 | /// A pointer type for memory allocation. 24 | pub struct OwnedVal< 25 | T: DropRaw + ?Sized, 26 | #[cfg(feature = "alloc")] A: Allocator = Global, 27 | #[cfg(not(feature = "alloc"))] A: Allocator, 28 | > { 29 | ptr: NonNull, 30 | alloc: A, 31 | } 32 | 33 | impl Drop for OwnedVal { 34 | fn drop(&mut self) { 35 | let layout = Layout::for_value(&**self); 36 | // SAFETY: `self.ptr` is always valid for reads and writes, properly 37 | // aligned, and valid for dropping. 38 | unsafe { 39 | T::drop_raw(self.as_mut()); 40 | } 41 | // SAFETY: `self.ptr` is always allocated via `self.alloc` and `layout` 42 | // is guaranteed to fit it. 43 | unsafe { 44 | self.alloc.deallocate(self.ptr.cast(), layout); 45 | } 46 | } 47 | } 48 | 49 | impl OwnedVal { 50 | /// Returns a reference to the underlying allocator. 51 | /// 52 | /// Note: this is an associated function, which means that you have to call 53 | /// it as `OwnedVal::allocator(&v)` instead of `owned_val.allocator()`. This 54 | /// is so that there is no conflict with a method on the inner type. 55 | pub fn allocator(v: &Self) -> &A { 56 | &v.alloc 57 | } 58 | 59 | /// Constructs an owned `Val` from a raw pointer in the given allocator. 60 | /// 61 | /// After calling this function, the raw pointer is owned by the resulting 62 | /// `OwnedVal`. Specifically, the `OwnedVal` destructor will call the 63 | /// `DropRaw` destructor of `T` and free the allocated memory. For this to 64 | /// be safe, the memory must have been allocated in accordance with the 65 | /// memory layout used by `OwnedVal`. 66 | /// 67 | /// # Safety 68 | /// 69 | /// - `ptr` must point to a memory block currently allocated by `alloc`. 70 | /// - The layout used to allocate `ptr` must exactly match the return value 71 | /// of `Layout::for_value`. 72 | /// - `ptr` must point to an initialized `T`. 73 | pub unsafe fn from_raw_in(ptr: *mut T, alloc: A) -> Self { 74 | Self { 75 | // SAFETY: `ptr` is allocated by `alloc`, and so must not be null. 76 | ptr: unsafe { NonNull::new_unchecked(ptr) }, 77 | alloc, 78 | } 79 | } 80 | 81 | /// Constructs an owned `Val` from an initialized `Frame`. 82 | /// 83 | /// # Safety 84 | /// 85 | /// `frame` must be initialized. 86 | pub unsafe fn assume_init(frame: Frame) -> Self 87 | where 88 | T: Pointee, 89 | ::Metadata: Metadata, 90 | { 91 | let (ptr, alloc) = Frame::into_raw_with_allocator(frame); 92 | // SAFETY: 93 | // - `Frame`'s `ptr` is always allocated in its returned `alloc` with 94 | // the layout returned from `Metadata::pointee_layout` (which is 95 | // equivalent to `Layout::for_value`). 96 | // - The caller has guaranteed that `frame`'s pointer is initialized. 97 | unsafe { Self::from_raw_in(ptr, alloc) } 98 | } 99 | 100 | /// Consumes the `OwnedVal`, returning a wrapped raw pointer and the 101 | /// allocator. 102 | /// 103 | /// The pointer will be properly aligned and non-null. 104 | /// 105 | /// After calling this function, the caller is responsible for the memory 106 | /// previously managed by the `OwnedVal`. In particular, the caller should 107 | /// properly destroy `T` with `DropRaw` and release the memory, taking into 108 | /// account the memory layout used by `OwnedVal`. The easiest way to do this 109 | /// is to convert the raw pointer back into an `OwnedVal` with the 110 | /// `OwnedVal::from_raw_in` function, allowing the `OwnedVal` destructor to 111 | /// perform the cleanup. 112 | /// 113 | /// Note: this is an associated function, which means that you have to call 114 | /// it as `OwnedVal::into_raw(b)` instead of `b.into_raw()`. This is so that 115 | /// there is no conflict with a method on the inner type. 116 | pub fn into_raw_parts(b: Self) -> (*mut T, A) { 117 | let b = ManuallyDrop::new(b); 118 | // SAFETY: `b.alloc` is a valid `A` that is moved into the return value 119 | // and not dropped. 120 | let alloc = unsafe { ::core::ptr::read(&b.alloc) }; 121 | (b.ptr.as_ptr(), alloc) 122 | } 123 | 124 | /// Returns a `Ref` of the owned value. 125 | pub fn as_ref(&self) -> Ref<'_, T> { 126 | // SAFETY: `self.ptr` is always non-null, properly aligned, and valid 127 | // for reads. Because `self` owns the value and it is borrowed, the 128 | // value pointed to by `self.ptr` may only be aliased by shared 129 | // references. And finally, it's an invariant of `OwnedVal` that the 130 | // value pointed to is initialized. 131 | unsafe { Ref::new_unchecked(self.ptr.as_ptr()) } 132 | } 133 | 134 | /// Returns a `Mut` of the owned value. 135 | pub fn as_mut(&mut self) -> Mut<'_, T> { 136 | // SAFETY: `self.ptr` is always non-null, properly aligned, and valid 137 | // for reads. Because `self` owns the value and it is mutably borrowed, 138 | // the value pointed to by `self.ptr` may not be aliased. And finally, 139 | // it's an invariant of `OwnedVal` that the value pointed to is 140 | // initialized. 141 | unsafe { Mut::new_unchecked(self.ptr.as_ptr()) } 142 | } 143 | } 144 | 145 | impl OwnedVal { 146 | /// Allocates memory in the given allocator then places `x` into it. 147 | pub fn new_in(x: T, alloc: A) -> OwnedVal { 148 | let mut frame = Frame::new_in(alloc); 149 | frame.write(x); 150 | // SAFETY: We initialized `frame` by writing to it. 151 | unsafe { Self::assume_init(frame) } 152 | } 153 | } 154 | 155 | #[cfg(feature = "alloc")] 156 | impl OwnedVal { 157 | /// Allocates memory in the `Global` allocator and then places `x` into it. 158 | pub fn new(x: T) -> Self { 159 | Self::new_in(x, Global) 160 | } 161 | } 162 | 163 | // SAFETY: `OwnedVal` returns the same value from `target`, `deref`, and 164 | // `deref_mut`. 165 | unsafe impl Pointer for OwnedVal 166 | where 167 | T: DropRaw + Pointee + ?Sized, 168 | A: Allocator, 169 | { 170 | type Target = T; 171 | 172 | fn target(&self) -> *mut Self::Target { 173 | OwnedVal::as_ref(self).as_ptr() 174 | } 175 | } 176 | 177 | // SAFETY: The pointee of `OwnedVal` is located in `A::Region` because it 178 | // is allocated in `A`. 179 | unsafe impl Within for OwnedVal 180 | where 181 | T: DropRaw + Pointee + ?Sized, 182 | A: RegionalAllocator, 183 | { 184 | } 185 | 186 | impl Deref for OwnedVal { 187 | type Target = T; 188 | 189 | #[inline] 190 | fn deref(&self) -> &Self::Target { 191 | // SAFETY: 192 | // - `self.ptr` is always properly aligned and dereferenceable. 193 | // - `self.ptr` always points to an initialized value of `T`. 194 | // - Because `OwnedVal` is borrowed for `'_`, the returned 195 | // reference is also valid for `'_` and has shared read-only aliasing. 196 | unsafe { &*self.ptr.as_ptr() } 197 | } 198 | } 199 | 200 | // Note that `T` must be `Unpin` to avoid violating the immovability invariant 201 | // of `OwnedVal`. 202 | impl DerefMut for OwnedVal { 203 | #[inline] 204 | fn deref_mut(&mut self) -> &mut Self::Target { 205 | // SAFETY: 206 | // - `self.ptr` is always properly aligned and dereferenceable. 207 | // - `self.ptr` always points to an initialized value of `T`. 208 | // - Because `OwnedVal` is mutably borrowed for `'_`, the returned 209 | // reference is also valid for `'_` and has unique read-write 210 | // aliasing. 211 | unsafe { &mut *self.ptr.as_ptr() } 212 | } 213 | } 214 | 215 | impl fmt::Debug for OwnedVal 216 | where 217 | T: DebugRaw + DropRaw + ?Sized, 218 | A: Allocator, 219 | { 220 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 221 | DebugRaw::fmt_raw(self.as_ref(), f) 222 | } 223 | } 224 | 225 | impl fmt::Display for OwnedVal 226 | where 227 | T: DisplayRaw + DropRaw + ?Sized, 228 | A: Allocator, 229 | { 230 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 231 | DisplayRaw::fmt_raw(self.as_ref(), f) 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /situ/src/pinned.rs: -------------------------------------------------------------------------------- 1 | use ::mischief::Region; 2 | 3 | /// A type with values that are always located in a particular region. 4 | /// 5 | /// While values of types that implement `Pinned` must be located in `R`, 6 | /// uninitialized values do not. This is why [`Slot`](::mischief::Slot) cannot 7 | /// implement `Within` when its type impelements `Pinned`. 8 | /// 9 | /// # Safety 10 | /// 11 | /// Values of this type must only ever be located in `R`. 12 | pub unsafe trait Pinned {} 13 | -------------------------------------------------------------------------------- /situ/src/ref.rs: -------------------------------------------------------------------------------- 1 | use ::core::{fmt, marker::PhantomData, ops::Deref, ptr::NonNull}; 2 | use ::mischief::{ 3 | Pointer, 4 | Region, 5 | RestructurablePointer, 6 | Singleton, 7 | Unique, 8 | Within, 9 | }; 10 | use ::munge::{Destructure, Restructure}; 11 | 12 | use crate::{ 13 | fmt::{DebugRaw, DisplayRaw}, 14 | Pinned, 15 | }; 16 | 17 | /// An immutable reference, like `&T`. 18 | /// 19 | /// Internally, the reference is stored as a pointer to avoid provenance 20 | /// narrowing. 21 | pub struct Ref<'a, T: ?Sized> { 22 | ptr: NonNull, 23 | _phantom: PhantomData<&'a T>, 24 | } 25 | 26 | impl<'a, T: ?Sized> Clone for Ref<'a, T> { 27 | fn clone(&self) -> Self { 28 | // SAFETY: `self.as_ptr()` is the internal pointer of this `Ref`, and 29 | // upholds all of the safety requirements of `Ref::new_unchecked`. 30 | unsafe { Ref::new_unchecked(self.as_ptr()) } 31 | } 32 | } 33 | 34 | impl<'a, T: ?Sized> Copy for Ref<'a, T> {} 35 | 36 | impl<'a, T: ?Sized> Ref<'a, T> { 37 | /// Creates a new `Ref` from a shared pointer. 38 | /// 39 | /// # Safety 40 | /// 41 | /// - `ptr` must be non-null, properly aligned, and valid for reads. 42 | /// - `ptr` must not alias any other mutable references for `'a`. 43 | /// - The value pointed to by `ptr` must be initialized. 44 | pub unsafe fn new_unchecked(ptr: *const T) -> Self { 45 | Self { 46 | // SAFETY: The caller has guaranteed that `ptr` is non-null. 47 | ptr: unsafe { NonNull::new_unchecked(ptr.cast_mut()) }, 48 | _phantom: PhantomData, 49 | } 50 | } 51 | 52 | /// Returns a pointer to the referenced value. 53 | pub fn as_ptr(self) -> *mut T { 54 | self.ptr.as_ptr() 55 | } 56 | } 57 | 58 | // SAFETY: `Ref` returns the same value from `target` and `deref`. 59 | unsafe impl Pointer for Ref<'_, T> { 60 | type Target = T; 61 | 62 | fn target(&self) -> *mut Self::Target { 63 | self.ptr.as_ptr() 64 | } 65 | } 66 | 67 | impl Deref for Ref<'_, T> { 68 | type Target = T; 69 | 70 | fn deref(&self) -> &Self::Target { 71 | // SAFETY: 72 | // - `self.ptr` is always properly aligned and dereferenceable. 73 | // - `self.ptr` always points to an initialized value of `T`. 74 | // - Because `Ref<'a, T>` lives for `'a` at most, the lifetime of 75 | // `&self` must be shorter than `'a`. That lifetime is used for the 76 | // returned reference, so the returned reference is valid for `'a` and 77 | // has shared read-only aliasing. 78 | unsafe { self.ptr.as_ref() } 79 | } 80 | } 81 | 82 | impl fmt::Debug for Ref<'_, T> { 83 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 84 | DebugRaw::fmt_raw(*self, f) 85 | } 86 | } 87 | 88 | impl fmt::Display for Ref<'_, T> { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | DisplayRaw::fmt_raw(*self, f) 91 | } 92 | } 93 | 94 | // SAFETY: `Destructure::underlying` for `Ref` returns the same pointer as 95 | // `Pointer::target`. 96 | unsafe impl RestructurablePointer for Ref<'_, T> {} 97 | 98 | // SAFETY: `T` is only located in `R`, so the targets of all `Ref<'_, T>` must 99 | // be located in `R`. 100 | unsafe impl + ?Sized, R: Region> Within for Ref<'_, T> {} 101 | 102 | // SAFETY: 103 | // - `Ref<'a, T>` is destructured by reference, so its `Destructuring` type is 104 | // `Ref`. 105 | // - `underlying` returns the pointer inside the `Ref<'a, T>`, which is 106 | // guaranteed to be non-null, properly-aligned, and valid for reads. 107 | unsafe impl<'a, T: ?Sized> Destructure for Ref<'a, T> { 108 | type Underlying = T; 109 | type Destructuring = ::munge::Ref; 110 | 111 | fn underlying(&mut self) -> *mut Self::Underlying { 112 | self.as_ptr() 113 | } 114 | } 115 | 116 | // SAFETY: `restructure` returns a `Ref<'a, U>` that borrows the restructured 117 | // field because `Ref<'a, T>` is destructured by reference. 118 | unsafe impl<'a, T, U: 'a> Restructure for Ref<'a, T> { 119 | type Restructured = Ref<'a, U>; 120 | 121 | unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured { 122 | // SAFETY: 123 | // - A pointer to a subfield of a `Ref` is also non-null, properly 124 | // aligned, and valid for reads and writes. 125 | // - `munge` enforces that the field pointer cannot alias another 126 | // accessible reference to the field. Because `Ref` is a shared borrow 127 | // of the entire object, there cannot be another mutable reference to 128 | // one of its fields. 129 | // - All of the fields of a `Ref` must be initialized and immovable 130 | // because the overall `Ref` is initialized and immovable. 131 | unsafe { Ref::new_unchecked(ptr) } 132 | } 133 | } 134 | 135 | // SAFETY: Because the borrowed `T` is unique and shared references borrow their 136 | // state from the underlying `T`, all `Ref` to unique `T` must be sharing the 137 | // same value. 138 | unsafe impl Singleton for Ref<'_, T> {} 139 | -------------------------------------------------------------------------------- /situ/src/str.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for the `str` primitive type. 2 | 3 | use ::core::str; 4 | 5 | use crate::{Mut, Ref}; 6 | 7 | /// Converts a slice of bytes to a string slice without checking that the string 8 | /// contains valid UTF-8. 9 | /// 10 | /// # Safety 11 | /// 12 | /// The bytes passed in must be valid UTF-8. 13 | pub unsafe fn from_raw_utf8_unchecked(v: Ref<'_, [u8]>) -> Ref<'_, str> { 14 | // SAFETY: The caller has guaranteed that the bytes of `v` are valid UTF-8. 15 | let ptr = v.as_ptr(); 16 | let str_ptr = 17 | ::ptr_meta::from_raw_parts(ptr.cast(), ::ptr_meta::metadata(ptr)); 18 | // SAFETY: `str_ptr` is the pointer from `v`, and so: 19 | // - Is non-null, properly aligned, and valid for reads. 20 | // - Does not alias alias any other mutable references for `'_`. 21 | // - Points to an initialized value. 22 | unsafe { Ref::new_unchecked(str_ptr) } 23 | } 24 | 25 | /// Converts a slice of bytes to a string slice. 26 | pub fn from_raw_utf8(v: Ref<'_, [u8]>) -> Result, str::Utf8Error> { 27 | str::from_utf8(&v)?; 28 | // SAFETY: `from_utf8` has checked that the byte slice is valid UTF-8. 29 | Ok(unsafe { from_raw_utf8_unchecked(v) }) 30 | } 31 | 32 | /// Converts a slice of bytes to a mutable string slice without checking that 33 | /// the string contains valid UTF-8. 34 | /// 35 | /// # Safety 36 | /// 37 | /// The bytes passed in must be valid UTF-8. 38 | pub unsafe fn from_raw_utf8_unchecked_mut(v: Mut<'_, [u8]>) -> Mut<'_, str> { 39 | // SAFETY: The caller has guaranteed that the bytes of `v` are valid UTF-8. 40 | let ptr = v.as_ptr(); 41 | let str_ptr = 42 | ::ptr_meta::from_raw_parts_mut(ptr.cast(), ::ptr_meta::metadata(ptr)); 43 | // SAFETY: `str_ptr` is the pointer from `v`, and so: 44 | // - Is non-null, properly aligned, and valid for reads. 45 | // - Does not alias alias any other accessible references for `'_`. 46 | // - Points to an initialized, immovable value. 47 | unsafe { Mut::new_unchecked(str_ptr) } 48 | } 49 | 50 | /// Converts a slice of bytes to a mutable string slice. 51 | pub fn from_raw_utf8_mut( 52 | mut v: Mut<'_, [u8]>, 53 | ) -> Result, str::Utf8Error> { 54 | str::from_utf8_mut(&mut v)?; 55 | // SAFETY: `from_utf8_mut` has checked that the byte slice is valid UTF-8. 56 | Ok(unsafe { from_raw_utf8_unchecked_mut(v) }) 57 | } 58 | -------------------------------------------------------------------------------- /situ_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "situ_derive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | proc-macro = true 8 | 9 | [dependencies] 10 | proc-macro2 = "1.0" 11 | quote = "1.0" 12 | syn = "1.0" 13 | 14 | [dependencies.macroix] 15 | version = "0.1" 16 | path = "../macroix" 17 | 18 | [dependencies.raw_enum] 19 | version = "0.1" 20 | path = "../raw_enum" 21 | -------------------------------------------------------------------------------- /situ_derive/src/drop_raw.rs: -------------------------------------------------------------------------------- 1 | use ::macroix::{repr::Repr, visit_fields, AttrValue}; 2 | use ::proc_macro2::TokenStream; 3 | use ::quote::quote; 4 | use ::raw_enum::RawEnum; 5 | use ::syn::{ 6 | parse2, 7 | parse_quote, 8 | Data, 9 | DeriveInput, 10 | Error, 11 | Fields, 12 | Index, 13 | Path, 14 | }; 15 | 16 | pub fn derive(mut input: DeriveInput) -> Result { 17 | let mut repr = None; 18 | let mut situ = None; 19 | for attr in input.attrs.iter() { 20 | if attr.path.is_ident("repr") { 21 | Repr::merge_attr(&mut repr, attr.tokens.clone())?; 22 | } else if attr.path.is_ident("situ") { 23 | situ = Some(parse2::>(attr.tokens.clone())?.value); 24 | } 25 | } 26 | let situ = situ.unwrap_or_else(|| parse_quote! { ::situ }); 27 | 28 | let name = &input.ident; 29 | 30 | let where_clause = input.generics.make_where_clause(); 31 | visit_fields(&input.data, |f| { 32 | let ty = &f.ty; 33 | where_clause 34 | .predicates 35 | .push(parse_quote! { #ty: #situ::DropRaw }); 36 | }); 37 | 38 | let (drop_raw, util) = match &input.data { 39 | Data::Enum(data_enum) => { 40 | let raw_enum = RawEnum::for_derive(&input)?; 41 | 42 | let raw_variants = &raw_enum.idents.variants; 43 | let raw_enum_fn = &raw_enum.idents.raw_enum_fn; 44 | let raw_variant_fn = &raw_enum.idents.variant_fn; 45 | 46 | let match_arms = data_enum.variants.iter().map(|v| { 47 | let ident = &v.ident; 48 | let drop_raw_variant = drop_raw_fields(&v.fields, &situ, true); 49 | quote! { 50 | #raw_variants::#ident(this_ptr) => { 51 | #drop_raw_variant 52 | } 53 | } 54 | }); 55 | 56 | ( 57 | Some(quote! { 58 | let this_raw = #raw_enum_fn(this_ptr); 59 | match #raw_variant_fn(this_raw) { 60 | #(#match_arms)* 61 | } 62 | }), 63 | Some(raw_enum.tokens), 64 | ) 65 | } 66 | Data::Struct(data_struct) => { 67 | (drop_raw_fields(&data_struct.fields, &situ, false), None) 68 | } 69 | Data::Union(data_union) => { 70 | return Err(Error::new_spanned( 71 | data_union.union_token, 72 | "`DropRaw` cannot be derived for unions", 73 | )) 74 | } 75 | }; 76 | 77 | let (impl_generics, ty_generics, where_clause) = 78 | input.generics.split_for_impl(); 79 | 80 | Ok(quote! { 81 | const _: () = { 82 | #util 83 | 84 | impl #impl_generics #situ::DropRaw for #name #ty_generics 85 | #where_clause 86 | { 87 | unsafe fn drop_raw(mut this: #situ::Mut<'_, Self>) { 88 | let this_ptr = #situ::Mut::as_ptr(&this); 89 | #drop_raw 90 | } 91 | } 92 | }; 93 | }) 94 | } 95 | 96 | fn drop_raw_fields( 97 | fields: &Fields, 98 | situ: &Path, 99 | skip_discriminant: bool, 100 | ) -> Option { 101 | match fields { 102 | Fields::Named(fields) => { 103 | let move_fields = fields.named.iter().map(|f| { 104 | let ty = &f.ty; 105 | let ident = &f.ident; 106 | quote! { 107 | <#ty as #situ::DropRaw>::drop_raw( 108 | #situ::Mut::new_unchecked( 109 | ::core::ptr::addr_of_mut!((*this_ptr).#ident) 110 | ) 111 | ); 112 | } 113 | }); 114 | Some(quote! { 115 | #(#move_fields)* 116 | }) 117 | } 118 | Fields::Unnamed(fields) => { 119 | let move_fields = 120 | fields.unnamed.iter().enumerate().map(|(i, _)| { 121 | // In enum tuple structs, the tag is the first element so we 122 | // have to skip over it. 123 | let offset = if skip_discriminant { 1 } else { 0 }; 124 | let i = Index::from(i + offset); 125 | quote! { 126 | #situ::DropRaw::drop_raw( 127 | #situ::Mut::new_unchecked( 128 | ::core::ptr::addr_of_mut!((*this_ptr).#i) 129 | ) 130 | ); 131 | } 132 | }); 133 | Some(quote! { 134 | #(#move_fields)* 135 | }) 136 | } 137 | Fields::Unit => None, 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /situ_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Procedural macros for `situ`. 2 | 3 | #![deny( 4 | missing_docs, 5 | unsafe_op_in_unsafe_fn, 6 | clippy::as_conversions, 7 | clippy::missing_safety_doc, 8 | clippy::undocumented_unsafe_blocks, 9 | rustdoc::broken_intra_doc_links, 10 | rustdoc::missing_crate_level_docs 11 | )] 12 | 13 | mod drop_raw; 14 | 15 | use ::proc_macro::TokenStream; 16 | use ::syn::{parse_macro_input, DeriveInput}; 17 | 18 | /// Derives `DropRaw` on the annotated type. 19 | #[proc_macro_derive(DropRaw, attributes(situ))] 20 | pub fn derive_drop_raw(input: TokenStream) -> TokenStream { 21 | let derive_input = parse_macro_input!(input as DeriveInput); 22 | drop_raw::derive(derive_input) 23 | .unwrap_or_else(|e| e.to_compile_error()) 24 | .into() 25 | } 26 | --------------------------------------------------------------------------------