Deserialize a provenance graph from bytes, returning the graph and its hash. The hash is computed over the input bytes (the entire serialized form).
(data: &[u8])
| 265 | /// |
| 266 | /// The hash is computed over the input bytes (the entire serialized form). |
| 267 | pub fn deserialize(data: &[u8]) -> Result<(Self, Hash), ProvenanceGraphError> { |
| 268 | if data.len() < MAGIC.len() + 1 { |
| 269 | return Err(ProvenanceGraphError::Codec { |
| 270 | reason: format!( |
| 271 | "data too short: {} bytes (minimum {})", |
| 272 | data.len(), |
| 273 | MAGIC.len() + 1 |
| 274 | ), |
| 275 | }); |
| 276 | } |
| 277 | |
| 278 | if &data[..4] != MAGIC { |
| 279 | return Err(ProvenanceGraphError::Codec { |
| 280 | reason: format!("invalid magic: expected {:?}, got {:?}", MAGIC, &data[..4]), |
| 281 | }); |
| 282 | } |
| 283 | |
| 284 | // Peek at the version byte without fully deserializing. |
| 285 | // The first field in the postcard payload is `version: u8`. |
| 286 | let version_byte = data[4]; |
| 287 | |
| 288 | if version_byte > SCHEMA_VERSION { |
| 289 | return Err(ProvenanceGraphError::UnsupportedVersion { |
| 290 | version: version_byte, |
| 291 | max_supported: SCHEMA_VERSION, |
| 292 | }); |
| 293 | } |
| 294 | |
| 295 | let graph: Self = if version_byte <= 1 { |
| 296 | // v1 payload: no `profile` field. Deserialize into the v1 shim |
| 297 | // struct (identical to the current struct minus `profile`) and |
| 298 | // upgrade to v2 in-memory with `profile: None`. |
| 299 | let v1: ProvenanceGraphV1 = |
| 300 | postcard::from_bytes(&data[4..]).map_err(|e| ProvenanceGraphError::Codec { |
| 301 | reason: format!("postcard deserialize failed (v1): {}", e), |
| 302 | })?; |
| 303 | ProvenanceGraph { |
| 304 | version: SCHEMA_VERSION, |
| 305 | timestamp: v1.timestamp, |
| 306 | session_id: v1.session_id, |
| 307 | agent_name: v1.agent_name, |
| 308 | agent_display_name: v1.agent_display_name, |
| 309 | agent_vendor: v1.agent_vendor, |
| 310 | nodes: v1.nodes, |
| 311 | edges: v1.edges, |
| 312 | changes_explained: v1.changes_explained, |
| 313 | previous: v1.previous, |
| 314 | stats: v1.stats, |
| 315 | profile: None, |
| 316 | } |
| 317 | } else { |
| 318 | postcard::from_bytes(&data[4..]).map_err(|e| ProvenanceGraphError::Codec { |
| 319 | reason: format!("postcard deserialize failed: {}", e), |
| 320 | })? |
| 321 | }; |
| 322 | |
| 323 | let hash = Hash::of(data); |
| 324 | Ok((graph, hash)) |