├── .github └── workflows │ └── rust.yml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE-APACHE-2.0 ├── LICENSE-MIT ├── README.crates-io.md ├── README.md ├── cxx-tests ├── Cargo.toml ├── build.rs └── src │ ├── cxx_support_test_cpp.cc │ ├── cxx_support_test_cpp.h │ ├── lib.rs │ ├── new_helpers.h │ └── tests.rs ├── rust-toolchain.toml ├── rustfmt.toml └── src ├── alloc_support.rs ├── cxx_support.rs ├── drop_flag.rs ├── lib.rs ├── move_ref.rs ├── new ├── copy_new.rs ├── factories.rs ├── impls.rs ├── mod.rs └── move_new.rs └── slot.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Rust 16 | 17 | on: 18 | push: 19 | branches: [ master ] 20 | pull_request: 21 | branches: [ master ] 22 | 23 | env: 24 | CARGO_TERM_COLOR: always 25 | 26 | jobs: 27 | lints: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v2 31 | 32 | - name: cargo fmt 33 | run: cargo fmt -- --check --files-with-diff 34 | - name: cargo clippy 35 | run: cargo clippy --verbose 36 | 37 | tests: 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v2 41 | 42 | - name: cargo test 43 | run: cargo test --verbose --all 44 | - name: cargo doc 45 | run: cargo doc --verbose 46 | 47 | miri: 48 | runs-on: ubuntu-latest 49 | steps: 50 | - uses: actions/checkout@v2 51 | 52 | - name: rustup component add miri 53 | run: rustup +nightly-2021-10-10 component add miri 54 | - name: cargo miri test 55 | run: cargo +nightly-2021-10-10 miri test --verbose -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | [package] 16 | name = "moveit" 17 | version = "0.6.0" 18 | authors = ["Miguel Young de la Sota "] 19 | edition = "2018" 20 | repository = "https://github.com/google/moveit" 21 | 22 | keywords = ["ffi", "no_std", "macros", "lifetime", "ownership"] 23 | readme = "README.crates-io.md" 24 | license = "Apache-2.0 OR MIT" 25 | description = "A library for safe, in-place construction of Rust (and C++!) objects." 26 | 27 | [features] 28 | alloc = [] 29 | default = ["alloc"] 30 | 31 | [dependencies.cxx] 32 | version = "1.0" 33 | optional = true 34 | 35 | [workspace] 36 | members = ["cxx-tests"] 37 | -------------------------------------------------------------------------------- /LICENSE-APACHE-2.0: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2022 Google LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.crates-io.md: -------------------------------------------------------------------------------- 1 | # moveit 2 | 3 | A library for safe, in-place construction of Rust (and C++!) objects. 4 | 5 | ## How It Works 6 | 7 | `moveit` revolves around `unsafe trait`s that impose additional guarantees 8 | on `!Unpin` types, such that they can be moved in the C++ sense. There are 9 | two senses of "move" frequently used: 10 | - The Rust sense, which is a blind memcpy and analogous-ish to the 11 | C++ "std::is_trivially_moveable` type-trait. Rust moves also render the 12 | moved-from object inaccessible. 13 | - The C++ sense, where a move is really like a mutating `Clone` operation, 14 | which leave the moved-from value accessible to be destroyed at the end of 15 | the scope. 16 | 17 | C++ also has *constructors*, which are special functions that produce a new 18 | value in a particular location. In particular, C++ constructors may assume 19 | that the address of `*this` will not change; all C++ objects are effectively 20 | pinned and new objects must be constructed using copy or move constructors. 21 | 22 | The [`New`], [`CopyNew`], and [`MoveNew`] traits bring these concepts 23 | into Rust. A [`New`] is like a nilary [`FnOnce`], except that instead of 24 | returning its result, it writes it to a `Pin<&mut MaybeUninit>`, which is 25 | in the "memory may be repurposed" state described in the 26 | [`Pin` documentation] (i.e., either it is freshly allocated or the 27 | destructor was recently run). This allows a [`New`] to rely on the 28 | pointer's address remaining stable, much like `*this` in C++. 29 | 30 | Types that implement [`CopyNew`] may be *copy-constructed*: given any 31 | pointer to `T: CopyNew`, we can generate a constructor that constructs a 32 | new, identical `T` at a designated location. [`MoveNew`] types may be 33 | *move-constructed*: given an *owning* pointer (see [`DerefMove`]) to `T`, 34 | we can generate a similar constructor, except that it also destroys the 35 | `T` and the owning pointer's storage. 36 | 37 | None of this violates the existing `Pin` guarantees: moving out of a 38 | `Pin

