# HG changeset patch # User Raphaël Gomès # Date 2023-06-27 14:32:09 # 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 --git a/rust/hg-core/src/revlog/index.rs b/rust/hg-core/src/revlog/index.rs --- a/rust/hg-core/src/revlog/index.rs +++ b/rust/hg-core/src/revlog/index.rs @@ -2,13 +2,17 @@ use std::fmt::Debug; 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 @@ impl std::ops::Index; +} + +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 @@ impl Index { 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 --git a/rust/hg-core/src/revlog/node.rs b/rust/hg-core/src/revlog/node.rs --- a/rust/hg-core/src/revlog/node.rs +++ b/rust/hg-core/src/revlog/node.rs @@ -20,6 +20,10 @@ use std::fmt; /// 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.