snid 0.2.1

Polyglot sortable identifier protocol with UUID v7-compatible ordering and extended identifier families
Documentation
//! Conformance vector loading and validation tests.

#[allow(unused_imports)]
use crate::core::Snid;
#[allow(unused_imports)]
use crate::error::Error;
#[allow(unused_imports)]
use crate::types::{Bid, Eid, Kid, Lid, Nid, Wid, Xid};

#[cfg(feature = "data")]
use serde::Deserialize;

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct VectorFile {
    pub core: Vec<CoreVector>,
    pub spatial: SpatialVector,
    pub neural: NeuralVector,
    pub ledger: LedgerVector,
    pub world: WorldVector,
    pub edge: EdgeVector,
    pub capability: CapabilityVector,
    pub ephemeral: EIDVector,
    pub bid: BIDVector,
    pub compatibility: CompatibilityVector,
    pub uuidv7: UUIDv7Vector,
    pub negative: NegativeVector,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct CoreVector {
    pub atom: String,
    pub bytes_hex: String,
    pub wire: String,
    pub underscore_wire: String,
    pub timestamp_millis: i64,
    pub tensor_hi: i64,
    pub tensor_lo: i64,
    pub llm_format: LLMFormatVector,
    pub llm_format_v2: LLMFormatVectorV2,
    pub time_bin_hour: i64,
    pub ghosted_bytes_hex: String,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct LLMFormatVector {
    pub atom: String,
    pub timestamp_millis: i64,
    pub machine_or_shard: u32,
    pub sequence: u16,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct LLMFormatVectorV2 {
    pub kind: String,
    pub atom: String,
    pub timestamp_millis: Option<i64>,
    pub spatial_anchor: Option<u64>,
    pub machine_or_shard: Option<u32>,
    pub sequence: Option<u16>,
    pub ghosted: bool,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct SpatialVector {
    pub atom: String,
    pub bytes_hex: String,
    pub wire: String,
    pub h3_cell_hex: String,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct NeuralVector {
    pub head_hex: String,
    pub bytes_hex: String,
    pub semantic_hex: String,
    pub hamming_to_zero: i32,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct LedgerVector {
    pub head_hex: String,
    pub bytes_hex: String,
    pub prev_hex: String,
    pub payload_hex: String,
    pub key_hex: String,
    pub blake3_hex: String,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct WorldVector {
    pub head_hex: String,
    pub bytes_hex: String,
    pub scenario_hex: String,
    pub tensor_words: [i64; 4],
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct EdgeVector {
    pub head_hex: String,
    pub bytes_hex: String,
    pub edge_hex: String,
    pub tensor_words: [i64; 4],
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct CapabilityVector {
    pub head_hex: String,
    pub actor_hex: String,
    pub resource_hex: String,
    pub capability_hex: String,
    pub key_hex: String,
    pub bytes_hex: String,
    pub tensor_words: [i64; 4],
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct EIDVector {
    pub bytes_hex: String,
    pub timestamp_millis: u64,
    pub counter: u16,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct BIDVector {
    pub topology_hex: String,
    pub content_hex: String,
    pub wire: String,
    pub r2_key: String,
    pub neo4j_id: String,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct CompatibilityVector {
    pub bytes_hex: String,
    pub wire: String,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct UUIDv7Vector {
    pub bytes_hex: String,
    pub uuid_string: String,
    pub timestamp_millis: i64,
    pub version: i32,
    pub variant: i32,
}

#[cfg(feature = "data")]
#[derive(Deserialize)]
pub struct NegativeVector {
    pub invalid_atom_wire: String,
    pub invalid_binary_hex: String,
    pub invalid_wire_checksum: String,
    pub invalid_adapter_hex: String,
}

#[cfg(test)]
mod tests {
    #[allow(unused_imports)]
    use super::*;
    #[allow(unused_imports)]
    use crate::core::Snid;
    #[allow(unused_imports)]
    use crate::types::{Bid, Eid, Kid, Lid, Nid, Wid, Xid};

    #[cfg(feature = "data")]
    #[test]
    fn validates_vectors() {
        let raw = std::fs::read_to_string("../conformance/vectors.json")
            .or_else(|_| std::fs::read_to_string("../SNID/conformance/vectors.json"))
            .expect("vectors.json");
        let vectors: VectorFile = serde_json::from_str(&raw).expect("parse vectors");

        for case in vectors.core {
            let expected = Snid::from_hex(&case.bytes_hex).unwrap();
            let (parsed, atom) = Snid::parse_wire(&case.wire).unwrap();
            assert_eq!(parsed, expected);
            assert_eq!(atom, case.atom);
            assert_eq!(expected.to_wire(&case.atom).unwrap(), case.wire);
            assert_eq!(expected.timestamp_millis(), case.timestamp_millis);
            assert_eq!(expected.to_tensor_words(), (case.tensor_hi, case.tensor_lo));
            let llm = expected.to_llm_format(&case.atom).unwrap();
            assert_eq!(llm.atom, case.llm_format.atom);
            assert_eq!(llm.timestamp_millis, case.llm_format.timestamp_millis);
            assert_eq!(llm.machine_or_shard, case.llm_format.machine_or_shard);
            assert_eq!(llm.sequence, case.llm_format.sequence);
            let llm_v2 = expected.to_llm_format_v2(&case.atom).unwrap();
            assert_eq!(llm_v2.kind, case.llm_format_v2.kind);
            assert_eq!(llm_v2.atom, case.llm_format_v2.atom);
            assert_eq!(llm_v2.timestamp_millis, case.llm_format_v2.timestamp_millis);
            assert_eq!(llm_v2.machine_or_shard, case.llm_format_v2.machine_or_shard);
            assert_eq!(llm_v2.sequence, case.llm_format_v2.sequence);
            assert_eq!(llm_v2.ghosted, case.llm_format_v2.ghosted);
            assert_eq!(expected.time_bin(3_600_000), case.time_bin_hour);
            assert_eq!(
                hex::encode(expected.with_ghost_bit(true).0),
                case.ghosted_bytes_hex
            );
            let (underscore, _) = Snid::parse_wire(&case.underscore_wire).unwrap();
            assert_eq!(underscore, expected);
        }

        let sgid = Snid::from_hex(&vectors.spatial.bytes_hex).unwrap();
        assert_eq!(
            sgid.to_wire(&vectors.spatial.atom).unwrap(),
            vectors.spatial.wire
        );
        assert_eq!(
            format!("{:x}", sgid.h3_cell().unwrap()),
            vectors.spatial.h3_cell_hex
        );

        let head = Snid::from_hex(&vectors.neural.head_hex).unwrap();
        let semantic: [u8; 16] = hex::decode(vectors.neural.semantic_hex)
            .unwrap()
            .try_into()
            .unwrap();
        let nid = Nid::from_parts(head, semantic);
        assert_eq!(hex::encode(nid.0), vectors.neural.bytes_hex);
        assert_eq!(
            nid.hamming_distance(&Nid([0u8; 32])) as i32,
            vectors.neural.hamming_to_zero
        );

        let head = Snid::from_hex(&vectors.ledger.head_hex).unwrap();
        let prev: [u8; 32] = hex::decode(vectors.ledger.prev_hex)
            .unwrap()
            .try_into()
            .unwrap();
        let payload = hex::decode(vectors.ledger.payload_hex).unwrap();
        let key = hex::decode(vectors.ledger.key_hex).unwrap();
        let lid = Lid::from_parts(head, prev, &payload, &key).unwrap();
        assert_eq!(hex::encode(lid.0), vectors.ledger.bytes_hex);

        let world_head = Snid::from_hex(&vectors.world.head_hex).unwrap();
        let scenario: [u8; 16] = hex::decode(vectors.world.scenario_hex)
            .unwrap()
            .try_into()
            .unwrap();
        let wid = Wid::from_parts(world_head, scenario);
        assert_eq!(hex::encode(wid.0), vectors.world.bytes_hex);
        assert_eq!(
            wid.to_tensor256_words(),
            (
                vectors.world.tensor_words[0],
                vectors.world.tensor_words[1],
                vectors.world.tensor_words[2],
                vectors.world.tensor_words[3]
            )
        );

        let edge_head = Snid::from_hex(&vectors.edge.head_hex).unwrap();
        let edge_hash: [u8; 16] = hex::decode(vectors.edge.edge_hex)
            .unwrap()
            .try_into()
            .unwrap();
        let xid = Xid::from_parts(edge_head, edge_hash);
        assert_eq!(hex::encode(xid.0), vectors.edge.bytes_hex);
        assert_eq!(
            xid.to_tensor256_words(),
            (
                vectors.edge.tensor_words[0],
                vectors.edge.tensor_words[1],
                vectors.edge.tensor_words[2],
                vectors.edge.tensor_words[3]
            )
        );

        let kid_head = Snid::from_hex(&vectors.capability.head_hex).unwrap();
        let actor = Snid::from_hex(&vectors.capability.actor_hex).unwrap();
        let resource = hex::decode(vectors.capability.resource_hex).unwrap();
        let capability = hex::decode(vectors.capability.capability_hex).unwrap();
        let key = hex::decode(vectors.capability.key_hex).unwrap();
        let kid = Kid::from_parts(kid_head, actor, &resource, &capability, &key).unwrap();
        assert_eq!(hex::encode(kid.0), vectors.capability.bytes_hex);
        assert!(kid.verify(actor, &resource, &capability, &key));
        assert_eq!(
            kid.to_tensor256_words(),
            (
                vectors.capability.tensor_words[0],
                vectors.capability.tensor_words[1],
                vectors.capability.tensor_words[2],
                vectors.capability.tensor_words[3]
            )
        );

        let eid_bytes: [u8; 8] = hex::decode(vectors.ephemeral.bytes_hex)
            .unwrap()
            .try_into()
            .unwrap();
        let eid = Eid(u64::from_be_bytes(eid_bytes));
        assert_eq!(eid.timestamp_millis(), vectors.ephemeral.timestamp_millis);
        assert_eq!(eid.counter(), vectors.ephemeral.counter);

        let topology = Snid::from_hex(&vectors.bid.topology_hex).unwrap();
        let content: [u8; 32] = hex::decode(vectors.bid.content_hex)
            .unwrap()
            .try_into()
            .unwrap();
        let bid = Bid::from_parts(topology, content);
        assert_eq!(bid.wire().unwrap(), vectors.bid.wire);
        assert_eq!(bid.r2_key(), vectors.bid.r2_key);
        assert_eq!(bid.topology.to_wire("MAT").unwrap(), vectors.bid.neo4j_id);
        assert_eq!(Bid::parse_wire(&vectors.bid.wire).unwrap(), bid);

        let compat = Snid::from_hex(&vectors.compatibility.bytes_hex).unwrap();
        assert_eq!(compat.to_wire("MAT").unwrap(), vectors.compatibility.wire);
        let (parsed, _) = Snid::parse_wire(&vectors.compatibility.wire).unwrap();
        assert_eq!(parsed, compat);

        let uuidv7 = Snid::from_hex(&vectors.uuidv7.bytes_hex).unwrap();
        let uuid_str = format!(
            "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
            uuidv7.0[0], uuidv7.0[1], uuidv7.0[2], uuidv7.0[3],
            uuidv7.0[4], uuidv7.0[5],
            uuidv7.0[6], uuidv7.0[7],
            uuidv7.0[8], uuidv7.0[9],
            uuidv7.0[10], uuidv7.0[11], uuidv7.0[12], uuidv7.0[13], uuidv7.0[14], uuidv7.0[15]
        );
        assert_eq!(uuid_str, vectors.uuidv7.uuid_string);
        assert_eq!(uuidv7.timestamp_millis(), vectors.uuidv7.timestamp_millis);
        let version = uuidv7.0[6] >> 4;
        assert_eq!(version as i32, vectors.uuidv7.version);
        let variant = (uuidv7.0[8] >> 6) & 0b11;
        assert_eq!(variant as i32, vectors.uuidv7.variant);

        assert!(Snid::parse_wire(&vectors.negative.invalid_atom_wire).is_err());
        assert!(Snid::from_hex(&vectors.negative.invalid_binary_hex).is_err());
        assert!(Snid::parse_wire(&vectors.negative.invalid_wire_checksum).is_err());
        assert!(Snid::from_hex(&vectors.negative.invalid_adapter_hex).is_err());
    }
}