` does not perform a move in the Rust sense, but rather in the C++ 39 | sense: it mutates through the pinned pointer in a safe manner to construct 40 | a new `P::Target`, and then destroys the pointer and its contents. 41 | 42 | In general, move-constructible types are going to want to be `!Unpin` so 43 | that they can be self-referential. Self-referential types are one of the 44 | primary motivations for move constructors. 45 | 46 | ## Constructors 47 | 48 | A constructor is any type that implements [`New`]. Constructors are like 49 | closures that have guaranteed RVO, which can be used to construct a 50 | self-referential type in-place. To use the example from the `Pin` docs: 51 | ```rust 52 | use std::marker::PhantomPinned; 53 | use std::mem::MaybeUninit; 54 | use std::pin::Pin; 55 | use std::ptr; 56 | use std::ptr::NonNull; 57 | 58 | use moveit::new; 59 | use moveit::new::New; 60 | use moveit::moveit; 61 | 62 | // This is a self-referential struct because the slice field points to the 63 | // data field. We cannot inform the compiler about that with a normal 64 | // reference, as this pattern cannot be described with the usual borrowing 65 | // rules. Instead we use a raw pointer, though one which is known not to be 66 | // null, as we know it's pointing at the string. 67 | struct Unmovable { 68 | data: String, 69 | slice: NonNull, 70 | _pin: PhantomPinned, 71 | } 72 | 73 | impl Unmovable { 74 | // Defer construction until the final location is known. 75 | fn new(data: String) -> impl New { 76 | new::of(Unmovable { 77 | data, 78 | // We only create the pointer once the data is in place 79 | // otherwise it will have already moved before we even started. 80 | slice: NonNull::dangling(), 81 | _pin: PhantomPinned, 82 | }).with(|this| unsafe { 83 | let this = this.get_unchecked_mut(); 84 | this.slice = NonNull::from(&this.data); 85 | }) 86 | 87 | // It is also possible to use other `new::` helpers, such as 88 | // `new::by` and `new::by_raw`, to configure construction behavior. 89 | } 90 | } 91 | 92 | // The constructor can't be used directly, and needs to be emplaced. 93 | moveit! { 94 | let unmoved = Unmovable::new("hello".to_string()); 95 | } 96 | // The pointer should point to the correct location, 97 | // so long as the struct hasn't moved. 98 | // Meanwhile, we are free to move the pointer around. 99 | let mut still_unmoved = unmoved; 100 | assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data)); 101 | 102 | // Since our type doesn't implement Unpin, this will fail to compile: 103 | // let mut new_unmoved = Unmovable::new("world".to_string()); 104 | // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); 105 | 106 | // However, we can implement `MoveNew` to allow it to be "moved" again. 107 | ``` 108 | 109 | The [`new`] module provides various helpers for making constructors. As a 110 | rule, functions which, in Rust, would normally construct and return a value 111 | should return `impl New` instead. This is analogous to have `async fn`s and 112 | `.iter()` functions work. 113 | 114 | ## Emplacement 115 | 116 | The example above makes use of the [`moveit!()`] macro, one of many ways to 117 | turn a constructor into a value. `moveit` gives you two choices for running 118 | a constructor: 119 | - On the stack, using the [`MoveRef`] type (this is what [`moveit!()`] 120 | generates). 121 | - On the heap, using the extension methods from the [`Emplace`] trait. 122 | 123 | For example, we could have placed the above in a `Box` by writing 124 | `Box::emplace(Unmovable::new())`. 125 | 126 | [`Pin` documentation]: https://doc.rust-lang.org/std/pin/index.html#drop-guarantee 127 | 128 | License: Apache-2.0 129 | 130 | This is not an officially supported Google product. 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `moveit` 2 | 3 | A library for safe, in-place construction of Rust (and C++!) objects. 4 | 5 | --- 6 | 7 | This is not an officially supported Google product. 8 | -------------------------------------------------------------------------------- /cxx-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | [package] 16 | name = "moveit-cxx-tests" 17 | version = "0.0.0" 18 | authors = ["Miguel Young de la Sota "] 19 | edition = "2018" 20 | repository = "https://github.com/google/moveit" 21 | publish = false 22 | 23 | [dependencies] 24 | cxx = "1.0" 25 | once_cell = "1.9" 26 | 27 | [dependencies.moveit] 28 | path = ".." 29 | features = ["cxx"] 30 | 31 | [build-dependencies] 32 | cxx-build = "1" 33 | -------------------------------------------------------------------------------- /cxx-tests/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | cxx_build::bridge("src/tests.rs") 17 | .flag_if_supported("-std=c++14") 18 | .include("src") 19 | .file("src/cxx_support_test_cpp.cc") 20 | .compile("moveit-cxx-tests"); 21 | 22 | println!("cargo:rerun-if-changed=src/tests.rs"); 23 | println!("cargo:rerun-if-changed=src/cxx_support_test_cpp.h"); 24 | println!("cargo:rerun-if-changed=src/new_helpers.h"); 25 | } 26 | -------------------------------------------------------------------------------- /cxx-tests/src/cxx_support_test_cpp.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Build in test mode only to test cxx integration. 16 | 17 | #include "cxx_support_test_cpp.h" 18 | 19 | Status status = Status::Unallocated; 20 | -------------------------------------------------------------------------------- /cxx-tests/src/cxx_support_test_cpp.h: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Build in test mode only to test cxx integration. 16 | 17 | #ifndef CXX_SUPPORT_TEST_CPP 18 | #define CXX_SUPPORT_TEST_CPP 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "moveit-cxx-tests/src/tests.rs.h" 28 | #include "new_helpers.h" 29 | 30 | // Test code status reporting 31 | 32 | extern Status status; 33 | 34 | inline Status GetStatus() { return status; } 35 | 36 | inline void SetStatus(Status new_status) { status = new_status; } 37 | 38 | inline void ResetStatus() { SetStatus(Status::Unallocated); } 39 | 40 | // Actual classes that would really be in production 41 | // code 42 | 43 | class Foo { 44 | public: 45 | Foo() { 46 | data[0] = 0; 47 | SetStatus(Status::Initialized); 48 | } 49 | bool GetA() const { return data[0] != 0; } 50 | void Modify() { data[0] = 1; } 51 | ~Foo() { SetStatus(Status::Destructed); } 52 | // We test using a custom operator new/delete 53 | // pair partly for purposes of recording status, 54 | // and partly so that we can verify that moveit 55 | // will work for C++ classes which do similar. 56 | void *operator new(size_t count) { 57 | SetStatus(Status::Allocated); 58 | return ::operator new(count); 59 | } 60 | void *operator new(size_t count, void *ptr) { 61 | SetStatus(Status::Allocated); 62 | return ::operator new(count, ptr); 63 | } 64 | void operator delete(void *ptr) noexcept { 65 | ::operator delete(ptr); 66 | SetStatus(Status::Deallocated); 67 | } 68 | 69 | private: 70 | uint32_t data[4]; 71 | }; 72 | 73 | class Bar { 74 | public: 75 | Bar() { 76 | data[0] = 0; 77 | SetStatus(Status::Initialized); 78 | } 79 | ~Bar() { SetStatus(Status::Destructed); } 80 | 81 | private: 82 | uint32_t data[4]; 83 | }; 84 | 85 | // Everything below here would be generated by some code generator 86 | 87 | inline Foo *foo_create_uninitialized() { return new_appropriately(1); } 88 | 89 | inline void foo_free_uninitialized(Foo *foo) { 90 | SetStatus(Status::DeallocatedUninitialized); 91 | delete_appropriately(foo); 92 | // This should end up calling operator delete 93 | // and replacing DeallocatedUninitialized with 94 | // Deallocated. 95 | } 96 | 97 | inline Bar *bar_create_uninitialized() { return new_appropriately(1); } 98 | 99 | inline void bar_free_uninitialized(Bar *bar) { 100 | SetStatus(Status::DeallocatedUninitialized); 101 | delete_appropriately(bar); 102 | } 103 | 104 | inline void foo_constructor(Foo *foo) { new (foo) Foo(); } 105 | inline void foo_destructor(Foo *foo) { foo->~Foo(); } 106 | inline void foo_move(Foo *dest, Foo *src) { new (dest) Foo(std::move(*src)); } 107 | 108 | inline void bar_constructor(Bar *bar) { new (bar) Bar(); } 109 | inline void bar_destructor(Bar *bar) { bar->~Bar(); } 110 | inline void bar_move(Bar *dest, Bar *src) { new (dest) Bar(std::move(*src)); } 111 | 112 | #endif // CXX_SUPPORT_TEST_CPP -------------------------------------------------------------------------------- /cxx-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Tests for `cxx` support in `moveit`. This is a separate crate because 16 | //! these tests require linking C++ code in a `build.rs`, which we do not 17 | //! want to apply to normal users of `moveit`. 18 | 19 | #[cfg(test)] 20 | mod tests; 21 | -------------------------------------------------------------------------------- /cxx-tests/src/new_helpers.h: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Build in test mode only to test cxx integration. 16 | 17 | #ifndef NEW_HELPERS 18 | #define NEW_HELPERS 19 | 20 | // Mechanics to call custom deallocators 21 | 22 | template 23 | auto delete_imp(T *ptr, int) -> decltype((void)T::operator delete(ptr)) { 24 | T::operator delete(ptr); 25 | } 26 | 27 | template void delete_imp(T *ptr, long) { ::operator delete(ptr); } 28 | 29 | template void delete_appropriately(T *obj) { 30 | // 0 is a better match for the first 'delete_imp' so will match 31 | // preferentially. 32 | delete_imp(obj, 0); 33 | } 34 | 35 | template 36 | auto new_imp(size_t count, int) -> decltype(T::operator new(count)) { 37 | return T::operator new(count); 38 | } 39 | 40 | template void *new_imp(size_t count, long) { 41 | return ::operator new(count); 42 | } 43 | 44 | template T *new_appropriately(size_t count) { 45 | // 0 is a better match for the first 'delete_imp' so will match 46 | // preferentially. 47 | return static_cast(new_imp(count, 0)); 48 | } 49 | 50 | #endif -------------------------------------------------------------------------------- /cxx-tests/src/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use once_cell::sync::OnceCell; 16 | use std::sync::Mutex; 17 | use std::sync::MutexGuard; 18 | 19 | use cxx::UniquePtr; 20 | use moveit::moveit; 21 | use moveit::Emplace; 22 | 23 | #[cxx::bridge] 24 | mod ffi { 25 | #[derive(Debug)] 26 | enum Status { 27 | Unallocated, 28 | Allocated, 29 | Initialized, 30 | Destructed, 31 | Deallocated, 32 | DeallocatedUninitialized, 33 | } 34 | 35 | unsafe extern "C++" { 36 | include!("cxx_support_test_cpp.h"); 37 | type Foo = super::bindgenish::Foo; 38 | fn foo_create_uninitialized() -> *mut Foo; 39 | unsafe fn foo_free_uninitialized(ptr: *mut Foo); 40 | unsafe fn foo_constructor(_this: *mut Foo); 41 | unsafe fn foo_destructor(_this: *mut Foo); 42 | unsafe fn foo_move(_this: *mut Foo, src: *mut Foo); 43 | 44 | type Bar = super::bindgenish::Bar; 45 | fn bar_create_uninitialized() -> *mut Bar; 46 | unsafe fn bar_free_uninitialized(ptr: *mut Bar); 47 | unsafe fn bar_constructor(_this: *mut Bar); 48 | unsafe fn bar_destructor(_this: *mut Bar); 49 | unsafe fn bar_move(_this: *mut Bar, src: *mut Bar); 50 | 51 | fn GetA(self: &Foo) -> bool; 52 | fn Modify(self: Pin<&mut Foo>); 53 | 54 | fn ResetStatus(); 55 | fn GetStatus() -> Status; 56 | } 57 | // Ensures that cxx creates bindings for UniquePtr 58 | // even though that isn't used in any of the above APIs. 59 | impl UniquePtr {} 60 | impl UniquePtr {} 61 | } 62 | 63 | mod bindgenish { 64 | use std::marker::PhantomData; 65 | use std::marker::PhantomPinned; 66 | use std::mem; 67 | use std::mem::MaybeUninit; 68 | use std::pin::Pin; 69 | 70 | use cxx::kind::Opaque; 71 | use cxx::type_id; 72 | use cxx::ExternType; 73 | 74 | use moveit::MakeCppStorage; 75 | use moveit::MoveNew; 76 | use moveit::New; 77 | 78 | #[repr(C)] 79 | pub struct Foo { 80 | // opaque 81 | _pin: PhantomData, 82 | _data: [u32; 4], 83 | } 84 | 85 | unsafe impl ExternType for Foo { 86 | type Id = type_id!("Foo"); 87 | type Kind = Opaque; 88 | } 89 | 90 | unsafe impl MakeCppStorage for Foo { 91 | unsafe fn allocate_uninitialized_cpp_storage() -> *mut Self { 92 | super::ffi::foo_create_uninitialized() 93 | } 94 | 95 | unsafe fn free_uninitialized_cpp_storage(ptr: *mut Self) { 96 | super::ffi::foo_free_uninitialized(ptr); 97 | } 98 | } 99 | 100 | impl Foo { 101 | pub fn new() -> impl New { 102 | unsafe { 103 | moveit::new::by_raw(|space| { 104 | let space = Pin::into_inner_unchecked(space).as_mut_ptr(); 105 | super::ffi::foo_constructor(space) 106 | }) 107 | } 108 | } 109 | } 110 | 111 | unsafe impl MoveNew for Foo { 112 | unsafe fn move_new( 113 | mut src: Pin>, 114 | this: Pin<&mut MaybeUninit>, 115 | ) { 116 | let src: &mut _ = Pin::into_inner_unchecked(src.as_mut()); 117 | let this = Pin::into_inner_unchecked(this).as_mut_ptr(); 118 | super::ffi::foo_move(this, src); 119 | super::ffi::foo_destructor(src); 120 | } 121 | } 122 | 123 | impl Drop for Foo { 124 | fn drop(&mut self) { 125 | unsafe { super::ffi::foo_destructor(self) }; 126 | } 127 | } 128 | 129 | #[repr(C)] 130 | pub struct Bar { 131 | // opaque 132 | _pin: PhantomData, 133 | _data: [u32; 4], 134 | } 135 | 136 | unsafe impl ExternType for Bar { 137 | type Id = type_id!("Bar"); 138 | type Kind = Opaque; 139 | } 140 | 141 | unsafe impl MakeCppStorage for Bar { 142 | unsafe fn allocate_uninitialized_cpp_storage() -> *mut Self { 143 | super::ffi::bar_create_uninitialized() 144 | } 145 | 146 | unsafe fn free_uninitialized_cpp_storage(ptr: *mut Self) { 147 | super::ffi::bar_free_uninitialized(ptr); 148 | } 149 | } 150 | 151 | impl Bar { 152 | pub fn new() -> impl New { 153 | unsafe { 154 | moveit::new::by_raw(|space| { 155 | let space = Pin::into_inner_unchecked(space).as_mut_ptr(); 156 | super::ffi::bar_constructor(space) 157 | }) 158 | } 159 | } 160 | } 161 | 162 | unsafe impl MoveNew for Bar { 163 | unsafe fn move_new( 164 | mut src: Pin>, 165 | this: Pin<&mut MaybeUninit>, 166 | ) { 167 | let src: &mut _ = Pin::into_inner_unchecked(src.as_mut()); 168 | let this = mem::transmute(this); 169 | super::ffi::bar_move(this, src); 170 | super::ffi::bar_destructor(src); 171 | } 172 | } 173 | 174 | impl Drop for Bar { 175 | fn drop(&mut self) { 176 | unsafe { super::ffi::bar_destructor(self) }; 177 | } 178 | } 179 | } 180 | 181 | /// Queries C++ to find the current state of object lifetimes. 182 | /// Its main purpose is actually to sneakily enforce a mutex such that 183 | /// tests do not run in parallel and corrupt that state. 184 | struct StatusChecker<'a>(MutexGuard<'a, ()>); 185 | 186 | impl<'a> StatusChecker<'a> { 187 | fn new() -> Self { 188 | static MUTEX: OnceCell> = OnceCell::new(); 189 | let guard = MUTEX.get_or_init(|| Mutex::new(())).lock().unwrap(); 190 | ffi::ResetStatus(); 191 | Self(guard) 192 | } 193 | 194 | fn assert_status(&self, expected: ffi::Status) { 195 | assert_eq!(ffi::GetStatus(), expected); 196 | } 197 | } 198 | 199 | #[test] 200 | fn test_stack_emplacement() { 201 | let status_checker = StatusChecker::new(); 202 | { 203 | status_checker.assert_status(ffi::Status::Unallocated); 204 | moveit!(let mut bar = bindgenish::Bar::new()); 205 | status_checker.assert_status(ffi::Status::Initialized); 206 | drop(bar); 207 | } 208 | status_checker.assert_status(ffi::Status::Destructed); 209 | } 210 | 211 | #[test] 212 | fn test_stack_emplacement_complex() { 213 | let status_checker = StatusChecker::new(); 214 | { 215 | status_checker.assert_status(ffi::Status::Unallocated); 216 | moveit!(let mut foo = bindgenish::Foo::new()); 217 | status_checker.assert_status(ffi::Status::Initialized); 218 | assert!(!foo.GetA()); 219 | foo.as_mut().Modify(); 220 | assert!(foo.GetA()); 221 | } 222 | status_checker.assert_status(ffi::Status::Destructed); 223 | } 224 | 225 | #[test] 226 | fn test_box_emplacement() { 227 | let status_checker = StatusChecker::new(); 228 | status_checker.assert_status(ffi::Status::Unallocated); 229 | { 230 | let bar = Box::emplace(bindgenish::Bar::new()); 231 | status_checker.assert_status(ffi::Status::Initialized); 232 | drop(bar); 233 | } 234 | status_checker.assert_status(ffi::Status::Destructed); 235 | } 236 | 237 | #[test] 238 | fn test_box_emplacement_complex() { 239 | let status_checker = StatusChecker::new(); 240 | status_checker.assert_status(ffi::Status::Unallocated); 241 | { 242 | let mut foo = Box::emplace(bindgenish::Foo::new()); 243 | status_checker.assert_status(ffi::Status::Initialized); 244 | assert!(!foo.GetA()); 245 | foo.as_mut().Modify(); 246 | assert!(foo.GetA()); 247 | } 248 | status_checker.assert_status(ffi::Status::Destructed); 249 | } 250 | 251 | #[test] 252 | fn test_unique_ptr_emplacement() { 253 | let status_checker = StatusChecker::new(); 254 | status_checker.assert_status(ffi::Status::Unallocated); 255 | { 256 | let bar = UniquePtr::emplace(bindgenish::Bar::new()); 257 | status_checker.assert_status(ffi::Status::Initialized); 258 | drop(bar); 259 | } 260 | // We have no custom operator delete so the last status 261 | // we record is merely 'destructed' 262 | status_checker.assert_status(ffi::Status::Destructed); 263 | } 264 | 265 | #[test] 266 | fn test_unique_ptr_emplacement_complex() { 267 | let status_checker = StatusChecker::new(); 268 | status_checker.assert_status(ffi::Status::Unallocated); 269 | { 270 | let mut foo = UniquePtr::emplace(bindgenish::Foo::new()); 271 | status_checker.assert_status(ffi::Status::Initialized); 272 | assert!(!foo.GetA()); 273 | foo.pin_mut().Modify(); 274 | assert!(foo.GetA()); 275 | } 276 | status_checker.assert_status(ffi::Status::Deallocated); 277 | } 278 | 279 | #[test] 280 | fn test_move_from_up() { 281 | let status_checker = StatusChecker::new(); 282 | status_checker.assert_status(ffi::Status::Unallocated); 283 | let bar = UniquePtr::emplace(bindgenish::Bar::new()); 284 | status_checker.assert_status(ffi::Status::Initialized); 285 | moveit!(let bar2 = moveit::new::mov(bar)); 286 | // No custom operator::delete for this type 287 | status_checker.assert_status(ffi::Status::DeallocatedUninitialized); 288 | drop(bar2); 289 | status_checker.assert_status(ffi::Status::Destructed); 290 | } 291 | 292 | #[test] 293 | fn test_move_from_up_complex() { 294 | let status_checker = StatusChecker::new(); 295 | status_checker.assert_status(ffi::Status::Unallocated); 296 | let mut foo = UniquePtr::emplace(bindgenish::Foo::new()); 297 | status_checker.assert_status(ffi::Status::Initialized); 298 | assert!(!foo.GetA()); 299 | foo.pin_mut().Modify(); 300 | assert!(foo.GetA()); 301 | moveit!(let mut foo2 = moveit::new::mov(foo)); 302 | // If this line determines the status to be DeallocatedUninitialized, 303 | // we've failed to call the overridden operator delete 304 | status_checker.assert_status(ffi::Status::Deallocated); 305 | assert_eq!(foo2.GetA(), true); 306 | drop(foo2); 307 | status_checker.assert_status(ffi::Status::Destructed); 308 | } 309 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | [toolchain] 16 | channel = "1.68.2" 17 | profile = "default" 18 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 80 2 | tab_spaces = 2 -------------------------------------------------------------------------------- /src/alloc_support.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Support for the `alloc` crate, when available. 16 | 17 | use core::mem::MaybeUninit; 18 | use core::pin::Pin; 19 | 20 | use alloc::boxed::Box; 21 | 22 | use crate::move_ref::MoveRef; 23 | use crate::move_ref::{AsMove, DerefMove}; 24 | use crate::slot::DroppingSlot; 25 | 26 | impl AsMove for Box { 27 | type Storage = Box>; 28 | 29 | #[inline] 30 | fn as_move<'frame>( 31 | self, 32 | storage: DroppingSlot<'frame, Self::Storage>, 33 | ) -> Pin> 34 | where 35 | Self: 'frame, 36 | { 37 | MoveRef::into_pin(self.deref_move(storage)) 38 | } 39 | } 40 | 41 | unsafe impl DerefMove for Box { 42 | #[inline] 43 | fn deref_move<'frame>( 44 | self, 45 | storage: DroppingSlot<'frame, Self::Storage>, 46 | ) -> MoveRef<'frame, Self::Target> 47 | where 48 | Self: 'frame, 49 | { 50 | let cast = 51 | unsafe { Box::from_raw(Box::into_raw(self).cast::>()) }; 52 | 53 | let (storage, drop_flag) = storage.put(cast); 54 | unsafe { MoveRef::new_unchecked(storage.assume_init_mut(), drop_flag) } 55 | } 56 | } 57 | 58 | #[cfg(test)] 59 | mod tests { 60 | use crate::move_ref::test::Immovable; 61 | use crate::moveit; 62 | use crate::new::mov; 63 | use crate::Emplace; 64 | 65 | #[test] 66 | fn test_mov_box() { 67 | let foo = Box::emplace(Immovable::new()); 68 | moveit!(let _foo = mov(foo)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/cxx_support.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Support for `cxx` types. 16 | 17 | use std::mem::MaybeUninit; 18 | use std::pin::Pin; 19 | 20 | use cxx::memory::UniquePtrTarget; 21 | use cxx::UniquePtr; 22 | 23 | use crate::move_ref::AsMove; 24 | use crate::slot::DroppingSlot; 25 | use crate::DerefMove; 26 | use crate::Emplace; 27 | use crate::MoveRef; 28 | use crate::TryNew; 29 | 30 | /// A type which has the ability to create heap storage space 31 | /// for itself in C++, without initializing that storage. 32 | /// 33 | /// # Safety 34 | /// 35 | /// Implementers must ensure that the pointer returned by 36 | /// `allocate_uninitialized_cpp_storage` is a valid, non-null, 37 | /// pointer to a new but uninitialized storage block, and that 38 | /// such blocks must be freeable using either of these routes: 39 | /// 40 | /// * before they're initialized, using `free_uninitialized_cpp_storage` 41 | /// * after they're initialized, via a delete expression like `delete p;` 42 | pub unsafe trait MakeCppStorage: Sized { 43 | /// Allocates heap space for this type in C++ and return a pointer 44 | /// to that space, but do not initialize that space (i.e. do not 45 | /// yet call a constructor). 46 | /// 47 | /// # Safety 48 | /// 49 | /// To avoid memory leaks, callers must ensure that this space is 50 | /// freed using `free_uninitialized_cpp_storage`, or is converted into 51 | /// a [`UniquePtr`] such that it can later be freed by 52 | /// `std::unique_ptr>`. 53 | unsafe fn allocate_uninitialized_cpp_storage() -> *mut Self; 54 | 55 | /// Frees a C++ allocation which has not yet 56 | /// had a constructor called. 57 | /// 58 | /// # Safety 59 | /// 60 | /// Callers guarantee that the pointer here was allocated by 61 | /// `allocate_uninitialized_cpp_storage` and has not been 62 | /// initialized. 63 | unsafe fn free_uninitialized_cpp_storage(ptr: *mut Self); 64 | } 65 | 66 | impl Emplace for UniquePtr { 67 | type Output = Self; 68 | 69 | fn try_emplace>(n: N) -> Result { 70 | unsafe { 71 | let uninit_ptr = T::allocate_uninitialized_cpp_storage(); 72 | let uninit = 73 | Pin::new_unchecked(&mut *(uninit_ptr as *mut MaybeUninit)); 74 | // FIXME - this is not panic safe. 75 | let result = n.try_new(uninit); 76 | if let Err(err) = result { 77 | T::free_uninitialized_cpp_storage(uninit_ptr); 78 | return Err(err); 79 | } 80 | Ok(UniquePtr::from_raw(uninit_ptr)) 81 | } 82 | } 83 | } 84 | 85 | /// This is an implementation detail of the support for moving out of 86 | /// a [`cxx::UniquePtr`]. It stores a raw pointer which points to 87 | /// C++ space which is allocated yet unoccupied, and will arrange to 88 | /// deallocate that if it goes out of scope. 89 | #[doc(hidden)] 90 | pub struct DeallocateSpaceGuard(*mut T); 91 | 92 | impl DeallocateSpaceGuard { 93 | fn assume_init_mut(&mut self) -> &mut T { 94 | unsafe { &mut *self.0 } 95 | } 96 | } 97 | 98 | impl Drop for DeallocateSpaceGuard { 99 | fn drop(&mut self) { 100 | unsafe { T::free_uninitialized_cpp_storage(self.0) }; 101 | } 102 | } 103 | 104 | impl AsMove for UniquePtr 105 | where 106 | T: UniquePtrTarget + MakeCppStorage, 107 | { 108 | type Storage = DeallocateSpaceGuard; 109 | 110 | #[inline] 111 | fn as_move<'frame>( 112 | self, 113 | storage: DroppingSlot<'frame, Self::Storage>, 114 | ) -> Pin> 115 | where 116 | Self: 'frame, 117 | { 118 | let cast = DeallocateSpaceGuard(self.into_raw()); 119 | let (storage, drop_flag) = storage.put(cast); 120 | let this = 121 | unsafe { MoveRef::new_unchecked(storage.assume_init_mut(), drop_flag) }; 122 | MoveRef::into_pin(this) 123 | } 124 | } 125 | 126 | unsafe impl DerefMove for UniquePtr 127 | where 128 | T: MakeCppStorage + UniquePtrTarget, 129 | T: Unpin, 130 | { 131 | #[inline] 132 | fn deref_move<'frame>( 133 | self, 134 | storage: DroppingSlot<'frame, Self::Storage>, 135 | ) -> MoveRef<'frame, Self::Target> 136 | where 137 | Self: 'frame, 138 | { 139 | Pin::into_inner(self.as_move(storage)) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/drop_flag.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Drop flags. 16 | //! 17 | //! The [`Pin

