diff --git a/rust/catalyst-signed-doc-macro/src/lib.rs b/rust/catalyst-signed-doc-macro/src/lib.rs index ef56a68afb..bd30821277 100644 --- a/rust/catalyst-signed-doc-macro/src/lib.rs +++ b/rust/catalyst-signed-doc-macro/src/lib.rs @@ -2,15 +2,16 @@ //! spec. mod error; +mod rules; mod signed_doc_spec; +mod types_consts; -use proc_macro2::TokenStream; -use quote::quote; +use crate::error::process_error; -use crate::{error::process_error, signed_doc_spec::CatalystSignedDocSpec}; - -/// Defines consts for all Catalyst Signed Documents types values -/// e.g. +/// Defines consts for all Catalyst Signed Documents types values, which are +/// defined inside the `signed_doc.json` spec. +/// +/// E.G. /// ```ignore /// pub const PROPOSAL: DocType = DocType::try_from_uuid(catalyst_types::uuid::uuid!( /// "7808d2ba-d511-40af-84e8-c0d1625fdfdc" @@ -20,33 +21,21 @@ use crate::{error::process_error, signed_doc_spec::CatalystSignedDocSpec}; pub fn catalyst_signed_documents_types_consts( _: proc_macro::TokenStream ) -> proc_macro::TokenStream { - catalyst_signed_documents_types_consts_impl() + types_consts::catalyst_signed_documents_types_consts_impl() .unwrap_or_else(process_error) .into() } -/// `catalyst_signed_documents_types_consts` macro implementation -fn catalyst_signed_documents_types_consts_impl() -> anyhow::Result { - let spec = CatalystSignedDocSpec::load_signed_doc_spec()?; - - let mut consts_definitions = Vec::new(); - for (doc_name, doc_spec) in spec.docs { - let const_type_name_ident = doc_name.ident(); - let doc_name = doc_name.name(); - let type_uuid = doc_spec.doc_type; - - let const_definition = quote! { - #[doc = #doc_name ] - #[doc = "type constant definition"] - pub const #const_type_name_ident: crate::DocType = match crate::DocType::try_from_uuid(catalyst_types::uuid::uuid!(#type_uuid)) { - Ok(v) => v, - Err(_) => panic!("invalid uuid v4 value"), - }; - }; - consts_definitions.push(const_definition); - } - - Ok(quote! { - #(#consts_definitions)* - }) +/// Defines `documents_rules` function which will return a defined +/// `catalyst_signed_doc::Rules` instances for each corresponding document type, which are +/// defined inside the `signed_doc.json` spec. +/// +/// ```ignore +/// fn documents_rules() -> impl Iterator +/// ``` +#[proc_macro] +pub fn catalyst_signed_documents_rules(_: proc_macro::TokenStream) -> proc_macro::TokenStream { + rules::catalyst_signed_documents_rules_impl() + .unwrap_or_else(process_error) + .into() } diff --git a/rust/catalyst-signed-doc-macro/src/rules/mod.rs b/rust/catalyst-signed-doc-macro/src/rules/mod.rs new file mode 100644 index 0000000000..cca3014436 --- /dev/null +++ b/rust/catalyst-signed-doc-macro/src/rules/mod.rs @@ -0,0 +1,54 @@ +//! `catalyst_signed_documents_rules!` macro implementation + +use proc_macro2::TokenStream; +use quote::quote; + +use crate::signed_doc_spec::CatalystSignedDocSpec; + +/// `catalyst_signed_documents_rules` macro implementation +pub(crate) fn catalyst_signed_documents_rules_impl() -> anyhow::Result { + let spec = CatalystSignedDocSpec::load_signed_doc_spec()?; + + let mut rules_definitions = Vec::new(); + for (doc_name, _doc_spec) in spec.docs { + let const_type_name_ident = doc_name.ident(); + + // TODO: implement a proper initialization for all specific validation rules + let rules = quote! { + crate::validator::rules::Rules { + id: crate::validator::rules::IdRule, + ver: crate::validator::rules::VerRule, + content_type: crate::validator::rules::ContentTypeRule { + exp: ContentType::Json, + }, + content_encoding: crate::validator::rules::ContentEncodingRule { + exp: ContentEncoding::Brotli, + optional: false, + }, + content: crate::validator::rules::ContentRule::NotSpecified, + parameters: crate::validator::rules::ParametersRule::NotSpecified, + doc_ref: crate::validator::rules::RefRule::NotSpecified, + reply: crate::validator::rules::ReplyRule::NotSpecified, + section: crate::validator::rules::SectionRule::NotSpecified, + kid: crate::validator::rules::SignatureKidRule { + exp: &[], + }, + signature: crate::validator::rules::SignatureRule { + mutlisig: false + }, + } + }; + + let rule_definition = quote! { + (crate::doc_types::#const_type_name_ident, #rules), + }; + rules_definitions.push(rule_definition); + } + + Ok(quote! { + /// Returns an iterator with all defined Catalyst Signed Documents validation rules per corresponding document type + fn documents_rules() -> impl Iterator { + [ #(#rules_definitions)* ].into_iter() + } + }) +} diff --git a/rust/catalyst-signed-doc-macro/src/types_consts.rs b/rust/catalyst-signed-doc-macro/src/types_consts.rs new file mode 100644 index 0000000000..ad407737ec --- /dev/null +++ b/rust/catalyst-signed-doc-macro/src/types_consts.rs @@ -0,0 +1,32 @@ +//! `catalyst_signed_documents_types_consts!` macro implementation + +use proc_macro2::TokenStream; +use quote::quote; + +use crate::signed_doc_spec::CatalystSignedDocSpec; + +/// `catalyst_signed_documents_types_consts` macro implementation +pub(crate) fn catalyst_signed_documents_types_consts_impl() -> anyhow::Result { + let spec = CatalystSignedDocSpec::load_signed_doc_spec()?; + + let mut consts_definitions = Vec::new(); + for (doc_name, doc_spec) in spec.docs { + let const_type_name_ident = doc_name.ident(); + let doc_name = doc_name.name(); + let type_uuid = doc_spec.doc_type; + + let const_definition = quote! { + #[doc = #doc_name ] + #[doc = "type constant definition"] + pub const #const_type_name_ident: crate::DocType = match crate::DocType::try_from_uuid(catalyst_types::uuid::uuid!(#type_uuid)) { + Ok(v) => v, + Err(_) => panic!("invalid uuid v4 value"), + }; + }; + consts_definitions.push(const_definition); + } + + Ok(quote! { + #(#consts_definitions)* + }) +} diff --git a/rust/signed_doc/src/validator/mod.rs b/rust/signed_doc/src/validator/mod.rs index 09db8a1263..983b851ab0 100644 --- a/rust/signed_doc/src/validator/mod.rs +++ b/rust/signed_doc/src/validator/mod.rs @@ -3,11 +3,9 @@ pub(crate) mod json_schema; pub(crate) mod rules; -use std::{ - collections::HashMap, - sync::{Arc, LazyLock}, -}; +use std::{collections::HashMap, sync::LazyLock}; +use catalyst_signed_doc_macro; use catalyst_types::catalyst_id::role_index::RoleId; use rules::{ ContentEncodingRule, ContentRule, ContentSchema, ContentTypeRule, IdRule, ParametersRule, @@ -25,8 +23,10 @@ use crate::{ CatalystSignedDocument, ContentEncoding, ContentType, }; +catalyst_signed_doc_macro::catalyst_signed_documents_rules!(); + /// A table representing a full set or validation rules per document id. -static DOCUMENT_RULES: LazyLock>> = LazyLock::new(document_rules_init); +static DOCUMENT_RULES: LazyLock> = LazyLock::new(document_rules_init); /// Proposal /// Require field: type, id, ver, template, parameters @@ -158,18 +158,16 @@ fn proposal_submission_action_rule() -> Rules { } /// `DOCUMENT_RULES` initialization function -fn document_rules_init() -> HashMap> { - let mut document_rules_map = HashMap::new(); - - let proposal_rules = Arc::new(proposal_rule()); - let comment_rules = Arc::new(proposal_comment_rule()); - let action_rules = Arc::new(proposal_submission_action_rule()); +fn document_rules_init() -> HashMap { + let mut document_rules_map: HashMap = documents_rules().collect(); - document_rules_map.insert(PROPOSAL.clone(), Arc::clone(&proposal_rules)); - document_rules_map.insert(PROPOSAL_COMMENT.clone(), Arc::clone(&comment_rules)); + // TODO: remove this redefinitions of the validation rules after + // `catalyst_signed_documents_rules!` macro would be fully finished + document_rules_map.insert(PROPOSAL.clone(), proposal_rule()); + document_rules_map.insert(PROPOSAL_COMMENT.clone(), proposal_comment_rule()); document_rules_map.insert( PROPOSAL_SUBMISSION_ACTION.clone(), - Arc::clone(&action_rules), + proposal_submission_action_rule(), ); document_rules_map diff --git a/rust/signed_doc/src/validator/rules/template.rs b/rust/signed_doc/src/validator/rules/content.rs similarity index 98% rename from rust/signed_doc/src/validator/rules/template.rs rename to rust/signed_doc/src/validator/rules/content.rs index 9d96c9a529..8b9c8ac24f 100644 --- a/rust/signed_doc/src/validator/rules/template.rs +++ b/rust/signed_doc/src/validator/rules/content.rs @@ -1,6 +1,6 @@ //! `template` rule type impl. -use std::fmt::Write; +use std::fmt::{Debug, Write}; use crate::{ metadata::ContentType, @@ -16,7 +16,19 @@ pub(crate) enum ContentSchema { Json(json_schema::JsonSchema), } +impl Debug for ContentSchema { + fn fmt( + &self, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + match self { + Self::Json(_) => writeln!(f, "JsonSchema"), + } + } +} + /// Document's content validation rule +#[derive(Debug)] pub(crate) enum ContentRule { /// Based on the 'template' field and loaded corresponding template document Templated { diff --git a/rust/signed_doc/src/validator/rules/content_encoding.rs b/rust/signed_doc/src/validator/rules/content_encoding.rs index 7b56410672..9ebfb15432 100644 --- a/rust/signed_doc/src/validator/rules/content_encoding.rs +++ b/rust/signed_doc/src/validator/rules/content_encoding.rs @@ -3,6 +3,7 @@ use crate::{metadata::ContentEncoding, CatalystSignedDocument}; /// `content-encoding` field validation rule +#[derive(Debug)] pub(crate) struct ContentEncodingRule { /// expected `content-encoding` field pub(crate) exp: ContentEncoding, diff --git a/rust/signed_doc/src/validator/rules/content_type.rs b/rust/signed_doc/src/validator/rules/content_type.rs index 313d220ceb..7cc31169e3 100644 --- a/rust/signed_doc/src/validator/rules/content_type.rs +++ b/rust/signed_doc/src/validator/rules/content_type.rs @@ -3,7 +3,7 @@ use crate::{metadata::ContentType, CatalystSignedDocument}; /// `content-type` field validation rule -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug)] pub(crate) struct ContentTypeRule { /// expected `content-type` field pub(crate) exp: ContentType, diff --git a/rust/signed_doc/src/validator/rules/doc_ref.rs b/rust/signed_doc/src/validator/rules/doc_ref.rs index d5bd1ae5dd..938f19bf02 100644 --- a/rust/signed_doc/src/validator/rules/doc_ref.rs +++ b/rust/signed_doc/src/validator/rules/doc_ref.rs @@ -8,7 +8,7 @@ use crate::{ }; /// `ref` field validation rule -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug)] pub(crate) enum RefRule { /// Is 'ref' specified Specified { @@ -52,7 +52,7 @@ impl RefRule { return Ok(false); } } - if &Self::NotSpecified == self { + if let Self::NotSpecified = self { if let Some(doc_ref) = doc.doc_meta().doc_ref() { doc.report().unknown_field( "ref", diff --git a/rust/signed_doc/src/validator/rules/id.rs b/rust/signed_doc/src/validator/rules/id.rs index a9cc03d4d9..8eeee742a7 100644 --- a/rust/signed_doc/src/validator/rules/id.rs +++ b/rust/signed_doc/src/validator/rules/id.rs @@ -7,6 +7,7 @@ use anyhow::Context; use crate::{providers::CatalystSignedDocumentProvider, CatalystSignedDocument}; /// Signed Document `id` field validation rule +#[derive(Debug)] pub(crate) struct IdRule; impl IdRule { diff --git a/rust/signed_doc/src/validator/rules/mod.rs b/rust/signed_doc/src/validator/rules/mod.rs index 7554325786..dd4b7f9a04 100644 --- a/rust/signed_doc/src/validator/rules/mod.rs +++ b/rust/signed_doc/src/validator/rules/mod.rs @@ -8,6 +8,7 @@ use crate::{ CatalystSignedDocument, }; +mod content; mod content_encoding; mod content_type; mod doc_ref; @@ -17,9 +18,9 @@ mod reply; mod section; mod signature; mod signature_kid; -mod template; mod ver; +pub(crate) use content::{ContentRule, ContentSchema}; pub(crate) use content_encoding::ContentEncodingRule; pub(crate) use content_type::ContentTypeRule; pub(crate) use doc_ref::RefRule; @@ -29,10 +30,10 @@ pub(crate) use reply::ReplyRule; pub(crate) use section::SectionRule; pub(crate) use signature::SignatureRule; pub(crate) use signature_kid::SignatureKidRule; -pub(crate) use template::{ContentRule, ContentSchema}; pub(crate) use ver::VerRule; /// Struct represented a full collection of rules for all fields +#[derive(Debug)] pub(crate) struct Rules { /// 'id' field validation rule pub(crate) id: IdRule, diff --git a/rust/signed_doc/src/validator/rules/parameters.rs b/rust/signed_doc/src/validator/rules/parameters.rs index 3811d48fa7..19dfc9188f 100644 --- a/rust/signed_doc/src/validator/rules/parameters.rs +++ b/rust/signed_doc/src/validator/rules/parameters.rs @@ -9,7 +9,7 @@ use crate::{ }; /// `parameters` field validation rule -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug)] pub(crate) enum ParametersRule { /// Is `parameters` specified Specified { diff --git a/rust/signed_doc/src/validator/rules/reply.rs b/rust/signed_doc/src/validator/rules/reply.rs index 1a77f5d81b..edb49a4bbc 100644 --- a/rust/signed_doc/src/validator/rules/reply.rs +++ b/rust/signed_doc/src/validator/rules/reply.rs @@ -6,7 +6,7 @@ use crate::{ }; /// `reply` field validation rule -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug)] pub(crate) enum ReplyRule { /// Is 'reply' specified Specified { diff --git a/rust/signed_doc/src/validator/rules/section.rs b/rust/signed_doc/src/validator/rules/section.rs index ea856f461d..33aba6eb1f 100644 --- a/rust/signed_doc/src/validator/rules/section.rs +++ b/rust/signed_doc/src/validator/rules/section.rs @@ -3,6 +3,7 @@ use crate::CatalystSignedDocument; /// `section` field validation rule +#[derive(Debug)] pub(crate) enum SectionRule { /// Is 'section' specified #[allow(dead_code)] diff --git a/rust/signed_doc/src/validator/rules/signature_kid.rs b/rust/signed_doc/src/validator/rules/signature_kid.rs index 0de1113e45..db69ffe568 100644 --- a/rust/signed_doc/src/validator/rules/signature_kid.rs +++ b/rust/signed_doc/src/validator/rules/signature_kid.rs @@ -5,6 +5,7 @@ use catalyst_types::catalyst_id::role_index::RoleId; use crate::CatalystSignedDocument; /// COSE signature `kid` (Catalyst Id) role validation +#[derive(Debug)] pub(crate) struct SignatureKidRule { /// expected `RoleId` values for the `kid` field pub(crate) exp: &'static [RoleId], diff --git a/rust/signed_doc/src/validator/rules/ver.rs b/rust/signed_doc/src/validator/rules/ver.rs index 1a12bbe371..294c53b6da 100644 --- a/rust/signed_doc/src/validator/rules/ver.rs +++ b/rust/signed_doc/src/validator/rules/ver.rs @@ -3,6 +3,7 @@ use crate::{providers::CatalystSignedDocumentProvider, CatalystSignedDocument}; /// Signed Document `ver` field validation rule +#[derive(Debug)] pub(crate) struct VerRule; impl VerRule {