use std::fmt;
use serde::de::Error as _;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::codec::to_canonical_json;
use crate::diagnostic::{Diagnostic, DiagnosticCategory};
use crate::fingerprint::{
CanonicalizationVersion, Fingerprint, FingerprintDomain, SemanticProfileId,
};
use crate::limits::MAX_CANONICAL_STRING_BYTES;
use crate::semantic_profile::{InterfaceKind, SemanticProfile};
pub const EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID: &str = "typebridge.managed-scope/exclusive/v1";
pub const MANAGED_SCOPE_PROFILE_FINGERPRINT_DOMAIN: &str =
"typebridge.schema.managed-scope-profile";
pub const MANAGED_SCOPE_PROFILE_CANONICALIZATION: &str = "typebridge.managed-scope-profile/v1";
pub const SEMANTIC_PROFILE_FINGERPRINT_DOMAIN: &str = "typebridge.schema.semantic-profile";
pub const SEMANTIC_PROFILE_CANONICALIZATION: &str = "typebridge.semantic-profile/v1";
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ManagedScopeId(String);
impl ManagedScopeId {
pub fn new(value: impl Into<String>) -> Result<Self, Diagnostic> {
let value = value.into();
if value.is_empty() || value.len() > MAX_CANONICAL_STRING_BYTES {
return Err(Diagnostic::stable(
DiagnosticCategory::InvalidContract,
"malformed_managed_scope_id",
"managed scope ID is empty or exceeds the canonical string limit",
)
.with_detail(
"maximum_bytes",
i64::try_from(MAX_CANONICAL_STRING_BYTES).unwrap_or(i64::MAX),
));
}
Ok(Self(value))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for ManagedScopeId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl Serialize for ManagedScopeId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for ManagedScopeId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::new(String::deserialize(deserializer)?).map_err(D::Error::custom)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ManagedScopeProfileId(String);
impl ManagedScopeProfileId {
#[must_use]
pub fn exclusive() -> Self {
Self(EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID.to_owned())
}
pub fn new(value: impl Into<String>) -> Result<Self, Diagnostic> {
let value = value.into();
if value != EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID {
return Err(Diagnostic::stable(
DiagnosticCategory::UnsupportedCapability,
"unsupported_managed_scope_profile",
"managed scope profile is not present in the frozen registry",
));
}
Ok(Self(value))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for ManagedScopeProfileId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl Serialize for ManagedScopeProfileId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for ManagedScopeProfileId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::new(String::deserialize(deserializer)?).map_err(D::Error::custom)
}
}
#[derive(Serialize)]
struct ExclusiveManagedScopeProfileView {
internal_facts: &'static str,
non_internal_facts: &'static str,
profile_id: &'static str,
}
pub fn exclusive_managed_scope_profile_bytes() -> Result<Vec<u8>, Diagnostic> {
to_canonical_json(&ExclusiveManagedScopeProfileView {
internal_facts: "excluded",
non_internal_facts: "managed",
profile_id: EXCLUSIVE_MANAGED_SCOPE_PROFILE_ID,
})
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(transparent)]
pub struct ManagedScopeProfileFingerprint(Fingerprint);
impl ManagedScopeProfileFingerprint {
pub fn exclusive() -> Result<Self, Diagnostic> {
Ok(Self(Fingerprint::compute(
FingerprintDomain::new(MANAGED_SCOPE_PROFILE_FINGERPRINT_DOMAIN)?,
CanonicalizationVersion::new(MANAGED_SCOPE_PROFILE_CANONICALIZATION)?,
None,
&exclusive_managed_scope_profile_bytes()?,
)))
}
pub const fn as_fingerprint(&self) -> &Fingerprint {
&self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ManagedScopeProfileBinding {
fingerprint: ManagedScopeProfileFingerprint,
id: ManagedScopeProfileId,
}
impl ManagedScopeProfileBinding {
pub fn exclusive() -> Result<Self, Diagnostic> {
Ok(Self {
fingerprint: ManagedScopeProfileFingerprint::exclusive()?,
id: ManagedScopeProfileId::exclusive(),
})
}
pub const fn id(&self) -> &ManagedScopeProfileId {
&self.id
}
pub const fn fingerprint(&self) -> &ManagedScopeProfileFingerprint {
&self.fingerprint
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ManagedScopeBinding {
id: ManagedScopeId,
profile: ManagedScopeProfileBinding,
}
impl ManagedScopeBinding {
pub fn exclusive(id: ManagedScopeId) -> Result<Self, Diagnostic> {
Ok(Self {
id,
profile: ManagedScopeProfileBinding::exclusive()?,
})
}
pub const fn id(&self) -> &ManagedScopeId {
&self.id
}
pub const fn profile(&self) -> &ManagedScopeProfileBinding {
&self.profile
}
}
#[derive(Serialize)]
struct SemanticProfileView<'a> {
id: &'a SemanticProfileId,
key_owns_default: crate::value::Cardinality,
owns_default: crate::value::Cardinality,
plays_default: crate::value::Cardinality,
relates_default: crate::value::Cardinality,
}
pub fn semantic_profile_canonical_bytes(profile: &SemanticProfile) -> Result<Vec<u8>, Diagnostic> {
to_canonical_json(&SemanticProfileView {
id: profile.id(),
key_owns_default: profile.effective_cardinality(InterfaceKind::Owns, None, true),
owns_default: profile.default_cardinality(InterfaceKind::Owns),
plays_default: profile.default_cardinality(InterfaceKind::Plays),
relates_default: profile.default_cardinality(InterfaceKind::Relates),
})
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(transparent)]
pub struct SemanticProfileFingerprint(Fingerprint);
impl SemanticProfileFingerprint {
pub fn compute(profile: &SemanticProfile) -> Result<Self, Diagnostic> {
Ok(Self(Fingerprint::compute(
FingerprintDomain::new(SEMANTIC_PROFILE_FINGERPRINT_DOMAIN)?,
CanonicalizationVersion::new(SEMANTIC_PROFILE_CANONICALIZATION)?,
None,
&semantic_profile_canonical_bytes(profile)?,
)))
}
pub const fn as_fingerprint(&self) -> &Fingerprint {
&self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct SemanticProfileBinding {
fingerprint: SemanticProfileFingerprint,
id: SemanticProfileId,
}
impl SemanticProfileBinding {
pub fn resolve(id: SemanticProfileId) -> Result<Self, Diagnostic> {
let profile = SemanticProfile::resolve(&id)?;
Ok(Self {
fingerprint: profile.content_fingerprint()?,
id,
})
}
pub fn typedb_3_12_1() -> Result<Self, Diagnostic> {
Self::resolve(SemanticProfileId::new("typedb-3.12.1/v1")?)
}
pub const fn id(&self) -> &SemanticProfileId {
&self.id
}
pub const fn fingerprint(&self) -> &SemanticProfileFingerprint {
&self.fingerprint
}
}
impl SemanticProfile {
pub fn content_fingerprint(&self) -> Result<SemanticProfileFingerprint, Diagnostic> {
SemanticProfileFingerprint::compute(self)
}
}