# HG changeset patch # User Raphaël Gomès # Date 1687876329 -7200 # Node ID b4d152a28742dbbd206e12fa3a223cf93fe1df68 # Parent 1ef4a36a934d15cd29422ed02c4873320ebe34d1 rust-index: add append method This is the first time the Rust index has any notion of mutability. This will be used in a future patch from Python, to start synchronizing the Rust index and the C index. diff -r 1ef4a36a934d -r b4d152a28742 rust/hg-core/src/revlog/index.rs --- a/rust/hg-core/src/revlog/index.rs Mon Jun 26 19:16:07 2023 +0200 +++ b/rust/hg-core/src/revlog/index.rs Tue Jun 27 16:32:09 2023 +0200 @@ -2,13 +2,17 @@ use std::ops::Deref; use byteorder::{BigEndian, ByteOrder}; +use bytes_cast::{unaligned, BytesCast}; +use super::REVIDX_KNOWN_FLAGS; use crate::errors::HgError; +use crate::node::{NODE_BYTES_LENGTH, STORED_NODE_ID_BYTES}; use crate::revlog::node::Node; use crate::revlog::{Revision, NULL_REVISION}; -use crate::{Graph, GraphError, RevlogIndex, UncheckedRevision}; +use crate::{Graph, GraphError, RevlogError, RevlogIndex, UncheckedRevision}; pub const INDEX_ENTRY_SIZE: usize = 64; +pub const COMPRESSION_MODE_INLINE: u8 = 2; pub struct IndexHeader { header_bytes: [u8; 4], @@ -120,6 +124,81 @@ } } +pub struct RevisionDataParams { + flags: u16, + data_offset: u64, + data_compressed_length: i32, + data_uncompressed_length: i32, + data_delta_base: i32, + link_rev: i32, + parent_rev_1: i32, + parent_rev_2: i32, + node_id: [u8; NODE_BYTES_LENGTH], + _sidedata_offset: u64, + _sidedata_compressed_length: i32, + data_compression_mode: u8, + _sidedata_compression_mode: u8, + _rank: i32, +} + +#[derive(BytesCast)] +#[repr(C)] +pub struct RevisionDataV1 { + data_offset_or_flags: unaligned::U64Be, + data_compressed_length: unaligned::I32Be, + data_uncompressed_length: unaligned::I32Be, + data_delta_base: unaligned::I32Be, + link_rev: unaligned::I32Be, + parent_rev_1: unaligned::I32Be, + parent_rev_2: unaligned::I32Be, + node_id: [u8; STORED_NODE_ID_BYTES], +} + +fn _static_assert_size_of_revision_data_v1() { + let _ = std::mem::transmute::; +} + +impl RevisionDataParams { + pub fn validate(&self) -> Result<(), RevlogError> { + if self.flags & !REVIDX_KNOWN_FLAGS != 0 { + return Err(RevlogError::corrupted(format!( + "unknown revlog index flags: {}", + self.flags + ))); + } + if self.data_compression_mode != COMPRESSION_MODE_INLINE { + return Err(RevlogError::corrupted(format!( + "invalid data compression mode: {}", + self.data_compression_mode + ))); + } + // FIXME isn't this only for v2 or changelog v2? + if self._sidedata_compression_mode != COMPRESSION_MODE_INLINE { + return Err(RevlogError::corrupted(format!( + "invalid sidedata compression mode: {}", + self._sidedata_compression_mode + ))); + } + Ok(()) + } + + pub fn into_v1(self) -> RevisionDataV1 { + let data_offset_or_flags = self.data_offset << 16 | self.flags as u64; + let mut node_id = [0; STORED_NODE_ID_BYTES]; + node_id[..NODE_BYTES_LENGTH].copy_from_slice(&self.node_id); + RevisionDataV1 { + data_offset_or_flags: data_offset_or_flags.into(), + data_compressed_length: self.data_compressed_length.into(), + data_uncompressed_length: self.data_uncompressed_length.into(), + data_delta_base: self.data_delta_base.into(), + link_rev: self.link_rev.into(), + parent_rev_1: self.parent_rev_1.into(), + parent_rev_2: self.parent_rev_2.into(), + node_id, + } + } +} + /// A Revlog index pub struct Index { bytes: IndexData, @@ -283,6 +362,20 @@ offset_override, } } + + /// TODO move this to the trait probably, along with other things + pub fn append( + &mut self, + revision_data: RevisionDataParams, + ) -> Result<(), RevlogError> { + revision_data.validate()?; + let new_offset = self.bytes.len(); + if let Some(offsets) = self.offsets.as_mut() { + offsets.push(new_offset) + } + self.bytes.added.extend(revision_data.into_v1().as_bytes()); + Ok(()) + } } impl super::RevlogIndex for Index { diff -r 1ef4a36a934d -r b4d152a28742 rust/hg-core/src/revlog/node.rs --- a/rust/hg-core/src/revlog/node.rs Mon Jun 26 19:16:07 2023 +0200 +++ b/rust/hg-core/src/revlog/node.rs Tue Jun 27 16:32:09 2023 +0200 @@ -20,6 +20,10 @@ /// the future. pub const NODE_BYTES_LENGTH: usize = 20; +/// The length in bytes set aside on disk for a `Node`. Revlog up to v1 only +/// use 20 out of those 32. +pub const STORED_NODE_ID_BYTES: usize = 32; + /// Id of the null node. /// /// Used to indicate the absence of node.