diff options
Diffstat (limited to 'vendor/gix-index/src/extension/decode.rs')
-rw-r--r-- | vendor/gix-index/src/extension/decode.rs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/vendor/gix-index/src/extension/decode.rs b/vendor/gix-index/src/extension/decode.rs new file mode 100644 index 000000000..af032f4e3 --- /dev/null +++ b/vendor/gix-index/src/extension/decode.rs @@ -0,0 +1,80 @@ +use std::convert::TryInto; + +use crate::{extension, extension::Signature, util::from_be_u32}; + +pub(crate) fn header(data: &[u8]) -> (Signature, u32, &[u8]) { + let (signature, data) = data.split_at(4); + let (size, data) = data.split_at(4); + (signature.try_into().unwrap(), from_be_u32(size), data) +} + +mod error { + use crate::extension; + + /// The error returned when decoding extensions. + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error( + "Encountered mandatory extension '{}' which isn't implemented yet", + String::from_utf8_lossy(signature) + )] + MandatoryUnimplemented { signature: extension::Signature }, + #[error("Could not parse mandatory link extension")] + Link(#[from] extension::link::decode::Error), + } +} +pub use error::Error; + +pub(crate) fn all( + maybe_beginning_of_extensions: &[u8], + object_hash: gix_hash::Kind, +) -> Result<(Outcome, &[u8]), Error> { + let mut ext_iter = match extension::Iter::new_without_checksum(maybe_beginning_of_extensions, object_hash) { + Some(iter) => iter, + None => return Ok((Outcome::default(), maybe_beginning_of_extensions)), + }; + + let mut ext = Outcome::default(); + for (signature, ext_data) in ext_iter.by_ref() { + match signature { + extension::tree::SIGNATURE => { + ext.tree = extension::tree::decode(ext_data, object_hash); + } + extension::resolve_undo::SIGNATURE => { + ext.resolve_undo = extension::resolve_undo::decode(ext_data, object_hash); + } + extension::untracked_cache::SIGNATURE => { + ext.untracked = extension::untracked_cache::decode(ext_data, object_hash); + } + extension::fs_monitor::SIGNATURE => { + ext.fs_monitor = extension::fs_monitor::decode(ext_data); + } + extension::end_of_index_entry::SIGNATURE => {} // skip already done + extension::index_entry_offset_table::SIGNATURE => {} // not relevant/obtained already + mandatory if mandatory[0].is_ascii_lowercase() => match mandatory { + extension::link::SIGNATURE => ext.link = extension::link::decode(ext_data, object_hash)?.into(), + extension::sparse::SIGNATURE => { + if !ext_data.is_empty() { + // only used as a marker, if this changes we need this implementation. + return Err(Error::MandatoryUnimplemented { signature: mandatory }); + } + ext.is_sparse = true + } + unknown => return Err(Error::MandatoryUnimplemented { signature: unknown }), + }, + _unknown => {} // skip unknown extensions, too + } + } + Ok((ext, &maybe_beginning_of_extensions[ext_iter.consumed..])) +} + +#[derive(Default)] +pub(crate) struct Outcome { + pub tree: Option<extension::Tree>, + pub link: Option<extension::Link>, + pub resolve_undo: Option<extension::resolve_undo::Paths>, + pub untracked: Option<extension::UntrackedCache>, + pub fs_monitor: Option<extension::FsMonitor>, + pub is_sparse: bool, +} |