index.rs
95 lines
| 2.4 KiB
| application/rls-services+xml
|
RustLexer
Georges Racinet
|
r44870 | // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net> | ||
// | ||||
// This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | ||||
//! Minimal `RevlogIndex`, readable from standard Mercurial file format | ||||
use hg::*; | ||||
use memmap::*; | ||||
use std::fs::File; | ||||
use std::ops::Deref; | ||||
use std::path::Path; | ||||
use std::slice; | ||||
pub struct Index { | ||||
data: Box<dyn Deref<Target = [IndexEntry]> + Send>, | ||||
} | ||||
/// A fixed sized index entry. All numbers are big endian | ||||
#[repr(C)] | ||||
pub struct IndexEntry { | ||||
not_used_yet: [u8; 24], | ||||
p1: Revision, | ||||
p2: Revision, | ||||
node: Node, | ||||
unused_node: [u8; 12], | ||||
} | ||||
pub const INDEX_ENTRY_SIZE: usize = 64; | ||||
impl IndexEntry { | ||||
fn parents(&self) -> [Revision; 2] { | ||||
[Revision::from_be(self.p1), Revision::from_be(self.p1)] | ||||
} | ||||
} | ||||
impl RevlogIndex for Index { | ||||
fn len(&self) -> usize { | ||||
self.data.len() | ||||
} | ||||
fn node(&self, rev: Revision) -> Option<&Node> { | ||||
if rev == NULL_REVISION { | ||||
return None; | ||||
} | ||||
let i = rev as usize; | ||||
if i >= self.len() { | ||||
None | ||||
} else { | ||||
Some(&self.data[i].node) | ||||
} | ||||
} | ||||
} | ||||
impl Graph for &Index { | ||||
fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> { | ||||
let [p1, p2] = (*self).data[rev as usize].parents(); | ||||
let len = (*self).len(); | ||||
if p1 < NULL_REVISION | ||||
|| p2 < NULL_REVISION | ||||
|| p1 as usize >= len | ||||
|| p2 as usize >= len | ||||
{ | ||||
return Err(GraphError::ParentOutOfRange(rev)); | ||||
} | ||||
Ok([p1, p2]) | ||||
} | ||||
} | ||||
struct IndexMmap(Mmap); | ||||
impl Deref for IndexMmap { | ||||
type Target = [IndexEntry]; | ||||
fn deref(&self) -> &[IndexEntry] { | ||||
let ptr = self.0.as_ptr() as *const IndexEntry; | ||||
// Any misaligned data will be ignored. | ||||
debug_assert_eq!( | ||||
self.0.len() % std::mem::align_of::<IndexEntry>(), | ||||
0, | ||||
"Misaligned data in mmap" | ||||
); | ||||
unsafe { slice::from_raw_parts(ptr, self.0.len() / INDEX_ENTRY_SIZE) } | ||||
} | ||||
} | ||||
impl Index { | ||||
pub fn load_mmap(path: impl AsRef<Path>) -> Self { | ||||
let file = File::open(path).unwrap(); | ||||
let msg = "Index file is missing, or missing permission"; | ||||
let mmap = unsafe { MmapOptions::new().map(&file) }.expect(msg); | ||||
Self { | ||||
data: Box::new(IndexMmap(mmap)), | ||||
} | ||||
} | ||||
} | ||||