Mercurial > hg
view rust/hg-core/src/dirstate/parsers.rs @ 52303:b422acba55f1
rust-dirstate: remove star exports
This makes the crate's imports confusing and muddies the discovery of the
code.
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Mon, 04 Nov 2024 11:07:05 +0100 |
parents | db5c202eff36 |
children |
line wrap: on
line source
// Copyright 2019 Raphaël Gomès <rgomes@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. use crate::dirstate::entry::{DirstateEntry, EntryState}; use crate::errors::HgError; use crate::utils::hg_path::HgPath; use crate::DirstateParents; use byteorder::{BigEndian, WriteBytesExt}; use bytes_cast::{unaligned, BytesCast}; /// Parents are stored in the dirstate as byte hashes. pub const PARENT_SIZE: usize = 20; /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits. const MIN_ENTRY_SIZE: usize = 17; type ParseResult<'a> = ( &'a DirstateParents, Vec<(&'a HgPath, DirstateEntry)>, Vec<(&'a HgPath, &'a HgPath)>, ); pub fn parse_dirstate_parents( contents: &[u8], ) -> Result<&DirstateParents, HgError> { let contents_len = contents.len(); let (parents, _rest) = DirstateParents::from_bytes(contents).map_err(|_| { HgError::corrupted(format!( "Too little data for dirstate: {contents_len} bytes.", )) })?; Ok(parents) } #[logging_timer::time("trace")] pub fn parse_dirstate(contents: &[u8]) -> Result<ParseResult, HgError> { let mut copies = Vec::new(); let mut entries = Vec::new(); let parents = parse_dirstate_entries(contents, |path, entry, copy_source| { if let Some(source) = copy_source { copies.push((path, source)); } entries.push((path, *entry)); Ok(()) })?; Ok((parents, entries, copies)) } #[derive(BytesCast)] #[repr(C)] struct RawEntry { state: u8, mode: unaligned::I32Be, size: unaligned::I32Be, mtime: unaligned::I32Be, length: unaligned::I32Be, } pub fn parse_dirstate_entries<'a>( mut contents: &'a [u8], mut each_entry: impl FnMut( &'a HgPath, &DirstateEntry, Option<&'a HgPath>, ) -> Result<(), HgError>, ) -> Result<&'a DirstateParents, HgError> { let mut entry_idx = 0; let original_len = contents.len(); let (parents, rest) = DirstateParents::from_bytes(contents).map_err(|_| { HgError::corrupted(format!( "Too little data for dirstate: {} bytes.", original_len )) })?; contents = rest; while !contents.is_empty() { let (raw_entry, rest) = RawEntry::from_bytes(contents) .map_err(|_| HgError::corrupted(format!( "dirstate corrupted: ran out of bytes at entry header {}, offset {}.", entry_idx, original_len-contents.len())))?; let entry = DirstateEntry::from_v1_data( EntryState::try_from(raw_entry.state)?, raw_entry.mode.get(), raw_entry.size.get(), raw_entry.mtime.get(), ); let filename_len = raw_entry.length.get() as usize; let (paths, rest) = u8::slice_from_bytes(rest, filename_len) .map_err(|_| HgError::corrupted(format!( "dirstate corrupted: ran out of bytes at entry {}, offset {} (expected {} bytes).", entry_idx, original_len-contents.len(), filename_len)) )?; // `paths` is either a single path, or two paths separated by a NULL // byte let mut iter = paths.splitn(2, |&byte| byte == b'\0'); let path = HgPath::new( iter.next().expect("splitn always yields at least one item"), ); let copy_source = iter.next().map(HgPath::new); each_entry(path, &entry, copy_source)?; entry_idx += 1; contents = rest; } Ok(parents) } fn packed_filename_and_copy_source_size( filename: &HgPath, copy_source: Option<&HgPath>, ) -> usize { filename.len() + if let Some(source) = copy_source { b"\0".len() + source.len() } else { 0 } } pub fn packed_entry_size( filename: &HgPath, copy_source: Option<&HgPath>, ) -> usize { MIN_ENTRY_SIZE + packed_filename_and_copy_source_size(filename, copy_source) } pub fn pack_entry( filename: &HgPath, entry: &DirstateEntry, copy_source: Option<&HgPath>, packed: &mut Vec<u8>, ) { let length = packed_filename_and_copy_source_size(filename, copy_source); let (state, mode, size, mtime) = entry.v1_data(); // Unwrapping because `impl std::io::Write for Vec<u8>` never errors packed.write_u8(state).unwrap(); packed.write_i32::<BigEndian>(mode).unwrap(); packed.write_i32::<BigEndian>(size).unwrap(); packed.write_i32::<BigEndian>(mtime).unwrap(); packed.write_i32::<BigEndian>(length as i32).unwrap(); packed.extend(filename.as_bytes()); if let Some(source) = copy_source { packed.push(b'\0'); packed.extend(source.as_bytes()); } }