11//! Catalyst Signed Document spec type
22
3+ // cspell: words pascalcase
4+
5+ pub ( crate ) mod content_type;
36pub ( crate ) mod doc_ref;
47pub ( crate ) mod payload;
58pub ( crate ) mod template;
69
710use std:: { collections:: HashMap , ops:: Deref } ;
811
12+ use inflector:: cases:: pascalcase:: to_pascal_case;
913use proc_macro2:: Ident ;
1014use quote:: format_ident;
1115
1216/// Catalyst Signed Document spec representation struct
1317#[ derive( serde:: Deserialize ) ]
1418pub ( crate ) struct CatalystSignedDocSpec {
19+ /// A collection of document's supported content types
20+ #[ serde( rename = "contentTypes" ) ]
21+ #[ allow( dead_code) ]
22+ pub ( crate ) content_types : HashMap < ContentTypeTemplate , ContentTypeSpec > ,
1523 /// A collection of document's specs
1624 pub ( crate ) docs : HashMap < DocumentName , DocSpec > ,
1725}
1826
27+ // A thin wrapper over the RFC2046 content type strings.
28+ #[ derive( serde:: Deserialize , PartialEq , Eq , Hash ) ]
29+ pub ( crate ) struct ContentTypeTemplate ( pub ( crate ) String ) ;
30+
31+ impl ContentTypeTemplate {
32+ /// returns a content type template as a `Ident` in the following form.
33+ ///
34+ /// text/css; charset=utf-8; template=handlebars
35+ /// => `CssHandlebars`
36+ ///
37+ /// text/css; charset=utf-8
38+ /// => `Css`
39+ pub ( crate ) fn ident ( & self ) -> Ident {
40+ let raw = self . 0 . as_str ( ) ;
41+
42+ // split into parts like "text/css; charset=utf-8; template=handlebars"
43+ let mut parts = raw. split ( ';' ) . map ( str:: trim) ;
44+
45+ // first part is "type/subtype"
46+ let first = parts. next ( ) . unwrap_or_default ( ) ; // e.g. "text/css"
47+ let subtype = first. split ( '/' ) . nth ( 1 ) . unwrap_or_default ( ) ; // "css"
48+
49+ // look for "template=..."
50+ let template = parts
51+ . find_map ( |p| p. strip_prefix ( "template=" ) )
52+ . map ( to_pascal_case) ;
53+
54+ // build PascalCase
55+ let mut ident = String :: new ( ) ;
56+ ident. push_str ( & to_pascal_case ( subtype) ) ;
57+ if let Some ( t) = template {
58+ ident. push_str ( & t) ;
59+ }
60+
61+ format_ident ! ( "{}" , ident)
62+ }
63+ }
64+
65+ /// Catalyst Signed Document supported content type declaration struct
66+ #[ derive( serde:: Deserialize ) ]
67+ pub ( crate ) struct ContentTypeSpec {
68+ /// CoAP Content-Formats
69+ #[ allow( dead_code) ]
70+ coap_type : Option < u32 > ,
71+ }
72+
1973// A thin wrapper over the string document name values
2074#[ derive( serde:: Deserialize , PartialEq , Eq , Hash ) ]
2175pub ( crate ) struct DocumentName ( String ) ;
@@ -46,6 +100,7 @@ impl DocumentName {
46100pub ( crate ) struct DocSpec {
47101 #[ serde( rename = "type" ) ]
48102 pub ( crate ) doc_type : String ,
103+ pub ( crate ) headers : Headers ,
49104 pub ( crate ) metadata : Metadata ,
50105 pub ( crate ) payload : payload:: Payload ,
51106}
@@ -60,6 +115,14 @@ pub(crate) struct Metadata {
60115 pub ( crate ) template : template:: Template ,
61116}
62117
118+ /// Document's metadata fields definition
119+ #[ derive( serde:: Deserialize ) ]
120+ #[ allow( clippy:: missing_docs_in_private_items) ]
121+ pub ( crate ) struct Headers {
122+ #[ serde( rename = "content type" ) ]
123+ pub ( crate ) content_type : content_type:: ContentType ,
124+ }
125+
63126/// "required" field definition
64127#[ derive( serde:: Deserialize , PartialEq , Eq ) ]
65128#[ serde( rename_all = "lowercase" ) ]
@@ -106,7 +169,8 @@ impl CatalystSignedDocSpec {
106169 // #[allow(dependency_on_unit_never_type_fallback)]
107170 pub ( crate ) fn load_signed_doc_spec ( ) -> anyhow:: Result < CatalystSignedDocSpec > {
108171 let signed_doc_str = include_str ! ( "../../../../specs/signed_doc.json" ) ;
109- let signed_doc_spec = serde_json:: from_str ( signed_doc_str) ?;
172+ let signed_doc_spec = serde_json:: from_str ( signed_doc_str)
173+ . map_err ( |e| anyhow:: anyhow!( "Invalid Catalyst Signed Documents JSON Spec: {e}" ) ) ?;
110174 Ok ( signed_doc_spec)
111175 }
112176}
0 commit comments