├── .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 |
3 |
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 |
{
13 | ptr: P,
14 | region: PhantomData
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 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 {
133 | type Target = P::Target;
134 |
135 | fn deref(&self) -> &Self::Target {
136 | self.ptr().deref()
137 | }
138 | }
139 |
140 | impl {
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 {
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 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
45 | where
46 | F: FnOnce(P) -> Q,
47 | Q: Pointer + Within
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