MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / deserialize

Method deserialize

atomic-core/src/change/change.rs:458–572  ·  view source on GitHub ↗

Deserialize a change from a reader (V3 format). Reads a complete V3 change file, validates the structure, decompresses sections, and verifies the content hash against the trailer. # Arguments `reader` - Where to read the serialized change from # Returns A tuple of `(change, hash)` where hash is the verified content hash. # Errors Returns an error if: - The file header is invalid (wrong magi

(reader: &mut R)

Source from the content-addressed store, hash-verified

456 /// - Any section fails to decompress or deserialize
457 /// - The content hash doesn't match the trailer
458 pub fn deserialize<R: Read>(reader: &mut R) -> Result<(Self, Hash), ChangeError> {
459 use format_v3::*;
460
461 // Detect V2 (bincode) format and give a clear error.
462 // V2 files start with a little-endian u64 version number (1 or 2).
463 // V3 files start with b"ATOM". If the first 4 bytes look like a
464 // small integer rather than ASCII "ATOM", it's an old format.
465 //
466 // We read into a buffer first so we can pass it to ChangeReader
467 // if it IS V3 (since Read is not Seek).
468 let mut header_peek = [0u8; 4];
469 reader.read_exact(&mut header_peek)?;
470
471 if &header_peek != b"ATOM" {
472 // Check if it looks like a V2 version number (1 or 2 as LE u64)
473 let maybe_version = u32::from_le_bytes(header_peek);
474 if maybe_version == 1 || maybe_version == 2 {
475 return Err(ChangeError::Invalid(format!(
476 "This change file uses the legacy V2 format (version {}). \
477 It must be re-recorded with the current version of Atomic. \
478 Delete .atomic/ and run: atomic init && atomic add -r . && atomic record -m \"re-record\"",
479 maybe_version
480 )));
481 }
482 return Err(ChangeError::Format(FormatError::InvalidMagic {
483 got: header_peek,
484 }));
485 }
486
487 // It's V3 — reconstruct a reader with the magic bytes prepended.
488 // Chain the 4 bytes we already read with the rest of the stream.
489 let rest = reader;
490 let mut combined = std::io::Cursor::new(header_peek).chain(rest);
491
492 // 1. Open the reader (reads header + hash table)
493 let mut change_reader = ChangeReader::open(&mut combined)?;
494 let hash_table = change_reader.hash_table().clone();
495
496 // 2. Read all sections
497 let mut header: Option<ChangeHeader> = None;
498 let mut dependencies: Vec<Hash> = Vec::new();
499 let mut provenance: Vec<Provenance> = Vec::new();
500 let mut hunks: Vec<GraphOp<Option<Hash>>> = Vec::new();
501 let mut file_ops: Vec<FileOps> = Vec::new();
502 let mut contents: Vec<u8> = Vec::new();
503 let mut unhashed: Option<serde_json::Value> = None;
504
505 while let Some(section) = change_reader.next_section()? {
506 match section.section_type {
507 SectionType::Header => {
508 header = Some(section.deserialize()?);
509 }
510 SectionType::Dependencies => {
511 let dep_indices: Vec<u16> = section.deserialize()?;
512 for idx in dep_indices {
513 if let Some(hash_bytes) = hash_table.resolve(idx) {
514 dependencies.push(Hash::from_bytes(*hash_bytes));
515 }

Callers

nothing calls this directly

Calls 8

hash_tableMethod · 0.80
next_sectionMethod · 0.80
expand_graph_opMethod · 0.80
cloneMethod · 0.45
resolveMethod · 0.45
pushMethod · 0.45
opsMethod · 0.45
verifyMethod · 0.45

Tested by

no test coverage detected