Skip to content

Commit 227e0f9

Browse files
committed
updated pair.rs and README.md
1 parent 83025fd commit 227e0f9

File tree

2 files changed

+54
-49
lines changed

2 files changed

+54
-49
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ self-referential struct.
1414

1515
# Example Usage
1616

17-
A typical use case might look something like this:
17+
Here's one example use case:
1818
```rust
1919
use pair::{Dependent, Owner, Pair};
2020

@@ -49,12 +49,11 @@ impl<'any> Owner<'any> for MyBuffer {
4949

5050
// You can now use MyBuffer in a Pair:
5151
fn main() {
52+
let buffer = MyBuffer { data: String::from("this is an example") };
53+
5254
// A Pair can be constructed from an owner value (MyBuffer, in this example)
5355
// and a function to construct the dependent value (parse, in this example)
54-
let mut pair = Pair::new(
55-
MyBuffer { data: String::from("this is an example") },
56-
parse,
57-
);
56+
let mut pair = Pair::new(buffer, parse);
5857

5958
// You can obtain a reference to the owner via a reference to the pair
6059
let owner: &MyBuffer = pair.owner();
@@ -100,6 +99,7 @@ point, the owner can safely be recovered and the `Pair` deconstructed.
10099

101100
# Related Projects
102101

102+
<!-- TODO: improve this table -->
103103
| Crate | Macro free | No `alloc` | Maintained | Soundness |
104104
| ----- | :--------: | :-------------: | :--------: | :-------: |
105105
| `pair` |||| No known issues |

src/pair.rs

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -121,18 +121,20 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
121121
/// differences between constructors.
122122
///
123123
/// # Errors
124+
///
124125
/// If `make_dependent` returns an error.
125126
pub fn try_new_from_box<F, E>(owner: Box<O>, make_dependent: F) -> Result<Self, (Box<O>, E)>
126127
where
127128
F: FnOnce(&O) -> Result<Dependent<'_, O>, E>,
128129
{
129130
// Convert owner into a NonNull, so we are no longer restricted by the aliasing requirements
130131
// of Box
131-
let owner = non_null_from_box(owner);
132+
let owner: Box<O> = owner;
133+
let owner: NonNull<O> = non_null_from_box(owner);
132134

133-
// We're about to call `make_dependent(..)` - if it panics, we want to be able to drop the
134-
// boxed owner before unwinding the rest of the stack to avoid unnecessarily leaking memory
135-
// (and potentially other resources).
135+
// We're about to call `make_dependent(..)` - if it panics, we want to drop the boxed owner
136+
// before unwinding the rest of the stack to avoid unnecessarily leaking memory (and
137+
// potentially other resources).
136138
let panic_drop_guard = DropGuard(|| {
137139
// If this code is executing, it means `make_dependent` panicked and we never
138140
// `mem::forget(..)`'d this drop guard. Recover and drop the boxed owner.
@@ -152,10 +154,10 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
152154
});
153155

154156
let maybe_dependent = {
155-
// Borrow `owner` to construct `dependent`. This borrow conceptually lasts from now
156-
// until drop, where we will drop `dependent` and then drop owner.
157+
// Borrow the owner to construct the dependent. This borrow conceptually lasts from now
158+
// until the pair is deconstructed, at which point we will drop the dependent.
157159
//
158-
// SAFETY: `owner` was just converted from a valid Box, and inherits the alignment and
160+
// SAFETY: `owner` was just converted from a Box, and inherits the alignment and
159161
// validity guarantees of Box. Additionally, the value behind the pointer is currently
160162
// not borrowed at all - this marks the beginning of a shared borrow which will last
161163
// until the returned `Pair` is deconstructed (or ends immediately if `make_dependent`
@@ -173,29 +175,30 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
173175
let dependent = match maybe_dependent {
174176
Ok(dependent) => dependent,
175177
Err(err) => {
176-
// SAFETY: `owner` was just created from a Box earlier in this function, and not
178+
// SAFETY: `owner` was created from a Box earlier in this function, and not
177179
// invalidated since then. Because we haven't given away access to a `Self`, and the
178-
// one borrow we took of the dependent to pass to `make_dependent` has expired, we
179-
// know there are no outstanding borrows to owner. Therefore, reconstructing the
180+
// one borrow we took of the owner to pass to `make_dependent` has expired, we know
181+
// there are no outstanding borrows of the owner. Therefore, reconstructing the
180182
// original Box<O> is okay.
181183
let owner: Box<O> = unsafe { Box::from_raw(owner.as_ptr()) };
182184

183185
return Err((owner, err));
184186
}
185187
};
186188

187-
// We're about to call `Box::new(..)` - if it panics, we want to be able to drop the boxed
188-
// owner before unwinding the rest of the stack to avoid unnecessarily leaking memory (and
189-
// potentially other resources).
189+
// We're about to call `Box::new(..)` - if it panics, we want to drop the boxed owner before
190+
// unwinding the rest of the stack to avoid unnecessarily leaking memory (and potentially
191+
// other resources).
190192
let panic_drop_guard = DropGuard(|| {
191193
// If this code is executing, it means `Box::new(..)` panicked and we never
192194
// `mem::forget(..)`'d this drop guard. Recover and drop the boxed owner.
193195

194-
// SAFETY: `owner` was just created from a Box earlier in `try_new_from_box`, and not
196+
// SAFETY: `owner` was created from a Box earlier in `try_new_from_box`, and not
195197
// invalidated since then. Because we haven't given away access to a `Self`, and the one
196198
// borrow of the owner stored in the dependent has expired (since we gave ownership of
197199
// the dependent to the `Box::new(..)` call that panicked), we know there are no
198-
// outstanding borrows to owner. Therefore, reconstructing the original Box<O> is okay.
200+
// outstanding borrows of the owner. Therefore, reconstructing the original Box<O> is
201+
// okay.
199202
let owner: Box<O> = unsafe { Box::from_raw(owner.as_ptr()) };
200203

201204
// If the owner's drop *also* panics, that will be a double-panic. This will cause an
@@ -225,12 +228,12 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
225228

226229
/// Returns a reference to the owner.
227230
pub fn owner(&self) -> &O {
228-
// SAFETY: `self.owner` was originally converted from a valid Box, and inherited the
229-
// alignment and validity guarantees of Box - and neither our code nor any of our exposed
230-
// APIs could have invalidated those since construction. Additionally, the value behind the
231-
// pointer is currently in a shared borrow state (no exclusive borrows, no other code
232-
// assuming unique ownership), and will be until the Pair is deconstructed. Here, we only
233-
// add another shared borrow.
231+
// SAFETY: `self.owner` was originally created from a Box, and inherited the alignment and
232+
// validity guarantees of Box - and neither our code nor any of our exposed APIs could have
233+
// invalidated those since construction. Additionally, the value behind the pointer is
234+
// currently in a shared borrow state (no exclusive borrows, no other code assuming unique
235+
// ownership), and will be until the pair is deconstructed. Here, we only add another shared
236+
// borrow.
234237
unsafe { self.owner.as_ref() }
235238
}
236239

@@ -247,15 +250,16 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
247250
where
248251
F: for<'any> FnOnce(&'self_borrow Dependent<'any, O>) -> T,
249252
{
250-
// SAFETY: `self.dependent` was originally converted from a valid Box<Dependent<'_, O>>, and
253+
// SAFETY: `self.dependent` was originally created from a Box<Dependent<'_, O>>, and
251254
// type-erased to a NonNull<()>. As such, it inherited the alignment and validity guarantees
252255
// of Box (for a Dependent<'_, O>) - and neither our code nor any of our exposed APIs could
253256
// have invalidated those since construction. Additionally, because we have a shared
254257
// reference to self, we know that the value behind the pointer is currently either not
255258
// borrowed at all, or in a shared borrow state (no exclusive borrows, no other code
256-
// assuming unique ownership). Here, we only either create the first shared borrow, or add
257-
// another.
258-
let dependent = unsafe { self.dependent.cast::<Dependent<'_, O>>().as_ref() };
259+
// assuming unique ownership), and will stay in one of those states until our shared borrow
260+
// of `self` expires. Here, we only either create the first shared borrow, or add another.
261+
let dependent: &Dependent<'_, O> =
262+
unsafe { self.dependent.cast::<Dependent<'_, O>>().as_ref() };
259263

260264
f(dependent)
261265
}
@@ -299,14 +303,15 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
299303
{
300304
let owner: &O = self.owner();
301305

302-
// SAFETY: `self.dependent` was originally converted from a valid Box<Dependent<'_, O>>, and
306+
// SAFETY: `self.dependent` was originally created from a Box<Dependent<'_, O>>, and
303307
// type-erased to a NonNull<()>. As such, it inherited the alignment and validity guarantees
304308
// of Box (for a Dependent<'_, O>) - and neither our code nor any of our exposed APIs could
305309
// have invalidated those since construction. Additionally, because we have an exclusive
306310
// reference to self (and Pair::owner(..) doesn't borrow the dependent), we know that the
307311
// value behind the pointer is currently not borrowed at all, and can't be until our
308312
// exclusive borrow of `self` expires.
309-
let dependent = unsafe { self.dependent.cast::<Dependent<'_, O>>().as_mut() };
313+
let dependent: &mut Dependent<'_, O> =
314+
unsafe { self.dependent.cast::<Dependent<'_, O>>().as_mut() };
310315

311316
f(owner, dependent)
312317
}
@@ -318,7 +323,7 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
318323
pub fn into_boxed_owner(self) -> Box<O> {
319324
// Prevent dropping `self` at the end of this scope - otherwise, the Pair drop
320325
// implementation would attempt to drop the owner and dependent again, which would be...
321-
// not good (unsound).
326+
// not good.
322327
//
323328
// It's important that we do this before calling the dependent's drop, since a panic in that
324329
// drop would otherwise cause a double free when we attempt to drop the dependent again when
@@ -331,9 +336,9 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
331336
let dependent: Box<Dependent<'_, O>> =
332337
unsafe { Box::from_raw(this.dependent.cast::<Dependent<'_, O>>().as_ptr()) };
333338

334-
// We're about to drop the dependent - if it panics, we want to be able to drop the boxed
335-
// owner before unwinding the rest of the stack to avoid unnecessarily leaking memory (and
336-
// potentially other resources).
339+
// We're about to drop the dependent - if it panics, we want to drop the boxed owner before
340+
// unwinding the rest of the stack to avoid unnecessarily leaking memory (and potentially
341+
// other resources).
337342
let panic_drop_guard = DropGuard(|| {
338343
// If this code is executing, it means the dependent's drop panicked and we never
339344
// `mem::forget(..)`'d this drop guard. Recover and drop the boxed owner.
@@ -386,13 +391,13 @@ impl<O: for<'any> Owner<'any> + ?Sized> Pair<O> {
386391
// O::Dependent. It doesn't see any indication of O::Dependent in the signature for Pair (because
387392
// we've type erased it), so dropck has no idea that we will drop an O::Dependent in our drop.
388393
//
389-
// This sounds like a problem, but I believe it is not. The signature of Owner and HasDependent
390-
// enforce that the dependent only borrows the owner, or things which the owner also borrows.
391-
// Additionally, the compiler will ensure that anything the owner borrows are valid until the pair's
392-
// drop. Therefore, the dependent cannot contain any references which will be invalidated before the
393-
// drop of the Pair<O>. As far as I know, this is the only concern surrounding dropck not
394-
// understanding the semantics of Pair, and cannot cause unsoundness for the reasons described
395-
// above.
394+
// This sounds like a problem, but I believe it is not. The signature of `Owner` enforces that the
395+
// dependent only borrows the owner, or things which the owner also borrows. Additionally, the
396+
// compiler will ensure that anything the owner borrows are valid until the pair's drop (because
397+
// dropck sees that we hold an `O`). Therefore, the dependent cannot contain any references which
398+
// will be invalidated before the drop of the Pair<O>. As far as I know, this is the only concern
399+
// surrounding dropck not understanding the semantics of Pair, and cannot cause unsoundness for the
400+
// reasons described above.
396401
impl<O: for<'any> Owner<'any> + ?Sized> Drop for Pair<O> {
397402
fn drop(&mut self) {
398403
// Drop the dependent `Box<Dependent<'_, O>>`
@@ -403,9 +408,9 @@ impl<O: for<'any> Owner<'any> + ?Sized> Drop for Pair<O> {
403408
let dependent =
404409
unsafe { Box::from_raw(self.dependent.cast::<Dependent<'_, O>>().as_ptr()) };
405410

406-
// We're about to drop the dependent - if it panics, we want to be able to drop the boxed
407-
// owner before unwinding the rest of the stack to avoid unnecessarily leaking memory (and
408-
// potentially other resources).
411+
// We're about to drop the dependent - if it panics, we want to drop the boxed owner before
412+
// unwinding the rest of the stack to avoid unnecessarily leaking memory (and potentially
413+
// other resources).
409414
let panic_drop_guard = DropGuard(|| {
410415
// If this code is executing, it means the dependent's drop panicked and we never
411416
// `mem::forget(..)`'d this drop guard. Recover and drop the boxed owner.
@@ -429,12 +434,12 @@ impl<O: for<'any> Owner<'any> + ?Sized> Drop for Pair<O> {
429434
// The dependent's drop didn't panic - disarm our drop guard
430435
core::mem::forget(panic_drop_guard);
431436

432-
// Drop the owner `Box<O>`
433-
437+
// Recover the owner
438+
//
434439
// SAFETY: `self.owner` was originally created from a Box, and never invalidated since then.
435440
// Because we are in drop, and we just dropped the dependent, we know there are no
436441
// outstanding borrows to owner. Therefore, reconstructing the original Box<O> is okay.
437-
let owner = unsafe { Box::from_raw(self.owner.as_ptr()) };
442+
let owner: Box<O> = unsafe { Box::from_raw(self.owner.as_ptr()) };
438443

439444
drop(owner);
440445
}

0 commit comments

Comments
 (0)