`] guarantees state that if we have a `T` allocated somewhere, 18 | //! and we construct a pinned reference to it such as a `Pin<&'a mut T>`, then 19 | //! before that "somewhere" in memory is reused by another Rust object, `T`'s 20 | //! destructor must run. 21 | //! 22 | //! Normally, this isn't a problem for Rust code, since the storage of an object 23 | //! is destroyed immediately after it is destroyed. [`DerefMove`], however, 24 | //! breaks this expectation: it separates the destructors from its storage and 25 | //! contents into two separately destroyed objects: a [`AsMove::Storage`] and a 26 | //! [`MoveRef`]. If the [`MoveRef`] is [`mem::forget`]'ed, we lose: the storage 27 | //! will potentially be re-used. 28 | //! 29 | //! Therefore, we must somehow detect that [`MoveRef`]s fail to be destroyed 30 | //! when the destructor for the corresponding storage is run, and remediate it, 31 | //! either by leaking heap storage or aborting if we would free stack storage 32 | //! (a panic is insufficient, since that location can be reused if the panic is 33 | //! caught). 34 | //! 35 | //! A [`DropFlag`] allows us to achieve this. It is a generalized, library-level 36 | //! version of the Rust language's drop flags, which it uses to dynamically 37 | //! determine whether to run destructors of stack-allocated values that might 38 | //! have been moved from. Unlike Rust language drop flags, a [`DropFlag`] is 39 | //! actually a counter, rather than a boolean. This allows storage that holds 40 | //! many objects, like a vector, ensure that all contents have been properly 41 | //! destroyed. 42 | //! 43 | //! This module also provides two helper types simplify safe creation and 44 | //! management of drop flags. 45 | //! 46 | //! See the [Rustonomicon entry](https://doc.rust-lang.org/nomicon/drop-flags.html) 47 | //! for the Rust language equivalent. 48 | //! 49 | //! # Safety 50 | //! 51 | //! No function in this module is `unsafe`: instead, functions that construct 52 | //! [`MoveRef`]s out of [`DropFlag`]s are `unsafe`, and their callers are 53 | //! responsible for ensuring that the passed-in [`DropFlag`] helps uphold the 54 | //! relevant invariants. 55 | 56 | use core::cell::Cell; 57 | use core::mem; 58 | use core::mem::ManuallyDrop; 59 | use core::ops::Deref; 60 | use core::ops::DerefMut; 61 | 62 | #[cfg(doc)] 63 | use { 64 | crate::move_ref::{AsMove, DerefMove, MoveRef}, 65 | alloc::boxed::Box, 66 | core::pin::Pin, 67 | }; 68 | 69 | /// A drop flag, for tracking successful destruction. 70 | /// 71 | /// A `DropFlag` is a reference to a counter somewhere on the stack that lives 72 | /// adjacent to storage for some value. It is just a counter: `unsafe` code is 73 | /// expected to associate semantic meaning to it. 74 | /// 75 | /// A flag with a value of zero is usually called "dead", and setting a flag to 76 | /// the dead state is called clearing it. 77 | /// 78 | /// See the [module documentation][self] for more information. 79 | #[derive(Clone, Copy)] 80 | pub struct DropFlag<'frame> { 81 | counter: &'frame Cell, 82 | } 83 | 84 | impl DropFlag<'_> { 85 | /// Increments the internal counter. 86 | /// 87 | /// This function does not provide any overflow protection; `unsafe` code is 88 | /// responsible for making sure that cannot happen. 89 | #[inline] 90 | pub fn inc(self) { 91 | self.counter.set(self.counter.get() + 1) 92 | } 93 | 94 | /// Decrements the internal counter and returns true if it became zero. 95 | /// 96 | /// This function will return `false` if the counter was already zero. 97 | #[inline] 98 | pub fn dec_and_check_if_died(self) -> bool { 99 | if self.counter.get() == 0 { 100 | return false; 101 | } 102 | self.counter.set(self.counter.get() - 1); 103 | self.is_dead() 104 | } 105 | 106 | /// Returns whether the internal counter is zero. 107 | #[inline] 108 | pub fn is_dead(self) -> bool { 109 | self.counter.get() == 0 110 | } 111 | 112 | /// Lengthens the lifetime of `self`. 113 | #[inline] 114 | #[allow(unused)] 115 | pub(crate) unsafe fn longer_lifetime<'a>(self) -> DropFlag<'a> { 116 | DropFlag { 117 | counter: mem::transmute(self.counter), 118 | } 119 | } 120 | } 121 | 122 | /// A wrapper for managing when a value gets dropped via a [`DropFlag`]. 123 | /// 124 | /// This type tracks the destruction state of some value relative to another 125 | /// value via its [`DropFlag`]: for example, it might be the storage of a value 126 | /// wrapped up in a [`MoveRef`]. When a `DroppingFlag` is destroyed, it will 127 | /// run the destructor for the wrapped value if and only if the [`DropFlag`] 128 | /// is dead. 129 | /// 130 | /// This type can be viewed as using a [`DropFlag`] to "complete" a 131 | /// [`ManuallyDrop`] by explicitly tracking whether it has been dropped. The 132 | /// flag can be used to signal whether to destroy or leak the value, but the 133 | /// destruction occurs lazily rather than immediately when the flag is flipped. 134 | /// 135 | /// This is useful as an [`AsMove::Storage`] type for types where the storage 136 | /// should be leaked if the inner type was somehow not destroyed, such as in 137 | /// the case of heap-allocated storage like [`Box`]. 138 | pub struct DroppingFlag { 139 | value: ManuallyDrop, 140 | counter: Cell, 141 | } 142 | 143 | impl DroppingFlag { 144 | /// Wraps a new value to have its drop state managed by a `DropFlag`. 145 | /// 146 | /// The drop flag will start out dead and needs to be manually incremented. 147 | pub fn new(value: T) -> Self { 148 | Self { 149 | value: ManuallyDrop::new(value), 150 | counter: Cell::new(0), 151 | } 152 | } 153 | 154 | /// Gets a reference to the drop flag. 155 | /// 156 | /// This function is safe; the returned reference to the drop flag cannot be 157 | /// used to make a previously dropped value live again. 158 | pub fn flag(slot: &Self) -> DropFlag { 159 | DropFlag { 160 | counter: &slot.counter, 161 | } 162 | } 163 | 164 | /// Splits this slot into a reference to the wrapped value plus a reference to 165 | /// the drop flag. 166 | /// 167 | /// This function is safe; the returned reference to the drop flag cannot be 168 | /// used to make a previously dropped value live again, since the value is 169 | /// not destroyed before the wrapper is. 170 | pub fn as_parts(slot: &Self) -> (&T, DropFlag) { 171 | ( 172 | &slot.value, 173 | DropFlag { 174 | counter: &slot.counter, 175 | }, 176 | ) 177 | } 178 | 179 | /// Splits this slot into a reference to the wrapped value plus a reference to 180 | /// the drop flag. 181 | /// 182 | /// This function is safe; the returned reference to the drop flag cannot be 183 | /// used to make a previously dropped value live again, since the value is 184 | /// not destroyed before the wrapper is. 185 | pub fn as_parts_mut(slot: &mut Self) -> (&mut T, DropFlag) { 186 | ( 187 | &mut slot.value, 188 | DropFlag { 189 | counter: &slot.counter, 190 | }, 191 | ) 192 | } 193 | } 194 | 195 | impl Deref for DroppingFlag { 196 | type Target = T; 197 | #[inline] 198 | fn deref(&self) -> &T { 199 | &self.value 200 | } 201 | } 202 | 203 | impl DerefMut for DroppingFlag { 204 | #[inline] 205 | fn deref_mut(&mut self) -> &mut T { 206 | &mut self.value 207 | } 208 | } 209 | 210 | impl Drop for DroppingFlag { 211 | fn drop(&mut self) { 212 | if Self::flag(self).is_dead() { 213 | unsafe { 214 | ManuallyDrop::drop(&mut self.value); 215 | } 216 | } 217 | } 218 | } 219 | 220 | /// An RAII trap that ensures a drop flag is correctly cleared. 221 | /// 222 | /// This type is *similar* to a [`DroppingFlag`], except that it does not wrap 223 | /// a value and rather than leaking memory aborts the program if its flag is 224 | /// not cleared. 225 | /// 226 | /// This type is useful for safely constructing [`MoveRef`]s. 227 | pub struct TrappedFlag { 228 | counter: Cell, 229 | 230 | // In debug mode, we capture the location the trap is created at, to help 231 | // connect an eventual failure to the matching storage. 232 | #[cfg(debug_assertions)] 233 | location: &'static core::panic::Location<'static>, 234 | } 235 | 236 | impl TrappedFlag { 237 | /// Creates a new trap with a dead flag. 238 | #[cfg(debug_assertions)] 239 | #[track_caller] 240 | pub fn new() -> Self { 241 | Self { 242 | counter: Cell::new(0), 243 | location: core::panic::Location::caller(), 244 | } 245 | } 246 | 247 | /// Creates a new trap with a dead flag. 248 | #[cfg(not(debug_assertions))] 249 | pub fn new() -> Self { 250 | Self { 251 | counter: Cell::new(0), 252 | } 253 | } 254 | 255 | /// Returns a reference to the [`DropFlag`]. 256 | pub fn flag(&self) -> DropFlag { 257 | DropFlag { 258 | counter: &self.counter, 259 | } 260 | } 261 | 262 | /// Preemptively checks that this flag has been cleared. 263 | /// 264 | /// Aborts (rather than panicking!) if the assertion fails. 265 | pub fn assert_cleared(&self) { 266 | if self.flag().is_dead() { 267 | return; 268 | } 269 | 270 | // We can force an abort by triggering a panic mid-unwind. 271 | // This is the only way to force an LLVM abort from inside of `core`. 272 | struct DoublePanic; 273 | impl Drop for DoublePanic { 274 | fn drop(&mut self) { 275 | // In tests, we don't double-panic so that we can observe the 276 | // failure correctly. 277 | if cfg!(not(test)) { 278 | panic!() 279 | } 280 | } 281 | } 282 | 283 | let _dp = DoublePanic; 284 | 285 | #[cfg(debug_assertions)] 286 | panic!("a critical drop flag at {} was not cleared!", self.location); 287 | 288 | #[cfg(not(debug_assertions))] 289 | panic!("a critical drop flag was not cleared!"); 290 | } 291 | } 292 | 293 | impl Default for TrappedFlag { 294 | fn default() -> Self { 295 | Self::new() 296 | } 297 | } 298 | 299 | impl Drop for TrappedFlag { 300 | fn drop(&mut self) { 301 | self.assert_cleared(); 302 | } 303 | } 304 | 305 | /// A [`DropFlag`] source that doesn't do anything with it. 306 | /// 307 | /// This is similar to `TrappedFlag`, but where it does not abort the program 308 | /// if used incorrectly. This type is generally only useful when some separate 309 | /// mechanism is ensuring that invariants are not violated. 310 | pub struct QuietFlag { 311 | counter: Cell, 312 | } 313 | 314 | impl QuietFlag { 315 | /// Creates a new dead flag. 316 | pub fn new() -> Self { 317 | Self { 318 | counter: Cell::new(0), 319 | } 320 | } 321 | 322 | /// Returns a reference to the [`DropFlag`]. 323 | pub fn flag(&self) -> DropFlag { 324 | DropFlag { 325 | counter: &self.counter, 326 | } 327 | } 328 | } 329 | 330 | impl Default for QuietFlag { 331 | fn default() -> Self { 332 | Self::new() 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! A library for safe, in-place construction of Rust (and C++!) objects. 16 | //! 17 | //! # How It Works 18 | //! 19 | //! `moveit` revolves around `unsafe trait`s that impose additional guarantees 20 | //! on `!Unpin` types, such that they can be moved in the C++ sense. There are 21 | //! two senses of "move" frequently used: 22 | //! - The Rust sense, which is a blind memcpy and analogous-ish to the 23 | //! C++ "std::is_trivially_moveable` type-trait. Rust moves also render the 24 | //! moved-from object inaccessible. 25 | //! - The C++ sense, where a move is really like a mutating `Clone` operation, 26 | //! which leave the moved-from value accessible to be destroyed at the end of 27 | //! the scope. 28 | //! 29 | //! C++ also has *constructors*, which are special functions that produce a new 30 | //! value in a particular location. In particular, C++ constructors may assume 31 | //! that the address of `*this` will not change; all C++ objects are effectively 32 | //! pinned and new objects must be constructed using copy or move constructors. 33 | //! 34 | //! The [`New`], [`CopyNew`], and [`MoveNew`] traits bring these concepts 35 | //! into Rust. A [`New`] is like a nilary [`FnOnce`], except that instead of 36 | //! returning its result, it writes it to a `Pin<&mut MaybeUninit>`, which is 37 | //! in the "memory may be repurposed" state described in the 38 | //! [`Pin` documentation] (i.e., either it is freshly allocated or the 39 | //! destructor was recently run). This allows a [`New`] to rely on the 40 | //! pointer's address remaining stable, much like `*this` in C++. 41 | //! 42 | //! Types that implement [`CopyNew`] may be *copy-constructed*: given any 43 | //! pointer to `T: CopyNew`, we can generate a constructor that constructs a 44 | //! new, identical `T` at a designated location. [`MoveNew`] types may be 45 | //! *move-constructed*: given an *owning* pointer (see [`DerefMove`]) to `T`, 46 | //! we can generate a similar constructor, except that it also destroys the 47 | //! `T` and the owning pointer's storage. 48 | //! 49 | //! None of this violates the existing `Pin` guarantees: moving out of a 50 | //! `Pin

