├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src ├── lib.rs ├── lift.rs ├── rc.rs ├── rcref.rs └── utils.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .cargo 2 | target 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static-rc" 3 | version = "0.7.0" 4 | authors = ["Matthieu M. "] 5 | edition = "2024" 6 | description = "Compile-time reference counting" 7 | repository = "https://github.com/matthieu-m/static-rc" 8 | license = "MIT OR Apache-2.0" 9 | keywords = ["experimental", "reference-counting"] 10 | categories = ["memory-management", "no-std"] 11 | 12 | [features] 13 | 14 | # Enables `alloc` (hence `StaticRc`) by default. 15 | default = ["alloc"] 16 | 17 | # Checks `split`/`join` at compile-time rather than run-time. 18 | # This currently requires nightly, see src/lib.rs for the features required. 19 | compile-time-ratio = [] 20 | 21 | # Enables `alloc`, and therefore `StaticRc`. 22 | alloc = [] 23 | 24 | # Enables `lift`, an experimental feature to allow tying the knot. 25 | experimental-lift = [] 26 | 27 | # Enables `AsyncIterator` on `StaticRc`. 28 | # This currently requires nightly, and specifically the `async_iterator` feature. 29 | nightly-async-iterator = [] 30 | 31 | # Enables `CoerceUnsized` on `StaticRc`. 32 | # This currently requires nightly, and specifically the `coerce_unsized` feature. 33 | nightly-coerce-unsized = [] 34 | 35 | # Enables `DispatchFromDyn` on `StaticRc`. 36 | # This currently requires nightly, and specifically the `dispatch_from_dyn` feature. 37 | nightly-dispatch-from-dyn = [] 38 | 39 | # Enables `Generator` on `StaticRc`. 40 | # This currently requires nightly, and specifically the `generator_trait` feature. 41 | nightly-generator-trait = [] 42 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 matthieu-m 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2021 matthieu-m 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `StaticRc` is a safe reference-counted pointer, similar to `Rc` or `Arc`, though performing its reference-counting at 2 | compile-time rather than run-time, and therefore avoiding most run-time overhead. 3 | 4 | # Motivating Example 5 | 6 | A number of collections, such as linked-lists, binary-trees, or B-Trees are most easily implemented with aliasing 7 | pointers. 8 | 9 | Traditionally, this requires either `unsafe` raw pointers, or using `Rc` or `Arc` depending on the scenario. A key 10 | observation, however, is that in those collections the exact number of aliases is known at compile-time: 11 | 12 | - A doubly linked-list has 2 pointers to each node. 13 | - A binary-tree has 3 pointers to each node: one from the parent, and one from each child. 14 | - A B-Tree of cardinality N has N+1 pointers to each node. 15 | 16 | In this type of scenario, `static-rc` offers the safety of `Rc` and `Arc`, with the performance of `unsafe` raw 17 | pointers. 18 | 19 | 20 | # Goals 21 | 22 | Provide safe and efficient reference-counting: 23 | 24 | - Efficiency: most associated functions boil down to copying a `NonNull`, a trivial operation. 25 | - One key exception are `join` functions: a run-time check must be performed to ensure the instances being joined 26 | refer to the same pointer. Unsafe unchecked variants are available if their overhead is too high. 27 | - Safety: most associated functions are safe to use. 28 | - The few unsafe functions are strictly optional. 29 | 30 | 31 | # Maturity 32 | 33 | This crate is still very much experimental. 34 | 35 | Review: 36 | 37 | - Minimally reviewed. 38 | - Not audited. 39 | - Not formally proven. 40 | 41 | Documentation: 42 | 43 | - All `StaticRc` associated functions are documented, with example. 44 | - All `StaticRcRef` associated functions are documented, with example. 45 | 46 | Testing: 47 | 48 | - All compile-time assertions are tested with compile-fail tests. 49 | - All panics are tested with panic tests. 50 | - Miri runs the test-suite without any complain. 51 | 52 | 53 | # Debug checks 54 | 55 | This library contains a number of additional checks when building with `debug_assertions`, in particular the `Drop` 56 | implementation of `StaticRc` will catch any attempt at destroying a `StaticRc` where `N <> D`, as this would 57 | typically result in a leak. 58 | 59 | Those checks are not strictly necessary for safety, they are included to help point out logic errors. 60 | 61 | From experience, the `Drop` check on top of an extensive test-suite will help catch all those instances where one path 62 | accidentally let a pointer drop. 63 | 64 | 65 | # That's all folks! 66 | 67 | And thanks for reading. 68 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `StaticRc`, resp. `StaticRcRef`, use Rust's affine type system and const generics to track the shared ownership 2 | //! of a heap-allocated, resp. reference, value safely at compile-time, with no run-time overhead. 3 | //! 4 | //! The amount of `unsafe` used within is minimal, `StaticRc` mostly leverages `Box` for most of the heavy-duty 5 | //! operations. 6 | //! 7 | //! # Example of usage. 8 | //! 9 | //! ``` 10 | //! use static_rc::StaticRc; 11 | //! 12 | //! type Full = StaticRc; 13 | //! type TwoThird = StaticRc; 14 | //! type OneThird = StaticRc; 15 | //! 16 | //! let mut full = Full::new("Hello, world!".to_string()); 17 | //! 18 | //! assert_eq!("Hello, world!", &*full); 19 | //! 20 | //! // Mutation is allowed when having full ownership, just like for `Box`. 21 | //! *full = "Hello, you!".to_string(); 22 | //! 23 | //! assert_eq!("Hello, you!", &*full); 24 | //! 25 | //! // Mutation is no longer allowed from now on, due to aliasing, just like for `Rc`. 26 | //! let (two_third, one_third) = Full::split::<2, 1>(full); 27 | //! 28 | //! assert_eq!("Hello, you!", &*two_third); 29 | //! assert_eq!("Hello, you!", &*one_third); 30 | //! 31 | //! let mut full = Full::join(one_third, two_third); 32 | //! 33 | //! assert_eq!("Hello, you!", &*full); 34 | //! 35 | //! // Mutation is allowed again, since `full` has full ownership. 36 | //! *full = "Hello, world!".to_string(); 37 | //! 38 | //! assert_eq!("Hello, world!", &*full); 39 | //! 40 | //! // Finally, the value is dropped when `full` is. 41 | //! ``` 42 | //! 43 | //! # Options 44 | //! 45 | //! The crate is defined for `no_std` environment and only relies on `core` and `alloc` by default. 46 | //! 47 | //! The `alloc` crate can be opted out of, though this disables `StaticRc`. 48 | //! 49 | //! The crate only uses stable features by default, with a MSRV of 1.57 due to the use of `assert!` in `const` blocks. 50 | //! 51 | //! Additional, the crate offers several optional features which unlock additional capabilities by using nightly. 52 | //! Please see `Cargo.toml` for an up-to-date list of features, and their effects. 53 | 54 | // Regular features 55 | #![cfg_attr(not(test), no_std)] 56 | 57 | // Nightly features 58 | #![cfg_attr(feature = "compile-time-ratio", allow(incomplete_features))] 59 | #![cfg_attr(feature = "compile-time-ratio", feature(generic_const_exprs))] 60 | #![cfg_attr(feature = "nightly-async-iterator", feature(async_iterator))] 61 | #![cfg_attr(feature = "nightly-coerce-unsized", feature(coerce_unsized))] 62 | #![cfg_attr(feature = "nightly-dispatch-from-dyn", feature(dispatch_from_dyn))] 63 | #![cfg_attr(any(feature = "nightly-dispatch-from-dyn", feature = "nightly-coerce-unsized"), feature(unsize))] 64 | #![cfg_attr(feature = "nightly-generator-trait", feature(generator_trait))] 65 | 66 | // Lints 67 | #![deny(missing_docs)] 68 | 69 | #[cfg(feature = "alloc")] 70 | extern crate alloc; 71 | 72 | #[macro_use] 73 | mod utils; 74 | 75 | pub mod rcref; 76 | 77 | pub use self::rcref::StaticRcRef; 78 | 79 | #[cfg(feature = "alloc")] 80 | pub mod rc; 81 | 82 | #[cfg(feature = "alloc")] 83 | pub use self::rc::StaticRc; 84 | 85 | #[cfg(feature = "experimental-lift")] 86 | pub mod lift; 87 | 88 | #[cfg(feature = "experimental-lift")] 89 | pub use self::lift::{lift, lift_with, lift_with_mut}; 90 | -------------------------------------------------------------------------------- /src/lift.rs: -------------------------------------------------------------------------------- 1 | //! Lifting allows tying the note when linear or affine types -- such as `StaticRc` -- are used to implement cyclic 2 | //! data-structures such as linked-lists. 3 | 4 | use core::{ 5 | mem::ManuallyDrop, 6 | ptr, 7 | }; 8 | 9 | /// Lifts `root` into the slot provided by `fun`; returns the previous value of the slot, if any. 10 | /// 11 | /// This function is useful, for example, to "tie the knot" when appending 2 linked-lists: it is easy to splice the 12 | /// the head of the back linked-list at the back of the front linked-list, but then one has lost the head pointer 13 | /// and can no longer splice the tail of the front linked-list to it. 14 | /// 15 | /// # Panics 16 | /// 17 | /// If `fun` panics, then `root` is forgotten. This may result in a resource leak. 18 | /// 19 | /// # Experimental 20 | /// 21 | /// This function is highly experimental, see the ongoing discussion at 22 | /// https://users.rust-lang.org/t/can-you-break-the-lift/58858. 23 | pub fn lift(root: R, fun: F) -> R 24 | where 25 | F: for<'a> FnOnce(&'a R) -> &'a mut R, 26 | { 27 | // The move into Manually Drop must happen _before_ to appease `MIRIFLAGS=-Zmiri-track-raw-pointers` 28 | let root = ManuallyDrop::new(root); 29 | let slot = fun(&root) as *mut R as *mut ManuallyDrop; 30 | 31 | // Safety: 32 | // - `root` is still alive, hence any reference linked to `root` is _also_ alive. 33 | // - `root` is valid for reads. 34 | // - `slot` is valid for reads & writes. 35 | unsafe { replace(slot, &root as *const _) } 36 | } 37 | 38 | /// Lifts `root` into the slot provided by `fun`; returns the previous value of the slot, if any. 39 | /// 40 | /// # Panics 41 | /// 42 | /// If `fun` panics, then `root` is forgotten. This may result in a resource leak. 43 | /// 44 | /// # Note 45 | /// 46 | /// This function is similar to `lift`. The `extra` argument is required to work-around `for<'a>` not otherwise 47 | /// appropriately constraining its range of lifetime. 48 | pub fn lift_with(root: R, extra: &E, fun: F) -> R 49 | where 50 | F: for<'a> FnOnce(&'a R, &'a E) -> &'a mut R, 51 | { 52 | // The move into Manually Drop must happen _before_ to appease `MIRIFLAGS=-Zmiri-track-raw-pointers` 53 | let root = ManuallyDrop::new(root); 54 | let slot = fun(&root, extra) as *mut R as *mut ManuallyDrop; 55 | 56 | // Safety: 57 | // - `root` is still alive, hence any reference linked to `root` is _also_ alive. 58 | // - `root` is valid for reads. 59 | // - `slot` is valid for reads & writes. 60 | unsafe { replace(slot, &root as *const _) } 61 | } 62 | 63 | /// Lifts `root` into the slot provided by `fun`; returns the previous value of the slot, if any. 64 | /// 65 | /// # Panics 66 | /// 67 | /// If `fun` panics, then `root` is forgotten. This may result in a resource leak. 68 | /// 69 | /// # Note 70 | /// 71 | /// This function is similar to `lift`. The `extra` argument is required to work-around `for<'a>` not otherwise 72 | /// appropriately constraining its range of lifetime. 73 | pub fn lift_with_mut(root: R, extra: &mut E, fun: F) -> R 74 | where 75 | F: for<'a> FnOnce(&'a R, &'a mut E) -> &'a mut R, 76 | { 77 | // The move into Manually Drop must happen _before_ to appease `MIRIFLAGS=-Zmiri-track-raw-pointers` 78 | let root = ManuallyDrop::new(root); 79 | let slot = fun(&root, extra) as *mut R as *mut ManuallyDrop; 80 | 81 | // Safety: 82 | // - `root` is still alive, hence any reference linked to `root` is _also_ alive. 83 | // - `root` is valid for reads. 84 | // - `slot` is valid for reads & writes. 85 | unsafe { replace(slot, &root as *const _) } 86 | } 87 | 88 | // Replaces the content of `dest` with that of `src`, returns the content of `dest`. 89 | // 90 | // # Safety 91 | // 92 | // - `dest` is valid for both reads and writes. 93 | // - `src` is valid for reads. 94 | // 95 | // It is perfectly safe for `src` and `dest` to alias. 96 | unsafe fn replace(dest: *mut ManuallyDrop, src: *const ManuallyDrop) -> T { 97 | // Swap, manually. 98 | let result = ptr::read(dest); 99 | ptr::copy(src, dest, 1); 100 | 101 | ManuallyDrop::into_inner(result) 102 | } 103 | 104 | #[cfg(test)] 105 | mod tests { 106 | 107 | use std::{cell, mem}; 108 | 109 | use super::*; 110 | 111 | // Example from https://github.com/matthieu-m/static-rc/issues/14 by @noamtashma. 112 | // 113 | // Using `UnsafeCell` instead of `GhostCell` to avoid 3rd-party dependency. 114 | fn lift_self_impl(cell_ref: &cell::UnsafeCell>) -> &mut cell::UnsafeCell> { 115 | // cell_ref.borrow_mut(token) with GhostCell. 116 | let borrowed: &mut Box = unsafe { &mut *cell_ref.get() }; 117 | 118 | // GhostCell::from_mut 119 | let transmuted: &mut cell::UnsafeCell> = unsafe { mem::transmute(borrowed) }; 120 | 121 | transmuted 122 | } 123 | 124 | #[test] 125 | fn lift_self() { 126 | let cell = cell::UnsafeCell::new(Box::new(7)); 127 | 128 | lift(cell, lift_self_impl); 129 | } 130 | 131 | #[test] 132 | fn lift_with_self() { 133 | let cell = cell::UnsafeCell::new(Box::new(7)); 134 | 135 | lift_with(cell, &(), |cell_ref, _| lift_self_impl(cell_ref)); 136 | } 137 | 138 | #[test] 139 | fn lift_with_mut_self() { 140 | let cell = cell::UnsafeCell::new(Box::new(7)); 141 | 142 | lift_with_mut(cell, &mut (), |cell_ref, _| lift_self_impl(cell_ref)); 143 | } 144 | 145 | // Example from https://users.rust-lang.org/t/can-you-break-the-lift/58858/19 by @steffahn. 146 | // 147 | // Arranged and annotated by yours truly. 148 | struct Struct; 149 | 150 | #[allow(clippy::mut_from_ref)] 151 | trait LeakBorrow { 152 | fn foo(&self) -> &mut Box; 153 | } 154 | 155 | impl LeakBorrow for cell::RefCell> { 156 | fn foo(&self) -> &mut Box { 157 | let refmut: cell::RefMut<'_, _> = self.borrow_mut(); 158 | let refmut_refmut: &mut cell::RefMut<'_, _> = Box::leak(Box::new(refmut)); 159 | will_leak(&*refmut_refmut); 160 | 161 | &mut **refmut_refmut 162 | } 163 | } 164 | 165 | impl LeakBorrow for Struct { 166 | fn foo(&self) -> &mut Box { 167 | unimplemented!() 168 | } 169 | } 170 | 171 | #[test] 172 | fn lift_leak_borrow() { 173 | let root = Box::new(Struct) as Box; 174 | let root = Box::new(cell::RefCell::new(root)) as Box; 175 | lift(root, |b| b.foo()); 176 | } 177 | 178 | #[test] 179 | fn lift_with_leak_borrow() { 180 | let root = Box::new(Struct) as Box; 181 | let root = Box::new(cell::RefCell::new(root)) as Box; 182 | lift_with(root, &(), |b, _| b.foo()); 183 | } 184 | 185 | #[test] 186 | fn lift_with_mut_leak_borrow() { 187 | let root = Box::new(Struct) as Box; 188 | let root = Box::new(cell::RefCell::new(root)) as Box; 189 | lift_with_mut(root, &mut (), |b, _| b.foo()); 190 | } 191 | 192 | // Indicates that the pointed to memory will be leaked, to avoid it being reported. 193 | fn will_leak(_t: &T) { 194 | #[cfg(miri)] 195 | { 196 | unsafe { miri_static_root(_t as *const _ as *const u8) }; 197 | } 198 | } 199 | 200 | #[cfg(miri)] 201 | extern "Rust" { 202 | /// Miri-provided extern function to mark the block `ptr` points to as a "root" 203 | /// for some static memory. This memory and everything reachable by it is not 204 | /// considered leaking even if it still exists when the program terminates. 205 | /// 206 | /// `ptr` has to point to the beginning of an allocated block. 207 | fn miri_static_root(ptr: *const u8); 208 | } 209 | 210 | } // mod tests 211 | -------------------------------------------------------------------------------- /src/rc.rs: -------------------------------------------------------------------------------- 1 | //! `StaticRc` is a compile-time referenced counted heap-allocated pointer. 2 | 3 | use core::{ 4 | any, 5 | borrow, 6 | cmp, 7 | convert, 8 | fmt, 9 | future, 10 | hash, 11 | iter, 12 | marker, 13 | mem::{self, MaybeUninit}, 14 | ops, 15 | pin, 16 | ptr::{self, NonNull}, 17 | task, 18 | }; 19 | 20 | use alloc::boxed::Box; 21 | 22 | #[cfg(feature = "nightly-async-iterator")] 23 | use core::async_iter; 24 | 25 | #[cfg(feature = "nightly-coerce-unsized")] 26 | use core::ops::CoerceUnsized; 27 | 28 | #[cfg(feature = "nightly-dispatch-from-dyn")] 29 | use core::ops::DispatchFromDyn; 30 | 31 | /// A compile-time reference-counted pointer. 32 | /// 33 | /// The inherent methods of `StaticRc` are all associated functions to avoid conflicts with the the methods of the 34 | /// inner type `T` which are brought into scope by the `Deref` implementation. 35 | /// 36 | /// The parameters `NUM` and `DEN` DENote the ratio (`NUM / DEN`) of ownership of the pointer: 37 | /// 38 | /// - The ratio is always in the (0, 1] interval, that is: `NUM > 0` and `NUM <= DEN`. 39 | /// - When the ratio is equal to 1, that is when `NUM == DEN`, then the instance has full ownership of the pointee 40 | /// and extra capabilities are unlocked. 41 | pub struct StaticRc { 42 | pointer: NonNull, 43 | } 44 | 45 | impl StaticRc { 46 | /// Constructs a new `StaticRc`. 47 | /// 48 | /// This uses `Box` under the hood. 49 | /// 50 | /// # Example 51 | /// 52 | /// ```rust 53 | /// use static_rc::StaticRc; 54 | /// 55 | /// type Full = StaticRc; 56 | /// 57 | /// let rc = Full::new(42); 58 | /// assert_eq!(42, *rc); 59 | /// ``` 60 | #[inline(always)] 61 | pub fn new(value: T) -> Self 62 | where 63 | AssertLeType!(1, N): Sized, 64 | { 65 | #[cfg(not(feature = "compile-time-ratio"))] 66 | const { assert!(N > 0); } 67 | 68 | let pointer = NonNull::from(Box::leak(Box::new(value))); 69 | Self { pointer } 70 | } 71 | 72 | /// Constructs a new `Pin>`. 73 | /// 74 | /// # Example 75 | /// 76 | /// ```rust 77 | /// use static_rc::StaticRc; 78 | /// 79 | /// type Full = StaticRc; 80 | /// 81 | /// let rc = Full::pin(42); 82 | /// assert_eq!(42, *rc); 83 | /// ``` 84 | #[inline(always)] 85 | pub fn pin(value: T) -> pin::Pin 86 | where 87 | AssertLeType!(1, N): Sized, 88 | { 89 | #[cfg(not(feature = "compile-time-ratio"))] 90 | const { assert!(N > 0); } 91 | 92 | // Safety: 93 | // - The `value` is placed on the heap, and cannot be moved out of the heap without full ownership. 94 | unsafe { pin::Pin::new_unchecked(Self::new(value)) } 95 | } 96 | 97 | /// Returns the inner value. 98 | /// 99 | /// # Example 100 | /// 101 | /// ```rust 102 | /// use static_rc::StaticRc; 103 | /// 104 | /// type Full = StaticRc; 105 | /// 106 | /// let rc = Full::new(42); 107 | /// assert_eq!(42, Full::into_inner(rc)); 108 | /// ``` 109 | #[inline(always)] 110 | pub fn into_inner(this: Self) -> T { 111 | // Safety: 112 | // - Ratio = 1, hence full ownership. 113 | let boxed = unsafe { Box::from_raw(this.pointer.as_ptr()) }; 114 | mem::forget(this); 115 | 116 | *boxed 117 | } 118 | } 119 | 120 | impl StaticRc { 121 | /// Returns a mutable reference into the given `StaticRc`. 122 | /// 123 | /// # Example 124 | /// 125 | /// ```rust 126 | /// use static_rc::StaticRc; 127 | /// 128 | /// type Full = StaticRc; 129 | /// 130 | /// let mut rc = Full::new(42); 131 | /// let r: &mut i32 = Full::get_mut(&mut rc); 132 | /// *r = 33; 133 | /// assert_eq!(33, *rc); 134 | /// ``` 135 | #[inline(always)] 136 | pub fn get_mut(this: &mut Self) -> &mut T { 137 | // Safety: 138 | // - Ratio = 1, hence full ownership. 139 | unsafe { this.pointer.as_mut() } 140 | } 141 | 142 | /// Returns the inner value, boxed 143 | /// 144 | /// # Example 145 | /// 146 | /// ```rust 147 | /// use static_rc::StaticRc; 148 | /// 149 | /// type Full = StaticRc; 150 | /// 151 | /// let mut rc = Full::new(42); 152 | /// let boxed: Box<_> = Full::into_box(rc); 153 | /// assert_eq!(42, *boxed); 154 | /// ``` 155 | #[inline(always)] 156 | pub fn into_box(this: Self) -> Box { 157 | let pointer = this.pointer; 158 | mem::forget(this); 159 | 160 | // Safety: 161 | // - Ratio = 1, hence full ownership. 162 | // - `pointer` was allocated by Box. 163 | unsafe { Box::from_raw(pointer.as_ptr()) } 164 | } 165 | } 166 | 167 | impl StaticRc { 168 | /// Consumes the `StaticRc`, returning the wrapped pointer. 169 | /// 170 | /// To avoid a memory leak, the pointer must be converted back to `Self` using `StaticRc::from_raw`. 171 | /// 172 | /// # Example 173 | /// 174 | /// ```rust 175 | /// use static_rc::StaticRc; 176 | /// 177 | /// type Full = StaticRc; 178 | /// 179 | /// let rc = Full::new(42); 180 | /// let leaked = Full::into_raw(rc); 181 | /// 182 | /// let rc = unsafe { Full::from_raw(leaked) }; 183 | /// assert_eq!(42, *rc); 184 | /// ``` 185 | #[inline(always)] 186 | pub fn into_raw(this: Self) -> NonNull { 187 | let pointer = this.pointer; 188 | mem::forget(this); 189 | 190 | pointer 191 | } 192 | 193 | /// Provides a raw pointer to the data. 194 | /// 195 | /// `StaticRc` is not consumed or affected in any way, the pointer is valid as long as there are shared owners of 196 | /// the value. 197 | /// 198 | /// # Example 199 | /// 200 | /// ```rust 201 | /// use static_rc::StaticRc; 202 | /// 203 | /// type Full = StaticRc; 204 | /// 205 | /// let rc = Full::new(42); 206 | /// let pointer = Full::as_ptr(&rc); 207 | /// assert_eq!(42, unsafe { *pointer.as_ref() }); 208 | /// ``` 209 | #[inline(always)] 210 | pub fn as_ptr(this: &Self) -> NonNull { this.pointer } 211 | 212 | /// Provides a reference to the data. 213 | /// 214 | /// # Example 215 | /// 216 | /// ```rust 217 | /// use static_rc::StaticRc; 218 | /// 219 | /// type Full = StaticRc; 220 | /// 221 | /// let rc = Full::new(42); 222 | /// assert_eq!(42, *Full::get_ref(&rc)); 223 | /// ``` 224 | #[inline(always)] 225 | pub fn get_ref(this: &Self) -> &T { 226 | // Safety: 227 | // - The data is valid for as long as `this` lives. 228 | unsafe { this.pointer.as_ref() } 229 | } 230 | 231 | /// Constructs a `StaticRc` from a raw pointer. 232 | /// 233 | /// # Safety 234 | /// 235 | /// The raw pointer must have been previously returned by a call to `StaticRc::into_raw`: 236 | /// 237 | /// - If `U` is different from `T`, then specific restrictions on size and alignment apply. See `mem::transmute` 238 | /// for the restrictions applying to transmuting references. 239 | /// - If `N / D` is different from `NUM / DEN`, then specific restrictions apply. The user is responsible for 240 | /// ensuring proper management of the ratio of shares, and ultimately that the value is not dropped twice. 241 | /// 242 | /// # Example 243 | /// 244 | /// ```rust 245 | /// use static_rc::StaticRc; 246 | /// 247 | /// type Full = StaticRc; 248 | /// type Half = StaticRc; 249 | /// 250 | /// let rc = Full::new(42); 251 | /// let leaked = Full::into_raw(rc); 252 | /// 253 | /// let (one, two) = unsafe { (Half::from_raw(leaked), Half::from_raw(leaked)) }; 254 | /// let rc = Full::join(one, two); 255 | /// 256 | /// assert_eq!(42, *rc); 257 | /// ``` 258 | #[inline(always)] 259 | pub unsafe fn from_raw(pointer: NonNull) -> Self 260 | where 261 | AssertLeType!(1, NUM): Sized, 262 | { 263 | #[cfg(not(feature = "compile-time-ratio"))] 264 | const { assert!(NUM > 0); } 265 | 266 | Self { pointer } 267 | } 268 | 269 | /// Returns true if the two `StaticRc` point to the same allocation. 270 | /// 271 | /// # Example 272 | /// 273 | /// ```rust 274 | /// use static_rc::StaticRc; 275 | /// 276 | /// type Full = StaticRc; 277 | /// 278 | /// let rc = Full::new(42); 279 | /// let (one, two) = Full::split::<1, 1>(rc); 280 | /// 281 | /// assert!(StaticRc::ptr_eq(&one, &two)); 282 | /// 283 | /// Full::join(one, two); 284 | /// ``` 285 | #[inline(always)] 286 | pub fn ptr_eq(this: &Self, other: &StaticRc) -> bool { 287 | ptr::eq(StaticRc::as_ptr(this).as_ptr(), StaticRc::as_ptr(other).as_ptr()) 288 | } 289 | 290 | /// Adjusts the NUMerator and DENUMerator of the ratio of the instance, preserving the ratio. 291 | /// 292 | /// # Example 293 | /// 294 | /// ```rust 295 | /// use static_rc::StaticRc; 296 | /// 297 | /// type Full = StaticRc; 298 | /// 299 | /// let rc = Full::new(42); 300 | /// let rc = Full::adjust::<1, 1>(rc); 301 | /// 302 | /// assert_eq!(42, *rc); 303 | /// ``` 304 | #[inline(always)] 305 | pub fn adjust(this: Self) -> StaticRc 306 | where 307 | AssertLeType!(1, N): Sized, 308 | AssertEqType!(N * DEN, NUM * D): Sized, 309 | { 310 | #[cfg(not(feature = "compile-time-ratio"))] 311 | const { 312 | assert!(N > 0); 313 | assert!(NUM * D == N * DEN); 314 | } 315 | 316 | let pointer = this.pointer; 317 | mem::forget(this); 318 | 319 | StaticRc { pointer } 320 | } 321 | 322 | /// Converts an instance into a [`StaticRcRef`](super::StaticRcRef). 323 | /// 324 | /// The current instance is mutably borrowed for the duration the result can be used. 325 | /// 326 | /// # Example 327 | /// 328 | /// ```rust 329 | /// use static_rc::StaticRc; 330 | /// use static_rc::StaticRcRef; 331 | /// let rc: StaticRc<_, 2, 2> = StaticRc::new(5); 332 | /// let (mut rc1, mut rc2) = StaticRc::split::<1, 1>(rc); 333 | /// { 334 | /// // Modify without moving `rc1`, `rc2`. 335 | /// let rcref1 = StaticRc::as_rcref(&mut rc1); 336 | /// let rcref2 = StaticRc::as_rcref(&mut rc2); 337 | /// let mut rcref_owning: StaticRcRef<_, 2, 2> = StaticRcRef::join(rcref1, rcref2); 338 | /// *rcref_owning = 9; 339 | /// // Refs not used anymore, original rcs can be used again 340 | /// } 341 | /// let rc: StaticRc<_, 2, 2> = StaticRc::join(rc1, rc2); 342 | /// assert_eq!(*rc, 9); 343 | /// assert_eq!(*StaticRc::into_box(rc), 9); 344 | /// ``` 345 | #[inline(always)] 346 | pub fn as_rcref<'a>(this: &'a mut Self) -> super::StaticRcRef<'a, T, NUM, DEN> 347 | where 348 | AssertLeType!(1, NUM): Sized, 349 | { 350 | // Safety: 351 | // - The public documentation says that `StaticRcRef::from_raw` 352 | // can only be called on pointers returned from `StaticRcRef::into_raw`. 353 | // which this isn't. 354 | // - However, internally the library knows that `rc` and `rcref` have the same invariants: 355 | // - `this.pointer` is a valid aligned pointer into a valid value of `T`. 356 | // - The result is only usable for lifetime `'a`, and for the duration 357 | // of the lifetime `'a` `this` is mutably borrowed. 358 | // - `this` has NUM/DEN of the ownership. So it can lend NUM/DEN 359 | // of the right to mutate the value. Therefore, this is semantically sound 360 | // according to the general principle of this library. 361 | // 362 | // This is safe for generally the same reason `StaticRcRef::reborrow` is safe. 363 | // 364 | // `StaticRcRef::from_raw` has to have a comment documenting 365 | // internally that such a use is allowed. 366 | let ptr = this.pointer; 367 | unsafe { 368 | super::StaticRcRef::from_raw(ptr) 369 | } 370 | } 371 | 372 | /// Splits the current instance into two instances with the specified NUMerators. 373 | /// 374 | /// # Example 375 | /// 376 | /// ```rust 377 | /// use static_rc::StaticRc; 378 | /// 379 | /// type Full = StaticRc; 380 | /// type Half = StaticRc; 381 | /// 382 | /// let rc = Full::new(42); 383 | /// let (one, two): (Half, Half) = Full::split::<1, 1>(rc); 384 | /// 385 | /// assert_eq!(42, *one); 386 | /// 387 | /// Full::join(one, two); 388 | /// ``` 389 | #[inline(always)] 390 | pub fn split(this: Self) -> (StaticRc, StaticRc) 391 | where 392 | AssertLeType!(1, A): Sized, 393 | AssertLeType!(1, B): Sized, 394 | AssertEqType!(A + B, NUM): Sized, 395 | { 396 | #[cfg(not(feature = "compile-time-ratio"))] 397 | const { 398 | assert!(A > 0); 399 | assert!(B > 0); 400 | assert!(NUM == A + B); 401 | } 402 | 403 | let pointer = this.pointer; 404 | mem::forget(this); 405 | 406 | (StaticRc { pointer }, StaticRc { pointer }) 407 | } 408 | 409 | /// Splits the current instance into `DIM` instances with the specified Numerators and Denominators. 410 | /// 411 | /// # Example 412 | /// 413 | /// ```rust 414 | /// use static_rc::StaticRc; 415 | /// 416 | /// type Full = StaticRc; 417 | /// 418 | /// let rc = Full::new(42); 419 | /// let array = Full::split_array::<1, 2>(rc); 420 | /// 421 | /// assert_eq!(42, *array[0]); 422 | /// 423 | /// Full::join_array(array); 424 | /// ``` 425 | #[inline(always)] 426 | pub fn split_array(this: Self) -> [StaticRc; DIM] 427 | where 428 | AssertEqType!(N * DIM, NUM ): Sized, 429 | AssertLeType!(mem::size_of::<[StaticRc; DIM]>(), usize::MAX / 2 + 1): Sized, 430 | { 431 | #[cfg(not(feature = "compile-time-ratio"))] 432 | const { 433 | assert!(NUM == N * DIM); 434 | assert!(mem::size_of::<[StaticRc; DIM]>() <= (isize::MAX as usize)); 435 | } 436 | 437 | let pointer = this.pointer; 438 | mem::forget(this); 439 | 440 | let mut array = MaybeUninit::uninit(); 441 | 442 | for i in 0..DIM { 443 | // Safety: 444 | // - `destination` within bounds of allocated array (< DIM). 445 | // - Offset doesn't overflow `isize`, as per array-size assertion. 446 | // - Offset doesn't wrap around, as per array-size assertion. 447 | let destination = unsafe { (array.as_mut_ptr() as *mut StaticRc).add(i) }; 448 | 449 | // Safety: 450 | // - `destination` is valid for writes. 451 | // - `destination` is correctly aligned. 452 | unsafe { ptr::write(destination, StaticRc { pointer }); } 453 | } 454 | 455 | // Safety: 456 | // - Every element of the array is now initialized. 457 | unsafe { array.assume_init() } 458 | } 459 | 460 | /// Joins two instances into a single instance. 461 | /// 462 | /// # Panics 463 | /// 464 | /// If the two instances do no point to the same allocation, as determined by `StaticRc::ptr_eq`. 465 | /// 466 | /// # Example 467 | /// 468 | /// ```rust 469 | /// use static_rc::StaticRc; 470 | /// 471 | /// type Full = StaticRc; 472 | /// 473 | /// let rc = Full::new(42); 474 | /// let (one, two) = Full::split::<1, 2>(rc); 475 | /// 476 | /// let rc = Full::join(one, two); 477 | /// assert_eq!(42, *rc); 478 | /// ``` 479 | #[inline(always)] 480 | pub fn join(left: StaticRc, right: StaticRc) -> Self 481 | where 482 | AssertEqType!(NUM, A + B): Sized, 483 | { 484 | let (left, right) = Self::validate_pair(left, right); 485 | 486 | // Safety: 487 | // - `left` and `right` point to the same allocation. 488 | unsafe { Self::join_impl(left, right) } 489 | } 490 | 491 | /// Joins two instances into a single instance without checking whether they point to the same allocation. 492 | /// 493 | /// Unless `compile-time-ratio` is activated, the ratios are checked nevertheless. 494 | /// 495 | /// # Safety 496 | /// 497 | /// The caller must guarantee that those instances point to the same allocation. 498 | /// 499 | /// # Panics 500 | /// 501 | /// In debug, if the two instances do not point to the same allocation, as determined by `StaticRc::ptr_eq`. 502 | /// 503 | /// # Example 504 | /// 505 | /// ```rust 506 | /// use static_rc::StaticRc; 507 | /// 508 | /// type Full = StaticRc; 509 | /// 510 | /// let rc = Full::new(42); 511 | /// let (one, two) = Full::split::<1, 2>(rc); 512 | /// 513 | /// let rc = unsafe { Full::join_unchecked(one, two) }; 514 | /// assert_eq!(42, *rc); 515 | /// ``` 516 | #[inline(always)] 517 | pub unsafe fn join_unchecked( 518 | left: StaticRc, 519 | right: StaticRc, 520 | ) -> Self 521 | where 522 | AssertEqType!(NUM, A + B): Sized, 523 | { 524 | #[cfg(debug_assertions)] 525 | let (left, right) = Self::validate_pair(left, right); 526 | 527 | // Safety: 528 | // - `left` and `right` point to the same allocation, as per pre-condition. 529 | unsafe { Self::join_impl(left, right) } 530 | } 531 | 532 | /// Joins DIM instances into a single instance. 533 | /// 534 | /// # Panics 535 | /// 536 | /// If all instances do not point to the same allocation, as determined by `StaticRc::ptr_eq`. 537 | /// 538 | /// # Example 539 | /// 540 | /// ```rust 541 | /// use static_rc::StaticRc; 542 | /// 543 | /// type Full = StaticRc; 544 | /// 545 | /// let rc = Full::new(42); 546 | /// let array = Full::split_array::<1, 2>(rc); 547 | /// let rc = Full::join_array(array); 548 | /// 549 | /// assert_eq!(42, *rc); 550 | /// ``` 551 | #[inline(always)] 552 | pub fn join_array(array: [StaticRc; DIM]) -> Self 553 | where 554 | AssertLeType!(1, NUM): Sized, 555 | AssertEqType!(N * DIM, NUM): Sized, 556 | { 557 | let array = Self::validate_array(array); 558 | 559 | unsafe { Self::join_array_impl(array) } 560 | } 561 | 562 | /// Joins DIM instances into a single instance. 563 | /// 564 | /// # Safety 565 | /// 566 | /// All instances must point to the same allocation, as determined by `StaticRc::ptr_eq`. 567 | /// 568 | /// # Panics 569 | /// 570 | /// In debug, if all instances do not point to the same allocation, as determined by `StaticRc::ptr_eq`. 571 | /// 572 | /// # Example 573 | /// 574 | /// ```rust 575 | /// use static_rc::StaticRc; 576 | /// 577 | /// type Full = StaticRc; 578 | /// 579 | /// let rc = Full::new(42); 580 | /// let array = Full::split_array::<1, 2>(rc); 581 | /// let rc = unsafe { Full::join_array_unchecked(array) }; 582 | /// 583 | /// assert_eq!(42, *rc); 584 | /// ``` 585 | #[inline(always)] 586 | pub unsafe fn join_array_unchecked(array: [StaticRc; DIM]) 587 | -> Self 588 | where 589 | AssertLeType!(1, NUM): Sized, 590 | AssertEqType!(N * DIM, NUM): Sized, 591 | { 592 | #[cfg(debug_assertions)] 593 | let array = Self::validate_array(array); 594 | 595 | // Safety: 596 | // - All instances point to the same allocation, as per pre-condition. 597 | unsafe { Self::join_array_impl(array) } 598 | } 599 | 600 | // Internal; joins without validating origin. 601 | #[inline(always)] 602 | unsafe fn join_impl( 603 | left: StaticRc, 604 | right: StaticRc, 605 | ) -> Self 606 | where 607 | AssertEqType!(NUM, A + B): Sized, 608 | { 609 | #[cfg(not(feature = "compile-time-ratio"))] 610 | const { assert!(NUM == A + B); } 611 | 612 | let pointer = left.pointer; 613 | mem::forget(left); 614 | mem::forget(right); 615 | 616 | Self { pointer } 617 | } 618 | 619 | // Internal; joins without validating origin. 620 | #[inline(always)] 621 | unsafe fn join_array_impl(array: [StaticRc; DIM]) 622 | -> Self 623 | where 624 | AssertLeType!(1, NUM): Sized, 625 | AssertEqType!(N * DIM, NUM): Sized, 626 | { 627 | #[cfg(not(feature = "compile-time-ratio"))] 628 | const { 629 | assert!(NUM > 0); 630 | assert!(NUM == N * DIM); 631 | } 632 | 633 | let pointer = array[0].pointer; 634 | mem::forget(array); 635 | 636 | Self { pointer, } 637 | } 638 | 639 | fn validate_pair(left: StaticRc, right: StaticRc) 640 | -> (StaticRc, StaticRc) 641 | { 642 | if StaticRc::ptr_eq(&left, &right) { 643 | return (left, right); 644 | } 645 | 646 | let left = StaticRc::into_raw(left); 647 | let right = StaticRc::into_raw(right); 648 | 649 | panic!("Cannot join pair with multiple origins: {:?} != {:?}", left.as_ptr(), right.as_ptr()); 650 | } 651 | 652 | fn validate_array(array: [StaticRc; DIM]) -> [StaticRc; DIM] { 653 | let first = &array[0]; 654 | let divergent = array[1..].iter().find(|e| !StaticRc::ptr_eq(first, e)); 655 | 656 | if let Some(divergent) = divergent { 657 | let first = first.pointer.as_ptr(); 658 | let divergent = divergent.pointer.as_ptr(); 659 | 660 | mem::forget(array); 661 | 662 | panic!("Cannot join array with multiple origins: {first:?} != {divergent:?}"); 663 | } 664 | 665 | array 666 | } 667 | } 668 | 669 | impl StaticRc { 670 | /// Attempts to downcast `Self` to a concrete type. 671 | pub fn downcast(self) -> Result, Self> { 672 | if Self::get_ref(&self).is::() { 673 | let pointer = Self::into_raw(self).cast::(); 674 | Ok(StaticRc { pointer }) 675 | } else { 676 | Err(self) 677 | } 678 | } 679 | } 680 | 681 | impl Drop for StaticRc { 682 | #[inline(always)] 683 | fn drop(&mut self) { 684 | debug_assert_eq!(NUM, DEN, "{NUM} != {DEN}"); 685 | 686 | if NUM == DEN { 687 | // Safety: 688 | // - Ratio = 1, hence full ownership. 689 | // - `self.pointer` was allocated by Box. 690 | let _ = unsafe { Box::from_raw(self.pointer.as_ptr()) }; 691 | } 692 | } 693 | } 694 | 695 | impl convert::AsMut for StaticRc { 696 | #[inline(always)] 697 | fn as_mut(&mut self) -> &mut T { Self::get_mut(self) } 698 | } 699 | 700 | impl convert::AsRef for StaticRc { 701 | #[inline(always)] 702 | fn as_ref(&self) -> &T { Self::get_ref(self) } 703 | } 704 | 705 | impl borrow::Borrow for StaticRc { 706 | #[inline(always)] 707 | fn borrow(&self) -> &T { Self::get_ref(self) } 708 | } 709 | 710 | impl borrow::BorrowMut for StaticRc { 711 | #[inline(always)] 712 | fn borrow_mut(&mut self) -> &mut T { Self::get_mut(self) } 713 | } 714 | 715 | #[cfg(feature = "nightly-coerce-unsized")] 716 | impl CoerceUnsized> for StaticRc 717 | where 718 | T: ?Sized + marker::Unsize, 719 | U: ?Sized, 720 | {} 721 | 722 | impl fmt::Debug for StaticRc { 723 | #[inline(always)] 724 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 725 | fmt::Debug::fmt(Self::get_ref(self), f) 726 | } 727 | } 728 | 729 | impl Default for StaticRc 730 | where 731 | AssertLeType!(1, N): Sized, 732 | { 733 | #[inline(always)] 734 | fn default() -> Self { Self::new(T::default()) } 735 | } 736 | 737 | impl ops::Deref for StaticRc { 738 | type Target = T; 739 | 740 | #[inline(always)] 741 | fn deref(&self) -> &T { Self::get_ref(self) } 742 | } 743 | 744 | impl ops::DerefMut for StaticRc { 745 | #[inline(always)] 746 | fn deref_mut(&mut self) -> &mut T { Self::get_mut(self) } 747 | } 748 | 749 | impl fmt::Display for StaticRc { 750 | #[inline(always)] 751 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 752 | fmt::Display::fmt(Self::get_ref(self), f) 753 | } 754 | } 755 | 756 | #[cfg(feature = "nightly-dispatch-from-dyn")] 757 | impl DispatchFromDyn> for StaticRc 758 | where 759 | T: ?Sized + marker::Unsize, 760 | U: ?Sized, 761 | {} 762 | 763 | impl iter::DoubleEndedIterator for StaticRc { 764 | #[inline(always)] 765 | fn next_back(&mut self) -> Option { Self::get_mut(self).next_back() } 766 | 767 | #[inline(always)] 768 | fn nth_back(&mut self, n: usize) -> Option { Self::get_mut(self).nth_back(n) } 769 | } 770 | 771 | impl cmp::Eq for StaticRc {} 772 | 773 | impl iter::ExactSizeIterator for StaticRc { 774 | #[inline(always)] 775 | fn len(&self) -> usize { Self::get_ref(self).len() } 776 | } 777 | 778 | impl From> for StaticRc { 779 | #[inline(always)] 780 | fn from(value: Box) -> Self { 781 | let pointer = NonNull::from(Box::leak(value)); 782 | Self { pointer } 783 | } 784 | } 785 | 786 | impl From<&'_ [T]> for StaticRc<[T], N, N> { 787 | #[inline(always)] 788 | fn from(value: &[T]) -> Self { Self::from(Box::from(value)) } 789 | } 790 | 791 | impl From<&'_ str> for StaticRc { 792 | #[inline(always)] 793 | fn from(value: &str) -> Self { Self::from(Box::from(value)) } 794 | } 795 | 796 | impl From<[T; LEN]> for StaticRc<[T], N, N> { 797 | #[inline(always)] 798 | fn from(value: [T; LEN]) -> Self { Self::from(Box::from(value)) } 799 | } 800 | 801 | impl From> for StaticRc<[T], N, N> { 802 | #[inline(always)] 803 | fn from(value: alloc::borrow::Cow<'_, [T]>) -> Self { Self::from(Box::from(value)) } 804 | } 805 | 806 | impl From> for StaticRc { 807 | #[inline(always)] 808 | fn from(value: alloc::borrow::Cow<'_, str>) -> Self { Self::from(Box::from(value)) } 809 | } 810 | 811 | impl From for StaticRc { 812 | #[inline(always)] 813 | fn from(value: alloc::string::String) -> Self { Self::from(Box::from(value)) } 814 | } 815 | 816 | impl From for StaticRc { 817 | #[inline(always)] 818 | fn from(value: T) -> Self { Self::from(Box::from(value)) } 819 | } 820 | 821 | impl From> for StaticRc<[T], N, N> { 822 | #[inline(always)] 823 | fn from(value: alloc::vec::Vec) -> Self { Self::from(Box::from(value)) } 824 | } 825 | 826 | impl From> for alloc::vec::Vec { 827 | #[inline(always)] 828 | fn from(value: StaticRc<[T], N, N>) -> Self { Self::from(StaticRc::into_box(value)) } 829 | } 830 | 831 | impl From> for alloc::rc::Rc { 832 | #[inline(always)] 833 | fn from(value: StaticRc) -> Self { Self::from(StaticRc::into_box(value)) } 834 | } 835 | 836 | impl From> for alloc::sync::Arc { 837 | #[inline(always)] 838 | fn from(value: StaticRc) -> Self { Self::from(StaticRc::into_box(value)) } 839 | } 840 | 841 | impl From> for alloc::string::String { 842 | #[inline(always)] 843 | fn from(value: StaticRc) -> Self { Self::from(StaticRc::into_box(value)) } 844 | } 845 | 846 | impl From> for StaticRc<[u8], NUM, DEN> { 847 | #[inline(always)] 848 | fn from(value: StaticRc) -> Self { 849 | let pointer = value.pointer.as_ptr() as *mut [u8]; 850 | mem::forget(value); 851 | 852 | // Safety: 853 | // - `value.pointer` was not null, hence `pointer` is not null. 854 | debug_assert!(!pointer.is_null()); 855 | let pointer = unsafe { NonNull::new_unchecked(pointer) }; 856 | 857 | Self { pointer } 858 | } 859 | } 860 | 861 | impl iter::FromIterator> for alloc::string::String { 862 | #[inline(always)] 863 | fn from_iter>>(iter: I) -> Self { 864 | Self::from_iter(iter.into_iter().map(StaticRc::into_box)) 865 | } 866 | } 867 | 868 | impl iter::FromIterator for StaticRc<[T], N, N> { 869 | #[inline(always)] 870 | fn from_iter>(iter: I) -> Self { Self::from(Box::from_iter(iter)) } 871 | } 872 | 873 | impl iter::FusedIterator for StaticRc {} 874 | 875 | impl future::Future for StaticRc { 876 | type Output = F::Output; 877 | 878 | fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll { 879 | F::poll(pin::Pin::new(&mut *self), cx) 880 | } 881 | } 882 | 883 | #[cfg(feature = "nightly-generator-trait")] 884 | impl + marker::Unpin, R, const N: usize> ops::Generator for StaticRc { 885 | type Yield = G::Yield; 886 | type Return = G::Return; 887 | 888 | fn resume(mut self: pin::Pin<&mut Self>, arg: R) -> ops::GeneratorState { 889 | G::resume(pin::Pin::new(&mut *self), arg) 890 | } 891 | } 892 | 893 | #[cfg(feature = "nightly-generator-trait")] 894 | impl, R, const N: usize> ops::Generator for pin::Pin> { 895 | type Yield = G::Yield; 896 | type Return = G::Return; 897 | 898 | fn resume(mut self: pin::Pin<&mut Self>, arg: R) -> ops::GeneratorState { 899 | G::resume((*self).as_mut(), arg) 900 | } 901 | } 902 | 903 | impl hash::Hash for StaticRc { 904 | #[inline(always)] 905 | fn hash(&self, state: &mut H) { 906 | Self::get_ref(self).hash(state); 907 | } 908 | } 909 | 910 | impl iter::Iterator for StaticRc { 911 | type Item = I::Item; 912 | 913 | #[inline(always)] 914 | fn next(&mut self) -> Option { Self::get_mut(self).next() } 915 | 916 | #[inline(always)] 917 | fn size_hint(&self) -> (usize, Option) { Self::get_ref(self).size_hint() } 918 | 919 | #[inline(always)] 920 | fn nth(&mut self, n: usize) -> Option { Self::get_mut(self).nth(n) } 921 | 922 | #[inline(always)] 923 | fn last(self) -> Option { Self::into_box(self).last() } 924 | } 925 | 926 | impl cmp::Ord for StaticRc { 927 | #[inline(always)] 928 | fn cmp(&self, other: &Self) -> cmp::Ordering { 929 | if Self::ptr_eq(self, other) { 930 | cmp::Ordering::Equal 931 | } else { 932 | Self::get_ref(self).cmp(Self::get_ref(other)) 933 | } 934 | } 935 | } 936 | 937 | impl cmp::PartialEq> 938 | for StaticRc 939 | where 940 | T: ?Sized + PartialEq 941 | { 942 | #[inline(always)] 943 | fn eq(&self, other: &StaticRc) -> bool { Self::get_ref(self).eq(StaticRc::get_ref(other)) } 944 | 945 | #[inline(always)] 946 | #[allow(clippy::partialeq_ne_impl)] 947 | fn ne(&self, other: &StaticRc) -> bool { Self::get_ref(self).ne(StaticRc::get_ref(other)) } 948 | } 949 | 950 | impl cmp::PartialOrd> 951 | for StaticRc 952 | where 953 | T: ?Sized + PartialOrd 954 | { 955 | #[inline(always)] 956 | fn partial_cmp(&self, other: &StaticRc) -> Option { 957 | Self::get_ref(self).partial_cmp(StaticRc::get_ref(other)) 958 | } 959 | 960 | #[inline(always)] 961 | fn lt(&self, other: &StaticRc) -> bool { 962 | Self::get_ref(self).lt(StaticRc::get_ref(other)) 963 | } 964 | 965 | #[inline(always)] 966 | fn le(&self, other: &StaticRc) -> bool { 967 | Self::get_ref(self).le(StaticRc::get_ref(other)) 968 | } 969 | 970 | #[inline(always)] 971 | fn gt(&self, other: &StaticRc) -> bool { 972 | Self::get_ref(self).gt(StaticRc::get_ref(other)) 973 | } 974 | 975 | #[inline(always)] 976 | fn ge(&self, other: &StaticRc) -> bool { 977 | Self::get_ref(self).ge(StaticRc::get_ref(other)) 978 | } 979 | } 980 | 981 | impl fmt::Pointer for StaticRc { 982 | #[inline(always)] 983 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 984 | fmt::Pointer::fmt(&Self::as_ptr(self).as_ptr(), f) 985 | } 986 | } 987 | 988 | #[cfg(feature = "nightly-async-iterator")] 989 | impl async_iter::AsyncIterator for StaticRc { 990 | type Item = S::Item; 991 | 992 | fn poll_next(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll> { 993 | pin::Pin::new(&mut **self).poll_next(cx) 994 | } 995 | 996 | fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } 997 | } 998 | 999 | impl marker::Unpin for StaticRc {} 1000 | 1001 | unsafe impl marker::Send for StaticRc {} 1002 | 1003 | unsafe impl marker::Sync for StaticRc {} 1004 | 1005 | #[doc(hidden)] 1006 | pub mod compile_tests { 1007 | 1008 | /// ```compile_fail,E0505 1009 | /// let mut a = String::from("foo"); 1010 | /// let mut rc = static_rc::StaticRc::<_,1,1>::new(a); 1011 | /// 1012 | /// let mut reborrow = static_rc::StaticRc::as_rcref(&mut rc); 1013 | /// std::mem::drop(rc); 1014 | /// assert_eq!(*reborrow, "foo"); // This should fail to compile. 1015 | /// ``` 1016 | pub fn rc_reborrow_and_move() {} 1017 | 1018 | /// ```compile_fail,E0502 1019 | /// let mut a = String::from("foo"); 1020 | /// let mut rc = static_rc::StaticRc::<_,1,1>::new(a); 1021 | /// 1022 | /// let mut reborrow = static_rc::StaticRc::as_rcref(&mut rc); 1023 | /// assert_eq!(*rc, "foo"); 1024 | /// assert_eq!(*reborrow, "foo"); // This should fail to compile. 1025 | /// ``` 1026 | pub fn rc_reborrow_and_use() {} 1027 | 1028 | } // mod compile_tests 1029 | 1030 | #[doc(hidden)] 1031 | pub mod compile_ratio_tests { 1032 | 1033 | /// ```compile_fail,E0080 1034 | /// type Zero = static_rc::StaticRc; 1035 | /// 1036 | /// Zero::new(42); 1037 | /// ``` 1038 | pub fn rc_new_zero() {} 1039 | 1040 | /// ```compile_fail,E0080 1041 | /// type Zero = static_rc::StaticRc; 1042 | /// 1043 | /// Zero::pin(42); 1044 | /// ``` 1045 | pub fn rc_pin_zero() {} 1046 | 1047 | /// ```compile_fail,E0080 1048 | /// type Zero = static_rc::StaticRc; 1049 | /// 1050 | /// let pointer = core::ptr::NonNull::dangling(); 1051 | /// 1052 | /// unsafe { Zero::from_raw(pointer) }; 1053 | /// ``` 1054 | pub fn rc_from_raw_zero() {} 1055 | 1056 | /// ```compile_fail,E0080 1057 | /// type One = static_rc::StaticRc; 1058 | /// 1059 | /// let rc = One::new(42); 1060 | /// 1061 | /// One::adjust::<0, 0>(rc); 1062 | /// ``` 1063 | pub fn rc_adjust_zero() {} 1064 | 1065 | /// ```compile_fail,E0080 1066 | /// type One = static_rc::StaticRc; 1067 | /// 1068 | /// let rc = One::new(42); 1069 | /// 1070 | /// One::adjust::<2, 3>(rc); 1071 | /// ``` 1072 | pub fn rc_adjust_ratio() {} 1073 | 1074 | /// ```compile_fail,E0080 1075 | /// type Two = static_rc::StaticRc; 1076 | /// 1077 | /// let rc = Two::new(42); 1078 | /// 1079 | /// Two::split::<0, 2>(rc); 1080 | /// ``` 1081 | pub fn rc_split_zero_first() {} 1082 | 1083 | /// ```compile_fail,E0080 1084 | /// type Two = static_rc::StaticRc; 1085 | /// 1086 | /// let rc = Two::new(42); 1087 | /// 1088 | /// Two::split::<2, 0>(rc); 1089 | /// ``` 1090 | pub fn rc_split_zero_second() {} 1091 | 1092 | /// ```compile_fail,E0080 1093 | /// type Two = static_rc::StaticRc; 1094 | /// 1095 | /// let rc = Two::new(42); 1096 | /// 1097 | /// Two::split::<1, 2>(rc); 1098 | /// ``` 1099 | pub fn rc_split_sum() {} 1100 | 1101 | /// ```compile_fail,E0080 1102 | /// type Two = static_rc::StaticRc; 1103 | /// 1104 | /// let rc = Two::new(42); 1105 | /// 1106 | /// Two::split_array::<2, 2>(rc); 1107 | /// ``` 1108 | pub fn rc_split_array_ratio() {} 1109 | 1110 | /// ```compile_fail,E0080 1111 | /// type Two = static_rc::StaticRc; 1112 | /// 1113 | /// let rc = Two::new(42); 1114 | /// let (one, two) = Two::split::<1, 1>(rc); 1115 | /// 1116 | /// static_rc::StaticRc::<_, 1, 2>::join(one, two); 1117 | /// ``` 1118 | pub fn rc_join_ratio() {} 1119 | 1120 | /// ```compile_fail,E0080 1121 | /// type Two = static_rc::StaticRc; 1122 | /// 1123 | /// let rc = Two::new(42); 1124 | /// let (one, two) = Two::split::<1, 1>(rc); 1125 | /// 1126 | /// unsafe { static_rc::StaticRc::<_, 1, 2>::join_unchecked(one, two) }; 1127 | /// ``` 1128 | pub fn rc_join_unchecked_ratio() {} 1129 | 1130 | /// ```compile_fail,E0080 1131 | /// type Two = static_rc::StaticRc; 1132 | /// 1133 | /// let rc = Two::new(42); 1134 | /// let array: [_; 2] = Two::split_array::<1, 2>(rc); 1135 | /// 1136 | /// static_rc::StaticRc::<_, 1, 2>::join_array(array); 1137 | /// ``` 1138 | pub fn rc_join_array_ratio() {} 1139 | 1140 | /// ```compile_fail,E0080 1141 | /// type Two = static_rc::StaticRc; 1142 | /// 1143 | /// let rc = Two::new(42); 1144 | /// let array: [_; 2] = Two::split_array::<1, 2>(rc); 1145 | /// 1146 | /// unsafe { static_rc::StaticRc::<_, 1, 2>::join_array_unchecked(array) }; 1147 | /// ``` 1148 | pub fn rc_join_array_unchecked_ratio() {} 1149 | 1150 | } // mod compile_ratio_tests 1151 | -------------------------------------------------------------------------------- /src/rcref.rs: -------------------------------------------------------------------------------- 1 | //! `StaticRcRef` is a compile-time referenced counted access to a mutable reference. 2 | 3 | use core::{ 4 | any, 5 | borrow, 6 | cmp, 7 | convert, 8 | fmt, 9 | future, 10 | hash, 11 | iter, 12 | marker::{self, PhantomData}, 13 | mem::{self, MaybeUninit}, 14 | ops, 15 | pin, 16 | ptr::{self, NonNull}, 17 | task, 18 | }; 19 | 20 | #[cfg(feature = "nightly-async-iterator")] 21 | use core::async_iter; 22 | 23 | #[cfg(feature = "nightly-coerce-unsized")] 24 | use core::ops::CoerceUnsized; 25 | 26 | #[cfg(feature = "nightly-dispatch-from-dyn")] 27 | use core::ops::DispatchFromDyn; 28 | 29 | /// A compile-time reference-counted pointer. 30 | /// 31 | /// The inherent methods of `StaticRc` are all associated functions to avoid conflicts with the the methods of the 32 | /// inner type `T` which are brought into scope by the `Deref` implementation. 33 | /// 34 | /// The parameters `NUM` and `DEN` DENote the ratio (`NUM / DEN`) of ownership of the pointer: 35 | /// 36 | /// - The ratio is always in the (0, 1] interval, that is: `NUM > 0` and `NUM <= DEN`. 37 | /// - When the ratio is equal to 1, that is when `NUM == DEN`, then the instance has full ownership of the pointee 38 | /// and extra capabilities are unlocked. 39 | pub struct StaticRcRef<'a, T: ?Sized, const NUM: usize, const DEN: usize> { 40 | pointer: NonNull, 41 | _marker: PhantomData<&'a mut T>, 42 | } 43 | 44 | impl<'a, T: ?Sized, const N: usize> StaticRcRef<'a, T, N, N> { 45 | /// Constructs a new `StaticRcRef<'a, T, N, N>`. 46 | /// 47 | /// # Example 48 | /// 49 | /// ```rust 50 | /// use static_rc::StaticRcRef; 51 | /// 52 | /// type Full<'a> = StaticRcRef<'a, i32, 1, 1>; 53 | /// 54 | /// let mut value = 42; 55 | /// let rc = Full::new(&mut value); 56 | /// assert_eq!(42, *rc); 57 | /// ``` 58 | #[inline(always)] 59 | pub fn new(value: &'a mut T) -> Self 60 | where 61 | AssertLeType!(1, N): Sized, 62 | { 63 | #[cfg(not(feature = "compile-time-ratio"))] 64 | const { assert!(N > 0); } 65 | 66 | let pointer = NonNull::from(value); 67 | Self { pointer, _marker: PhantomData } 68 | } 69 | 70 | /// Returns the inner value. 71 | /// 72 | /// # Example 73 | /// 74 | /// ```rust 75 | /// use static_rc::StaticRcRef; 76 | /// 77 | /// type Full<'a> = StaticRcRef<'a, i32, 1, 1>; 78 | /// 79 | /// let mut value = 42; 80 | /// let rc = Full::new(&mut value); 81 | /// let inner: &mut i32 = Full::into_inner(rc); 82 | /// assert_eq!(42, *inner); 83 | /// ``` 84 | #[inline(always)] 85 | pub fn into_inner(this: Self) -> &'a mut T { 86 | // Safety: 87 | // - Ratio = 1, hence full ownership. 88 | // - Original lifetime is restored. 89 | unsafe { &mut *this.pointer.as_ptr() } 90 | } 91 | 92 | /// Returns a mutable reference into the given `StaticRcRef`. 93 | /// 94 | /// # Example 95 | /// 96 | /// ```rust 97 | /// use static_rc::StaticRcRef; 98 | /// 99 | /// type Full<'a> = StaticRcRef<'a, i32, 1, 1>; 100 | /// 101 | /// let mut value = 42; 102 | /// let mut rc = Full::new(&mut value); 103 | /// assert_eq!(42, *Full::get_mut(&mut rc)); 104 | /// ``` 105 | #[inline(always)] 106 | pub fn get_mut(this: &mut Self) -> &mut T { 107 | // Safety: 108 | // - Ratio = 1, hence full ownership. 109 | unsafe { this.pointer.as_mut() } 110 | } 111 | } 112 | 113 | impl<'a, T: ?Sized, const NUM: usize, const DEN: usize> StaticRcRef<'a, T, NUM, DEN> { 114 | /// Consumes the `StaticRcRef`, returning the wrapped pointer. 115 | /// 116 | /// # Example 117 | /// 118 | /// ```rust 119 | /// use static_rc::StaticRcRef; 120 | /// 121 | /// type Full<'a> = StaticRcRef<'a, i32, 1, 1>; 122 | /// 123 | /// let mut value = 42; 124 | /// let rc = Full::new(&mut value); 125 | /// let pointer = Full::into_raw(rc); 126 | /// assert_eq!(&mut value as *mut _, pointer.as_ptr()); 127 | /// ``` 128 | #[inline(always)] 129 | pub fn into_raw(this: Self) -> NonNull { this.pointer } 130 | 131 | /// Provides a raw pointer to the data. 132 | /// 133 | /// `StaticRcRef` is not consumed or affected in any way, the pointer is valid as long as the original value is. 134 | /// 135 | /// # Example 136 | /// 137 | /// ```rust 138 | /// use static_rc::StaticRcRef; 139 | /// 140 | /// type Full<'a> = StaticRcRef<'a, i32, 1, 1>; 141 | /// 142 | /// let mut value = 42; 143 | /// let pointer = &mut value as *mut _; 144 | /// 145 | /// let rc = Full::new(&mut value); 146 | /// let other_pointer = Full::as_ptr(&rc); 147 | /// 148 | /// assert_eq!(pointer, other_pointer.as_ptr()); 149 | /// ``` 150 | #[inline(always)] 151 | pub fn as_ptr(this: &Self) -> NonNull { this.pointer } 152 | 153 | /// Provides a reference to the data. 154 | /// 155 | /// # Example 156 | /// 157 | /// ```rust 158 | /// use static_rc::StaticRcRef; 159 | /// 160 | /// type Full<'a> = StaticRcRef<'a, i32, 1, 1>; 161 | /// 162 | /// let mut value = 42; 163 | /// let rc = Full::new(&mut value); 164 | /// 165 | /// let r = Full::get_ref(&rc); 166 | /// 167 | /// assert_eq!(42, *r); 168 | /// ``` 169 | #[inline(always)] 170 | pub fn get_ref(this: &Self) -> &T { 171 | // Safety: 172 | // - The data is valid for as long as `this` lives. 173 | unsafe { this.pointer.as_ref() } 174 | } 175 | 176 | /// Constructs a `StaticRcRef<'a, T, NUM, DEN>` from a raw pointer. 177 | /// 178 | /// # Safety 179 | /// 180 | /// The raw pointer must have been previously returned by a call to `StaticRcRef<'a, U, N, D>::into_raw`: 181 | /// 182 | /// - If `U` is different from `T`, then specific restrictions on size and alignment apply. See `mem::transmute` 183 | /// for the restrictions applying to transmuting references. 184 | /// - If `N / D` is different from `NUM / DEN`, then specific restrictions apply. The user is responsible for 185 | /// ensuring proper management of the ratio of shares, and ultimately that the value is not dropped twice. 186 | // Internal comment: Internally, calling `from_raw` in the specific case of `StaticRc::as_rcref` 187 | // is allowed. This isn't allowed as an external user of the library. 188 | #[inline(always)] 189 | pub unsafe fn from_raw(pointer: NonNull) -> Self 190 | where 191 | AssertLeType!(1, NUM): Sized, 192 | { 193 | #[cfg(not(feature = "compile-time-ratio"))] 194 | const { assert!(NUM > 0); } 195 | 196 | Self { pointer, _marker: PhantomData, } 197 | } 198 | 199 | /// Returns true if the two `StaticRcRef` point to the same allocation. 200 | /// 201 | /// # Example 202 | /// 203 | /// ```rust 204 | /// use static_rc::StaticRcRef; 205 | /// 206 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 207 | /// 208 | /// let mut value = 42; 209 | /// let rc = Full::new(&mut value); 210 | /// let (one, two) = Full::split::<1, 1>(rc); 211 | /// 212 | /// assert!(StaticRcRef::ptr_eq(&one, &two)); 213 | /// ``` 214 | #[inline(always)] 215 | pub fn ptr_eq(this: &Self, other: &StaticRcRef<'a, T, N, D>) -> bool { 216 | ptr::eq(StaticRcRef::as_ptr(this).as_ptr(), StaticRcRef::as_ptr(other).as_ptr()) 217 | } 218 | 219 | /// Adjusts the NUMerator and DENumerator of the ratio of the instance, preserving the ratio. 220 | /// 221 | /// # Example 222 | /// 223 | /// ```rust 224 | /// use static_rc::StaticRcRef; 225 | /// 226 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 227 | /// 228 | /// let mut value = 42; 229 | /// let rc = Full::new(&mut value); 230 | /// let rc = Full::adjust::<1, 1>(rc); 231 | /// 232 | /// assert_eq!(42, *rc); 233 | /// ``` 234 | #[inline(always)] 235 | pub fn adjust(this: Self) -> StaticRcRef<'a, T, N, D> 236 | where 237 | AssertLeType!(1, N): Sized, 238 | AssertEqType!(N * DEN, NUM * D): Sized, 239 | { 240 | #[cfg(not(feature = "compile-time-ratio"))] 241 | const { 242 | assert!(N > 0); 243 | assert!(NUM * D == N * DEN); 244 | } 245 | 246 | StaticRcRef { pointer: this.pointer, _marker: PhantomData } 247 | } 248 | 249 | /// Reborrows into another [`StaticRcRef`]. 250 | /// 251 | /// The current instance is mutably borrowed for the duration the result can be used. 252 | /// 253 | /// # Example 254 | /// 255 | /// ```rust 256 | /// use static_rc::StaticRcRef; 257 | /// let mut x = 5; 258 | /// let rc_full: StaticRcRef = StaticRcRef::new(&mut x); 259 | /// let (mut rc1, mut rc2) = StaticRcRef::split::<1, 1>(rc_full); 260 | /// { 261 | /// // Modify without moving `rc1`, `rc2`. 262 | /// let rc_borrow1 = StaticRcRef::reborrow(&mut rc1); 263 | /// let rc_borrow2 = StaticRcRef::reborrow(&mut rc2); 264 | /// let mut rcref_full: StaticRcRef<_, 2, 2> = StaticRcRef::join(rc_borrow1, rc_borrow2); 265 | /// *rcref_full = 9; 266 | /// // Reborrow ends, can use the original refs again 267 | /// } 268 | /// let rc_full: StaticRcRef<_, 2, 2> = StaticRcRef::join(rc1, rc2); 269 | /// assert_eq!(*rc_full, 9); 270 | /// assert_eq!(x, 9); 271 | /// ``` 272 | #[inline(always)] 273 | pub fn reborrow<'reborrow>(this: &'reborrow mut Self) -> StaticRcRef<'reborrow, T, NUM, DEN> { 274 | // Safety (even though this doesn't use the `unsafe` keyword): 275 | // - `this.pointer` is a valid aligned pointer into a valid value of `T`. 276 | // - The result is only usable for lifetime `'a`, and for the duration 277 | // of the lifetime `'a` `this` is mutably borrowed. 278 | // - `this` has NUM/DEN of the right to mutate the value. So it can lend NUM/DEN 279 | // of the right to mutate the value. Therefore, this is semantically sound 280 | // according to the general principle of this library. 281 | StaticRcRef { 282 | pointer: this.pointer, 283 | _marker: PhantomData, 284 | } 285 | } 286 | 287 | /// Splits the current instance into two instances with the specified NUMerators. 288 | /// 289 | /// # Example 290 | /// 291 | /// ```rust 292 | /// use static_rc::StaticRcRef; 293 | /// 294 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 295 | /// 296 | /// let mut value = 42; 297 | /// let rc = Full::new(&mut value); 298 | /// let (one, two) = Full::split::<1, 1>(rc); 299 | /// 300 | /// assert_eq!(42, *one); 301 | /// assert_eq!(42, *two); 302 | /// ``` 303 | #[inline(always)] 304 | pub fn split(this: Self) -> (StaticRcRef<'a, T, A, DEN>, StaticRcRef<'a, T, B, DEN>) 305 | where 306 | AssertLeType!(1, A): Sized, 307 | AssertLeType!(1, B): Sized, 308 | AssertEqType!(A + B, NUM): Sized, 309 | { 310 | #[cfg(not(feature = "compile-time-ratio"))] 311 | const { 312 | assert!(A > 0); 313 | assert!(B > 0); 314 | assert!(NUM == A + B); 315 | } 316 | 317 | let pointer = this.pointer; 318 | let _marker = PhantomData; 319 | 320 | (StaticRcRef { pointer, _marker, }, StaticRcRef { pointer, _marker, }) 321 | } 322 | 323 | /// Splits the current instance into DIM instances with the specified Numerators. 324 | /// 325 | /// # Example 326 | /// 327 | /// ```rust 328 | /// use static_rc::StaticRcRef; 329 | /// 330 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 331 | /// 332 | /// let mut value = 42; 333 | /// let rc = Full::new(&mut value); 334 | /// let array = Full::split_array::<1, 2>(rc); 335 | /// 336 | /// assert_eq!(42, *array[0]); 337 | /// assert_eq!(42, *array[1]); 338 | /// ``` 339 | #[inline(always)] 340 | pub fn split_array(this: Self) -> [StaticRcRef<'a, T, N, DEN>; DIM] 341 | where 342 | T: 'a, 343 | AssertEqType!(N * DIM, NUM): Sized, 344 | AssertLeType!(mem::size_of::<[StaticRcRef<'a, T, N, DEN>; DIM]>(), usize::MAX / 2 + 1): Sized, 345 | { 346 | #[cfg(not(feature = "compile-time-ratio"))] 347 | const { 348 | assert!(NUM == N * DIM); 349 | 350 | assert!(mem::size_of::<[StaticRcRef; DIM]>() <= (isize::MAX as usize)); 351 | } 352 | 353 | let pointer = this.pointer; 354 | let _marker = PhantomData; 355 | 356 | let mut array = MaybeUninit::uninit(); 357 | 358 | for i in 0..DIM { 359 | // Safety: 360 | // - `destination` within bounds of allocated array (< DIM). 361 | // - Offset doesn't overflow `isize`, as per array-size assertion. 362 | // - Offset doesn't wrap around, as per array-size assertion. 363 | let destination = unsafe { (array.as_mut_ptr() as *mut StaticRcRef).add(i) }; 364 | 365 | // Safety: 366 | // - `destination` is valid for writes. 367 | // - `destination` is correctly aligned. 368 | unsafe { ptr::write(destination, StaticRcRef { pointer, _marker, }); } 369 | } 370 | 371 | // Safety: 372 | // - Every element of the array is now initialized. 373 | unsafe { array.assume_init() } 374 | } 375 | 376 | /// Joins two instances into a single instance. 377 | /// 378 | /// # Panics 379 | /// 380 | /// If the two instances do no point to the same allocation, as determined by `StaticRcRef::ptr_eq`. 381 | /// 382 | /// # Example 383 | /// 384 | /// ```rust 385 | /// use static_rc::StaticRcRef; 386 | /// 387 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 388 | /// 389 | /// let mut value = 42; 390 | /// let rc = Full::new(&mut value); 391 | /// let (one, two) = Full::split::<1, 1>(rc); 392 | /// let rc = Full::join(one, two); 393 | /// 394 | /// assert_eq!(42, *rc); 395 | /// ``` 396 | #[inline(always)] 397 | pub fn join(left: StaticRcRef<'a, T, A, DEN>, right: StaticRcRef<'a, T, B, DEN>) -> Self 398 | where 399 | AssertEqType!(NUM, A + B): Sized, 400 | { 401 | assert!(StaticRcRef::ptr_eq(&left, &right), "{:?} != {:?}", left.pointer.as_ptr(), right.pointer.as_ptr()); 402 | 403 | // Safety: 404 | // - `left` and `right` point to the same pointer. 405 | unsafe { Self::join_unchecked(left, right) } 406 | } 407 | 408 | /// Joins two instances into a single instance without checking whether they point to the same allocation. 409 | /// 410 | /// Unless `compile-time-ratio` is activated, the ratios are checked nevertheless. 411 | /// 412 | /// # Safety 413 | /// 414 | /// The caller must guarantee that those instances point to the same allocation. 415 | /// 416 | /// # Panics 417 | /// 418 | /// In debug, if the two instances do no point to the same allocation, as determined by `StaticRcRef::ptr_eq`. 419 | /// 420 | /// # Example 421 | /// 422 | /// ```rust 423 | /// use static_rc::StaticRcRef; 424 | /// 425 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 426 | /// 427 | /// let mut value = 42; 428 | /// let rc = Full::new(&mut value); 429 | /// let (one, two) = Full::split::<1, 1>(rc); 430 | /// let rc = unsafe { Full::join_unchecked(one, two) }; 431 | /// 432 | /// assert_eq!(42, *rc); 433 | /// ``` 434 | #[inline(always)] 435 | pub unsafe fn join_unchecked( 436 | left: StaticRcRef<'a, T, A, DEN>, 437 | _right: StaticRcRef<'a, T, B, DEN>, 438 | ) -> Self 439 | where 440 | AssertEqType!(NUM, A + B): Sized, 441 | { 442 | #[cfg(not(feature = "compile-time-ratio"))] 443 | const { assert!(NUM == A + B); } 444 | 445 | debug_assert!(StaticRcRef::ptr_eq(&left, &_right), "{:?} != {:?}", left.pointer.as_ptr(), _right.pointer.as_ptr()); 446 | 447 | Self { pointer: left.pointer, _marker: PhantomData, } 448 | } 449 | 450 | /// Joins DIM instances into a single instance. 451 | /// 452 | /// # Panics 453 | /// 454 | /// If all instances do not point to the same allocation, as determined by `StaticRcRef::ptr_eq`. 455 | /// 456 | /// # Example 457 | /// 458 | /// ```rust 459 | /// use static_rc::StaticRcRef; 460 | /// 461 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 462 | /// 463 | /// let mut value = 42; 464 | /// let rc = Full::new(&mut value); 465 | /// let array = Full::split_array::<1, 2>(rc); 466 | /// let rc = Full::join_array(array); 467 | /// 468 | /// assert_eq!(42, *rc); 469 | /// ``` 470 | #[inline(always)] 471 | pub fn join_array(array: [StaticRcRef<'a, T, N, DEN>; DIM]) -> Self 472 | where 473 | AssertLeType!(1, NUM): Sized, 474 | AssertEqType!(N * DIM, NUM): Sized, 475 | { 476 | let first = &array[0]; 477 | for successive in &array[1..] { 478 | assert!(StaticRcRef::ptr_eq(first, successive), 479 | "{:?} != {:?}", first.pointer.as_ptr(), successive.pointer.as_ptr()); 480 | } 481 | 482 | // Safety: 483 | // - All instances point to the same allocation, as checked in the above loop. 484 | unsafe { Self::join_array_unchecked(array) } 485 | } 486 | 487 | /// Joins DIM instances into a single instance. 488 | /// 489 | /// # Safety 490 | /// 491 | /// All `StaticRcRef` joined must point to the same allocation, as determined by `StaticRcRef::ptr_eq`. 492 | /// 493 | /// # Panics 494 | /// 495 | /// In debug, if all instances do not point to the same allocation, as determined by `StaticRcRef::ptr_eq`. 496 | /// 497 | /// # Example 498 | /// 499 | /// ```rust 500 | /// use static_rc::StaticRcRef; 501 | /// 502 | /// type Full<'a> = StaticRcRef<'a, i32, 2, 2>; 503 | /// 504 | /// let mut value = 42; 505 | /// let rc = Full::new(&mut value); 506 | /// let array = Full::split_array::<1, 2>(rc); 507 | /// let rc = unsafe { Full::join_array_unchecked(array) }; 508 | /// 509 | /// assert_eq!(42, *rc); 510 | /// ``` 511 | #[inline(always)] 512 | pub unsafe fn join_array_unchecked(array: [StaticRcRef<'a, T, N, DEN>; DIM]) 513 | -> Self 514 | where 515 | AssertLeType!(1, NUM): Sized, 516 | AssertEqType!(N * DIM, NUM): Sized, 517 | { 518 | #[cfg(not(feature = "compile-time-ratio"))] 519 | const { 520 | assert!(NUM > 0); 521 | assert!(NUM == N * DIM); 522 | } 523 | 524 | let _first = &array[0]; 525 | for _successive in &array[1..] { 526 | debug_assert!(StaticRcRef::ptr_eq(_first, _successive), 527 | "{:?} != {:?}", _first.pointer.as_ptr(), _successive.pointer.as_ptr()); 528 | } 529 | 530 | Self { pointer: array[0].pointer, _marker: PhantomData, } 531 | } 532 | 533 | 534 | } 535 | 536 | impl<'a, const NUM: usize, const DEN: usize> StaticRcRef<'a, dyn any::Any, NUM, DEN> { 537 | /// Attempts to downcast `Self` to a concrete type. 538 | pub fn downcast(self) -> Result, Self> { 539 | if Self::get_ref(&self).is::() { 540 | let pointer = Self::into_raw(self).cast::(); 541 | Ok(StaticRcRef { pointer, _marker: PhantomData, }) 542 | } else { 543 | Err(self) 544 | } 545 | } 546 | } 547 | 548 | impl<'a, T: ?Sized, const N: usize> convert::AsMut for StaticRcRef<'a, T, N, N> { 549 | #[inline(always)] 550 | fn as_mut(&mut self) -> &mut T { Self::get_mut(self) } 551 | } 552 | 553 | impl<'a, T: ?Sized, const NUM: usize, const DEN: usize> convert::AsRef for StaticRcRef<'a, T, NUM, DEN> { 554 | #[inline(always)] 555 | fn as_ref(&self) -> &T { Self::get_ref(self) } 556 | } 557 | 558 | impl<'a, T: ?Sized, const NUM: usize, const DEN: usize> borrow::Borrow for StaticRcRef<'a, T, NUM, DEN> { 559 | #[inline(always)] 560 | fn borrow(&self) -> &T { Self::get_ref(self) } 561 | } 562 | 563 | impl<'a, T: ?Sized, const N: usize> borrow::BorrowMut for StaticRcRef<'a, T, N, N> { 564 | #[inline(always)] 565 | fn borrow_mut(&mut self) -> &mut T { Self::get_mut(self) } 566 | } 567 | 568 | #[cfg(feature = "nightly-coerce-unsized")] 569 | impl<'a, T, U, const NUM: usize, const DEN: usize> CoerceUnsized> for StaticRcRef<'a, T, NUM, DEN> 570 | where 571 | T: ?Sized + marker::Unsize, 572 | U: ?Sized, 573 | {} 574 | 575 | impl<'a, T: ?Sized + fmt::Debug, const NUM: usize, const DEN: usize> fmt::Debug for StaticRcRef<'a, T, NUM, DEN> { 576 | #[inline(always)] 577 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 578 | fmt::Debug::fmt(Self::get_ref(self), f) 579 | } 580 | } 581 | 582 | impl<'a, T: ?Sized, const NUM: usize, const DEN: usize> ops::Deref for StaticRcRef<'a, T, NUM, DEN> { 583 | type Target = T; 584 | 585 | #[inline(always)] 586 | fn deref(&self) -> &T { Self::get_ref(self) } 587 | } 588 | 589 | impl<'a, T: ?Sized, const N: usize> ops::DerefMut for StaticRcRef<'a, T, N, N> { 590 | #[inline(always)] 591 | fn deref_mut(&mut self) -> &mut T { Self::get_mut(self) } 592 | } 593 | 594 | impl<'a, T: ?Sized + fmt::Display, const NUM: usize, const DEN: usize> fmt::Display for StaticRcRef<'a, T, NUM, DEN> { 595 | #[inline(always)] 596 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 597 | fmt::Display::fmt(Self::get_ref(self), f) 598 | } 599 | } 600 | 601 | #[cfg(feature = "nightly-dispatch-from-dyn")] 602 | impl<'a, T, U, const NUM: usize, const DEN: usize> DispatchFromDyn> for StaticRcRef<'a, T, NUM, DEN> 603 | where 604 | T: ?Sized + marker::Unsize, 605 | U: ?Sized, 606 | {} 607 | 608 | impl<'a, I: iter::DoubleEndedIterator + ?Sized, const N: usize> iter::DoubleEndedIterator for StaticRcRef<'a, I, N, N> { 609 | #[inline(always)] 610 | fn next_back(&mut self) -> Option { Self::get_mut(self).next_back() } 611 | 612 | #[inline(always)] 613 | fn nth_back(&mut self, n: usize) -> Option { Self::get_mut(self).nth_back(n) } 614 | } 615 | 616 | impl<'a, T: ?Sized + cmp::Eq, const NUM: usize, const DEN: usize> cmp::Eq for StaticRcRef<'a, T, NUM, DEN> {} 617 | 618 | impl<'a, I: iter::ExactSizeIterator + ?Sized, const N: usize> iter::ExactSizeIterator for StaticRcRef<'a, I, N, N> { 619 | #[inline(always)] 620 | fn len(&self) -> usize { Self::get_ref(self).len() } 621 | } 622 | 623 | impl<'a, const NUM: usize, const DEN: usize> From> for StaticRcRef<'a, [u8], NUM, DEN> { 624 | #[inline(always)] 625 | fn from(value: StaticRcRef<'a, str, NUM, DEN>) -> Self { 626 | let pointer = value.pointer.as_ptr() as *mut [u8]; 627 | 628 | // Safety: 629 | // - `value.pointer` was not null, hence `pointer` is not null. 630 | debug_assert!(!pointer.is_null()); 631 | let pointer = unsafe { NonNull::new_unchecked(pointer) }; 632 | 633 | Self { pointer, _marker: PhantomData, } 634 | } 635 | } 636 | 637 | impl<'a, I: iter::FusedIterator + ?Sized, const N: usize> iter::FusedIterator for StaticRcRef<'a, I, N, N> {} 638 | 639 | impl<'a, F: ?Sized + future::Future + marker::Unpin, const N: usize> future::Future for StaticRcRef<'a, F, N, N> { 640 | type Output = F::Output; 641 | 642 | fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll { 643 | F::poll(pin::Pin::new(&mut *self), cx) 644 | } 645 | } 646 | 647 | #[cfg(feature = "nightly-generator-trait")] 648 | impl<'a, G: ?Sized + ops::Generator + marker::Unpin, R, const N: usize> ops::Generator for StaticRcRef<'a, G, N, N> { 649 | type Yield = G::Yield; 650 | type Return = G::Return; 651 | 652 | fn resume(mut self: pin::Pin<&mut Self>, arg: R) -> ops::GeneratorState { 653 | G::resume(pin::Pin::new(&mut *self), arg) 654 | } 655 | } 656 | 657 | #[cfg(feature = "nightly-generator-trait")] 658 | impl<'a, G: ?Sized + ops::Generator, R, const N: usize> ops::Generator for pin::Pin> { 659 | type Yield = G::Yield; 660 | type Return = G::Return; 661 | 662 | fn resume(mut self: pin::Pin<&mut Self>, arg: R) -> ops::GeneratorState { 663 | G::resume((*self).as_mut(), arg) 664 | } 665 | } 666 | 667 | impl<'a, T: ?Sized + hash::Hash, const NUM: usize, const DEN: usize> hash::Hash for StaticRcRef<'a, T, NUM, DEN> { 668 | #[inline(always)] 669 | fn hash(&self, state: &mut H) { 670 | Self::get_ref(self).hash(state); 671 | } 672 | } 673 | 674 | impl<'a, I: iter::Iterator + ?Sized, const N: usize> iter::Iterator for StaticRcRef<'a, I, N, N> { 675 | type Item = I::Item; 676 | 677 | #[inline(always)] 678 | fn next(&mut self) -> Option { Self::get_mut(self).next() } 679 | 680 | #[inline(always)] 681 | fn size_hint(&self) -> (usize, Option) { Self::get_ref(self).size_hint() } 682 | 683 | #[inline(always)] 684 | fn nth(&mut self, n: usize) -> Option { Self::get_mut(self).nth(n) } 685 | 686 | #[inline(always)] 687 | fn last(mut self) -> Option { Self::get_mut(&mut self).last() } 688 | } 689 | 690 | impl<'a, T: ?Sized + cmp::Ord, const NUM: usize, const DEN: usize> cmp::Ord for StaticRcRef<'a, T, NUM, DEN> { 691 | #[inline(always)] 692 | fn cmp(&self, other: &Self) -> cmp::Ordering { 693 | if Self::ptr_eq(self, other) { 694 | cmp::Ordering::Equal 695 | } else { 696 | Self::get_ref(self).cmp(Self::get_ref(other)) 697 | } 698 | } 699 | } 700 | 701 | impl<'a, T, const NUM: usize, const DEN: usize, const N: usize, const D: usize> cmp::PartialEq> 702 | for StaticRcRef<'a, T, NUM, DEN> 703 | where 704 | T: ?Sized + PartialEq 705 | { 706 | #[inline(always)] 707 | fn eq(&self, other: &StaticRcRef<'a, T, N, D>) -> bool { Self::get_ref(self).eq(StaticRcRef::get_ref(other)) } 708 | 709 | #[inline(always)] 710 | #[allow(clippy::partialeq_ne_impl)] 711 | fn ne(&self, other: &StaticRcRef<'a, T, N, D>) -> bool { Self::get_ref(self).ne(StaticRcRef::get_ref(other)) } 712 | } 713 | 714 | impl<'a, T, const NUM: usize, const DEN: usize, const N: usize, const D: usize> cmp::PartialOrd> 715 | for StaticRcRef<'a, T, NUM, DEN> 716 | where 717 | T: ?Sized + PartialOrd 718 | { 719 | #[inline(always)] 720 | fn partial_cmp(&self, other: &StaticRcRef<'a, T, N, D>) -> Option { 721 | Self::get_ref(self).partial_cmp(StaticRcRef::get_ref(other)) 722 | } 723 | 724 | #[inline(always)] 725 | fn lt(&self, other: &StaticRcRef<'a, T, N, D>) -> bool { 726 | Self::get_ref(self).lt(StaticRcRef::get_ref(other)) 727 | } 728 | 729 | #[inline(always)] 730 | fn le(&self, other: &StaticRcRef<'a, T, N, D>) -> bool { 731 | Self::get_ref(self).le(StaticRcRef::get_ref(other)) 732 | } 733 | 734 | #[inline(always)] 735 | fn gt(&self, other: &StaticRcRef<'a, T, N, D>) -> bool { 736 | Self::get_ref(self).gt(StaticRcRef::get_ref(other)) 737 | } 738 | 739 | #[inline(always)] 740 | fn ge(&self, other: &StaticRcRef<'a, T, N, D>) -> bool { 741 | Self::get_ref(self).ge(StaticRcRef::get_ref(other)) 742 | } 743 | } 744 | 745 | impl<'a, T: ?Sized, const NUM: usize, const DEN: usize> fmt::Pointer for StaticRcRef<'a, T, NUM, DEN> { 746 | #[inline(always)] 747 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 748 | fmt::Pointer::fmt(&Self::as_ptr(self).as_ptr(), f) 749 | } 750 | } 751 | 752 | #[cfg(feature = "nightly-async-iterator")] 753 | impl<'a, S: ?Sized + async_iter::AsyncIterator + marker::Unpin, const N: usize> async_iter::AsyncIterator for StaticRcRef<'a, S, N, N> { 754 | type Item = S::Item; 755 | 756 | fn poll_next(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll> { 757 | pin::Pin::new(&mut **self).poll_next(cx) 758 | } 759 | 760 | fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } 761 | } 762 | 763 | impl<'a, T: ?Sized, const NUM: usize, const DEN: usize> marker::Unpin for StaticRcRef<'a, T, NUM, DEN> {} 764 | 765 | unsafe impl<'a, T: ?Sized + marker::Send, const NUM: usize, const DEN: usize> marker::Send for StaticRcRef<'a, T, NUM, DEN> {} 766 | 767 | unsafe impl<'a, T: ?Sized + marker::Sync, const NUM: usize, const DEN: usize> marker::Sync for StaticRcRef<'a, T, NUM, DEN> {} 768 | 769 | #[doc(hidden)] 770 | pub mod compile_tests { 771 | 772 | /// ```compile_fail,E0597 773 | /// let a = String::from("foo"); 774 | /// let mut a_ref = &a; 775 | /// let mut rc = static_rc::StaticRcRef::<'_, _,1,1>::new(&mut a_ref); 776 | /// { 777 | /// let b = String::from("bar"); 778 | /// *rc = &b; // a_ref now points to b 779 | /// } 780 | /// // b is now dropped 781 | /// assert_ne!(a_ref, "bar"); // This should fail to compile. 782 | /// ``` 783 | pub fn rcref_prevent_use_after_free() {} 784 | 785 | /// ```compile_fail,E0505 786 | /// let mut a = String::from("foo"); 787 | /// let mut rc = static_rc::StaticRcRef::<'_, _,1,1>::new(&mut a); 788 | /// 789 | /// let mut reborrow = static_rc::StaticRcRef::reborrow(&mut rc); 790 | /// std::mem::drop(rc); 791 | /// assert_eq!(*reborrow, "foo"); // This should fail to compile. 792 | /// ``` 793 | pub fn rcref_reborrow_and_move() {} 794 | 795 | /// ```compile_fail,E0502 796 | /// let mut a = String::from("foo"); 797 | /// let mut rc = static_rc::StaticRcRef::<'_, _,1,1>::new(&mut a); 798 | /// 799 | /// let mut reborrow = static_rc::StaticRcRef::reborrow(&mut rc); 800 | /// assert_eq!(*rc, "foo"); 801 | /// assert_eq!(*reborrow, "foo"); // This should fail to compile. 802 | /// ``` 803 | pub fn rcref_reborrow_and_use() {} 804 | 805 | } // mod compile_tests 806 | 807 | #[doc(hidden)] 808 | pub mod compile_ratio_tests { 809 | 810 | /// ```compile_fail,E0080 811 | /// type Zero<'a> = static_rc::StaticRcRef<'a, i32, 0, 0>; 812 | /// 813 | /// let mut value = 42; 814 | /// 815 | /// Zero::new(&mut value); 816 | /// ``` 817 | pub fn rcref_new_zero() {} 818 | 819 | /// ```compile_fail,E0080 820 | /// type Zero<'a> = static_rc::StaticRcRef<'a, i32, 0, 0>; 821 | /// 822 | /// let pointer = core::ptr::NonNull::dangling(); 823 | /// 824 | /// unsafe { Zero::from_raw(pointer) }; 825 | /// ``` 826 | pub fn rcref_from_raw_zero() {} 827 | 828 | /// ```compile_fail,E0080 829 | /// type One<'a> = static_rc::StaticRcRef<'a, i32, 1, 1>; 830 | /// 831 | /// let mut value = 42; 832 | /// let rc = One::new(&mut value); 833 | /// 834 | /// One::adjust::<0, 0>(rc); 835 | /// ``` 836 | pub fn rcref_adjust_zero() {} 837 | 838 | /// ```compile_fail,E0080 839 | /// type One<'a> = static_rc::StaticRcRef<'a, i32, 1, 1>; 840 | /// 841 | /// let mut value = 42; 842 | /// let rc = One::new(&mut value); 843 | /// 844 | /// One::adjust::<2, 3>(rc); 845 | /// ``` 846 | pub fn rcref_adjust_ratio() {} 847 | 848 | /// ```compile_fail,E0080 849 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 850 | /// 851 | /// let mut value = 42; 852 | /// let rc = Two::new(&mut value); 853 | /// 854 | /// Two::split::<0, 2>(rc); 855 | /// ``` 856 | pub fn rcref_split_zero_first() {} 857 | 858 | /// ```compile_fail,E0080 859 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 860 | /// 861 | /// let mut value = 42; 862 | /// let rc = Two::new(&mut value); 863 | /// 864 | /// Two::split::<2, 0>(rc); 865 | /// ``` 866 | pub fn rcref_split_zero_second() {} 867 | 868 | /// ```compile_fail,E0080 869 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 870 | /// 871 | /// let mut value = 42; 872 | /// let rc = Two::new(&mut value); 873 | /// 874 | /// Two::split::<1, 2>(rc); 875 | /// ``` 876 | pub fn rcref_split_sum() {} 877 | 878 | /// ```compile_fail,E0080 879 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 880 | /// 881 | /// let mut value = 42; 882 | /// let rc = Two::new(&mut value); 883 | /// 884 | /// Two::split_array::<2, 2>(rc); 885 | /// ``` 886 | pub fn rcref_split_array_ratio() {} 887 | 888 | /// ```compile_fail,E0080 889 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 890 | /// 891 | /// let mut value = 42; 892 | /// let rc = Two::new(&mut value); 893 | /// let (one, two) = Two::split::<1, 1>(rc); 894 | /// 895 | /// static_rc::StaticRcRef::<'_, _, 1, 2>::join(one, two); 896 | /// ``` 897 | pub fn rcref_join_ratio() {} 898 | 899 | /// ```compile_fail,E0080 900 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 901 | /// 902 | /// let mut value = 42; 903 | /// let rc = Two::new(&mut value); 904 | /// let (one, two) = Two::split::<1, 1>(rc); 905 | /// 906 | /// unsafe { static_rc::StaticRcRef::<'_, _, 1, 2>::join_unchecked(one, two) }; 907 | /// ``` 908 | pub fn rcref_join_unchecked_ratio() {} 909 | 910 | /// ```compile_fail,E0080 911 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 912 | /// 913 | /// let mut value = 42; 914 | /// let rc = Two::new(&mut value); 915 | /// let array: [_; 2] = Two::split_array::<1, 2>(rc); 916 | /// 917 | /// static_rc::StaticRcRef::<'_, _, 1, 2>::join_array(array); 918 | /// ``` 919 | pub fn rcref_join_array_ratio() {} 920 | 921 | /// ```compile_fail,E0080 922 | /// type Two<'a> = static_rc::StaticRcRef<'a, i32, 2, 2>; 923 | /// 924 | /// let mut value = 42; 925 | /// let rc = Two::new(&mut value); 926 | /// let array: [_; 2] = Two::split_array::<1, 2>(rc); 927 | /// 928 | /// unsafe { static_rc::StaticRcRef::<'_, _, 1, 2>::join_array_unchecked(array) }; 929 | /// ``` 930 | pub fn rcref_join_array_unchecked_ratio() {} 931 | 932 | } // mod compile_ratio_tests 933 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | //! A work-around arithmetic conditions in `where` clauses. 2 | 3 | #[cfg(feature = "compile-time-ratio")] 4 | macro_rules! AssertLeType { 5 | ($left:expr, $right:expr) => { 6 | [(); $right - $left] 7 | }; 8 | } 9 | 10 | #[cfg(not(feature = "compile-time-ratio"))] 11 | macro_rules! AssertLeType { 12 | ($left:expr, $right:expr) => { 13 | () 14 | }; 15 | } 16 | 17 | macro_rules! AssertEqType { 18 | ($left:expr, $right: expr) => { 19 | (AssertLeType!($left, $right), AssertLeType!($right, $left)) 20 | }; 21 | } 22 | --------------------------------------------------------------------------------