Skip to main content

vole_document/field/
resource.rs

1//! Cross-document content-addressed resource sharing (Phase 12.8, ADR-0034).
2//!
3//! A *shareable resource* is a byte sequence embedded verbatim in more than one
4//! document — an image, a font, or an embedded attachment. Its identity is
5//! **content identity**: a [`ResourceBlob`](crate::field::node::NodeKind::ResourceBlob)
6//! node holds the exact bytes inline, so its canonical encoding (hence its
7//! [`NodeId`]) depends only on those bytes and is identical across every document
8//! and every format that embeds them. There is no second keying scheme: the
9//! existing content-addressed seed store physically shares one blob and one cache
10//! entry for all occurrences.
11//!
12//! Two honesty rules govern this module:
13//!
14//! * **Only byte-identical units share.** Recognition is a *byte signature*
15//!   (PNG/JPEG/GIF/WOFF/WOFF2/TTF/OTF), never a member name or a declared media
16//!   type: a name is logical bytes and never authority (research B), and the
17//!   plan forbids cross-format *semantic* dedup (ADR-0034 §3). A wrong
18//!   classification can only cost a little space, never correctness, because
19//!   sharing still requires exact byte equality.
20//! * **A shared blob is not a compression claim.** It pays its own byte cost for
21//!   the first document that carries it; a second document carrying the same bytes
22//!   writes nothing. Reuse is scored as *work* (`nodes_reused`,
23//!   `retained_inverse_work_fraction`), never as a byte fraction.
24
25use crate::error::Result;
26use crate::field::FieldStore;
27use crate::field::node::{NodeKind, SeedNode};
28use crate::store::NodeId;
29
30/// Largest resource recorded as one content-addressed blob (1 MiB). A unit above
31/// this bound keeps its exact source-span leaf and simply does not share; bounding
32/// the blob keeps a single seed node within a sane framing envelope.
33pub const MAX_SHARED_RESOURCE_BYTES: usize = 1 << 20;
34
35/// Format-neutral provenance for a shared resource blob. It is part of the node's
36/// canonical encoding, hence of its [`NodeId`]: it must be identical in every
37/// adapter or the same bytes would hash differently and never share.
38pub const RESOURCE_BLOB_PROVENANCE: &str = "res:blob";
39
40/// The content-addressed node for a shareable resource: the exact bytes held
41/// inline, no dependencies. Identical bytes always encode to identical canonical
42/// bytes, hence to one [`NodeId`], across every format.
43pub fn resource_blob_node(bytes: &[u8]) -> SeedNode {
44    let mut node = SeedNode::new(
45        NodeKind::ResourceBlob,
46        bytes.len() as u64,
47        bytes.to_vec(),
48        Vec::new(),
49        RESOURCE_BLOB_PROVENANCE,
50    );
51    node.limits.max_output_bytes = node.limits.max_output_bytes.max(bytes.len() as u64);
52    node
53}
54
55/// Whether `bytes` carry a recognized binary-resource signature and are within
56/// the sharing size bound. Purely a byte-level fact about the payload.
57pub fn is_shareable_resource(bytes: &[u8]) -> bool {
58    bytes.len() <= MAX_SHARED_RESOURCE_BYTES && starts_with_signature(bytes)
59}
60
61fn starts_with_signature(b: &[u8]) -> bool {
62    const SIGNATURES: &[&[u8]] = &[
63        b"\x89PNG\r\n\x1a\n", // PNG
64        b"\xFF\xD8\xFF",      // JPEG (JFIF/EXIF)
65        b"GIF87a",            // GIF 87a
66        b"GIF89a",            // GIF 89a
67        b"wOFF",              // WOFF
68        b"wOF2",              // WOFF2
69        b"\x00\x01\x00\x00",  // TrueType
70        b"OTTO",              // OpenType/CFF
71        b"ttcf",              // TrueType collection
72    ];
73    SIGNATURES.iter().any(|sig| b.starts_with(sig))
74}
75
76/// The outcome of registering one shared resource blob.
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct ResourceRegistration {
79    /// The resource's content id.
80    pub id: NodeId,
81    /// Bytes held by the blob.
82    pub len: u64,
83    /// Whether the id already existed in the store: a **representation** fact —
84    /// `true` means the bytes were already present and nothing new was written.
85    /// This is the `nodes_id_shared` witness; it is *not* a work-reuse witness.
86    pub preexisting: bool,
87}
88
89/// Register a shared resource blob in `store`, returning its content id and
90/// whether the id already existed. Idempotent: a repeat writes nothing.
91pub fn register_resource_blob(
92    store: &mut FieldStore,
93    bytes: &[u8],
94) -> Result<ResourceRegistration> {
95    let node = resource_blob_node(bytes);
96    let id = node.content_id();
97    let preexisting = store.seeds().contains_node(&id)?;
98    store.seeds_mut().put_node(&node.encode_canonical())?;
99    Ok(ResourceRegistration {
100        id,
101        len: bytes.len() as u64,
102        preexisting,
103    })
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn signatures_are_recognized_and_bounded() {
112        assert!(is_shareable_resource(b"\x89PNG\r\n\x1a\nrest"));
113        assert!(is_shareable_resource(b"\xFF\xD8\xFF\xE0jpeg"));
114        assert!(is_shareable_resource(b"GIF89a...."));
115        assert!(is_shareable_resource(b"wOFF...."));
116        // Not a resource: XML, plain text, and an empty slice.
117        assert!(!is_shareable_resource(b"<?xml version=\"1.0\"?>"));
118        assert!(!is_shareable_resource(b"plain text"));
119        assert!(!is_shareable_resource(b""));
120    }
121
122    #[test]
123    fn identical_bytes_produce_one_content_id() {
124        let bytes = b"\x89PNG\r\n\x1a\nshared-image-bytes";
125        let a = resource_blob_node(bytes);
126        let b = resource_blob_node(bytes);
127        assert_eq!(a.content_id(), b.content_id());
128        let different = resource_blob_node(b"\x89PNG\r\n\x1a\nother-image-bytes");
129        assert_ne!(a.content_id(), different.content_id());
130    }
131
132    #[test]
133    fn oversized_units_do_not_share() {
134        let mut big = vec![0u8; MAX_SHARED_RESOURCE_BYTES + 1];
135        big[0] = 0x89;
136        big[1] = b'P';
137        assert!(!is_shareable_resource(&big));
138    }
139}