Skip to content

Commit 9b04d25

Browse files
authored
feat(rust/signed-doc): ContentRule and TemplateRule initialisation (#548)
* wip * add Payload and Template types * add TemplateRule initialisation * add content type rule
1 parent 313b638 commit 9b04d25

File tree

9 files changed

+102
-8
lines changed

9 files changed

+102
-8
lines changed

rust/catalyst-signed-doc-macro/src/types_consts.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ pub(crate) fn catalyst_signed_documents_types_consts_impl() -> anyhow::Result<To
1010

1111
let mut consts_definitions = Vec::new();
1212
for (doc_name, doc_spec) in spec.docs {
13+
if doc_spec.draft {
14+
continue;
15+
}
1316
let const_type_name_ident = doc_name.ident();
1417
let doc_name = doc_name.name();
1518
let type_uuid = doc_spec.doc_type;
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! 'copyright' field definition
22
33
#[derive(serde::Deserialize)]
4-
pub struct Copyright {
5-
pub versions: Vec<Version>,
4+
pub(crate) struct Copyright {
5+
pub(crate) versions: Vec<Version>,
66
}
77

88
#[derive(serde::Deserialize)]
9-
pub struct Version {
10-
pub version: String,
9+
pub(crate) struct Version {
10+
pub(crate) version: String,
1111
}

rust/catalyst-signed-doc-spec/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,21 @@ pub mod doc_types;
77
pub mod headers;
88
pub mod is_required;
99
pub mod metadata;
10+
pub mod payload;
1011

1112
use std::{collections::HashMap, fmt::Display};
1213

1314
use build_info as build_info_lib;
1415

15-
use crate::{copyright::Copyright, headers::Headers, metadata::Metadata};
16+
use crate::{copyright::Copyright, headers::Headers, metadata::Metadata, payload::Payload};
1617

1718
build_info_lib::build_info!(pub(crate) fn build_info);
1819

1920
/// Catalyst Signed Document spec representation struct
2021
#[derive(serde::Deserialize)]
2122
pub struct CatalystSignedDocSpec {
2223
pub docs: HashMap<DocumentName, DocSpec>,
23-
pub copyright: Copyright,
24+
copyright: Copyright,
2425
}
2526

2627
// A thin wrapper over the string document name values
@@ -60,10 +61,12 @@ impl DocumentName {
6061
/// Specific document type definition
6162
#[derive(serde::Deserialize)]
6263
pub struct DocSpec {
64+
pub draft: bool,
6365
#[serde(rename = "type")]
6466
pub doc_type: String,
6567
pub headers: Headers,
6668
pub metadata: Metadata,
69+
pub payload: Payload,
6770
}
6871

6972
impl CatalystSignedDocSpec {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//! `metadata` field definition
22
33
pub mod doc_ref;
4+
pub mod template;
45

56
/// Document's metadata fields definition
67
#[derive(serde::Deserialize)]
78
#[allow(clippy::missing_docs_in_private_items)]
89
pub struct Metadata {
10+
pub template: template::Template,
911
#[serde(rename = "ref")]
1012
pub doc_ref: doc_ref::Ref,
1113
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//! `signed_doc.json` "template" field JSON definition
2+
3+
use crate::{is_required::IsRequired, DocumentName};
4+
5+
/// `signed_doc.json` "template" field JSON object
6+
#[derive(serde::Deserialize)]
7+
#[allow(clippy::missing_docs_in_private_items, dead_code)]
8+
pub struct Template {
9+
pub required: IsRequired,
10+
#[serde(rename = "type")]
11+
pub doc_type: Option<DocumentName>,
12+
pub multiple: Option<bool>,
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//! `signed_doc.json` "payload" field JSON definition
2+
3+
/// `signed_doc.json` "payload" field JSON object
4+
#[derive(serde::Deserialize)]
5+
#[allow(clippy::missing_docs_in_private_items)]
6+
pub struct Payload {
7+
pub nil: bool,
8+
pub schema: Option<serde_json::Value>,
9+
}

rust/signed_doc/src/validator/rules/content.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::fmt::Debug;
44

5+
use catalyst_signed_doc_spec::payload::Payload;
56
use minicbor::Encode;
67

78
use crate::{
@@ -39,6 +40,26 @@ pub(crate) enum ContentRule {
3940
}
4041

4142
impl ContentRule {
43+
/// Generating `ContentRule` from specs
44+
pub(crate) fn new(spec: &Payload) -> anyhow::Result<Self> {
45+
if spec.nil {
46+
anyhow::ensure!(
47+
spec.schema.is_none(),
48+
"'schema' field could not been specified when 'nil' is 'true' for 'payload' definition"
49+
);
50+
return Ok(Self::Nil);
51+
}
52+
53+
if let Some(schema) = &spec.schema {
54+
let schema_str = schema.to_string();
55+
Ok(Self::StaticSchema(ContentSchema::Json(
56+
json_schema::JsonSchema::try_from(&serde_json::from_str(&schema_str)?)?,
57+
)))
58+
} else {
59+
Ok(Self::NotNil)
60+
}
61+
}
62+
4263
/// Field validation rule
4364
#[allow(clippy::unused_async)]
4465
pub(crate) async fn check(

rust/signed_doc/src/validator/rules/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,21 @@ impl Rules {
118118

119119
let mut doc_rules = Vec::new();
120120
for doc_spec in spec.docs.values() {
121+
if doc_spec.draft {
122+
continue;
123+
}
124+
121125
let rules = Self {
122126
id: IdRule,
123127
ver: VerRule,
124128
content_type: ContentTypeRule::new(&doc_spec.headers.content_type)?,
125129
content_encoding: ContentEncodingRule::new(&doc_spec.headers.content_encoding)?,
126-
template: TemplateRule::NotSpecified,
130+
template: TemplateRule::new(&spec.docs, &doc_spec.metadata.template)?,
127131
parameters: ParametersRule::NotSpecified,
128132
doc_ref: RefRule::new(&spec.docs, &doc_spec.metadata.doc_ref)?,
129133
reply: ReplyRule::NotSpecified,
130134
section: SectionRule::NotSpecified,
131-
content: ContentRule::Nil,
135+
content: ContentRule::new(&doc_spec.payload)?,
132136
kid: SignatureKidRule { exp: &[] },
133137
signature: SignatureRule { mutlisig: false },
134138
original_author: OriginalAuthorRule,

rust/signed_doc/src/validator/rules/template.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
//! `template` rule type impl.
22
3+
use std::collections::HashMap;
4+
5+
use catalyst_signed_doc_spec::{
6+
is_required::IsRequired, metadata::template::Template, DocSpec, DocumentName,
7+
};
8+
39
use crate::{
410
providers::CatalystSignedDocumentProvider,
511
validator::{
@@ -22,6 +28,39 @@ pub(crate) enum TemplateRule {
2228
}
2329

2430
impl TemplateRule {
31+
/// Generating `TemplateRule` from specs
32+
pub(crate) fn new(
33+
docs: &HashMap<DocumentName, DocSpec>,
34+
spec: &Template,
35+
) -> anyhow::Result<Self> {
36+
if let IsRequired::Excluded = spec.required {
37+
anyhow::ensure!(
38+
spec.doc_type.is_none() && spec.multiple.is_none(),
39+
"'type' and 'multiple' fields could not been specified when 'required' is 'excluded' for 'template' metadata definition"
40+
);
41+
return Ok(Self::NotSpecified);
42+
}
43+
44+
anyhow::ensure!(
45+
spec.multiple.is_some_and(|v| !v),
46+
"'multiple' must be `false` for 'template' metadata definition"
47+
);
48+
anyhow::ensure!(
49+
spec.required != IsRequired::Optional,
50+
"'required' field cannot been 'optional' for 'template' metadata definition"
51+
);
52+
53+
let doc_name = spec.doc_type.as_ref().ok_or(anyhow::anyhow!(
54+
"'type' field should exists for the required 'template' metadata definition"
55+
))?;
56+
let docs_spec = docs.get(doc_name).ok_or(anyhow::anyhow!(
57+
"cannot find a document definition {doc_name}"
58+
))?;
59+
let allowed_type = docs_spec.doc_type.as_str().parse()?;
60+
61+
Ok(Self::Specified { allowed_type })
62+
}
63+
2564
/// Field validation rule
2665
pub(crate) async fn check<Provider>(
2766
&self,

0 commit comments

Comments
 (0)