Skip to main content

type_bridge_contract/
schema_fingerprint.rs

1//! Domain-separated fingerprints for schema comparison scopes.
2
3use serde::Serialize;
4
5use crate::diagnostic::{Diagnostic, DiagnosticCategory};
6use crate::fingerprint::{
7    CanonicalizationVersion, Fingerprint, FingerprintDomain, SemanticProfileId,
8};
9
10const SCHEMA_CANONICALIZATION: &str = "typebridge.schema-canonical-json/v1";
11const SCHEMA_DOCUMENT_SET_CANONICALIZATION: &str = "typebridge.schema-document-set/v1";
12const MANAGED_DECLARED_CANONICALIZATION: &str = "typebridge.managed-declared/v1";
13const MANAGED_SEMANTIC_CANONICALIZATION: &str = "typebridge.managed-semantic/v1";
14
15/// Fingerprint of an ordered schema document set's portable paths and exact-source digests.
16#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
17#[serde(transparent)]
18pub struct SchemaDocumentSetFingerprint(Fingerprint);
19
20impl SchemaDocumentSetFingerprint {
21    /// Compute a document-set fingerprint from canonical path-and-digest bytes.
22    pub fn compute(canonical_bytes: &[u8]) -> Result<Self, Diagnostic> {
23        Ok(Self(Fingerprint::compute(
24            FingerprintDomain::new("typebridge.schema.document-set")?,
25            CanonicalizationVersion::new(SCHEMA_DOCUMENT_SET_CANONICALIZATION)?,
26            None,
27            canonical_bytes,
28        )))
29    }
30
31    /// Return the generic fingerprint metadata and digest.
32    #[must_use]
33    pub const fn as_fingerprint(&self) -> &Fingerprint {
34        &self.0
35    }
36}
37
38/// Fingerprint of canonical direct schema semantics under one semantic profile.
39#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
40#[serde(transparent)]
41pub struct SemanticSchemaFingerprint(Fingerprint);
42
43impl SemanticSchemaFingerprint {
44    /// Compute a semantic schema fingerprint from canonical direct-semantic bytes.
45    pub fn compute(profile: SemanticProfileId, canonical_bytes: &[u8]) -> Result<Self, Diagnostic> {
46        Ok(Self(Fingerprint::compute(
47            FingerprintDomain::new("typebridge.schema.semantic")?,
48            CanonicalizationVersion::new(SCHEMA_CANONICALIZATION)?,
49            Some(profile),
50            canonical_bytes,
51        )))
52    }
53
54    /// Return the generic fingerprint metadata and digest.
55    #[must_use]
56    pub const fn as_fingerprint(&self) -> &Fingerprint {
57        &self.0
58    }
59}
60
61/// Fingerprint of declared identity after deterministic managed-scope filtering.
62#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
63#[serde(transparent)]
64pub struct ManagedDeclaredIdentityFingerprint(Fingerprint);
65
66impl ManagedDeclaredIdentityFingerprint {
67    /// Compute a managed declared-identity fingerprint from canonical filtered bytes.
68    pub fn compute(canonical_bytes: &[u8]) -> Result<Self, Diagnostic> {
69        Ok(Self(Fingerprint::compute(
70            FingerprintDomain::new("typebridge.schema.managed-declared-identity")?,
71            CanonicalizationVersion::new(MANAGED_DECLARED_CANONICALIZATION)?,
72            None,
73            canonical_bytes,
74        )))
75    }
76
77    /// Return the generic fingerprint metadata and digest.
78    #[must_use]
79    pub const fn as_fingerprint(&self) -> &Fingerprint {
80        &self.0
81    }
82
83    pub(crate) fn from_wire(fingerprint: Fingerprint) -> Result<Self, Diagnostic> {
84        if fingerprint.domain().as_str() != "typebridge.schema.managed-declared-identity"
85            || fingerprint.canonicalization().as_str() != MANAGED_DECLARED_CANONICALIZATION
86            || fingerprint.semantic_profile().is_some()
87        {
88            return Err(Diagnostic::stable(
89                DiagnosticCategory::Integrity,
90                "invalid_managed_declared_identity_fingerprint",
91                "managed declared-identity fingerprint metadata is invalid",
92            ));
93        }
94        Ok(Self(fingerprint))
95    }
96}
97
98/// Fingerprint of direct semantics after deterministic managed-scope filtering.
99#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
100#[serde(transparent)]
101pub struct ManagedSemanticSchemaFingerprint(Fingerprint);
102
103impl ManagedSemanticSchemaFingerprint {
104    /// Compute a managed semantic fingerprint from canonical filtered bytes.
105    pub fn compute(profile: SemanticProfileId, canonical_bytes: &[u8]) -> Result<Self, Diagnostic> {
106        Ok(Self(Fingerprint::compute(
107            FingerprintDomain::new("typebridge.schema.managed-semantic")?,
108            CanonicalizationVersion::new(MANAGED_SEMANTIC_CANONICALIZATION)?,
109            Some(profile),
110            canonical_bytes,
111        )))
112    }
113
114    /// Return the generic fingerprint metadata and digest.
115    #[must_use]
116    pub const fn as_fingerprint(&self) -> &Fingerprint {
117        &self.0
118    }
119
120    pub(crate) fn from_wire(fingerprint: Fingerprint) -> Result<Self, Diagnostic> {
121        if fingerprint.domain().as_str() != "typebridge.schema.managed-semantic"
122            || fingerprint.canonicalization().as_str() != MANAGED_SEMANTIC_CANONICALIZATION
123            || fingerprint.semantic_profile().is_none()
124        {
125            return Err(Diagnostic::stable(
126                DiagnosticCategory::Integrity,
127                "invalid_managed_semantic_schema_fingerprint",
128                "managed semantic-schema fingerprint metadata is invalid",
129            ));
130        }
131        Ok(Self(fingerprint))
132    }
133}
134
135impl SemanticSchemaFingerprint {
136    /// Adopt a decoded generic fingerprint only after checking the exact semantic-schema domain.
137    pub(crate) fn from_wire(fingerprint: Fingerprint) -> Result<Self, Diagnostic> {
138        if fingerprint.domain().as_str() != "typebridge.schema.semantic"
139            || fingerprint.canonicalization().as_str() != SCHEMA_CANONICALIZATION
140            || fingerprint.semantic_profile().is_none()
141        {
142            return Err(crate::diagnostic::Diagnostic::stable(
143                crate::diagnostic::DiagnosticCategory::Integrity,
144                "invalid_semantic_schema_fingerprint",
145                "semantic schema fingerprint wire metadata is inconsistent",
146            ));
147        }
148        Ok(Self(fingerprint))
149    }
150}