rust/hg-core/src/dirstate_tree/owning.rs
author Simon Sapin <simon.sapin@octobus.net>
Mon, 27 Sep 2021 13:52:49 +0200
changeset 48069 3d0a9c6e614d
parent 48041 37a41267d000
child 48567 d1210d56008b
permissions -rw-r--r--
dirstate: Remove the Rust abstraction DirstateMapMethods This Rust trait used to exist in order to allow the DirstateMap class exposed to Python to be backed by either of two implementations: one similar to the Python implementation based on a "flat" `HashMap<HgPathBuf, DirstateEntry>`, and the newer one based on a tree of nodes matching the directory structure of tracked files. A boxed trait object was used with dynamic dispatch. With the flat implementation removed and only the tree one remaining, this abstraction is not useful anymore and the concrete type can be stored directly. It remains that the trait was implemented separately for `DirstateMap<'_>` (which takes a lifetime parameter) and `OwningDirstateMap` (whose job is to wrap the former and hide the lifetime parameter), with the latter impl only forwarding calls. This changeset also removes this forwarding. Instead, the methods formerly of the `DirstateMapMethods` trait are now inherent methods implemented for `OwningDirstateMap` (where they will actually be used) but in the module that defines `DirstateMap`. This unusual setup gives access to the private fields of `DirstateMap` from those methods. Differential Revision: https://phab.mercurial-scm.org/D11517
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
     1
use super::dirstate_map::DirstateMap;
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
     2
use stable_deref_trait::StableDeref;
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
     3
use std::ops::Deref;
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     4
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     5
/// Keep a `DirstateMap<'on_disk>` next to the `on_disk` buffer that it
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
     6
/// borrows.
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     7
///
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     8
/// 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
     9
/// 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
    10
/// 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
    11
/// arbitrarily-nested data structures.
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    12
///
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    13
/// [`OwningRef`]: https://docs.rs/owning_ref/0.4.1/owning_ref/struct.OwningRef.html
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    14
pub struct OwningDirstateMap {
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    15
    /// 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
    16
    ///
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    17
    /// See <https://docs.rs/owning_ref/0.4.1/owning_ref/trait.StableAddress.html>.
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    18
    on_disk: Box<dyn Deref<Target = [u8]> + Send>,
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    19
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    20
    /// 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
    21
    /// 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
    22
    /// 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
    23
    /// 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
    24
    /// 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
    25
    ptr: *mut (),
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    26
}
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    27
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    28
impl OwningDirstateMap {
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    29
    pub fn new_empty<OnDisk>(on_disk: OnDisk) -> Self
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    30
    where
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    31
        OnDisk: Deref<Target = [u8]> + StableDeref + Send + 'static,
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    32
    {
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    33
        let on_disk = Box::new(on_disk);
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    34
        let bytes: &'_ [u8] = &on_disk;
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    35
        let map = DirstateMap::empty(bytes);
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    36
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    37
        // 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
    38
        // 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
    39
        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
    40
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    41
        // 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
    42
        let ptr: *mut () = ptr.cast();
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    43
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    44
        Self { on_disk, ptr }
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    45
    }
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    46
48069
3d0a9c6e614d dirstate: Remove the Rust abstraction DirstateMapMethods
Simon Sapin <simon.sapin@octobus.net>
parents: 48041
diff changeset
    47
    pub fn get_pair_mut<'a>(
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    48
        &'a mut self,
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    49
    ) -> (&'a [u8], &'a mut DirstateMap<'a>) {
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    50
        // 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
    51
        // 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
    52
        // 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
    53
        // `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
    54
        // 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
    55
        // 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
    56
        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
    57
        // 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
    58
        // 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
    59
        // raw pointer is   to a boxed value, and `self` owns that box.
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    60
        (&self.on_disk, unsafe { &mut *ptr })
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    61
    }
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    62
48069
3d0a9c6e614d dirstate: Remove the Rust abstraction DirstateMapMethods
Simon Sapin <simon.sapin@octobus.net>
parents: 48041
diff changeset
    63
    pub fn get_map_mut<'a>(&'a mut self) -> &'a mut DirstateMap<'a> {
3d0a9c6e614d dirstate: Remove the Rust abstraction DirstateMapMethods
Simon Sapin <simon.sapin@octobus.net>
parents: 48041
diff changeset
    64
        self.get_pair_mut().1
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    65
    }
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    66
48069
3d0a9c6e614d dirstate: Remove the Rust abstraction DirstateMapMethods
Simon Sapin <simon.sapin@octobus.net>
parents: 48041
diff changeset
    67
    pub fn get_map<'a>(&'a self) -> &'a DirstateMap<'a> {
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    68
        // 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
    69
        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
    70
        unsafe { &*ptr }
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    71
    }
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    72
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    73
    pub fn on_disk<'a>(&'a self) -> &'a [u8] {
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    74
        &self.on_disk
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
    75
    }
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    76
}
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    77
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    78
impl Drop for OwningDirstateMap {
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    79
    fn drop(&mut self) {
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    80
        // 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
    81
        // value is still alive.
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    82
        let _ = &self.on_disk;
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    83
        // 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
    84
        // 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
    85
        // 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
    86
        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
    87
        // 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
    88
        // 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
    89
        // 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
    90
        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
    91
    }
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    92
}
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    93
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    94
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
    95
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    96
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
    97
    _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
    98
}
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    99
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   100
// 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
   101
// 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
   102
// particular raw pointer represents a `Box<DirstateMap<'on_disk>>` that we
47954
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
   103
// own. Since that `Box` is `Send` as shown in above, it is sound to mark
4afd6cc447b9 rust: Make OwningDirstateMap generic and move it into hg-core
Simon Sapin <simon.sapin@octobus.net>
parents: 47682
diff changeset
   104
// this struct as `Send` too.
47123
d8ac62374943 dirstate-tree: Make `DirstateMap` borrow from a bytes buffer
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   105
unsafe impl Send for OwningDirstateMap {}