1use std::fmt;
4
5use serde::de::Error as _;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8use crate::codec::to_canonical_json;
9use crate::diagnostic::{Diagnostic, DiagnosticCategory};
10use crate::fingerprint::{
11 CanonicalizationVersion, Fingerprint, FingerprintDomain, SemanticProfileId,
12};
13use crate::limits::MAX_CANONICAL_STRING_BYTES;
14use crate::semantic_profile::{InterfaceKind, SemanticProfile};
15
16pub const EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID: &str = "typebridge.managed-scope/exclusive/v1";
18pub const MANAGED_SCOPE_PROFILE_FINGERPRINT_DOMAIN: &str =
20 "typebridge.schema.managed-scope-profile";
21pub const MANAGED_SCOPE_PROFILE_CANONICALIZATION: &str = "typebridge.managed-scope-profile/v1";
23pub const SEMANTIC_PROFILE_FINGERPRINT_DOMAIN: &str = "typebridge.schema.semantic-profile";
25pub const SEMANTIC_PROFILE_CANONICALIZATION: &str = "typebridge.semantic-profile/v1";
27
28#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct ManagedScopeId(String);
31
32impl ManagedScopeId {
33 pub fn new(value: impl Into<String>) -> Result<Self, Diagnostic> {
35 let value = value.into();
36 if value.is_empty() || value.len() > MAX_CANONICAL_STRING_BYTES {
37 return Err(Diagnostic::stable(
38 DiagnosticCategory::InvalidContract,
39 "malformed_managed_scope_id",
40 "managed scope ID is empty or exceeds the canonical string limit",
41 )
42 .with_detail(
43 "maximum_bytes",
44 i64::try_from(MAX_CANONICAL_STRING_BYTES).unwrap_or(i64::MAX),
45 ));
46 }
47 Ok(Self(value))
48 }
49
50 pub fn as_str(&self) -> &str {
52 &self.0
53 }
54}
55
56impl fmt::Display for ManagedScopeId {
57 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
58 formatter.write_str(self.as_str())
59 }
60}
61
62impl Serialize for ManagedScopeId {
63 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
64 where
65 S: Serializer,
66 {
67 serializer.serialize_str(self.as_str())
68 }
69}
70
71impl<'de> Deserialize<'de> for ManagedScopeId {
72 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
73 where
74 D: Deserializer<'de>,
75 {
76 Self::new(String::deserialize(deserializer)?).map_err(D::Error::custom)
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
82pub struct ManagedScopeProfileId(String);
83
84impl ManagedScopeProfileId {
85 #[must_use]
87 pub fn exclusive() -> Self {
88 Self(EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID.to_owned())
89 }
90
91 pub fn new(value: impl Into<String>) -> Result<Self, Diagnostic> {
93 let value = value.into();
94 if value != EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID {
95 return Err(Diagnostic::stable(
96 DiagnosticCategory::UnsupportedCapability,
97 "unsupported_managed_scope_profile",
98 "managed scope profile is not present in the frozen registry",
99 ));
100 }
101 Ok(Self(value))
102 }
103
104 pub fn as_str(&self) -> &str {
106 &self.0
107 }
108}
109
110impl fmt::Display for ManagedScopeProfileId {
111 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
112 formatter.write_str(self.as_str())
113 }
114}
115
116impl Serialize for ManagedScopeProfileId {
117 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
118 where
119 S: Serializer,
120 {
121 serializer.serialize_str(self.as_str())
122 }
123}
124
125impl<'de> Deserialize<'de> for ManagedScopeProfileId {
126 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
127 where
128 D: Deserializer<'de>,
129 {
130 Self::new(String::deserialize(deserializer)?).map_err(D::Error::custom)
131 }
132}
133
134#[derive(Serialize)]
135struct ExclusiveManagedScopeProfileView {
136 internal_facts: &'static str,
137 non_internal_facts: &'static str,
138 profile_id: &'static str,
139}
140
141pub fn exclusive_managed_scope_profile_bytes() -> Result<Vec<u8>, Diagnostic> {
143 to_canonical_json(&ExclusiveManagedScopeProfileView {
144 internal_facts: "excluded",
145 non_internal_facts: "managed",
146 profile_id: EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID,
147 })
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
152#[serde(transparent)]
153pub struct ManagedScopeProfileFingerprint(Fingerprint);
154
155impl ManagedScopeProfileFingerprint {
156 pub fn exclusive() -> Result<Self, Diagnostic> {
158 Ok(Self(Fingerprint::compute(
159 FingerprintDomain::new(MANAGED_SCOPE_PROFILE_FINGERPRINT_DOMAIN)?,
160 CanonicalizationVersion::new(MANAGED_SCOPE_PROFILE_CANONICALIZATION)?,
161 None,
162 &exclusive_managed_scope_profile_bytes()?,
163 )))
164 }
165
166 pub const fn as_fingerprint(&self) -> &Fingerprint {
168 &self.0
169 }
170}
171
172#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
174pub struct ManagedScopeProfileBinding {
175 fingerprint: ManagedScopeProfileFingerprint,
176 id: ManagedScopeProfileId,
177}
178
179impl ManagedScopeProfileBinding {
180 pub fn exclusive() -> Result<Self, Diagnostic> {
182 Ok(Self {
183 fingerprint: ManagedScopeProfileFingerprint::exclusive()?,
184 id: ManagedScopeProfileId::exclusive(),
185 })
186 }
187
188 pub const fn id(&self) -> &ManagedScopeProfileId {
190 &self.id
191 }
192
193 pub const fn fingerprint(&self) -> &ManagedScopeProfileFingerprint {
195 &self.fingerprint
196 }
197}
198
199#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
201pub struct ManagedScopeBinding {
202 id: ManagedScopeId,
203 profile: ManagedScopeProfileBinding,
204}
205
206impl ManagedScopeBinding {
207 pub fn exclusive(id: ManagedScopeId) -> Result<Self, Diagnostic> {
209 Ok(Self {
210 id,
211 profile: ManagedScopeProfileBinding::exclusive()?,
212 })
213 }
214
215 pub const fn id(&self) -> &ManagedScopeId {
217 &self.id
218 }
219
220 pub const fn profile(&self) -> &ManagedScopeProfileBinding {
222 &self.profile
223 }
224}
225
226#[derive(Serialize)]
227struct SemanticProfileView<'a> {
228 id: &'a SemanticProfileId,
229 key_owns_default: crate::value::Cardinality,
230 owns_default: crate::value::Cardinality,
231 plays_default: crate::value::Cardinality,
232 relates_default: crate::value::Cardinality,
233}
234
235pub fn semantic_profile_canonical_bytes(profile: &SemanticProfile) -> Result<Vec<u8>, Diagnostic> {
237 to_canonical_json(&SemanticProfileView {
238 id: profile.id(),
239 key_owns_default: profile.effective_cardinality(InterfaceKind::Owns, None, true),
240 owns_default: profile.default_cardinality(InterfaceKind::Owns),
241 plays_default: profile.default_cardinality(InterfaceKind::Plays),
242 relates_default: profile.default_cardinality(InterfaceKind::Relates),
243 })
244}
245
246#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
248#[serde(transparent)]
249pub struct SemanticProfileFingerprint(Fingerprint);
250
251impl SemanticProfileFingerprint {
252 pub fn compute(profile: &SemanticProfile) -> Result<Self, Diagnostic> {
254 Ok(Self(Fingerprint::compute(
255 FingerprintDomain::new(SEMANTIC_PROFILE_FINGERPRINT_DOMAIN)?,
256 CanonicalizationVersion::new(SEMANTIC_PROFILE_CANONICALIZATION)?,
257 None,
258 &semantic_profile_canonical_bytes(profile)?,
259 )))
260 }
261
262 pub const fn as_fingerprint(&self) -> &Fingerprint {
264 &self.0
265 }
266}
267
268#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
270pub struct SemanticProfileBinding {
271 fingerprint: SemanticProfileFingerprint,
272 id: SemanticProfileId,
273}
274
275impl SemanticProfileBinding {
276 pub fn resolve(id: SemanticProfileId) -> Result<Self, Diagnostic> {
278 let profile = SemanticProfile::resolve(&id)?;
279 Ok(Self {
280 fingerprint: profile.content_fingerprint()?,
281 id,
282 })
283 }
284
285 pub fn typedb_3_12_1() -> Result<Self, Diagnostic> {
287 Self::resolve(SemanticProfileId::new("typedb-3.12.1/v1")?)
288 }
289
290 pub const fn id(&self) -> &SemanticProfileId {
292 &self.id
293 }
294
295 pub const fn fingerprint(&self) -> &SemanticProfileFingerprint {
297 &self.fingerprint
298 }
299}
300
301impl SemanticProfile {
302 pub fn content_fingerprint(&self) -> Result<SemanticProfileFingerprint, Diagnostic> {
304 SemanticProfileFingerprint::compute(self)
305 }
306}