use crate::descriptor::encode::encode_generated_support_schema;
use crate::descriptor::types::{
BENCH_FIELDS, BenchSchema, DESCRIPTOR_FIELDS, DescriptorSchema, EncodeRefusal,
FieldCardinality, FieldShape, GeneratedSupportSchema, GeneratedSupportSchemaId,
MUTATION_DISCOVERY_FIELDS, MutationDiscoverySchema, SchemaField, SchemaRefusal,
};
use crate::identity::{ContentAddress, DomainTag, IdentityProfileVersion};
use std::collections::BTreeSet;
const GENERATED_SUPPORT_SCHEMA_DOMAIN: DomainTag = DomainTag::declared(
"generated-support-schema",
IdentityProfileVersion::declared(1),
);
impl GeneratedSupportSchemaId {
#[must_use]
pub const fn over(address: ContentAddress) -> Self {
Self(address)
}
}
crate::identity::content_address_reference! {
value GeneratedSupportSchemaId;
}
impl SchemaField {
#[must_use]
pub const fn declared(
name: &'static str,
shape: FieldShape,
cardinality: FieldCardinality,
) -> Self {
Self {
name,
shape,
cardinality,
}
}
#[must_use]
pub const fn name(self) -> &'static str {
self.name
}
#[must_use]
pub const fn shape(self) -> FieldShape {
self.shape
}
#[must_use]
pub const fn cardinality(self) -> FieldCardinality {
self.cardinality
}
}
fn parse_roster(fields: &'static [SchemaField]) -> Result<(), SchemaRefusal> {
if fields.is_empty() {
return Err(SchemaRefusal::EmptyRoster);
}
let mut names = BTreeSet::new();
for field in fields {
if field.name().is_empty() {
return Err(SchemaRefusal::EmptyFieldName);
}
if !names.insert(field.name()) {
return Err(SchemaRefusal::DuplicateFieldName(field.name()));
}
}
Ok(())
}
macro_rules! schema_member {
($($member:ident),+ $(,)?) => {
$(
impl $member {
pub fn declared(fields: &'static [SchemaField]) -> Result<Self, SchemaRefusal> {
parse_roster(fields)?;
Ok(Self { fields })
}
#[must_use]
pub const fn fields(self) -> &'static [SchemaField] {
self.fields
}
}
)+
};
}
schema_member!(DescriptorSchema, MutationDiscoverySchema, BenchSchema);
macro_rules! implement_generated_support_members {
([]; $( $member:ident: $member_type:ty => $fields:ident => $tag:literal, )+) => {
impl GeneratedSupportSchema {
#[must_use]
pub const fn declared($( $member: $member_type, )+) -> Self {
Self {
$(
$member,
)+
}
}
$(
#[doc = concat!("The root's `", stringify!($member), "` member.")]
#[must_use]
pub const fn $member(self) -> $member_type {
self.$member
}
)+
pub fn published() -> Result<Self, SchemaRefusal> {
Ok(Self::declared(
$(
<$member_type>::declared($fields)?,
)+
))
}
}
};
}
generated_support_members!(implement_generated_support_members);
impl GeneratedSupportSchema {
pub fn identity(&self) -> Result<GeneratedSupportSchemaId, EncodeRefusal> {
let preimage = encode_generated_support_schema(self)?;
Ok(GeneratedSupportSchemaId(ContentAddress::derived(
GENERATED_SUPPORT_SCHEMA_DOMAIN,
&preimage,
)))
}
}