author | Simon Sapin <simon.sapin@octobus.net> |
Fri, 30 Apr 2021 18:24:54 +0200 | |
changeset 47137 | d8ac62374943 |
child 47291 | 1766130fe9ba |
permissions | -rw-r--r-- |
47137
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
1 |
use cpython::PyBytes; |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
2 |
use cpython::Python; |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
3 |
use hg::dirstate_tree::dirstate_map::DirstateMap; |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
4 |
use hg::DirstateError; |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
5 |
use hg::DirstateParents; |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
6 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
7 |
/// Keep a `DirstateMap<'on_disk>` next to the `on_disk` buffer that it |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
8 |
/// borrows. This is similar to the owning-ref crate. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
9 |
/// |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
10 |
/// This is similar to [`OwningRef`] which is more limited because it |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
11 |
/// represents exactly one `&T` reference next to the value it borrows, as |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
12 |
/// opposed to a struct that may contain an arbitrary number of references in |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
13 |
/// arbitrarily-nested data structures. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
14 |
/// |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
15 |
/// [`OwningRef`]: https://docs.rs/owning_ref/0.4.1/owning_ref/struct.OwningRef.html |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
16 |
pub(super) struct OwningDirstateMap { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
17 |
/// Owned handle to a bytes buffer with a stable address. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
18 |
/// |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
19 |
/// See <https://docs.rs/owning_ref/0.4.1/owning_ref/trait.StableAddress.html>. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
20 |
on_disk: PyBytes, |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
21 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
22 |
/// Pointer for `Box<DirstateMap<'on_disk>>`, typed-erased because the |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
23 |
/// language cannot represent a lifetime referencing a sibling field. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
24 |
/// This is not quite a self-referencial struct (moving this struct is not |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
25 |
/// a problem as it doesn’t change the address of the bytes buffer owned |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
26 |
/// by `PyBytes`) but touches similar borrow-checker limitations. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
27 |
ptr: *mut (), |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
28 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
29 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
30 |
impl OwningDirstateMap { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
31 |
pub fn new( |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
32 |
py: Python, |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
33 |
on_disk: PyBytes, |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
34 |
) -> Result<(Self, Option<DirstateParents>), DirstateError> { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
35 |
let bytes: &'_ [u8] = on_disk.data(py); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
36 |
let (map, parents) = DirstateMap::new(bytes)?; |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
37 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
38 |
// Like in `bytes` above, this `'_` lifetime parameter borrows from |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
39 |
// the bytes buffer owned by `on_disk`. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
40 |
let ptr: *mut DirstateMap<'_> = Box::into_raw(Box::new(map)); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
41 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
42 |
// Erase the pointed type entirely in order to erase the lifetime. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
43 |
let ptr: *mut () = ptr.cast(); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
44 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
45 |
Ok((Self { on_disk, ptr }, parents)) |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
46 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
47 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
48 |
pub fn get_mut<'a>(&'a mut self) -> &'a mut DirstateMap<'a> { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
49 |
// SAFETY: We cast the type-erased pointer back to the same type it had |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
50 |
// in `new`, except with a different lifetime parameter. This time we |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
51 |
// connect the lifetime to that of `self`. This cast is valid because |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
52 |
// `self` owns the same `PyBytes` whose buffer `DirstateMap` |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
53 |
// references. That buffer has a stable memory address because the byte |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
54 |
// string value of a `PyBytes` is immutable. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
55 |
let ptr: *mut DirstateMap<'a> = self.ptr.cast(); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
56 |
// SAFETY: we dereference that pointer, connecting the lifetime of the |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
57 |
// new `&mut` to that of `self`. This is valid because the |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
58 |
// raw pointer is to a boxed value, and `self` owns that box. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
59 |
unsafe { &mut *ptr } |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
60 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
61 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
62 |
pub fn get<'a>(&'a self) -> &'a DirstateMap<'a> { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
63 |
// SAFETY: same reasoning as in `get_mut` above. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
64 |
let ptr: *mut DirstateMap<'a> = self.ptr.cast(); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
65 |
unsafe { &*ptr } |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
66 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
67 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
68 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
69 |
impl Drop for OwningDirstateMap { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
70 |
fn drop(&mut self) { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
71 |
// Silence a "field is never read" warning, and demonstrate that this |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
72 |
// value is still alive. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
73 |
let _ = &self.on_disk; |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
74 |
// SAFETY: this cast is the same as in `get_mut`, and is valid for the |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
75 |
// same reason. `self.on_disk` still exists at this point, drop glue |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
76 |
// will drop it implicitly after this `drop` method returns. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
77 |
let ptr: *mut DirstateMap<'_> = self.ptr.cast(); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
78 |
// SAFETY: `Box::from_raw` takes ownership of the box away from `self`. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
79 |
// This is fine because drop glue does nothig for `*mut ()` and we’re |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
80 |
// in `drop`, so `get` and `get_mut` cannot be called again. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
81 |
unsafe { drop(Box::from_raw(ptr)) } |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
82 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
83 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
84 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
85 |
fn _static_assert_is_send<T: Send>() {} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
86 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
87 |
fn _static_assert_fields_are_send() { |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
88 |
_static_assert_is_send::<PyBytes>(); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
89 |
_static_assert_is_send::<Box<DirstateMap<'_>>>(); |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
90 |
} |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
91 |
|
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
92 |
// SAFETY: we don’t get this impl implicitly because `*mut (): !Send` because |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
93 |
// thread-safety of raw pointers is unknown in the general case. However this |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
94 |
// particular raw pointer represents a `Box<DirstateMap<'on_disk>>` that we |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
95 |
// own. Since that `Box` and `PyBytes` are both `Send` as shown in above, it |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
96 |
// is sound to mark this struct as `Send` too. |
d8ac62374943
dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff
changeset
|
97 |
unsafe impl Send for OwningDirstateMap {} |