1
1
//! Catalyst Signed Document spec type
2
2
3
+ // cspell: words pascalcase
4
+
5
+ pub ( crate ) mod content_type;
3
6
pub ( crate ) mod doc_ref;
4
7
5
8
use std:: { collections:: HashMap , ops:: Deref } ;
6
9
10
+ use inflector:: cases:: pascalcase:: to_pascal_case;
7
11
use proc_macro2:: Ident ;
8
12
use quote:: format_ident;
9
13
10
14
/// Catalyst Signed Document spec representation struct
11
15
#[ derive( serde:: Deserialize ) ]
12
16
pub ( crate ) struct CatalystSignedDocSpec {
17
+ /// A collection of document's supported content types
18
+ #[ serde( rename = "contentTypes" ) ]
19
+ #[ allow( dead_code) ]
20
+ pub ( crate ) content_types : HashMap < ContentTypeTemplate , ContentTypeSpec > ,
13
21
/// A collection of document's specs
14
22
pub ( crate ) docs : HashMap < DocumentName , DocSpec > ,
15
23
}
16
24
25
+ // A thin wrapper over the RFC2046 content type strings.
26
+ #[ derive( serde:: Deserialize , PartialEq , Eq , Hash ) ]
27
+ pub ( crate ) struct ContentTypeTemplate ( pub ( crate ) String ) ;
28
+
29
+ impl ContentTypeTemplate {
30
+ /// returns a content type template as a `Ident` in the following form.
31
+ ///
32
+ /// text/css; charset=utf-8; template=handlebars
33
+ /// => `CssHandlebars`
34
+ ///
35
+ /// text/css; charset=utf-8
36
+ /// => `Css`
37
+ pub ( crate ) fn ident ( & self ) -> Ident {
38
+ let raw = self . 0 . as_str ( ) ;
39
+
40
+ // split into parts like "text/css; charset=utf-8; template=handlebars"
41
+ let mut parts = raw. split ( ';' ) . map ( str:: trim) ;
42
+
43
+ // first part is "type/subtype"
44
+ let first = parts. next ( ) . unwrap_or_default ( ) ; // e.g. "text/css"
45
+ let subtype = first. split ( '/' ) . nth ( 1 ) . unwrap_or_default ( ) ; // "css"
46
+
47
+ // look for "template=..."
48
+ let template = parts
49
+ . find_map ( |p| p. strip_prefix ( "template=" ) )
50
+ . map ( to_pascal_case) ;
51
+
52
+ // build PascalCase
53
+ let mut ident = String :: new ( ) ;
54
+ ident. push_str ( & to_pascal_case ( subtype) ) ;
55
+ if let Some ( t) = template {
56
+ ident. push_str ( & t) ;
57
+ }
58
+
59
+ format_ident ! ( "{}" , ident)
60
+ }
61
+ }
62
+
63
+ /// Catalyst Signed Document supported content type declaration struct
64
+ #[ derive( serde:: Deserialize ) ]
65
+ pub ( crate ) struct ContentTypeSpec {
66
+ /// CoAP Content-Formats
67
+ #[ allow( dead_code) ]
68
+ coap_type : Option < u32 > ,
69
+ }
70
+
17
71
// A thin wrapper over the string document name values
18
72
#[ derive( serde:: Deserialize , PartialEq , Eq , Hash ) ]
19
73
pub ( crate ) struct DocumentName ( String ) ;
@@ -44,7 +98,8 @@ pub(crate) struct DocSpec {
44
98
/// Document type UUID v4 value
45
99
#[ serde( rename = "type" ) ]
46
100
pub ( crate ) doc_type : String ,
47
-
101
+ /// `headers` field
102
+ pub ( crate ) headers : Headers ,
48
103
/// Document type metadata definitions
49
104
pub ( crate ) metadata : Metadata ,
50
105
}
@@ -57,6 +112,14 @@ pub(crate) struct Metadata {
57
112
pub ( crate ) doc_ref : doc_ref:: Ref ,
58
113
}
59
114
115
+ /// Document's metadata fields definition
116
+ #[ derive( serde:: Deserialize ) ]
117
+ #[ allow( clippy:: missing_docs_in_private_items) ]
118
+ pub ( crate ) struct Headers {
119
+ #[ serde( rename = "content type" ) ]
120
+ pub ( crate ) content_type : content_type:: ContentType ,
121
+ }
122
+
60
123
/// "required" field definition
61
124
#[ derive( serde:: Deserialize ) ]
62
125
#[ serde( rename_all = "lowercase" ) ]
@@ -103,7 +166,8 @@ impl CatalystSignedDocSpec {
103
166
// #[allow(dependency_on_unit_never_type_fallback)]
104
167
pub ( crate ) fn load_signed_doc_spec ( ) -> anyhow:: Result < CatalystSignedDocSpec > {
105
168
let signed_doc_str = include_str ! ( "../../../../specs/signed_doc.json" ) ;
106
- let signed_doc_spec = serde_json:: from_str ( signed_doc_str) ?;
169
+ let signed_doc_spec = serde_json:: from_str ( signed_doc_str)
170
+ . map_err ( |e| anyhow:: anyhow!( "Invalid Catalyst Signed Documents JSON Spec: {e}" ) ) ?;
107
171
Ok ( signed_doc_spec)
108
172
}
109
173
}
0 commit comments