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 {}