rust/hg-core/examples/nodemap/index.rs
changeset 44386 8f7c6656ac79
child 47955 e834b79def74
equal deleted inserted replaced
44385:a98ba6983a63 44386:8f7c6656ac79
       
     1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
       
     2 //
       
     3 // This software may be used and distributed according to the terms of the
       
     4 // GNU General Public License version 2 or any later version.
       
     5 
       
     6 //! Minimal `RevlogIndex`, readable from standard Mercurial file format
       
     7 use hg::*;
       
     8 use memmap::*;
       
     9 use std::fs::File;
       
    10 use std::ops::Deref;
       
    11 use std::path::Path;
       
    12 use std::slice;
       
    13 
       
    14 pub struct Index {
       
    15     data: Box<dyn Deref<Target = [IndexEntry]> + Send>,
       
    16 }
       
    17 
       
    18 /// A fixed sized index entry. All numbers are big endian
       
    19 #[repr(C)]
       
    20 pub struct IndexEntry {
       
    21     not_used_yet: [u8; 24],
       
    22     p1: Revision,
       
    23     p2: Revision,
       
    24     node: Node,
       
    25     unused_node: [u8; 12],
       
    26 }
       
    27 
       
    28 pub const INDEX_ENTRY_SIZE: usize = 64;
       
    29 
       
    30 impl IndexEntry {
       
    31     fn parents(&self) -> [Revision; 2] {
       
    32         [Revision::from_be(self.p1), Revision::from_be(self.p1)]
       
    33     }
       
    34 }
       
    35 
       
    36 impl RevlogIndex for Index {
       
    37     fn len(&self) -> usize {
       
    38         self.data.len()
       
    39     }
       
    40 
       
    41     fn node(&self, rev: Revision) -> Option<&Node> {
       
    42         if rev == NULL_REVISION {
       
    43             return None;
       
    44         }
       
    45         let i = rev as usize;
       
    46         if i >= self.len() {
       
    47             None
       
    48         } else {
       
    49             Some(&self.data[i].node)
       
    50         }
       
    51     }
       
    52 }
       
    53 
       
    54 impl Graph for &Index {
       
    55     fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
       
    56         let [p1, p2] = (*self).data[rev as usize].parents();
       
    57         let len = (*self).len();
       
    58         if p1 < NULL_REVISION
       
    59             || p2 < NULL_REVISION
       
    60             || p1 as usize >= len
       
    61             || p2 as usize >= len
       
    62         {
       
    63             return Err(GraphError::ParentOutOfRange(rev));
       
    64         }
       
    65         Ok([p1, p2])
       
    66     }
       
    67 }
       
    68 
       
    69 struct IndexMmap(Mmap);
       
    70 
       
    71 impl Deref for IndexMmap {
       
    72     type Target = [IndexEntry];
       
    73 
       
    74     fn deref(&self) -> &[IndexEntry] {
       
    75         let ptr = self.0.as_ptr() as *const IndexEntry;
       
    76         // Any misaligned data will be ignored.
       
    77         debug_assert_eq!(
       
    78             self.0.len() % std::mem::align_of::<IndexEntry>(),
       
    79             0,
       
    80             "Misaligned data in mmap"
       
    81         );
       
    82         unsafe { slice::from_raw_parts(ptr, self.0.len() / INDEX_ENTRY_SIZE) }
       
    83     }
       
    84 }
       
    85 
       
    86 impl Index {
       
    87     pub fn load_mmap(path: impl AsRef<Path>) -> Self {
       
    88         let file = File::open(path).unwrap();
       
    89         let msg = "Index file is missing, or missing permission";
       
    90         let mmap = unsafe { MmapOptions::new().map(&file) }.expect(msg);
       
    91         Self {
       
    92             data: Box::new(IndexMmap(mmap)),
       
    93         }
       
    94     }
       
    95 }