rust/hg-core/examples/nodemap/index.rs
author Raphaël Gomès <rgomes@octobus.net>
Fri, 18 Aug 2023 14:34:29 +0200
changeset 50979 4c5f6e95df84
parent 47955 e834b79def74
permissions -rw-r--r--
rust: make `Revision` a newtype This change is the one we've been building towards during this series. The aim is to make `Revision` mean more than a simple integer, holding the information that it is valid for a given revlog index. While this still allows for programmer error, since creating a revision directly and querying a different index with a "checked" revision are still possible, the friction created by the newtype will hopefully make us think twice about which type to use. Enough of the Rust ecosystem relies on the newtype pattern to be efficiently optimized away (even compiler in codegen testsĀ¹), so I'm not worried about this being a fundamental problem. [1] https://github.com/rust-lang/rust/blob/7a70647f195f6b0a0f1ebd72b1542ba91a32f43a/tests/codegen/vec-in-place.rs#L47
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
44386
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     1
// Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     2
//
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     3
// This software may be used and distributed according to the terms of the
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     4
// GNU General Public License version 2 or any later version.
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     5
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     6
//! Minimal `RevlogIndex`, readable from standard Mercurial file format
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     7
use hg::*;
47955
e834b79def74 rust: Switch to the memmap2-rs crate
Simon Sapin <simon.sapin@octobus.net>
parents: 44386
diff changeset
     8
use memmap2::*;
44386
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     9
use std::fs::File;
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    10
use std::ops::Deref;
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    11
use std::path::Path;
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    12
use std::slice;
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    13
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    14
pub struct Index {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    15
    data: Box<dyn Deref<Target = [IndexEntry]> + Send>,
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    16
}
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    17
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    18
/// A fixed sized index entry. All numbers are big endian
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    19
#[repr(C)]
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    20
pub struct IndexEntry {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    21
    not_used_yet: [u8; 24],
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    22
    p1: Revision,
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    23
    p2: Revision,
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    24
    node: Node,
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    25
    unused_node: [u8; 12],
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    26
}
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    27
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    28
pub const INDEX_ENTRY_SIZE: usize = 64;
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    29
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    30
impl IndexEntry {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    31
    fn parents(&self) -> [Revision; 2] {
50979
4c5f6e95df84 rust: make `Revision` a newtype
Raphaël Gomès <rgomes@octobus.net>
parents: 47955
diff changeset
    32
        [self.p1, self.p2]
44386
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    33
    }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    34
}
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    35
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    36
impl RevlogIndex for Index {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    37
    fn len(&self) -> usize {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    38
        self.data.len()
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    39
    }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    40
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    41
    fn node(&self, rev: Revision) -> Option<&Node> {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    42
        if rev == NULL_REVISION {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    43
            return None;
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    44
        }
50979
4c5f6e95df84 rust: make `Revision` a newtype
Raphaël Gomès <rgomes@octobus.net>
parents: 47955
diff changeset
    45
        Some(&self.data[rev.0 as usize].node)
44386
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    46
    }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    47
}
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    48
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    49
impl Graph for &Index {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    50
    fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
50979
4c5f6e95df84 rust: make `Revision` a newtype
Raphaël Gomès <rgomes@octobus.net>
parents: 47955
diff changeset
    51
        let [p1, p2] = self.data[rev.0 as usize].parents();
44386
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    52
        let len = (*self).len();
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    53
        if p1 < NULL_REVISION
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    54
            || p2 < NULL_REVISION
50979
4c5f6e95df84 rust: make `Revision` a newtype
Raphaël Gomès <rgomes@octobus.net>
parents: 47955
diff changeset
    55
            || p1.0 as usize >= len
4c5f6e95df84 rust: make `Revision` a newtype
Raphaël Gomès <rgomes@octobus.net>
parents: 47955
diff changeset
    56
            || p2.0 as usize >= len
44386
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    57
        {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    58
            return Err(GraphError::ParentOutOfRange(rev));
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    59
        }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    60
        Ok([p1, p2])
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    61
    }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    62
}
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    63
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    64
struct IndexMmap(Mmap);
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    65
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    66
impl Deref for IndexMmap {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    67
    type Target = [IndexEntry];
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    68
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    69
    fn deref(&self) -> &[IndexEntry] {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    70
        let ptr = self.0.as_ptr() as *const IndexEntry;
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    71
        // Any misaligned data will be ignored.
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    72
        debug_assert_eq!(
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    73
            self.0.len() % std::mem::align_of::<IndexEntry>(),
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    74
            0,
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    75
            "Misaligned data in mmap"
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    76
        );
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    77
        unsafe { slice::from_raw_parts(ptr, self.0.len() / INDEX_ENTRY_SIZE) }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    78
    }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    79
}
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    80
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    81
impl Index {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    82
    pub fn load_mmap(path: impl AsRef<Path>) -> Self {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    83
        let file = File::open(path).unwrap();
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    84
        let msg = "Index file is missing, or missing permission";
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    85
        let mmap = unsafe { MmapOptions::new().map(&file) }.expect(msg);
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    86
        Self {
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    87
            data: Box::new(IndexMmap(mmap)),
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    88
        }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    89
    }
8f7c6656ac79 rust-nodemap: pure Rust example
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    90
}