` does not perform a move in the Rust sense, but rather in the C++ 51 | //! sense: it mutates through the pinned pointer in a safe manner to construct 52 | //! a new `P::Target`, and then destroys the pointer and its contents. 53 | //! 54 | //! In general, move-constructible types are going to want to be `!Unpin` so 55 | //! that they can be self-referential. Self-referential types are one of the 56 | //! primary motivations for move constructors. 57 | //! 58 | //! # Constructors 59 | //! 60 | //! A constructor is any type that implements [`New`]. Constructors are like 61 | //! closures that have guaranteed RVO, which can be used to construct a 62 | //! self-referential type in-place. To use the example from the `Pin` docs: 63 | //! ``` 64 | //! use std::marker::PhantomPinned; 65 | //! use std::mem::MaybeUninit; 66 | //! use std::pin::Pin; 67 | //! use std::ptr; 68 | //! use std::ptr::NonNull; 69 | //! 70 | //! use moveit::new; 71 | //! use moveit::new::New; 72 | //! use moveit::moveit; 73 | //! 74 | //! // This is a self-referential struct because the slice field points to the 75 | //! // data field. We cannot inform the compiler about that with a normal 76 | //! // reference, as this pattern cannot be described with the usual borrowing 77 | //! // rules. Instead we use a raw pointer, though one which is known not to be 78 | //! // null, as we know it's pointing at the string. 79 | //! struct Unmovable { 80 | //! data: String, 81 | //! slice: NonNull, 82 | //! _pin: PhantomPinned, 83 | //! } 84 | //! 85 | //! impl Unmovable { 86 | //! // Defer construction until the final location is known. 87 | //! fn new(data: String) -> impl New { 88 | //! new::of(Unmovable { 89 | //! data, 90 | //! // We only create the pointer once the data is in place 91 | //! // otherwise it will have already moved before we even started. 92 | //! slice: NonNull::dangling(), 93 | //! _pin: PhantomPinned, 94 | //! }).with(|this| unsafe { 95 | //! let this = this.get_unchecked_mut(); 96 | //! this.slice = NonNull::from(&this.data); 97 | //! }) 98 | //! 99 | //! // It is also possible to use other `new::` helpers, such as 100 | //! // `new::by` and `new::by_raw`, to configure construction behavior. 101 | //! } 102 | //! } 103 | //! 104 | //! // The constructor can't be used directly, and needs to be emplaced. 105 | //! moveit! { 106 | //! let unmoved = Unmovable::new("hello".to_string()); 107 | //! } 108 | //! // The pointer should point to the correct location, 109 | //! // so long as the struct hasn't moved. 110 | //! // Meanwhile, we are free to move the pointer around. 111 | //! # #[allow(unused_mut)] 112 | //! let mut still_unmoved = unmoved; 113 | //! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data)); 114 | //! 115 | //! // Since our type doesn't implement Unpin, this will fail to compile: 116 | //! // let mut new_unmoved = Unmovable::new("world".to_string()); 117 | //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); 118 | //! 119 | //! // However, we can implement `MoveNew` to allow it to be "moved" again. 120 | //! ``` 121 | //! 122 | //! The [`new`] module provides various helpers for making constructors. As a 123 | //! rule, functions which, in Rust, would normally construct and return a value 124 | //! should return `impl New` instead. This is analogous to have `async fn`s and 125 | //! `.iter()` functions work. 126 | //! 127 | //! # Emplacement 128 | //! 129 | //! The example above makes use of the [`moveit!()`] macro, one of many ways to 130 | //! turn a constructor into a value. `moveit` gives you two choices for running 131 | //! a constructor: 132 | //! - On the stack, using the [`MoveRef`] type (this is what [`moveit!()`] 133 | //! generates). 134 | //! - On the heap, using the extension methods from the [`Emplace`] trait. 135 | //! 136 | //! For example, we could have placed the above in a `Box` by writing 137 | //! `Box::emplace(Unmovable::new())`. 138 | //! 139 | //! [`Pin` documentation]: https://doc.rust-lang.org/std/pin/index.html#drop-guarantee 140 | 141 | #![cfg_attr(not(any(test, feature = "cxx")), no_std)] 142 | #![deny(warnings, missing_docs, unused)] 143 | // These clippy lints are somewhat at odds with our use of `new()`. 144 | #![allow(clippy::new_ret_no_self, clippy::wrong_self_convention)] 145 | 146 | #[cfg(feature = "alloc")] 147 | extern crate alloc; 148 | 149 | #[cfg(feature = "alloc")] 150 | mod alloc_support; 151 | 152 | #[cfg(feature = "cxx")] 153 | mod cxx_support; 154 | 155 | pub mod drop_flag; 156 | pub mod move_ref; 157 | pub mod new; 158 | pub mod slot; 159 | 160 | // #[doc(inline)] 161 | pub use crate::{ 162 | move_ref::{AsMove, DerefMove, MoveRef}, 163 | new::{CopyNew, Emplace, MoveNew, New, TryNew}, 164 | slot::Slot, 165 | }; 166 | 167 | #[cfg(feature = "cxx")] 168 | pub use cxx_support::MakeCppStorage; 169 | -------------------------------------------------------------------------------- /src/move_ref.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Move references. 16 | //! 17 | //! A move reference represents an owned value that is stored "somewhere else". 18 | //! We own the value, not the storage. 19 | //! 20 | //! A [`MoveRef<'a, T>`] represents a *permanent* unique reference to `T` for 21 | //! the lifetime `'a`: it is the longest-lived *possible* reference to the 22 | //! pointee, making it closer to a [`Box`] 23 | //! 24 | //! Like [`&mut T`] but unlike [`Box`], a [`MoveRef`] is not responsible 25 | //! for destroying its storage, meaning that it is storage agnostic. The storage 26 | //! might be on the stack *or* on the heap; some RAII value on the stack is 27 | //! responsible for destroying just the storage, once the [`MoveRef`] itself 28 | //! is gone. 29 | //! 30 | //! The main mechanism for obtaining [`MoveRef`]s is the [`moveit!()`] macro, 31 | //! which is analogous to a theoretical `&move expr` operator. This macro 32 | //! wraps [`DerefMove`], much like `&mut expr` wraps [`DerefMut`]. 33 | //! 34 | //! Implementing [`DerefMove`] is a delicate affair; its documentation details 35 | //! exactly how it should be done. 36 | //! 37 | //! # Drop Flags 38 | //! 39 | //! In order to be sound, a `MoveRef` must also hold a pointer to a drop flag, 40 | //! which is used to detect if the `MoveRef` was dropped without destruction. 41 | //! 42 | //! In general, [`mem::forget`]ing a `MoveRef` is a very, very bad idea. In the 43 | //! best case it will leak memory, but in some cases will crash the program in 44 | //! order to observe safety guarantees. 45 | 46 | use core::mem; 47 | use core::ops::Deref; 48 | use core::ops::DerefMut; 49 | use core::pin::Pin; 50 | use core::ptr; 51 | 52 | #[cfg(doc)] 53 | use { 54 | crate::{drop_flag, moveit}, 55 | alloc::{boxed::Box, rc::Rc, sync::Arc}, 56 | core::mem::{ManuallyDrop, MaybeUninit}, 57 | }; 58 | 59 | use crate::drop_flag::DropFlag; 60 | use crate::slot::DroppingSlot; 61 | 62 | /// A `MoveRef<'a, T>` represents an owned `T` whose storage location is valid 63 | /// but unspecified. 64 | /// 65 | /// See [the module documentation][self] for more details. 66 | pub struct MoveRef<'a, T: ?Sized> { 67 | ptr: &'a mut T, 68 | drop_flag: DropFlag<'a>, 69 | } 70 | 71 | impl<'a, T: ?Sized> MoveRef<'a, T> { 72 | /// Creates a new `MoveRef` out of a mutable reference. 73 | /// 74 | /// # Safety 75 | /// 76 | /// `ptr` must satisfy the *longest-lived* criterion: after the return value 77 | /// goes out of scope, `ptr` must also be out-of-scope. Calling this function 78 | /// correctly is non-trivial, and should be left to [`moveit!()`] instead. 79 | /// 80 | /// In particular, if `ptr` outlives the returned `MoveRef`, it will point 81 | /// to dropped memory, which is UB. 82 | /// 83 | /// `drop_flag`'s value must not be dead, and must be a drop flag governing 84 | /// the destruction of `ptr`'s storage in an appropriate manner as described 85 | /// in [`moveit::drop_flag`][crate::drop_flag]. 86 | #[inline] 87 | pub unsafe fn new_unchecked(ptr: &'a mut T, drop_flag: DropFlag<'a>) -> Self { 88 | Self { ptr, drop_flag } 89 | } 90 | 91 | /// Converts a `MoveRef` into a `Pin>`. 92 | /// 93 | /// Because we own the referent, we are entitled to pin it permanently. See 94 | /// [`Box::into_pin()`] for a standard-library equivalent. 95 | #[inline] 96 | pub fn into_pin(this: Self) -> Pin { 97 | unsafe { Pin::new_unchecked(this) } 98 | } 99 | 100 | /// Returns this `MoveRef` as a raw pointer, without creating an 101 | /// intermediate reference. 102 | /// 103 | /// The usual caveats for casting a reference to a pointer apply. 104 | #[inline] 105 | pub fn as_ptr(this: &Self) -> *const T { 106 | this.ptr 107 | } 108 | 109 | /// Returns this `MoveRef` as a raw mutable pointer, without creating an 110 | /// intermediate reference. 111 | /// 112 | /// The usual caveats for casting a reference to a pointer apply. 113 | #[inline] 114 | pub fn as_mut_ptr(this: &mut Self) -> *mut T { 115 | this.ptr 116 | } 117 | 118 | #[allow(unused)] 119 | pub(crate) fn drop_flag(this: &Self) -> DropFlag<'a> { 120 | this.drop_flag 121 | } 122 | } 123 | 124 | // Extremely dangerous casts used by DerefMove below. 125 | impl<'a, T> MoveRef<'a, T> { 126 | /// Consumes `self`, blindly casting the inner pointer to `U`. 127 | pub(crate) unsafe fn cast(mut self) -> MoveRef<'a, U> { 128 | let mr = MoveRef { 129 | ptr: &mut *Self::as_mut_ptr(&mut self).cast(), 130 | drop_flag: self.drop_flag, 131 | }; 132 | mem::forget(self); 133 | mr 134 | } 135 | } 136 | 137 | impl<'a, T> MoveRef<'a, T> { 138 | /// Consume the `MoveRef`, returning the wrapped value. 139 | #[inline] 140 | pub fn into_inner(this: Self) -> T { 141 | unsafe { 142 | let val = ptr::read(this.ptr); 143 | let _ = this.cast::<()>(); 144 | val 145 | } 146 | } 147 | } 148 | 149 | impl Deref for MoveRef<'_, T> { 150 | type Target = T; 151 | 152 | #[inline] 153 | fn deref(&self) -> &Self::Target { 154 | self.ptr 155 | } 156 | } 157 | 158 | impl DerefMut for MoveRef<'_, T> { 159 | #[inline] 160 | fn deref_mut(&mut self) -> &mut Self::Target { 161 | self.ptr 162 | } 163 | } 164 | 165 | impl Drop for MoveRef<'_, T> { 166 | #[inline] 167 | fn drop(&mut self) { 168 | self.drop_flag.dec_and_check_if_died(); 169 | unsafe { ptr::drop_in_place(self.ptr) } 170 | } 171 | } 172 | 173 | impl<'a, T> From> for Pin> { 174 | #[inline] 175 | fn from(x: MoveRef<'a, T>) -> Self { 176 | MoveRef::into_pin(x) 177 | } 178 | } 179 | 180 | /// A trait for getting a pinned [`MoveRef`] for some pointer type `Self`. 181 | /// 182 | /// Conceptually, this trait is similar to [`DerefMove`], except that where 183 | /// [`DerefMove::deref_move`] produces a `MoveRef`, [`AsMove::as_move`] produces a 184 | /// `Pin>`. 185 | /// 186 | /// `DerefMove` can be seen as a refinement of `AsMove` where stronger guarantees about the memory 187 | /// behavior (specifically the Pin-safety) of `Self` are present. 188 | /// 189 | /// Codifying this notion is the fact that `DerefMove` requires that `Self: DerefMut + AsMove`, 190 | /// whereas `AsMove` only requires the weaker constraints of `Self: Deref`. 191 | /// 192 | /// Although `AsMove` is a supertrait of `DerefMove`, but `DerefMove` is *not* a supertrait of 193 | /// `AsMove`, the two traits are nevertheless intended to have their impls for a given type defined 194 | /// together *simultanteously*. 195 | /// 196 | /// It is expected in this situation that the impl for one of the traits will be (trivially) defined 197 | /// in terms of the other, depending on the API for the pointer type `Self` with respect to 198 | /// [`DerefMut`]. 199 | /// 200 | /// For example, the `Box: AsMove` impl is defined in terms of the `Box: DerefMove` impl, 201 | /// because it is always the case that `Box: DerefMut` regardless of whether `T: Unpin`. Hence, 202 | /// `Box: AsMove` simply performs the `Box: DerefMove` operation then subsequently 203 | /// (and trivially) pins the resulting `MoveRef` with [`MoveRef::into_pin`]. 204 | /// 205 | /// On the other hand, the `cxx::UniquePtr: DerefMove` impl is defined in terms of the 206 | /// `UniquePtr: AsMove` impl, because a `cxx::UniquePtr: DerefMut` only if `T: Unpin`. Given 207 | /// that `cxx::UniquePtr` behaves like `Pin>` with respect to `DerefMut`, it is always 208 | /// possible to safely produce a `Pin>`, but *not* always possible to safely produce a 209 | /// `MoveRef`. Hence, when `T: Unpin`, only then `cxx::UniquePtr: DerefMove` is defined, 210 | /// which simply performs the `cxx::UniquePtr: AsMove` operation then subsequently 211 | /// (and trivially) unpins the resulting `Pin>` with [`Pin::into_inner`]. 212 | pub trait AsMove: Deref + Sized { 213 | /// The "pure storage" form of `Self`, which owns the storage but not the 214 | /// pointee. 215 | type Storage: Sized; 216 | 217 | /// Gets a pinned `MoveRef` out of `Self`. 218 | /// 219 | /// This function is best paired with [`moveit!()`]: 220 | /// ``` 221 | /// # use core::pin::Pin; 222 | /// # use moveit::{moveit, slot::DroppingSlot, move_ref::AsMove}; 223 | /// let ptr = Box::pin(5); 224 | /// moveit::slot!(#[dropping] storage); 225 | /// ptr.as_move(storage); 226 | /// ``` 227 | /// Taking a trip through [`moveit!()`] is unavoidable due to the nature of 228 | /// `MoveRef`. 229 | /// 230 | /// Compare with [`Pin::as_mut()`]. 231 | fn as_move<'frame>( 232 | self, 233 | storage: DroppingSlot<'frame, Self::Storage>, 234 | ) -> Pin> 235 | where 236 | Self: 'frame; 237 | } 238 | 239 | impl<'f, T: ?Sized> AsMove for MoveRef<'f, T> { 240 | type Storage = (); 241 | 242 | #[inline] 243 | fn as_move<'frame>( 244 | self, 245 | storage: DroppingSlot<'frame, Self::Storage>, 246 | ) -> Pin> 247 | where 248 | Self: 'frame, 249 | { 250 | MoveRef::into_pin(DerefMove::deref_move(self, storage)) 251 | } 252 | } 253 | 254 | impl AsMove for Pin

