1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! Shared support for the golden-vector generator and the conformance gate.
//!
//! Both `tests/gen_vectors.rs` (the authority that *writes* `tests/vectors.json`)
//! and `tests/conformance.rs` (the gate that *reads* it) need the exact same
//! decoding of a vector's JSON `value` into an [`Ipld`] tree. Keeping that one
//! conversion here guarantees the file the generator emits is parsed identically
//! to the way the gate validates it.
//!
//! ## The JSON-expressible dag-cbor subset
//!
//! A vector's `value` is a plain JSON document restricted to the subset that
//! round-trips faithfully through *both* the serde data model and Python natives:
//! `null`, `bool`, integers (kept within `i64` range), strings, arrays, and
//! objects with string keys. JSON cannot faithfully carry CBOR byte strings or
//! distinguish them from text, so bytes are written as a tagged escape object
//! `{"$bytes": "<hex>"}` that *both* loaders (this one and the Python one)
//! expand into a real byte string. Non-integer floats are deliberately excluded
//! (JSON float ambiguity + dag-cbor float rules make them a separate concern),
//! as are `Link`/`ContentId` values — the shared JSON vector format carries no
//! native CID type, so the frozen `ContentId` serde repr is exercised in the
//! per-language suites instead. This shared file pins only the cross-language
//! subset the JSON format can faithfully carry.
use Ipld;
use BTreeMap;
/// The reserved key that escapes a CBOR byte string inside JSON.
///
/// A single-key object `{"$bytes": "<hex>"}` decodes to [`Ipld::Bytes`]; the hex
/// payload is the raw bytes. Both this loader and the Python loader recognize it.
pub const BYTES_TAG: &str = "$bytes";
/// Decode a hex string into raw bytes. Test-only; panics on malformed input so a
/// bad vector fails loudly rather than silently mis-encoding.
/// Encode raw bytes as a lowercase hex string (no separators).
/// Convert a vector's JSON `value` into the [`Ipld`] tree it denotes.
///
/// This is the heart of the shared contract: the same JSON produces the same
/// `Ipld`, so the generator and the gate canonicalize identical inputs. The
/// `{"$bytes": "<hex>"}` escape becomes [`Ipld::Bytes`]; everything else maps
/// structurally. Integers must fit `i64` (the JSON-expressible subset); floats
/// are rejected (excluded by design).