annotate rust/hg-core/examples/nodemap/index.rs @ 50976:4c5f6e95df84

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
author Rapha?l Gom?s <rgomes@octobus.net>
date Fri, 18 Aug 2023 14:34:29 +0200
parents e834b79def74
children bd8081e9fd62
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
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] {
50976
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 }
50976
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> {
50976
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
50976
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 }