{ 255 | type Storage = P::Storage; 256 | 257 | #[inline] 258 | fn as_move<'frame>( 259 | self, 260 | storage: DroppingSlot<'frame, Self::Storage>, 261 | ) -> Pin> 262 | where 263 | Self: 'frame, 264 | { 265 | unsafe { 266 | // SAFETY: 267 | // 268 | // It is safe to unwrap the `Pin` because `deref_move()` must not move out of the actual 269 | // storage, merely shuffle pointers around, and immediately after the call to `deref_move()` 270 | // we repin with `MoveRef::into_pin`, so the `Pin` API invariants are not violated later. 271 | MoveRef::into_pin(P::deref_move(Pin::into_inner_unchecked(self), storage)) 272 | } 273 | } 274 | } 275 | 276 | /// Moving dereference operations. 277 | /// 278 | /// *Note: This trait is intended to be defined in conjunction with [`AsMove`], 279 | /// and there is a subtle interdependency between the two traits. We recommend 280 | /// also reading it's documentation for a better understanding of how these 281 | /// traits fit together.* 282 | /// 283 | /// This trait is the `&move` analogue of [`Deref`], for taking a pointer that 284 | /// is the *sole owner* its pointee and converting it to a [`MoveRef`]. In 285 | /// particular, a pointer type `P` owns its contents if dropping it would cause 286 | /// its pointee's destructor to run. 287 | /// 288 | /// For example: 289 | /// - [`MoveRef`] implements `DerefMove` by definition. 290 | /// - [`Box`] implements `DerefMove`, since it drops the `T` in its 291 | /// destructor. 292 | /// - [`&mut T`] does *not* implement `DerefMove`, because it is 293 | /// necessarily a borrow of a longer-lived, "truly owning" reference. 294 | /// - [`Rc`] and [`Arc`] do *not* implement `DerefMove`, because even 295 | /// though they own their pointees, they are not the *sole* owners. Dropping 296 | /// a reference-counted pointer need not run the destructor if other pointers 297 | /// are still alive. 298 | /// - [`Pin

`] for `P: DerefMove` implements `DerefMove` only when 299 | /// `P::Target: Unpin`, since `DerefMove: DerefMut`. 300 | /// 301 | /// # Principle of Operation 302 | /// 303 | /// Unfortunately, because we don't yet have language support for `&move`, we 304 | /// need to break the implementation into two steps: 305 | /// - Inhibit the "inner destructor" of the pointee, so that the smart pointer 306 | /// is now managing dumb bytes. This is usually accomplished by converting the 307 | /// pointee type to [`MaybeUninit`]. 308 | /// - Extract a [`MoveRef`] out of the "deinitialized" pointer. 309 | /// 310 | /// The first part of this consists of converting the pointer into the 311 | /// "partially deinitialized" form, represented by the type 312 | /// [`AsMove::Storage`]: it is the pointer as "pure storage". 313 | /// 314 | /// This pointer should be placed into the [`DroppingSlot`] passed into 315 | /// `deref_move`, so that it has a fixed lifetime for the duration of the frame 316 | /// that the [`MoveRef`] will exist for. The [`DroppingSlot`] will also provide 317 | /// a drop flag to use to build the returned [`MoveRef`]. 318 | /// 319 | /// The mutable reference returned by the [`DroppingSlot`] should then be 320 | /// converted into a [`MoveRef`]. The end result is that the [`DroppingSlot`] 321 | /// owns the "outer" part of the pointer, while the [`MoveRef`] owns the "inner" 322 | /// part. The `'frame` lifetime enforces the correct destruction order of these 323 | /// two parts, since the [`MoveRef`] borrows the [`DroppingSlot`]. 324 | /// 325 | /// The [`moveit!()`] macro helps by constructing the [`DroppingSlot`] for you. 326 | /// 327 | /// ## Worked Example: [`Box`] 328 | /// 329 | /// To inhibit the inner destructor of [`Box`], we can use `Box>` 330 | /// as [`AsMove::Storage`]. [`MaybeUninit`] is preferred over [`ManuallyDrop`], 331 | /// since it helps avoid otherwise scary aliasing problems with `Box<&mut T>`. 332 | /// 333 | /// The first step is to "cast" `Box` into `Box>` via 334 | /// [`Box::into_raw()`] and [`Box::from_raw()`]. This is then placed into the 335 | /// final storage location using [`DroppingSlot::put()`]. 336 | /// 337 | /// This returns a `&mut Box>` and a [`DropFlag`]; the former is 338 | /// converted into an `&mut T` via [`MaybeUninit::assume_init_mut()`]. 339 | /// 340 | /// Finally, [`MoveRef::new_unchecked()`] is used to combine these into the 341 | /// return value. 342 | /// 343 | /// The first step is safe because we construct a `MoveRef` to reinstate the 344 | /// destructor at the end of the function. The second step is safe because 345 | /// we know, a priori, that the `Box` contains an initialized value. The final 346 | /// step is safe, because we know, a priori, that the `Box` owns its pointee. 347 | /// 348 | /// The use of the drop flag in this way makes it so that dropping the resulting 349 | /// `MoveRef` will leak the storage on the heap, exactly the same way as if we 350 | /// had leaked a `Box`. 351 | /// 352 | /// ## Worked Example: [`MoveRef`] 353 | /// 354 | /// We don't need to inhibit any destructors: we just need to convert a 355 | /// `MoveRef>` into a `MoveRef`, which we can do by using 356 | /// [`MoveRef::into_inner()`]. [`AsMove::Storage`] can be whatever, so we 357 | /// simply choose [`()`] for this; the choice is arbitrary. 358 | /// 359 | /// # Safety 360 | /// 361 | /// Implementing `DerefMove` correctly requires that the uniqueness requirement 362 | /// of [`MoveRef`] is upheld. In particular, the following function *must not* 363 | /// violate memory safety: 364 | /// ``` 365 | /// # use moveit::{DerefMove, MoveRef, moveit}; 366 | /// fn move_out_of

(p: P) -> P::Target 367 | /// where 368 | /// P: DerefMove, 369 | /// P::Target: Sized, 370 | /// { 371 | /// unsafe { 372 | /// // Replace `p` with a move reference into it. 373 | /// moveit!(let p = &move *p); 374 | /// 375 | /// // Move out of `p`. From this point on, the `P::Target` destructor must 376 | /// // run when, and only when, the function's return value goes out of 377 | /// // scope per the usual Rust rules. 378 | /// // 379 | /// // In particular, the original `p` or any pointer it came from must not 380 | /// // run the destructor when they go out of scope, under any circumstance. 381 | /// MoveRef::into_inner(p) 382 | /// } 383 | /// } 384 | /// ``` 385 | /// 386 | /// `deref_move()` must also be `Pin`-safe; even though it does not accept a 387 | /// pinned reference, it must take care to not move its contents at any time. 388 | /// In particular, the implementation of [`AsMove::as_move()`] must be safe by 389 | /// definition. 390 | pub unsafe trait DerefMove: DerefMut + AsMove { 391 | /// Moves out of `self`, producing a [`MoveRef`] that owns its contents. 392 | /// 393 | /// `storage` is a location *somewhere* responsible for rooting the lifetime 394 | /// of `*this`'s storage. The location is unimportant, so long as it outlives 395 | /// the resulting [`MoveRef`], which is enforced by the type signature. 396 | /// 397 | /// [`moveit!()`] provides a convenient syntax for calling this function. 398 | fn deref_move<'frame>( 399 | self, 400 | storage: DroppingSlot<'frame, Self::Storage>, 401 | ) -> MoveRef<'frame, Self::Target> 402 | where 403 | Self: 'frame; 404 | } 405 | 406 | unsafe impl<'a, T: ?Sized> DerefMove for MoveRef<'a, T> { 407 | #[inline] 408 | fn deref_move<'frame>( 409 | self, 410 | _storage: DroppingSlot<'frame, Self::Storage>, 411 | ) -> MoveRef<'frame, Self::Target> 412 | where 413 | Self: 'frame, 414 | { 415 | self 416 | } 417 | } 418 | 419 | /// Note that `DerefMove` cannot be used to move out of a `Pin

` when `P::Target: !Unpin`. 420 | /// ```compile_fail 421 | /// # use crate::{moveit::{Emplace, MoveRef, moveit}}; 422 | /// # use core::{marker::PhantomPinned, pin::Pin}; 423 | /// // Fails to compile because `Box: Deref` and `PhantomPinned: !Unpin`. 424 | /// let ptr: Pin> = Box::emplace(moveit::new::default::()); 425 | /// moveit!(let mref = &move *ptr); 426 | /// 427 | /// // Fails to compile because `MoveRef: Deref` and `PhantomPinned: !Unpin`. 428 | /// moveit! { 429 | /// let mref0: Pin> = moveit::new::default::(); 430 | /// let mref1 = &move *mref0; 431 | /// } 432 | unsafe impl

DerefMove for Pin

433 | where 434 | P: DerefMove, // needed for `AsMove: Pin

` for the call to `Self::as_move` 435 | P::Target: Unpin, // needed for the call to `Pin::into_inner` 436 | { 437 | #[inline] 438 | fn deref_move<'frame>( 439 | self, 440 | storage: DroppingSlot<'frame, Self::Storage>, 441 | ) -> MoveRef<'frame, Self::Target> 442 | where 443 | Self: 'frame, 444 | { 445 | Pin::into_inner(self.as_move(storage)) 446 | } 447 | } 448 | 449 | #[doc(hidden)] 450 | pub mod __macro { 451 | use super::*; 452 | use core::marker::PhantomData; 453 | 454 | /// Type-inference helper for `moveit!`. 455 | pub struct DerefPhantom(PhantomData<*const T>); 456 | impl DerefPhantom { 457 | #[inline] 458 | pub fn new(_: &T) -> Self { 459 | Self(PhantomData) 460 | } 461 | 462 | #[inline] 463 | pub fn deref_move<'frame>( 464 | self, 465 | this: T, 466 | storage: DroppingSlot<'frame, T::Storage>, 467 | ) -> MoveRef<'frame, T::Target> 468 | where 469 | Self: 'frame, 470 | { 471 | T::deref_move(this, storage) 472 | } 473 | } 474 | } 475 | 476 | /// Performs an emplacement operation. 477 | /// 478 | /// This macro allows for three exotic types of `let` bindings: 479 | /// ``` 480 | /// # use moveit::{moveit, new, move_ref::MoveRef}; 481 | /// # use core::pin::Pin; 482 | /// let bx = Box::new(42); 483 | /// 484 | /// moveit! { 485 | /// // Use a `New` to construct a new value in place on the stack. This 486 | /// // produces a value of type `Pin>`. 487 | /// let x = new::default::(); 488 | /// 489 | /// // Move out of an existing `DerefMove` type, such as a `Box`. This has 490 | /// // type `MoveRef<_>`, but can be pinned using `MoveRef::into_pin()`. 491 | /// let y = &move *bx; 492 | /// 493 | /// // Create a `MoveRef` of an existing type on the stack. This also has 494 | /// // type `MoveRef<_>`. 495 | /// let z = &move y; 496 | /// } 497 | /// ``` 498 | /// 499 | /// All three `lets`, including in-place construction, pin to the stack. 500 | /// Consider using something like [`Box::emplace()`] to perform construction on 501 | /// the heap. 502 | /// 503 | /// This macro also has *temporary* forms, where rather than creating a binding, 504 | /// a temporary (which cannot outlive its complete expression) is created: 505 | /// 506 | /// ``` 507 | /// # use moveit::{moveit, new, move_ref::MoveRef}; 508 | /// # use core::pin::Pin; 509 | /// fn do_thing(x: Pin>) { 510 | /// // ... 511 | /// # let _ = x; 512 | /// } 513 | /// 514 | /// do_thing(moveit!(new::of(42))); 515 | /// ``` 516 | /// 517 | /// Note that these bindings cannot outlive the subexpression: 518 | /// ```compile_fail 519 | /// # use moveit::{moveit, new}; 520 | /// let x = moveit!(new::of(42)); 521 | /// let y = *x; // Borrow checker error. 522 | /// ``` 523 | /// 524 | /// [`Box::emplace()`]: crate::new::Emplace::emplace 525 | #[macro_export] 526 | macro_rules! moveit { 527 | (let $name:ident $(: $ty:ty)? = &move *$expr:expr $(; $($rest:tt)*)?) => { 528 | $crate::moveit!(@move $name, $($ty)?, $expr); 529 | $crate::moveit!($($($rest)*)?); 530 | }; 531 | (let mut $name:ident $(: $ty:ty)? = &move *$expr:expr $(; $($rest:tt)*)?) => { 532 | $crate::moveit!(@move(mut) $name, $($ty)?, $expr); 533 | $crate::moveit!($($($rest)*)?); 534 | }; 535 | (let $name:ident $(: $ty:ty)? = &move $expr:expr $(; $($rest:tt)*)?) => { 536 | $crate::moveit!(@put $name, $($ty)?, $expr); 537 | $crate::moveit!($($($rest)*)?); 538 | }; 539 | (let mut $name:ident $(: $ty:ty)? = &move $expr:expr $(; $($rest:tt)*)?) => { 540 | $crate::emplace!(@put(mut) $name, $($ty)?, $expr); 541 | $crate::emplace!($($($rest)*)?); 542 | }; 543 | (let $name:ident $(: $ty:ty)? = $expr:expr $(; $($rest:tt)*)?) => { 544 | $crate::moveit!(@emplace $name, $($ty)?, $expr); 545 | $crate::moveit!($($($rest)*)?); 546 | }; 547 | (let mut $name:ident $(: $ty:ty)? = $expr:expr $(; $($rest:tt)*)?) => { 548 | $crate::moveit!(@emplace(mut) $name, $($ty)?, $expr); 549 | $crate::moveit!($($($rest)*)?); 550 | }; 551 | ($(;)?) => {}; 552 | 553 | (&move *$expr:expr) => { 554 | $crate::move_ref::DerefMove::deref_move( 555 | $expr, $crate::slot!(#[dropping]), 556 | ) 557 | }; 558 | 559 | (&move $expr:expr) => {$crate::slot!().put($expr)}; 560 | ($expr:expr) => {$crate::slot!().emplace($expr)}; 561 | 562 | (@move $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => { 563 | $crate::slot!(#[dropping] storage); 564 | 565 | #[allow(unused_mut)] 566 | let $($mut)? $name $(: $ty)? = $crate::move_ref::DerefMove::deref_move($expr, storage); 567 | }; 568 | (@put $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => { 569 | $crate::slot!(slot); 570 | let $($mut)? $name $(: $ty)? = slot.put($expr); 571 | }; 572 | (@emplace $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => { 573 | $crate::slot!(slot); 574 | let $($mut)? $name $(: $ty)? = slot.emplace($expr); 575 | }; 576 | } 577 | 578 | #[cfg(test)] 579 | pub(crate) mod test { 580 | use crate::new; 581 | use crate::MoveNew; 582 | use crate::New; 583 | 584 | use super::*; 585 | use std::alloc; 586 | use std::alloc::Layout; 587 | use std::marker::PhantomPinned; 588 | use std::mem::MaybeUninit; 589 | 590 | #[test] 591 | fn deref_move_of_move_ref() { 592 | moveit! { 593 | let x: MoveRef> = &move Box::new(5); 594 | let y: MoveRef> = &move *x; 595 | } 596 | let _ = y; 597 | } 598 | 599 | #[test] 600 | fn deref_move_of_box() { 601 | let x = Box::new(5); 602 | moveit!(let y: MoveRef = &move *x); 603 | let _ = y; 604 | } 605 | 606 | #[test] 607 | fn move_ref_into_inner() { 608 | moveit!(let x: MoveRef> = &move Box::new(5)); 609 | let _ = MoveRef::into_inner(x); 610 | } 611 | 612 | #[test] 613 | #[should_panic] 614 | fn unforgettable() { 615 | moveit!(let x: MoveRef = &move 42); 616 | mem::forget(x); 617 | } 618 | 619 | #[test] 620 | #[should_panic] 621 | fn unforgettable_temporary() { 622 | mem::forget(moveit!(&move 42)); 623 | } 624 | 625 | #[test] 626 | fn forgettable_box() { 627 | let mut x = Box::new(5); 628 | 629 | // Save the pointer for later, so that we can free it to make Miri happy. 630 | let ptr = x.as_mut() as *mut i32; 631 | 632 | moveit!(let y: MoveRef = &move *x); 633 | 634 | // This should leak but be otherwise safe. 635 | mem::forget(y); 636 | 637 | // Free the leaked pointer; Miri will notice if this turns out to be a 638 | // double-free. 639 | unsafe { 640 | alloc::dealloc(ptr as *mut u8, Layout::new::()); 641 | } 642 | } 643 | 644 | #[test] 645 | fn forgettable_box_temporary() { 646 | let mut x = Box::new(5); 647 | 648 | // Save the pointer for later, so that we can free it to make Miri happy. 649 | let ptr = x.as_mut() as *mut i32; 650 | 651 | // This should leak but be otherwise safe. 652 | mem::forget(moveit!(&move *x)); 653 | 654 | // Free the leaked pointer; Miri will notice if this turns out to be a 655 | // double-free. 656 | unsafe { 657 | alloc::dealloc(ptr as *mut u8, Layout::new::()); 658 | } 659 | } 660 | 661 | // This type is reused in test code in cxx_support. 662 | #[derive(Default)] 663 | pub(crate) struct Immovable { 664 | _pin: PhantomPinned, 665 | } 666 | 667 | impl Immovable { 668 | pub(crate) fn new() -> impl New { 669 | new::default() 670 | } 671 | } 672 | 673 | unsafe impl MoveNew for Immovable { 674 | unsafe fn move_new( 675 | _src: Pin>, 676 | _this: Pin<&mut MaybeUninit>, 677 | ) { 678 | } 679 | } 680 | 681 | #[test] 682 | fn test_mov() { 683 | moveit! { 684 | let foo = Immovable::new(); 685 | let _foo = new::mov(foo); 686 | } 687 | } 688 | } 689 | -------------------------------------------------------------------------------- /src/new/copy_new.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use core::mem; 16 | use core::mem::MaybeUninit; 17 | use core::ops::Deref; 18 | use core::pin::Pin; 19 | 20 | use crate::new; 21 | use crate::new::New; 22 | 23 | /// A copy constructible type: a destination-aware `Clone`. 24 | /// 25 | /// # Safety 26 | /// 27 | /// After [`CopyNew::copy_new()`] is called: 28 | /// - `this` must have been initialized. 29 | pub unsafe trait CopyNew: Sized { 30 | /// Copy-construct `src` into `this`, effectively re-pinning it at a new 31 | /// location. 32 | /// 33 | /// # Safety 34 | /// 35 | /// The same safety requirements of [`New::new()`] apply. 36 | unsafe fn copy_new(src: &Self, this: Pin<&mut MaybeUninit>); 37 | } 38 | 39 | /// Returns a new `New` that uses a copy constructor. 40 | #[inline] 41 | pub fn copy

(ptr: P) -> impl New 42 | where 43 | P: Deref, 44 | P::Target: CopyNew, 45 | { 46 | unsafe { 47 | new::by_raw(move |this| { 48 | CopyNew::copy_new(&*ptr, this); 49 | 50 | // Because `*ptr` is still intact, we can drop it normally. 51 | mem::drop(ptr) 52 | }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/new/factories.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use core::convert::TryFrom; 16 | use core::convert::TryInto; 17 | use core::marker::PhantomData; 18 | use core::mem::MaybeUninit; 19 | use core::pin::Pin; 20 | 21 | use crate::new::New; 22 | use crate::new::TryNew; 23 | 24 | /// Returns a [`New`] that uses the provided closure for construction. 25 | /// 26 | /// This is the most primitive [`New`]-creation function, and is almost-always 27 | /// preferred over implementing [`New`] directly. 28 | /// 29 | /// # Safety 30 | /// 31 | /// `f` must respect the safety requirements of [`New`], since it is used 32 | /// as an implementation basis. 33 | #[inline] 34 | pub unsafe fn by_raw(f: F) -> impl New 35 | where 36 | F: FnOnce(Pin<&mut MaybeUninit>), 37 | { 38 | struct FnNew { 39 | f: F, 40 | _ph: PhantomData, 41 | } 42 | 43 | unsafe impl New for FnNew 44 | where 45 | F: FnOnce(Pin<&mut MaybeUninit>), 46 | { 47 | type Output = T; 48 | #[inline] 49 | unsafe fn new(self, this: Pin<&mut MaybeUninit>) { 50 | (self.f)(this) 51 | } 52 | } 53 | 54 | FnNew:: { 55 | f, 56 | _ph: PhantomData, 57 | } 58 | } 59 | 60 | /// Returns a [`New`] that uses the provided closure for constructing a 61 | /// `T`. 62 | /// 63 | /// ``` 64 | /// # use moveit::{moveit, new}; 65 | /// moveit! { 66 | /// let x = new::by(|| 21 * 2); 67 | /// } 68 | /// assert_eq!(*x, 42); 69 | /// ``` 70 | #[inline] 71 | pub fn by(f: F) -> impl New 72 | where 73 | F: FnOnce() -> T, 74 | { 75 | unsafe { by_raw(|mut this| this.set(MaybeUninit::new(f()))) } 76 | } 77 | 78 | /// Returns a [`New`] that uses a [`From`] implementation to generate a `T`. 79 | /// 80 | /// ``` 81 | /// # use std::pin::Pin; 82 | /// # use moveit::{moveit, new, MoveRef}; 83 | /// moveit! { 84 | /// let x: Pin> = new::from("foo"); 85 | /// } 86 | /// assert_eq!(*x, "foo"); 87 | /// ``` 88 | #[inline] 89 | pub fn from, U>(val: U) -> impl New { 90 | by(|| val.into()) 91 | } 92 | 93 | /// Returns a [`New`] that simply returns the given value. 94 | /// 95 | /// ``` 96 | /// # use std::pin::Pin; 97 | /// # use moveit::{moveit, new}; 98 | /// moveit! { 99 | /// let x = new::of(42); 100 | /// } 101 | /// assert_eq!(*x, 42); 102 | /// ``` 103 | /// 104 | /// In general, you will almost always want [`from()`]. 105 | #[inline] 106 | pub fn of(val: T) -> impl New { 107 | by(|| val) 108 | } 109 | 110 | /// Returns a [`New`] calls [`Default`] to generate a `T`. 111 | /// 112 | /// ``` 113 | /// # use std::pin::Pin; 114 | /// # use moveit::{moveit, new}; 115 | /// moveit! { 116 | /// let x = new::default::(); 117 | /// } 118 | /// assert_eq!(*x, 0); 119 | /// ``` 120 | #[inline] 121 | pub fn default() -> impl New { 122 | by(Default::default) 123 | } 124 | 125 | /// Returns a [`TryNew`] that uses the provided closure for construction. 126 | /// 127 | /// This is the most primitive [`TryNew`]-creation function, and is 128 | /// almost-always preferred over implementing [`TryNew`] directly. 129 | /// 130 | /// # Safety 131 | /// 132 | /// `f` must respect the safety requirements of [`TryNew`], since it is used 133 | /// as an implementation basis. 134 | #[inline] 135 | pub unsafe fn try_by_raw(f: F) -> impl TryNew 136 | where 137 | F: FnOnce(Pin<&mut MaybeUninit>) -> Result<(), E>, 138 | { 139 | struct FnNew { 140 | f: F, 141 | _ph: PhantomData E>, 142 | } 143 | 144 | unsafe impl TryNew for FnNew 145 | where 146 | F: FnOnce(Pin<&mut MaybeUninit>) -> Result<(), E>, 147 | { 148 | type Output = T; 149 | type Error = E; 150 | #[inline] 151 | unsafe fn try_new( 152 | self, 153 | this: Pin<&mut MaybeUninit>, 154 | ) -> Result<(), E> { 155 | (self.f)(this) 156 | } 157 | } 158 | 159 | FnNew:: { 160 | f, 161 | _ph: PhantomData, 162 | } 163 | } 164 | 165 | /// Returns a [`TryNew`] that uses the provided closure for constructing a 166 | /// `T`. 167 | #[inline] 168 | pub fn try_by(f: F) -> impl TryNew 169 | where 170 | F: FnOnce() -> Result, 171 | { 172 | unsafe { 173 | try_by_raw(|this| { 174 | this.get_unchecked_mut().write(f()?); 175 | Ok(()) 176 | }) 177 | } 178 | } 179 | 180 | /// Returns a [`TryNew`] that uses a `TryFrom` implementation to generate a `T`. 181 | #[inline] 182 | pub fn try_from, U>( 183 | val: U, 184 | ) -> impl TryNew { 185 | try_by(|| val.try_into()) 186 | } 187 | -------------------------------------------------------------------------------- /src/new/impls.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Trivial impls for `std` types. 16 | 17 | use core::mem; 18 | use core::mem::MaybeUninit; 19 | use core::pin::Pin; 20 | 21 | use crate::move_ref::MoveRef; 22 | use crate::new::CopyNew; 23 | use crate::new::MoveNew; 24 | use crate::new::Swap; 25 | 26 | macro_rules! trivial_move { 27 | ($($ty:ty $(where [$($targs:tt)*])?),* $(,)?) => {$( 28 | unsafe impl<$($($targs)*)?> MoveNew for $ty { 29 | unsafe fn move_new( 30 | src: Pin>, 31 | this: Pin<&mut MaybeUninit>, 32 | ) { 33 | let src = Pin::into_inner_unchecked(src); 34 | let this = Pin::into_inner_unchecked(this); 35 | this.write(MoveRef::into_inner(src)); 36 | } 37 | } 38 | 39 | impl<$($($targs)*)?> Swap for $ty { 40 | fn swap_with(self: Pin<&mut Self>, that: Pin<&mut Self>) { 41 | unsafe { 42 | let zelf = Pin::into_inner_unchecked(self); 43 | let that = Pin::into_inner_unchecked(that); 44 | mem::swap(zelf, that); 45 | } 46 | } 47 | } 48 | )*} 49 | } 50 | 51 | macro_rules! trivial_copy { 52 | ($($ty:ty $(where [$($targs:tt)*])?),* $(,)?) => {$( 53 | unsafe impl<$($($targs)*)?> MoveNew for $ty { 54 | unsafe fn move_new( 55 | src: Pin>, 56 | this: Pin<&mut MaybeUninit>, 57 | ) { 58 | let src = Pin::into_inner_unchecked(src); 59 | let this = Pin::into_inner_unchecked(this); 60 | this.write(MoveRef::into_inner(src)); 61 | } 62 | } 63 | 64 | impl<$($($targs)*)?> Swap for $ty { 65 | fn swap_with(self: Pin<&mut Self>, that: Pin<&mut Self>) { 66 | unsafe { 67 | let zelf = Pin::into_inner_unchecked(self); 68 | let that = Pin::into_inner_unchecked(that); 69 | mem::swap(zelf, that); 70 | } 71 | } 72 | } 73 | 74 | unsafe impl<$($($targs)*)?> CopyNew for $ty where Self: Clone { 75 | unsafe fn copy_new( 76 | src: &Self, 77 | this: Pin<&mut MaybeUninit>, 78 | ) { 79 | let this = Pin::into_inner_unchecked(this); 80 | this.write(src.clone()); 81 | } 82 | } 83 | )*} 84 | } 85 | 86 | trivial_move! { 87 | &mut T where [T: ?Sized], 88 | 89 | core::sync::atomic::AtomicI8, 90 | core::sync::atomic::AtomicI16, 91 | core::sync::atomic::AtomicI32, 92 | core::sync::atomic::AtomicI64, 93 | core::sync::atomic::AtomicIsize, 94 | core::sync::atomic::AtomicU8, 95 | core::sync::atomic::AtomicU16, 96 | core::sync::atomic::AtomicU32, 97 | core::sync::atomic::AtomicU64, 98 | core::sync::atomic::AtomicUsize, 99 | core::sync::atomic::AtomicPtr where [T], 100 | } 101 | 102 | trivial_copy! { 103 | (), char, bool, 104 | i8, i16, i32, i64, i128, isize, 105 | u8, u16, u32, u64, u128, usize, 106 | 107 | &T where [T: ?Sized], 108 | *const T where [T: ?Sized], 109 | *mut T where [T: ?Sized], 110 | 111 | core::alloc::Layout, 112 | 113 | core::cell::UnsafeCell where [T], 114 | core::cell::Cell where [T], 115 | core::cell::RefCell where [T], 116 | core::cell::Ref<'_, T> where [T], 117 | core::cell::RefMut<'_, T> where [T], 118 | 119 | core::marker::PhantomData where [T: ?Sized], 120 | core::marker::PhantomPinned, 121 | 122 | core::mem::Discriminant where [T], 123 | core::mem::ManuallyDrop where [T], 124 | core::mem::MaybeUninit where [T], 125 | 126 | core::num::NonZeroI8, 127 | core::num::NonZeroI16, 128 | core::num::NonZeroI32, 129 | core::num::NonZeroI64, 130 | core::num::NonZeroI128, 131 | core::num::NonZeroIsize, 132 | core::num::NonZeroU8, 133 | core::num::NonZeroU16, 134 | core::num::NonZeroU32, 135 | core::num::NonZeroU64, 136 | core::num::NonZeroU128, 137 | core::num::NonZeroUsize, 138 | core::num::Wrapping where [T], 139 | 140 | core::option::Option where [T], 141 | 142 | core::pin::Pin where [T], 143 | core::ptr::NonNull where [T], 144 | 145 | core::result::Result where [T, E], 146 | 147 | core::time::Duration, 148 | } 149 | 150 | #[cfg(feature = "alloc")] 151 | trivial_copy! { 152 | alloc::boxed::Box where [T], 153 | 154 | alloc::collections::binary_heap::BinaryHeap where [T], 155 | alloc::collections::btree_map::BTreeMap where [K, V], 156 | alloc::collections::btree_set::BTreeSet where [T], 157 | alloc::collections::linked_list::LinkedList where [T], 158 | alloc::collections::vec_deque::VecDeque where [T], 159 | 160 | alloc::rc::Rc where [T], 161 | alloc::rc::Weak where [T], 162 | alloc::sync::Arc where [T], 163 | alloc::sync::Weak where [T], 164 | 165 | alloc::string::String, 166 | alloc::vec::Vec where [T], 167 | } 168 | -------------------------------------------------------------------------------- /src/new/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! In-place constructors. 16 | //! 17 | //! This module provides a range of helpers such as [`new::by()`] and 18 | //! [`new::from()`] for creating constructors. It is preferred style to 19 | //! `use moveit::new;` and refer to these helpers with a `new::` prefix. 20 | 21 | use core::convert::Infallible; 22 | use core::mem::MaybeUninit; 23 | use core::ops::Deref; 24 | use core::pin::Pin; 25 | 26 | #[cfg(doc)] 27 | use {crate::new, core::ops::DerefMut}; 28 | 29 | use alloc::{boxed::Box, rc::Rc, sync::Arc}; 30 | 31 | mod copy_new; 32 | mod factories; 33 | mod move_new; 34 | 35 | mod impls; 36 | 37 | pub use copy_new::*; 38 | pub use factories::*; 39 | pub use move_new::*; 40 | 41 | /// An in-place constructor for a particular type. 42 | /// 43 | /// # Safety 44 | /// 45 | /// [`New::new()`] must leave its destination argument in a valid, initialized 46 | /// state. 47 | #[must_use = "`New`s do nothing until emplaced into storage"] 48 | pub unsafe trait New: Sized { 49 | /// The type to construct. 50 | type Output; 51 | /// Construct a new value using the arguments stored in `self`. 52 | /// 53 | /// # Safety 54 | /// 55 | /// `this` must be freshly-created memory; this function must not 56 | /// be used to mutate a previously-pinned pointer that has had `self: Pin` 57 | /// functions called on it. 58 | unsafe fn new(self, this: Pin<&mut MaybeUninit>); 59 | 60 | /// Adds a post-construction operation. 61 | /// 62 | /// This function wraps `self` in an another [`New`] type which will call 63 | /// `post` once the main emplacement operation is complete. This is most 64 | /// useful for the case where creation of the value itself does not depend 65 | /// on the final address, but where some address-sensitive setup may want 66 | /// to occur; this can help minimize the scope (or even need for) `unsafe`. 67 | /// 68 | /// This function is best combined with other helpers: 69 | /// 70 | /// ``` 71 | /// # use moveit::{new, moveit, New}; 72 | /// # use std::pin::Pin; 73 | /// pub struct MyType { /* ... */ } 74 | /// 75 | /// impl MyType { 76 | /// pub fn new() -> impl New { 77 | /// new::of(MyType { /* ... */ }).with(|this| { 78 | /// // Address-sensitive setup can occur here. 79 | /// }) 80 | /// } 81 | /// } 82 | /// ``` 83 | /// 84 | /// Note: The return value of this function should not be relied upon; a 85 | /// future version will replace it with `impl New`. 86 | fn with(self, post: F) -> With 87 | where 88 | F: FnOnce(Pin<&mut Self::Output>), 89 | { 90 | With(self, post) 91 | } 92 | } 93 | 94 | /// An in-place constructor for a particular type, which can potentially fail. 95 | /// 96 | /// Emplacing a `TryNew` may allocate even when construction fails; prefer to 97 | /// use `Result` when possible, instead. 98 | /// 99 | /// # Safety 100 | /// 101 | /// [`TryNew::try_new()`] must leave its destination argument in a valid, 102 | /// initialized state when it returns `Ok`. 103 | #[must_use = "`New`s do nothing until emplaced into storage"] 104 | pub unsafe trait TryNew: Sized { 105 | /// The type to construct. 106 | type Output; 107 | /// The error the construction operation may return. 108 | type Error; 109 | /// Try to construct a new value using the arguments stored in `self`. 110 | /// 111 | /// # Safety 112 | /// 113 | /// `this` must be freshly-created memory; this function must not 114 | /// be used to mutate a previously-pinned pointer that has had `self: Pin` 115 | /// functions called on it. 116 | unsafe fn try_new( 117 | self, 118 | this: Pin<&mut MaybeUninit>, 119 | ) -> Result<(), Self::Error>; 120 | 121 | /// Adds a post-construction operation. 122 | /// 123 | /// This function is analogous to [`New::with()`]; see its documentation for 124 | /// more information. 125 | /// 126 | /// Note: The return value of this function should not be relied upon; a 127 | /// future version will replace it with `impl TryNew`. 128 | fn with(self, post: F) -> TryWith { 129 | TryWith(self, post) 130 | } 131 | } 132 | 133 | unsafe impl TryNew for N { 134 | type Output = N::Output; 135 | type Error = Infallible; 136 | unsafe fn try_new( 137 | self, 138 | this: Pin<&mut MaybeUninit>, 139 | ) -> Result<(), Self::Error> { 140 | self.new(this); 141 | Ok(()) 142 | } 143 | } 144 | 145 | /// A pointer type that may be "emplaced" as a stable address which a [`New`] may be used to 146 | /// construct a value with. 147 | /// 148 | /// The `Emplace::Output` type is usually either `Self` or `Pin` depending on the API of 149 | /// `Self` with respect to [`DerefMut`]. 150 | /// 151 | /// For example, `Arc`, `Box`, and `Rc` are all `Emplace>`. 152 | /// 153 | /// However, `cxx::UniquePtr: Emplace`, since `cxx::UniquePtr` already only 154 | /// allows obtaining pinned mutable references to `T` due to its more restrictive API, and hence 155 | /// `cxx::UniquePtr` does not need to be pinned itself. 156 | pub trait Emplace: Sized + Deref { 157 | /// The stable address type within which a value of type `T` is emplaced. 158 | type Output: Deref; 159 | 160 | /// Constructs a new smart pointer and emplaces `n` into its storage. 161 | fn emplace>(n: N) -> Self::Output { 162 | match Self::try_emplace(n) { 163 | Ok(x) => x, 164 | Err(e) => match e {}, 165 | } 166 | } 167 | 168 | /// Constructs a new smart pointer and tries to emplace `n` into its storage. 169 | fn try_emplace>(n: N) 170 | -> Result; 171 | } 172 | 173 | impl Emplace for Box { 174 | type Output = Pin; 175 | 176 | fn try_emplace>( 177 | n: N, 178 | ) -> Result { 179 | let mut uninit = Box::new(MaybeUninit::::uninit()); 180 | unsafe { 181 | let pinned = Pin::new_unchecked(&mut *uninit); 182 | n.try_new(pinned)?; 183 | Ok(Pin::new_unchecked(Box::from_raw( 184 | Box::into_raw(uninit).cast::(), 185 | ))) 186 | } 187 | } 188 | } 189 | 190 | impl Emplace for Rc { 191 | type Output = Pin; 192 | 193 | fn try_emplace>( 194 | n: N, 195 | ) -> Result { 196 | let uninit = Rc::new(MaybeUninit::::uninit()); 197 | unsafe { 198 | let pinned = Pin::new_unchecked(&mut *(Rc::as_ptr(&uninit) as *mut _)); 199 | n.try_new(pinned)?; 200 | Ok(Pin::new_unchecked(Rc::from_raw( 201 | Rc::into_raw(uninit).cast::(), 202 | ))) 203 | } 204 | } 205 | } 206 | 207 | impl Emplace for Arc { 208 | type Output = Pin; 209 | 210 | fn try_emplace>( 211 | n: N, 212 | ) -> Result { 213 | let uninit = Arc::new(MaybeUninit::::uninit()); 214 | unsafe { 215 | let pinned = Pin::new_unchecked(&mut *(Arc::as_ptr(&uninit) as *mut _)); 216 | n.try_new(pinned)?; 217 | Ok(Pin::new_unchecked(Arc::from_raw( 218 | Arc::into_raw(uninit).cast::(), 219 | ))) 220 | } 221 | } 222 | } 223 | 224 | #[doc(hidden)] 225 | pub struct With(N, F); 226 | 227 | unsafe impl New for With 228 | where 229 | F: FnOnce(Pin<&mut N::Output>), 230 | { 231 | type Output = N::Output; 232 | #[inline] 233 | unsafe fn new(self, mut this: Pin<&mut MaybeUninit>) { 234 | self.0.new(this.as_mut()); 235 | // Now that `new()` has returned, we can assume `this` is initialized. 236 | let this = this.map_unchecked_mut(|x| x.assume_init_mut()); 237 | (self.1)(this) 238 | } 239 | } 240 | 241 | #[doc(hidden)] 242 | pub struct TryWith(N, F); 243 | 244 | unsafe impl TryNew for TryWith 245 | where 246 | F: FnOnce(Pin<&mut N::Output>) -> Result<(), N::Error>, 247 | { 248 | type Output = N::Output; 249 | type Error = N::Error; 250 | #[inline] 251 | unsafe fn try_new( 252 | self, 253 | mut this: Pin<&mut MaybeUninit>, 254 | ) -> Result<(), Self::Error> { 255 | self.0.try_new(this.as_mut())?; 256 | // Now that `new()` has returned, we can assume `this` is initialized. 257 | let this = this.map_unchecked_mut(|x| x.assume_init_mut()); 258 | (self.1)(this) 259 | } 260 | } 261 | 262 | /// A swappable type, which is able to efficiently swap the contents of two of 263 | /// its values. 264 | /// 265 | /// Unlike [`New`], `Swap` is safe, because it does not impose any requirements 266 | /// on the swapped pointers. 267 | /// 268 | /// It is possible to implement swapping with a source type that isn't `Self`. 269 | pub trait Swap { 270 | /// Swaps the contents of `self` and `src` without running any destructors. 271 | fn swap_with(self: Pin<&mut Self>, src: Pin<&mut Rhs>); 272 | } 273 | -------------------------------------------------------------------------------- /src/new/move_new.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use core::mem::MaybeUninit; 16 | use core::pin::Pin; 17 | 18 | use crate::move_ref::AsMove; 19 | use crate::move_ref::MoveRef; 20 | use crate::new; 21 | use crate::new::New; 22 | use crate::slot; 23 | 24 | /// A move constructible type: a destination-aware `Clone` that destroys the 25 | /// moved-from value. 26 | /// 27 | /// # Safety 28 | /// 29 | /// After [`MoveNew::move_new()`] is called: 30 | /// - `src` should be treated as having been destroyed. 31 | /// - `this` must have been initialized. 32 | pub unsafe trait MoveNew: Sized { 33 | /// Move-construct `src` into `this`, effectively re-pinning it at a new 34 | /// location. 35 | /// 36 | /// # Safety 37 | /// 38 | /// The same safety requirements of [`New::new()`] apply, but, in addition, 39 | /// `*src` must not be used after this function is called, because it has 40 | /// effectively been destroyed. 41 | unsafe fn move_new( 42 | src: Pin>, 43 | this: Pin<&mut MaybeUninit>, 44 | ); 45 | } 46 | 47 | /// Returns a [`New`] that forwards to [`MoveNew`]. 48 | /// 49 | /// ``` 50 | /// # use moveit::{MoveRef, moveit, new}; 51 | /// let foo = Box::new(42); 52 | /// moveit! { 53 | /// let bar = &move foo; 54 | /// let baz = new::mov(bar); 55 | /// } 56 | /// ``` 57 | #[inline] 58 | pub fn mov

(ptr: P) -> impl New 59 | where 60 | P: AsMove, 61 | P::Target: MoveNew, 62 | { 63 | unsafe { 64 | new::by_raw(move |this| { 65 | MoveNew::move_new(ptr.as_move(slot!(#[dropping])), this); 66 | }) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/slot.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Explicit stack slots, which can be used for stack emplacement. 16 | //! 17 | //! A [`Slot`] is uninitialized storage on the stack that can be manipulated 18 | //! explicitly. Notionally, a [`Slot`] represents a `let x: T;` in some 19 | //! function's stack. 20 | //! 21 | //! [`Slot`]s mut be created with the [`slot!()`] macro: 22 | //! ``` 23 | //! # use moveit::{slot}; 24 | //! slot!(storage); 25 | //! let mut x = storage.put(42); 26 | //! *x /= 2; 27 | //! assert_eq!(*x, 21); 28 | //! ``` 29 | //! Unfortunately, due to the constrains of Rust today, it is not possible to 30 | //! produce a [`Slot`] as part of a larger expression; since it needs to expand 31 | //! to a `let` to bind the stack location, [`slot!()`] must be a statement, not 32 | //! an expression. 33 | //! 34 | //! [`Slot`]s can also be used to implement a sort of "guaranteed RVO": 35 | //! ``` 36 | //! # use moveit::{slot, Slot, move_ref::MoveRef}; 37 | //! fn returns_on_the_stack(val: i32, storage: Slot) -> Option> { 38 | //! if val == 0 { 39 | //! return None 40 | //! } 41 | //! Some(storage.put(val)) 42 | //! } 43 | //! 44 | //! slot!(storage); 45 | //! let val = returns_on_the_stack(42, storage); 46 | //! assert_eq!(*val.unwrap(), 42); 47 | //! ``` 48 | //! 49 | //! [`Slot`]s provide a natural location for emplacing values on the stack. 50 | //! The [`moveit!()`] macro is intended to make this operation 51 | //! straight-forward. 52 | //! 53 | //! # [`DroppingSlot`] 54 | //! 55 | //! [`DroppingSlot`] is a support type similar to [`Slot`] that is used for 56 | //! implementing [`DerefMove`], but which users should otherwise not construct 57 | //! themselves (despite it being otherwise perfectly safe to do so). 58 | 59 | use core::mem; 60 | use core::mem::MaybeUninit; 61 | use core::pin::Pin; 62 | use core::ptr; 63 | 64 | use crate::drop_flag::DropFlag; 65 | use crate::move_ref::MoveRef; 66 | use crate::new; 67 | use crate::new::New; 68 | use crate::new::TryNew; 69 | 70 | #[cfg(doc)] 71 | use { 72 | crate::{move_ref::DerefMove, moveit, slot}, 73 | alloc::boxed::Box, 74 | }; 75 | 76 | /// An empty slot on the stack into which a value could be emplaced. 77 | /// 78 | /// The `'frame` lifetime refers to the lifetime of the stack frame this 79 | /// `Slot`'s storage is allocated on. 80 | /// 81 | /// See [`slot!()`] and [the module documentation][self]. 82 | pub struct Slot<'frame, T> { 83 | ptr: &'frame mut MaybeUninit, 84 | drop_flag: DropFlag<'frame>, 85 | } 86 | 87 | impl<'frame, T> Slot<'frame, T> { 88 | /// Creates a new `Slot` with the given pointer as its basis. 89 | /// 90 | /// To safely construct a `Slot`, use [`slot!()`]. 91 | /// 92 | /// # Safety 93 | /// 94 | /// `ptr` must not be outlived by any other pointers to its allocation. 95 | /// 96 | /// `drop_flag`'s value must be dead, and must be a drop flag governing 97 | /// the destruction of `ptr`'s storage in an appropriate manner as described 98 | /// in [`moveit::drop_flag`][crate::drop_flag]. 99 | pub unsafe fn new_unchecked( 100 | ptr: &'frame mut MaybeUninit, 101 | drop_flag: DropFlag<'frame>, 102 | ) -> Self { 103 | Self { ptr, drop_flag } 104 | } 105 | 106 | /// Put `val` into this slot, returning a new [`MoveRef`]. 107 | pub fn put(self, val: T) -> MoveRef<'frame, T> { 108 | unsafe { 109 | // SAFETY: Pinning is conserved by this operation. 110 | Pin::into_inner_unchecked(self.pin(val)) 111 | } 112 | } 113 | 114 | /// Pin `val` into this slot, returning a new, pinned [`MoveRef`]. 115 | pub fn pin(self, val: T) -> Pin> { 116 | self.emplace(new::of(val)) 117 | } 118 | 119 | /// Emplace `new` into this slot, returning a new, pinned [`MoveRef`]. 120 | pub fn emplace>(self, new: N) -> Pin> { 121 | match self.try_emplace(new) { 122 | Ok(x) => x, 123 | Err(e) => match e {}, 124 | } 125 | } 126 | 127 | /// Try to emplace `new` into this slot, returning a new, pinned [`MoveRef`]. 128 | pub fn try_emplace>( 129 | self, 130 | new: N, 131 | ) -> Result>, N::Error> { 132 | unsafe { 133 | self.drop_flag.inc(); 134 | new.try_new(Pin::new_unchecked(self.ptr))?; 135 | Ok(MoveRef::into_pin(MoveRef::new_unchecked( 136 | self.ptr.assume_init_mut(), 137 | self.drop_flag, 138 | ))) 139 | } 140 | } 141 | 142 | /// Converts this into a slot for a pinned `T`. 143 | /// 144 | /// This is safe, since this `Slot` owns the referenced data, and 145 | /// `Pin` is explicitly a `repr(transparent)` type. 146 | pub fn into_pinned(self) -> Slot<'frame, Pin> { 147 | unsafe { self.cast() } 148 | } 149 | 150 | /// Converts this `Slot` from being a slot for a `T` to being a slot for 151 | /// some other type `U`. 152 | /// 153 | /// ``` 154 | /// # use moveit::{Slot, MoveRef}; 155 | /// moveit::slot!(place: u32); 156 | /// let foo: MoveRef = unsafe { place.cast::() }.put(42); 157 | /// ``` 158 | /// 159 | /// # Safety 160 | /// 161 | /// `T` must have at least the size and alignment as `U`. 162 | pub unsafe fn cast(self) -> Slot<'frame, U> { 163 | debug_assert!(mem::size_of::() >= mem::size_of::()); 164 | debug_assert!(mem::align_of::() >= mem::align_of::()); 165 | Slot { 166 | ptr: &mut *self.ptr.as_mut_ptr().cast(), 167 | drop_flag: self.drop_flag, 168 | } 169 | } 170 | } 171 | 172 | impl<'frame, T> Slot<'frame, Pin> { 173 | /// Converts this into a slot for an unpinned `T`. 174 | /// 175 | /// This is safe, since this `Slot` owns the referenced data, and 176 | /// `Pin` is explicitly a `repr(transparent)` type. 177 | /// 178 | /// Moreover, no actual unpinning is occurring: the referenced data must 179 | /// be uninitialized, so it cannot have a pinned referent. 180 | pub fn into_unpinned(self) -> Slot<'frame, T> { 181 | unsafe { self.cast() } 182 | } 183 | } 184 | 185 | /// Similar to a [`Slot`], but able to drop its contents. 186 | /// 187 | /// A `DroppingSlot` wraps a [`Slot`], and will drop its contents if the 188 | /// [`Slot`]'s drop flag is dead at the time of the `DroppingSlot`'s 189 | /// destruction. 190 | /// 191 | /// This type has an API similar to [`Slot`]'s, but rather than returning 192 | /// `MoveRef`s, which would own the contents of this slot, we return a `&mut T` 193 | /// and a [`DropFlag`], which the caller can assemble into an 194 | /// appropriately-shaped `MoveRef`. The drop flag will be one decrement away 195 | /// from being dead; callers should make sure to decremement it to trigger 196 | /// destruction. 197 | /// 198 | /// `DroppingSlot` is intended to be used with [`DerefMove::deref_move()`], 199 | /// and will usually not be created by `moveit`'s users. However, [`slot!()`] 200 | /// provides `DroppingSlot` support, too. These slots will silently forget their 201 | /// contents if the drop flag is left untouched, rather than crash. 202 | pub struct DroppingSlot<'frame, T> { 203 | ptr: &'frame mut MaybeUninit, 204 | drop_flag: DropFlag<'frame>, 205 | } 206 | 207 | impl<'frame, T> DroppingSlot<'frame, T> { 208 | /// Creates a new `DroppingSlot` with the given pointer as its basis. 209 | /// 210 | /// To safely construct a `DroppingSlot`, use [`slot!()`]. 211 | /// 212 | /// # Safety 213 | /// 214 | /// `ptr` must not be outlived by any other pointers to its allocation. 215 | /// 216 | /// `drop_flag`'s value must be dead, and must be a drop flag governing 217 | /// the destruction of `ptr`'s storage in an appropriate manner as described 218 | /// in [`moveit::drop_flag`][crate::drop_flag]. 219 | pub unsafe fn new_unchecked( 220 | ptr: &'frame mut MaybeUninit, 221 | drop_flag: DropFlag<'frame>, 222 | ) -> Self { 223 | drop_flag.inc(); 224 | Self { ptr, drop_flag } 225 | } 226 | 227 | /// Put `val` into this slot, returning a reference to it. 228 | pub fn put(self, val: T) -> (&'frame mut T, DropFlag<'frame>) { 229 | ({ self.ptr }.write(val), self.drop_flag) 230 | } 231 | 232 | /// Pin `val` into this slot, returning a reference to it. 233 | /// 234 | /// # Safety 235 | /// 236 | /// This function pins the memory this slot wraps, but does not guarantee its 237 | /// destructor is run; that is the caller's responsibility, by decrementing 238 | /// the given [`DropFlag`]. 239 | pub unsafe fn pin(self, val: T) -> (Pin<&'frame mut T>, DropFlag<'frame>) { 240 | self.emplace(new::of(val)) 241 | } 242 | 243 | /// Emplace `new` into this slot, returning a reference to it. 244 | /// 245 | /// # Safety 246 | /// 247 | /// This function pins the memory this slot wraps, but does not guarantee its 248 | /// destructor is run; that is the caller's responsibility, by decrementing 249 | /// the given [`DropFlag`]. 250 | pub unsafe fn emplace>( 251 | self, 252 | new: N, 253 | ) -> (Pin<&'frame mut T>, DropFlag<'frame>) { 254 | match self.try_emplace(new) { 255 | Ok((x, d)) => (x, d), 256 | Err(e) => match e {}, 257 | } 258 | } 259 | 260 | /// Try to emplace `new` into this slot, returning a reference to it. 261 | /// 262 | /// # Safety 263 | /// 264 | /// This function pins the memory this slot wraps, but does not guarantee its 265 | /// destructor is run; that is the caller's responsibility, by decrementing 266 | /// the given [`DropFlag`]. 267 | pub unsafe fn try_emplace>( 268 | self, 269 | new: N, 270 | ) -> Result<(Pin<&'frame mut T>, DropFlag<'frame>), N::Error> { 271 | self.drop_flag.inc(); 272 | new.try_new(Pin::new_unchecked(self.ptr))?; 273 | Ok(( 274 | Pin::new_unchecked(self.ptr.assume_init_mut()), 275 | self.drop_flag, 276 | )) 277 | } 278 | } 279 | 280 | #[doc(hidden)] 281 | #[allow(missing_docs)] 282 | pub mod __macro { 283 | use super::*; 284 | use crate::drop_flag::QuietFlag; 285 | pub use core; 286 | 287 | pub struct SlotDropper { 288 | val: MaybeUninit, 289 | drop_flag: QuietFlag, 290 | } 291 | 292 | impl SlotDropper { 293 | #[allow(clippy::new_without_default)] 294 | pub fn new() -> Self { 295 | Self { 296 | val: MaybeUninit::uninit(), 297 | drop_flag: QuietFlag::new(), 298 | } 299 | } 300 | 301 | // Workaround for `unsafe {}` unhygine wrt to lints. 302 | // 303 | // This function is still `unsafe`. 304 | pub fn new_unchecked_hygine_hack(&mut self) -> DroppingSlot { 305 | unsafe { 306 | DroppingSlot::new_unchecked(&mut self.val, self.drop_flag.flag()) 307 | } 308 | } 309 | } 310 | 311 | impl Drop for SlotDropper { 312 | fn drop(&mut self) { 313 | if self.drop_flag.flag().is_dead() { 314 | unsafe { ptr::drop_in_place(self.val.assume_init_mut()) } 315 | } 316 | } 317 | } 318 | 319 | // Workaround for `unsafe {}` unhygine wrt to lints. 320 | // 321 | // This function is still `unsafe`. 322 | pub fn new_unchecked_hygine_hack<'frame, T>( 323 | ptr: &'frame mut MaybeUninit, 324 | drop_flag: DropFlag<'frame>, 325 | ) -> Slot<'frame, T> { 326 | unsafe { Slot::new_unchecked(ptr, drop_flag) } 327 | } 328 | } 329 | 330 | /// Constructs a new [`Slot`]. 331 | /// 332 | /// Because [`Slot`]s need to own data on the stack, but that data cannot 333 | /// move with the [`Slot`], it must be constructed using this macro. For 334 | /// example: 335 | /// ``` 336 | /// moveit::slot!(x, y: bool); 337 | /// let x = x.put(5); 338 | /// let y = y.put(false); 339 | /// ``` 340 | /// 341 | /// This macro is especially useful for passing data into functions that want to 342 | /// emplace a value into the caller. 343 | /// 344 | /// The `slot!(#[dropping] x)` syntax can be used to create a [`DroppingSlot`] 345 | /// instead. This should be a comparatively rare operation. 346 | /// 347 | /// This macro can also be used without arguments to create a *temporary* 348 | /// [`Slot`]. Such types cannot be assigned to variables but can be used as 349 | /// part of a larger expression: 350 | /// 351 | /// ```compile_fail 352 | /// # use moveit::Slot; 353 | /// let bad: Slot = moveit::slot!(); 354 | /// bad.put(4); // Borrow check error. 355 | /// ``` 356 | /// 357 | /// ``` 358 | /// # use moveit::Slot; 359 | /// fn do_thing(x: Slot) { /* ... */ } 360 | /// do_thing(moveit::slot!()) 361 | /// ``` 362 | #[macro_export] 363 | macro_rules! slot { 364 | () => { 365 | $crate::slot::__macro::new_unchecked_hygine_hack( 366 | &mut $crate::slot::__macro::core::mem::MaybeUninit::uninit(), 367 | $crate::drop_flag::TrappedFlag::new().flag(), 368 | ) 369 | }; 370 | (#[dropping]) => { 371 | $crate::slot::__macro::SlotDropper::new().new_unchecked_hygine_hack() 372 | }; 373 | ($($name:ident $(: $ty:ty)?),* $(,)*) => {$( 374 | let mut uninit = $crate::slot::__macro::core::mem::MaybeUninit::< 375 | $crate::slot!(@tyof $($ty)?) 376 | >::uninit();let trap = $crate::drop_flag::TrappedFlag::new(); 377 | let $name = $crate::slot::__macro::new_unchecked_hygine_hack( 378 | &mut uninit, 379 | trap.flag() 380 | ); 381 | )*}; 382 | (#[dropping] $($name:ident $(: $ty:ty)?),* $(,)*) => {$( 383 | let mut uninit = $crate::slot::__macro::SlotDropper::< 384 | $crate::slot!(@tyof $($ty)?) 385 | >::new(); 386 | #[allow(unsafe_code, unused_unsafe)] 387 | let $name = uninit.new_unchecked_hygine_hack(); 388 | )*}; 389 | (@tyof) => {_}; 390 | (@tyof $ty:ty) => {$ty}; 391 | } 392 | --------------------------------------------------------------------------------