diff --git a/rust/hg-core/src/dirstate/dirs_multiset.rs b/rust/hg-core/src/dirstate/dirs_multiset.rs --- a/rust/hg-core/src/dirstate/dirs_multiset.rs +++ b/rust/hg-core/src/dirstate/dirs_multiset.rs @@ -29,10 +29,10 @@ match iterable { DirsIterable::Dirstate(vec) => { - for (ref filename, DirstateEntry { state, .. }) in vec { + for (filename, DirstateEntry { state, .. }) in vec { // This `if` is optimized out of the loop if let Some(skip) = skip_state { - if skip != state { + if skip != *state { multiset.add_path(filename); } } else { @@ -41,7 +41,7 @@ } } DirsIterable::Manifest(vec) => { - for ref filename in vec { + for filename in vec { multiset.add_path(filename); } } @@ -109,10 +109,11 @@ #[cfg(test)] mod tests { use super::*; + use std::collections::HashMap; #[test] fn test_delete_path_path_not_found() { - let mut map = DirsMultiset::new(DirsIterable::Manifest(vec![]), None); + let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None); let path = b"doesnotexist/"; assert_eq!( Err(DirstateMapError::PathNotFound(path.to_vec())), @@ -123,7 +124,7 @@ #[test] fn test_delete_path_empty_path() { let mut map = - DirsMultiset::new(DirsIterable::Manifest(vec![vec![]]), None); + DirsMultiset::new(DirsIterable::Manifest(&vec![vec![]]), None); let path = b""; assert_eq!(Ok(()), map.delete_path(path)); assert_eq!( @@ -163,7 +164,7 @@ #[test] fn test_add_path_empty_path() { - let mut map = DirsMultiset::new(DirsIterable::Manifest(vec![]), None); + let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None); let path = b""; map.add_path(path); @@ -172,7 +173,7 @@ #[test] fn test_add_path_successful() { - let mut map = DirsMultiset::new(DirsIterable::Manifest(vec![]), None); + let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None); map.add_path(b"a/"); assert_eq!(1, *map.inner.get(&b"a".to_vec()).unwrap()); @@ -219,13 +220,13 @@ fn test_dirsmultiset_new_empty() { use DirsIterable::{Dirstate, Manifest}; - let new = DirsMultiset::new(Manifest(vec![]), None); + let new = DirsMultiset::new(Manifest(&vec![]), None); let expected = DirsMultiset { inner: HashMap::new(), }; assert_eq!(expected, new); - let new = DirsMultiset::new(Dirstate(vec![]), None); + let new = DirsMultiset::new(Dirstate(&HashMap::new()), None); let expected = DirsMultiset { inner: HashMap::new(), }; @@ -245,7 +246,7 @@ .map(|(k, v)| (k.as_bytes().to_vec(), *v)) .collect(); - let new = DirsMultiset::new(Manifest(input_vec), None); + let new = DirsMultiset::new(Manifest(&input_vec), None); let expected = DirsMultiset { inner: expected_inner, }; @@ -270,7 +271,7 @@ .map(|(k, v)| (k.as_bytes().to_vec(), *v)) .collect(); - let new = DirsMultiset::new(Dirstate(input_map), None); + let new = DirsMultiset::new(Dirstate(&input_map), None); let expected = DirsMultiset { inner: expected_inner, }; @@ -290,7 +291,7 @@ .map(|(k, v)| (k.as_bytes().to_vec(), *v)) .collect(); - let new = DirsMultiset::new(Manifest(input_vec), Some('n' as i8)); + let new = DirsMultiset::new(Manifest(&input_vec), Some('n' as i8)); let expected = DirsMultiset { inner: expected_inner, }; @@ -319,11 +320,10 @@ .map(|(k, v)| (k.as_bytes().to_vec(), *v)) .collect(); - let new = DirsMultiset::new(Dirstate(input_map), Some('n' as i8)); + let new = DirsMultiset::new(Dirstate(&input_map), Some('n' as i8)); let expected = DirsMultiset { inner: expected_inner, }; assert_eq!(expected, new); } - } diff --git a/rust/hg-core/src/dirstate/mod.rs b/rust/hg-core/src/dirstate/mod.rs --- a/rust/hg-core/src/dirstate/mod.rs +++ b/rust/hg-core/src/dirstate/mod.rs @@ -1,16 +1,25 @@ +// dirstate module +// +// Copyright 2019 Raphaël Gomès +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +use std::collections::HashMap; + pub mod dirs_multiset; pub mod parsers; -#[derive(Debug, PartialEq, Copy, Clone)] -pub struct DirstateParents<'a> { - pub p1: &'a [u8], - pub p2: &'a [u8], +#[derive(Debug, PartialEq, Clone)] +pub struct DirstateParents { + pub p1: Vec, + pub p2: Vec, } /// The C implementation uses all signed types. This will be an issue /// either when 4GB+ source files are commonplace or in 2038, whichever /// comes first. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] pub struct DirstateEntry { pub state: i8, pub mode: i32, @@ -18,19 +27,12 @@ pub size: i32, } -pub type DirstateVec = Vec<(Vec, DirstateEntry)>; - -#[derive(Debug, PartialEq)] -pub struct CopyVecEntry<'a> { - pub path: &'a [u8], - pub copy_path: &'a [u8], -} - -pub type CopyVec<'a> = Vec>; +pub type StateMap = HashMap, DirstateEntry>; +pub type CopyMap = HashMap, Vec>; /// The Python implementation passes either a mapping (dirstate) or a flat /// iterable (manifest) -pub enum DirsIterable { - Dirstate(DirstateVec), - Manifest(Vec>), +pub enum DirsIterable<'a> { + Dirstate(&'a HashMap, DirstateEntry>), + Manifest(&'a Vec>), } diff --git a/rust/hg-core/src/dirstate/parsers.rs b/rust/hg-core/src/dirstate/parsers.rs --- a/rust/hg-core/src/dirstate/parsers.rs +++ b/rust/hg-core/src/dirstate/parsers.rs @@ -4,31 +4,31 @@ // GNU General Public License version 2 or any later version. use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use std::collections::HashMap; +use dirstate::{CopyMap, StateMap}; use std::io::Cursor; -use { - CopyVec, CopyVecEntry, DirstateEntry, DirstatePackError, DirstateParents, - DirstateParseError, DirstateVec, -}; +use std::time::Duration; +use {DirstateEntry, DirstatePackError, DirstateParents, DirstateParseError}; /// Parents are stored in the dirstate as byte hashes. const PARENT_SIZE: usize = 20; /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits. const MIN_ENTRY_SIZE: usize = 17; +// TODO parse/pack: is mutate-on-loop better for performance? + pub fn parse_dirstate( + state_map: &mut StateMap, + copy_map: &mut CopyMap, contents: &[u8], -) -> Result<(DirstateParents, DirstateVec, CopyVec), DirstateParseError> { +) -> Result { if contents.len() < PARENT_SIZE * 2 { return Err(DirstateParseError::TooLittleData); } - let mut dirstate_vec = vec![]; - let mut copies = vec![]; let mut curr_pos = PARENT_SIZE * 2; let parents = DirstateParents { - p1: &contents[..PARENT_SIZE], - p2: &contents[PARENT_SIZE..curr_pos], + p1: contents[..PARENT_SIZE].to_vec(), + p2: contents[PARENT_SIZE..curr_pos].to_vec(), }; while curr_pos < contents.len() { @@ -57,9 +57,9 @@ }; if let Some(copy_path) = copy { - copies.push(CopyVecEntry { path, copy_path }); + copy_map.insert(path.to_owned(), copy_path.to_owned()); }; - dirstate_vec.push(( + state_map.insert( path.to_owned(), DirstateEntry { state, @@ -67,28 +67,30 @@ size, mtime, }, - )); + ); curr_pos = curr_pos + MIN_ENTRY_SIZE + (path_len); } - Ok((parents, dirstate_vec, copies)) + Ok(parents) } pub fn pack_dirstate( - dirstate_vec: &DirstateVec, - copymap: &HashMap, Vec>, + state_map: &mut StateMap, + copy_map: &CopyMap, parents: DirstateParents, - now: i32, -) -> Result<(Vec, DirstateVec), DirstatePackError> { + now: Duration, +) -> Result, DirstatePackError> { if parents.p1.len() != PARENT_SIZE || parents.p2.len() != PARENT_SIZE { return Err(DirstatePackError::CorruptedParent); } - let expected_size: usize = dirstate_vec + let now = now.as_secs() as i32; + + let expected_size: usize = state_map .iter() - .map(|(ref filename, _)| { + .map(|(filename, _)| { let mut length = MIN_ENTRY_SIZE + filename.len(); - if let Some(ref copy) = copymap.get(filename) { + if let Some(ref copy) = copy_map.get(filename) { length += copy.len() + 1; } length @@ -97,13 +99,13 @@ let expected_size = expected_size + PARENT_SIZE * 2; let mut packed = Vec::with_capacity(expected_size); - let mut new_dirstate_vec = vec![]; + let mut new_state_map = vec![]; packed.extend(parents.p1); packed.extend(parents.p2); - for (ref filename, entry) in dirstate_vec { - let mut new_filename: Vec = filename.to_owned(); + for (ref filename, entry) in state_map.iter() { + let mut new_filename: Vec = filename.to_vec(); let mut new_mtime: i32 = entry.mtime; if entry.state == 'n' as i8 && entry.mtime == now.into() { // The file was last modified "simultaneously" with the current @@ -116,8 +118,8 @@ // contents of the file if the size is the same. This prevents // mistakenly treating such files as clean. new_mtime = -1; - new_dirstate_vec.push(( - filename.to_owned(), + new_state_map.push(( + filename.to_owned().to_vec(), DirstateEntry { mtime: new_mtime, ..*entry @@ -125,7 +127,7 @@ )); } - if let Some(copy) = copymap.get(filename) { + if let Some(copy) = copy_map.get(*filename) { new_filename.push('\0' as u8); new_filename.extend(copy); } @@ -142,66 +144,36 @@ return Err(DirstatePackError::BadSize(expected_size, packed.len())); } - Ok((packed, new_dirstate_vec)) + state_map.extend(new_state_map); + + Ok(packed) } - #[cfg(test)] mod tests { use super::*; + use std::collections::HashMap; #[test] fn test_pack_dirstate_empty() { - let dirstate_vec: DirstateVec = vec![]; + let mut state_map: StateMap = HashMap::new(); let copymap = HashMap::new(); let parents = DirstateParents { - p1: b"12345678910111213141", - p2: b"00000000000000000000", + p1: b"12345678910111213141".to_vec(), + p2: b"00000000000000000000".to_vec(), }; - let now: i32 = 15000000; - let expected = - (b"1234567891011121314100000000000000000000".to_vec(), vec![]); + let now = Duration::new(15000000, 0); + let expected = b"1234567891011121314100000000000000000000".to_vec(); assert_eq!( expected, - pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap() + pack_dirstate(&mut state_map, ©map, parents, now).unwrap() ); + + assert!(state_map.is_empty()) } #[test] fn test_pack_dirstate_one_entry() { - let dirstate_vec: DirstateVec = vec![( - vec!['f' as u8, '1' as u8], - DirstateEntry { - state: 'n' as i8, - mode: 0o644, - size: 0, - mtime: 791231220, - }, - )]; - let copymap = HashMap::new(); - let parents = DirstateParents { - p1: b"12345678910111213141", - p2: b"00000000000000000000", - }; - let now: i32 = 15000000; - let expected = ( - [ - 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, - 49, 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, - 0, 0, 0, 47, 41, 58, 244, 0, 0, 0, 2, 102, 49, - ] - .to_vec(), - vec![], - ); - - assert_eq!( - expected, - pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap() - ); - } - #[test] - fn test_pack_dirstate_one_entry_with_copy() { - let dirstate_vec: DirstateVec = vec![( + let expected_state_map: StateMap = [( b"f1".to_vec(), DirstateEntry { state: 'n' as i8, @@ -209,35 +181,36 @@ size: 0, mtime: 791231220, }, - )]; - let mut copymap = HashMap::new(); - copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); + )] + .iter() + .cloned() + .collect(); + let mut state_map = expected_state_map.clone(); + + let copymap = HashMap::new(); let parents = DirstateParents { - p1: b"12345678910111213141", - p2: b"00000000000000000000", + p1: b"12345678910111213141".to_vec(), + p2: b"00000000000000000000".to_vec(), }; - let now: i32 = 15000000; - let expected = ( - [ - 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, - 49, 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, - 0, 0, 0, 47, 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, - 112, 121, 110, 97, 109, 101, - ] - .to_vec(), - vec![], - ); + let now = Duration::new(15000000, 0); + let expected = [ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49, + 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47, + 41, 58, 244, 0, 0, 0, 2, 102, 49, + ] + .to_vec(); assert_eq!( expected, - pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap() + pack_dirstate(&mut state_map, ©map, parents, now).unwrap() ); - } + assert_eq!(expected_state_map, state_map); + } #[test] - fn test_parse_pack_one_entry_with_copy() { - let dirstate_vec: DirstateVec = vec![( + fn test_pack_dirstate_one_entry_with_copy() { + let expected_state_map: StateMap = [( b"f1".to_vec(), DirstateEntry { state: 'n' as i8, @@ -245,36 +218,76 @@ size: 0, mtime: 791231220, }, - )]; + )] + .iter() + .cloned() + .collect(); + let mut state_map = expected_state_map.clone(); let mut copymap = HashMap::new(); copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); let parents = DirstateParents { - p1: b"12345678910111213141", - p2: b"00000000000000000000", + p1: b"12345678910111213141".to_vec(), + p2: b"00000000000000000000".to_vec(), }; - let now: i32 = 15000000; - let result = - pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap(); + let now = Duration::new(15000000, 0); + let expected = [ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49, + 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47, + 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97, + 109, 101, + ] + .to_vec(); assert_eq!( - ( - parents, - dirstate_vec, - copymap - .iter() - .map(|(k, v)| CopyVecEntry { - path: k.as_slice(), - copy_path: v.as_slice() - }) - .collect() - ), - parse_dirstate(result.0.as_slice()).unwrap() + expected, + pack_dirstate(&mut state_map, ©map, parents, now).unwrap() + ); + assert_eq!(expected_state_map, state_map); + } + + #[test] + fn test_parse_pack_one_entry_with_copy() { + let mut state_map: StateMap = [( + b"f1".to_vec(), + DirstateEntry { + state: 'n' as i8, + mode: 0o644, + size: 0, + mtime: 791231220, + }, + )] + .iter() + .cloned() + .collect(); + let mut copymap = HashMap::new(); + copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); + let parents = DirstateParents { + p1: b"12345678910111213141".to_vec(), + p2: b"00000000000000000000".to_vec(), + }; + let now = Duration::new(15000000, 0); + let result = + pack_dirstate(&mut state_map, ©map, parents.clone(), now) + .unwrap(); + + let mut new_state_map: StateMap = HashMap::new(); + let mut new_copy_map: CopyMap = HashMap::new(); + let new_parents = parse_dirstate( + &mut new_state_map, + &mut new_copy_map, + result.as_slice(), + ) + .unwrap(); + assert_eq!( + (parents, state_map, copymap), + (new_parents, new_state_map, new_copy_map) ) } #[test] fn test_parse_pack_multiple_entries_with_copy() { - let dirstate_vec: DirstateVec = vec![ + let mut state_map: StateMap = [ ( b"f1".to_vec(), DirstateEntry { @@ -311,39 +324,40 @@ mtime: -1, }, ), - ]; + ] + .iter() + .cloned() + .collect(); let mut copymap = HashMap::new(); copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); copymap.insert(b"f4\xF6".to_vec(), b"copyname2".to_vec()); let parents = DirstateParents { - p1: b"12345678910111213141", - p2: b"00000000000000000000", + p1: b"12345678910111213141".to_vec(), + p2: b"00000000000000000000".to_vec(), }; - let now: i32 = 15000000; + let now = Duration::new(15000000, 0); let result = - pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap(); + pack_dirstate(&mut state_map, ©map, parents.clone(), now) + .unwrap(); + let mut new_state_map: StateMap = HashMap::new(); + let mut new_copy_map: CopyMap = HashMap::new(); + let new_parents = parse_dirstate( + &mut new_state_map, + &mut new_copy_map, + result.as_slice(), + ) + .unwrap(); assert_eq!( - (parents, dirstate_vec, copymap), - parse_dirstate(result.0.as_slice()) - .and_then(|(p, dvec, cvec)| Ok(( - p, - dvec, - cvec.iter() - .map(|entry| ( - entry.path.to_vec(), - entry.copy_path.to_vec() - )) - .collect() - ))) - .unwrap() + (parents, state_map, copymap), + (new_parents, new_state_map, new_copy_map) ) } #[test] /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4 fn test_parse_pack_one_entry_with_copy_and_time_conflict() { - let dirstate_vec: DirstateVec = vec![( + let mut state_map: StateMap = [( b"f1".to_vec(), DirstateEntry { state: 'n' as i8, @@ -351,21 +365,34 @@ size: 0, mtime: 15000000, }, - )]; + )] + .iter() + .cloned() + .collect(); let mut copymap = HashMap::new(); copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); let parents = DirstateParents { - p1: b"12345678910111213141", - p2: b"00000000000000000000", + p1: b"12345678910111213141".to_vec(), + p2: b"00000000000000000000".to_vec(), }; - let now: i32 = 15000000; + let now = Duration::new(15000000, 0); let result = - pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap(); + pack_dirstate(&mut state_map, ©map, parents.clone(), now) + .unwrap(); + + let mut new_state_map: StateMap = HashMap::new(); + let mut new_copy_map: CopyMap = HashMap::new(); + let new_parents = parse_dirstate( + &mut new_state_map, + &mut new_copy_map, + result.as_slice(), + ) + .unwrap(); assert_eq!( ( parents, - vec![( + [( b"f1".to_vec(), DirstateEntry { state: 'n' as i8, @@ -373,16 +400,13 @@ size: 0, mtime: -1 } - )], - copymap - .iter() - .map(|(k, v)| CopyVecEntry { - path: k.as_slice(), - copy_path: v.as_slice() - }) - .collect() + )] + .iter() + .cloned() + .collect::(), + copymap, ), - parse_dirstate(result.0.as_slice()).unwrap() + (new_parents, new_state_map, new_copy_map) ) } } diff --git a/rust/hg-core/src/lib.rs b/rust/hg-core/src/lib.rs --- a/rust/hg-core/src/lib.rs +++ b/rust/hg-core/src/lib.rs @@ -17,8 +17,7 @@ pub use dirstate::{ dirs_multiset::DirsMultiset, parsers::{pack_dirstate, parse_dirstate}, - CopyVec, CopyVecEntry, DirsIterable, DirstateEntry, DirstateParents, - DirstateVec, + CopyMap, DirsIterable, DirstateEntry, DirstateParents, StateMap, }; mod filepatterns; mod utils; @@ -66,6 +65,7 @@ TooLittleData, Overflow, CorruptedEntry(String), + Damaged, } #[derive(Debug, PartialEq)] diff --git a/rust/hg-cpython/src/dirstate/dirs_multiset.rs b/rust/hg-cpython/src/dirstate/dirs_multiset.rs --- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs +++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs @@ -15,7 +15,7 @@ ToPyObject, }; -use dirstate::extract_dirstate_vec; +use dirstate::extract_dirstate; use hg::{DirsIterable, DirsMultiset, DirstateMapError}; py_class!(pub class Dirs |py| { @@ -32,12 +32,10 @@ if let Some(skip) = skip { skip_state = Some(skip.extract::(py)?.data(py)[0] as i8); } - let dirs_map; - - if let Ok(map) = map.cast_as::(py) { - let dirstate_vec = extract_dirstate_vec(py, &map)?; - dirs_map = DirsMultiset::new( - DirsIterable::Dirstate(dirstate_vec), + let inner = if let Ok(map) = map.cast_as::(py) { + let dirstate = extract_dirstate(py, &map)?; + DirsMultiset::new( + DirsIterable::Dirstate(&dirstate), skip_state, ) } else { @@ -45,13 +43,13 @@ .iter(py)? .map(|o| Ok(o?.extract::(py)?.data(py).to_owned())) .collect(); - dirs_map = DirsMultiset::new( - DirsIterable::Manifest(map?), + DirsMultiset::new( + DirsIterable::Manifest(&map?), skip_state, ) - } + }; - Self::create_instance(py, RefCell::new(dirs_map)) + Self::create_instance(py, RefCell::new(inner)) } def addpath(&self, path: PyObject) -> PyResult { diff --git a/rust/hg-cpython/src/dirstate/mod.rs b/rust/hg-cpython/src/dirstate/mod.rs --- a/rust/hg-cpython/src/dirstate/mod.rs +++ b/rust/hg-cpython/src/dirstate/mod.rs @@ -13,7 +13,7 @@ use cpython::{ PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence, Python, }; -use hg::{DirstateEntry, DirstateVec}; +use hg::{DirstateEntry, StateMap}; use std::ffi::CStr; #[cfg(feature = "python27")] @@ -59,10 +59,7 @@ } } -pub fn extract_dirstate_vec( - py: Python, - dmap: &PyDict, -) -> Result { +pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result { dmap.items(py) .iter() .map(|(filename, stats)| { diff --git a/rust/hg-cpython/src/parsers.rs b/rust/hg-cpython/src/parsers.rs --- a/rust/hg-cpython/src/parsers.rs +++ b/rust/hg-cpython/src/parsers.rs @@ -12,17 +12,18 @@ //! use cpython::{ exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python, - ToPyObject, PythonObject + ToPyObject, }; use hg::{ - pack_dirstate, parse_dirstate, CopyVecEntry, DirstateEntry, - DirstatePackError, DirstateParents, DirstateParseError, + pack_dirstate, parse_dirstate, DirstateEntry, DirstatePackError, + DirstateParents, DirstateParseError, }; use std::collections::HashMap; use libc::c_char; -use dirstate::{decapsule_make_dirstate_tuple, extract_dirstate_vec}; +use dirstate::{decapsule_make_dirstate_tuple, extract_dirstate}; +use std::time::Duration; fn parse_dirstate_wrapper( py: Python, @@ -30,12 +31,15 @@ copymap: PyDict, st: PyBytes, ) -> PyResult { - match parse_dirstate(st.data(py)) { - Ok((parents, dirstate_vec, copies)) => { - for (filename, entry) in dirstate_vec { + let mut dirstate_map = HashMap::new(); + let mut copies = HashMap::new(); + + match parse_dirstate(&mut dirstate_map, &mut copies, st.data(py)) { + Ok(parents) => { + for (filename, entry) in dirstate_map { dmap.set_item( py, - PyBytes::new(py, &filename[..]), + PyBytes::new(py, &filename), decapsule_make_dirstate_tuple(py)?( entry.state as c_char, entry.mode, @@ -44,15 +48,17 @@ ), )?; } - for CopyVecEntry { path, copy_path } in copies { + for (path, copy_path) in copies { copymap.set_item( py, - PyBytes::new(py, path), - PyBytes::new(py, copy_path), + PyBytes::new(py, &path), + PyBytes::new(py, ©_path), )?; } - Ok((PyBytes::new(py, parents.p1), PyBytes::new(py, parents.p2)) - .to_py_object(py)) + Ok( + (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2)) + .to_py_object(py), + ) } Err(e) => Err(PyErr::new::( py, @@ -64,6 +70,9 @@ "overflow in dirstate".to_string() } DirstateParseError::CorruptedEntry(e) => e, + DirstateParseError::Damaged => { + "dirstate appears to be damaged".to_string() + } }, )), } @@ -81,7 +90,7 @@ let p2 = pl.get_item(py, 1).extract::(py)?; let p2: &[u8] = p2.data(py); - let dirstate_vec = extract_dirstate_vec(py, &dmap)?; + let mut dirstate_map = extract_dirstate(py, &dmap)?; let copies: Result, Vec>, PyErr> = copymap .items(py) @@ -95,12 +104,15 @@ .collect(); match pack_dirstate( - &dirstate_vec, + &mut dirstate_map, &copies?, - DirstateParents { p1, p2 }, - now.as_object().extract::(py)?, + DirstateParents { + p1: p1.to_owned(), + p2: p2.to_owned(), + }, + Duration::from_secs(now.value(py) as u64), ) { - Ok((packed, new_dirstate_vec)) => { + Ok(packed) => { for ( filename, DirstateEntry { @@ -109,7 +121,7 @@ size, mtime, }, - ) in new_dirstate_vec + ) in dirstate_map { dmap.set_item( py,