Mercurial > public > mercurial-scm > hg
comparison rust/hg-core/src/dirstate_tree/owning.rs @ 49005:12adf8c695ed
merge: stable into default
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Tue, 05 Apr 2022 11:09:03 +0200 |
parents | dd6b67d5c256 |
children | 6cce0afc1454 e98fd81bb151 |
comparison
equal
deleted
inserted
replaced
48997:20c6c9e43397 | 49005:12adf8c695ed |
---|---|
1 use crate::{DirstateError, DirstateParents}; | |
2 | |
1 use super::dirstate_map::DirstateMap; | 3 use super::dirstate_map::DirstateMap; |
2 use stable_deref_trait::StableDeref; | |
3 use std::ops::Deref; | 4 use std::ops::Deref; |
5 | |
6 use ouroboros::self_referencing; | |
4 | 7 |
5 /// Keep a `DirstateMap<'on_disk>` next to the `on_disk` buffer that it | 8 /// Keep a `DirstateMap<'on_disk>` next to the `on_disk` buffer that it |
6 /// borrows. | 9 /// borrows. |
7 /// | 10 #[self_referencing] |
8 /// This is similar to [`OwningRef`] which is more limited because it | |
9 /// represents exactly one `&T` reference next to the value it borrows, as | |
10 /// opposed to a struct that may contain an arbitrary number of references in | |
11 /// arbitrarily-nested data structures. | |
12 /// | |
13 /// [`OwningRef`]: https://docs.rs/owning_ref/0.4.1/owning_ref/struct.OwningRef.html | |
14 pub struct OwningDirstateMap { | 11 pub struct OwningDirstateMap { |
15 /// Owned handle to a bytes buffer with a stable address. | |
16 /// | |
17 /// See <https://docs.rs/owning_ref/0.4.1/owning_ref/trait.StableAddress.html>. | |
18 on_disk: Box<dyn Deref<Target = [u8]> + Send>, | 12 on_disk: Box<dyn Deref<Target = [u8]> + Send>, |
19 | 13 #[borrows(on_disk)] |
20 /// Pointer for `Box<DirstateMap<'on_disk>>`, typed-erased because the | 14 #[covariant] |
21 /// language cannot represent a lifetime referencing a sibling field. | 15 map: DirstateMap<'this>, |
22 /// This is not quite a self-referencial struct (moving this struct is not | |
23 /// a problem as it doesn’t change the address of the bytes buffer owned | |
24 /// by `on_disk`) but touches similar borrow-checker limitations. | |
25 ptr: *mut (), | |
26 } | 16 } |
27 | 17 |
28 impl OwningDirstateMap { | 18 impl OwningDirstateMap { |
29 pub fn new_empty<OnDisk>(on_disk: OnDisk) -> Self | 19 pub fn new_empty<OnDisk>(on_disk: OnDisk) -> Self |
30 where | 20 where |
31 OnDisk: Deref<Target = [u8]> + StableDeref + Send + 'static, | 21 OnDisk: Deref<Target = [u8]> + Send + 'static, |
32 { | 22 { |
33 let on_disk = Box::new(on_disk); | 23 let on_disk = Box::new(on_disk); |
34 let bytes: &'_ [u8] = &on_disk; | |
35 let map = DirstateMap::empty(bytes); | |
36 | 24 |
37 // Like in `bytes` above, this `'_` lifetime parameter borrows from | 25 OwningDirstateMapBuilder { |
38 // the bytes buffer owned by `on_disk`. | 26 on_disk, |
39 let ptr: *mut DirstateMap<'_> = Box::into_raw(Box::new(map)); | 27 map_builder: |bytes| DirstateMap::empty(&bytes), |
40 | 28 } |
41 // Erase the pointed type entirely in order to erase the lifetime. | 29 .build() |
42 let ptr: *mut () = ptr.cast(); | |
43 | |
44 Self { on_disk, ptr } | |
45 } | 30 } |
46 | 31 |
47 pub fn get_pair_mut<'a>( | 32 pub fn new_v1<OnDisk>( |
48 &'a mut self, | 33 on_disk: OnDisk, |
49 ) -> (&'a [u8], &'a mut DirstateMap<'a>) { | 34 ) -> Result<(Self, DirstateParents), DirstateError> |
50 // SAFETY: We cast the type-erased pointer back to the same type it had | 35 where |
51 // in `new`, except with a different lifetime parameter. This time we | 36 OnDisk: Deref<Target = [u8]> + Send + 'static, |
52 // connect the lifetime to that of `self`. This cast is valid because | 37 { |
53 // `self` owns the same `on_disk` whose buffer `DirstateMap` | 38 let on_disk = Box::new(on_disk); |
54 // references. That buffer has a stable memory address because our | 39 let mut parents = DirstateParents::NULL; |
55 // `Self::new_empty` counstructor requires `StableDeref`. | 40 |
56 let ptr: *mut DirstateMap<'a> = self.ptr.cast(); | 41 Ok(( |
57 // SAFETY: we dereference that pointer, connecting the lifetime of the | 42 OwningDirstateMapTryBuilder { |
58 // new `&mut` to that of `self`. This is valid because the | 43 on_disk, |
59 // raw pointer is to a boxed value, and `self` owns that box. | 44 map_builder: |bytes| { |
60 (&self.on_disk, unsafe { &mut *ptr }) | 45 DirstateMap::new_v1(&bytes).map(|(dmap, p)| { |
46 parents = p.unwrap_or(DirstateParents::NULL); | |
47 dmap | |
48 }) | |
49 }, | |
50 } | |
51 .try_build()?, | |
52 parents, | |
53 )) | |
61 } | 54 } |
62 | 55 |
63 pub fn get_map_mut<'a>(&'a mut self) -> &'a mut DirstateMap<'a> { | 56 pub fn new_v2<OnDisk>( |
64 self.get_pair_mut().1 | 57 on_disk: OnDisk, |
58 data_size: usize, | |
59 metadata: &[u8], | |
60 ) -> Result<Self, DirstateError> | |
61 where | |
62 OnDisk: Deref<Target = [u8]> + Send + 'static, | |
63 { | |
64 let on_disk = Box::new(on_disk); | |
65 | |
66 OwningDirstateMapTryBuilder { | |
67 on_disk, | |
68 map_builder: |bytes| { | |
69 DirstateMap::new_v2(&bytes, data_size, metadata) | |
70 }, | |
71 } | |
72 .try_build() | |
65 } | 73 } |
66 | 74 |
67 pub fn get_map<'a>(&'a self) -> &'a DirstateMap<'a> { | 75 pub fn with_dmap_mut<R>( |
68 // SAFETY: same reasoning as in `get_pair_mut` above. | 76 &mut self, |
69 let ptr: *mut DirstateMap<'a> = self.ptr.cast(); | 77 f: impl FnOnce(&mut DirstateMap) -> R, |
70 unsafe { &*ptr } | 78 ) -> R { |
79 self.with_map_mut(f) | |
71 } | 80 } |
72 | 81 |
73 pub fn on_disk<'a>(&'a self) -> &'a [u8] { | 82 pub fn get_map(&self) -> &DirstateMap { |
74 &self.on_disk | 83 self.borrow_map() |
84 } | |
85 | |
86 pub fn on_disk(&self) -> &[u8] { | |
87 self.borrow_on_disk() | |
75 } | 88 } |
76 } | 89 } |
77 | |
78 impl Drop for OwningDirstateMap { | |
79 fn drop(&mut self) { | |
80 // Silence a "field is never read" warning, and demonstrate that this | |
81 // value is still alive. | |
82 let _: &Box<dyn Deref<Target = [u8]> + Send> = &self.on_disk; | |
83 // SAFETY: this cast is the same as in `get_mut`, and is valid for the | |
84 // same reason. `self.on_disk` still exists at this point, drop glue | |
85 // will drop it implicitly after this `drop` method returns. | |
86 let ptr: *mut DirstateMap<'_> = self.ptr.cast(); | |
87 // SAFETY: `Box::from_raw` takes ownership of the box away from `self`. | |
88 // This is fine because drop glue does nothing for `*mut ()` and we’re | |
89 // in `drop`, so `get` and `get_mut` cannot be called again. | |
90 unsafe { drop(Box::from_raw(ptr)) } | |
91 } | |
92 } | |
93 | |
94 fn _static_assert_is_send<T: Send>() {} | |
95 | |
96 fn _static_assert_fields_are_send() { | |
97 _static_assert_is_send::<Box<DirstateMap<'_>>>(); | |
98 } | |
99 | |
100 // SAFETY: we don’t get this impl implicitly because `*mut (): !Send` because | |
101 // thread-safety of raw pointers is unknown in the general case. However this | |
102 // particular raw pointer represents a `Box<DirstateMap<'on_disk>>` that we | |
103 // own. Since that `Box` is `Send` as shown in above, it is sound to mark | |
104 // this struct as `Send` too. | |
105 unsafe impl Send for OwningDirstateMap {} |