rust-pyo3-dirstate: making bytes slices in core Sync
For the purposes of providing PyO3 bindings, the data fields that will be
exposed to Python have to be `Sync`, hence that is the case of
`OwningDirstateMap` and its `owner` field.
We had to do something similar for the PyO3 bindings of `revlog`.
In this case, it forces us to adapt the `Deref` wrapper of `PyBytes` used
in `hg-cpython`, because it must itself now be `Sync` and raw pointers are
not.
This looks even uglier than it used to, but it does not matter much, because
our ultimate goal is to remove the rust-cpython bindings altogether.
--- a/rust/hg-core/src/dirstate/owning.rs Fri Jan 24 16:05:16 2025 +0100
+++ b/rust/hg-core/src/dirstate/owning.rs Wed Jan 29 12:37:06 2025 +0100
@@ -11,7 +11,7 @@
/// Keep a `DirstateMap<'owner>` next to the `owner` buffer that it
/// borrows.
pub struct OwningDirstateMap {
- owner: Box<dyn Deref<Target = [u8]> + Send>,
+ owner: Box<dyn Deref<Target = [u8]> + Send + Sync>,
#[covariant]
dependent: DirstateMap,
}
@@ -23,7 +23,7 @@
identity: Option<DirstateIdentity>,
) -> Self
where
- OnDisk: Deref<Target = [u8]> + Send + 'static,
+ OnDisk: Deref<Target = [u8]> + Send + Sync + 'static,
{
let on_disk = Box::new(on_disk);
@@ -39,7 +39,7 @@
identity: Option<DirstateIdentity>,
) -> Result<(Self, DirstateParents), DirstateError>
where
- OnDisk: Deref<Target = [u8]> + Send + 'static,
+ OnDisk: Deref<Target = [u8]> + Send + Sync + 'static,
{
let on_disk = Box::new(on_disk);
let mut parents = DirstateParents::NULL;
@@ -63,7 +63,7 @@
identity: Option<DirstateIdentity>,
) -> Result<Self, DirstateError>
where
- OnDisk: Deref<Target = [u8]> + Send + 'static,
+ OnDisk: Deref<Target = [u8]> + Send + Sync + 'static,
{
let on_disk = Box::new(on_disk);
--- a/rust/hg-cpython/src/pybytes_deref.rs Fri Jan 24 16:05:16 2025 +0100
+++ b/rust/hg-cpython/src/pybytes_deref.rs Wed Jan 29 12:37:06 2025 +0100
@@ -18,13 +18,16 @@
/// Borrows the buffer inside `self.keep_alive`,
/// but the borrow-checker cannot express self-referential structs.
- data: *const [u8],
+ data: &'static [u8],
}
impl PyBytesDeref {
pub fn new(py: Python, bytes: PyBytes) -> Self {
+ let as_raw: *const [u8] = bytes.data(py);
Self {
- data: bytes.data(py),
+ // Safety: the raw pointer is valid as long as the PyBytes is still
+ // alive, and the objecs owns it.
+ data: unsafe { &*as_raw },
keep_alive: bytes,
}
}
@@ -38,9 +41,7 @@
type Target = [u8];
fn deref(&self) -> &[u8] {
- // Safety: the raw pointer is valid as long as the PyBytes is still
- // alive, and the returned slice borrows `self`.
- unsafe { &*self.data }
+ self.data
}
}