@@ -6,12 +6,13 @@ extern crate log;
6
6
7
7
use clap:: { Parser , ValueEnum } ;
8
8
use std:: {
9
- fs:: File ,
9
+ borrow:: Cow ,
10
+ fs:: { self , File } ,
10
11
io:: { self , Write } ,
11
12
path:: PathBuf ,
12
13
} ;
13
14
14
- #[ derive( Clone , Copy , Debug , Default , ValueEnum ) ]
15
+ #[ derive( Clone , Copy , Debug , Default , PartialEq , ValueEnum ) ]
15
16
pub enum Language {
16
17
#[ default]
17
18
Rust ,
@@ -48,6 +49,52 @@ impl Opts {
48
49
}
49
50
}
50
51
52
+ fn expand_node_name < ' a > (
53
+ schema : & ' a cw_schema:: SchemaV1 ,
54
+ node : & ' a cw_schema:: Node ,
55
+ ) -> Cow < ' a , str > {
56
+ match node. value {
57
+ cw_schema:: NodeType :: Array { items } => {
58
+ let items = & schema. definitions [ items] ;
59
+ format ! ( "Vec<{}>" , expand_node_name( schema, items) ) . into ( )
60
+ }
61
+ cw_schema:: NodeType :: Float => "f32" . into ( ) ,
62
+ cw_schema:: NodeType :: Double => "f64" . into ( ) ,
63
+ cw_schema:: NodeType :: Boolean => "bool" . into ( ) ,
64
+ cw_schema:: NodeType :: String => "String" . into ( ) ,
65
+ cw_schema:: NodeType :: Integer { signed, precision } => {
66
+ let ty = if signed { "i" } else { "u" } ;
67
+ format ! ( "{ty}{precision}" ) . into ( )
68
+ }
69
+ cw_schema:: NodeType :: Binary => "Vec<u8>" . into ( ) ,
70
+ cw_schema:: NodeType :: Optional { inner } => {
71
+ let inner = & schema. definitions [ inner] ;
72
+ format ! ( "Option<{}>" , expand_node_name( schema, inner) ) . into ( )
73
+ }
74
+ cw_schema:: NodeType :: Struct ( ..) => node. name . as_ref ( ) . into ( ) ,
75
+ cw_schema:: NodeType :: Tuple { ref items } => {
76
+ let items = items
77
+ . iter ( )
78
+ . map ( |item| expand_node_name ( schema, & schema. definitions [ * item] ) )
79
+ . collect :: < Vec < _ > > ( )
80
+ . join ( ", " ) ;
81
+
82
+ format ! ( "({})" , items) . into ( )
83
+ }
84
+ cw_schema:: NodeType :: Enum { .. } => node. name . as_ref ( ) . into ( ) ,
85
+ _ => todo ! ( ) ,
86
+ }
87
+ }
88
+
89
+ fn prepare_docs ( desc : Option < & str > ) -> Cow < ' _ , [ Cow < ' _ , str > ] > {
90
+ desc. map ( |desc| {
91
+ desc. lines ( )
92
+ . map ( |line| line. replace ( '"' , "\\ \" " ) . into ( ) )
93
+ . collect ( )
94
+ } )
95
+ . unwrap_or ( Cow :: Borrowed ( & [ ] ) )
96
+ }
97
+
51
98
fn main ( ) -> anyhow:: Result < ( ) > {
52
99
simple_logger:: SimpleLogger :: new ( )
53
100
. without_timestamps ( )
@@ -59,11 +106,111 @@ fn main() -> anyhow::Result<()> {
59
106
opts. language, opts. file
60
107
) ;
61
108
62
- let schema = std:: fs:: read_to_string ( & opts. file ) ?;
109
+ ensure ! ( opts. file. exists( ) , "Schema file does not exist" ) ;
110
+ ensure ! (
111
+ opts. language == Language :: Rust ,
112
+ "Only Rust code generation is supported at the moment"
113
+ ) ;
114
+
115
+ let schema = fs:: read_to_string ( & opts. file ) ?;
63
116
let schema: cw_schema:: Schema = serde_json:: from_str ( & schema) ?;
64
117
let cw_schema:: Schema :: V1 ( schema) = schema else {
65
118
bail ! ( "Unsupported schema version" ) ;
66
119
} ;
67
120
121
+ let mut output = opts. output ( ) ?;
122
+
123
+ schema. definitions . iter ( ) . for_each ( |node| {
124
+ debug ! ( "Processing node: {node:?}" ) ;
125
+
126
+ match node. value {
127
+ cw_schema:: NodeType :: Struct ( ref sty) => {
128
+ let structt = cw_schema_codegen:: rust:: StructTemplate {
129
+ name : & node. name ,
130
+ docs : prepare_docs ( node. description . as_deref ( ) ) ,
131
+ ty : match sty {
132
+ cw_schema:: StructType :: Unit => cw_schema_codegen:: rust:: TypeTemplate :: Unit ,
133
+ cw_schema:: StructType :: Named { ref properties } => {
134
+ cw_schema_codegen:: rust:: TypeTemplate :: Named {
135
+ fields : properties
136
+ . iter ( )
137
+ . map ( |( name, prop) | {
138
+ let ty = expand_node_name (
139
+ & schema,
140
+ & schema. definitions [ prop. value ] ,
141
+ ) ;
142
+ cw_schema_codegen:: rust:: FieldTemplate {
143
+ name : Cow :: Borrowed ( name) ,
144
+ docs : prepare_docs ( prop. description . as_deref ( ) ) ,
145
+ ty,
146
+ }
147
+ } )
148
+ . collect ( ) ,
149
+ }
150
+ }
151
+ _ => unreachable ! ( ) ,
152
+ } ,
153
+ } ;
154
+
155
+ writeln ! ( output, "{structt}" ) . unwrap ( ) ;
156
+ }
157
+ cw_schema:: NodeType :: Enum { ref cases, .. } => {
158
+ let enumm = cw_schema_codegen:: rust:: EnumTemplate {
159
+ name : & node. name ,
160
+ docs : prepare_docs ( node. description . as_deref ( ) ) ,
161
+ variants : cases
162
+ . iter ( )
163
+ . map (
164
+ |( name, case) | cw_schema_codegen:: rust:: EnumVariantTemplate {
165
+ name,
166
+ docs : prepare_docs ( case. description . as_deref ( ) ) ,
167
+ ty : match case. value {
168
+ cw_schema:: EnumValue :: Unit => {
169
+ cw_schema_codegen:: rust:: TypeTemplate :: Unit
170
+ }
171
+ cw_schema:: EnumValue :: Tuple { ref items } => {
172
+ let items = items
173
+ . iter ( )
174
+ . map ( |item| {
175
+ let node = & schema. definitions [ * item] ;
176
+ expand_node_name ( & schema, node)
177
+ } )
178
+ . collect ( ) ;
179
+
180
+ cw_schema_codegen:: rust:: TypeTemplate :: Tuple ( items)
181
+ }
182
+ cw_schema:: EnumValue :: Named { ref properties, .. } => {
183
+ cw_schema_codegen:: rust:: TypeTemplate :: Named {
184
+ fields : properties
185
+ . iter ( )
186
+ . map ( |( name, prop) | {
187
+ let ty = expand_node_name (
188
+ & schema,
189
+ & schema. definitions [ prop. value ] ,
190
+ ) ;
191
+ cw_schema_codegen:: rust:: FieldTemplate {
192
+ name : Cow :: Borrowed ( name) ,
193
+ docs : prepare_docs (
194
+ prop. description . as_deref ( ) ,
195
+ ) ,
196
+ ty,
197
+ }
198
+ } )
199
+ . collect ( ) ,
200
+ }
201
+ }
202
+ _ => unreachable ! ( ) ,
203
+ } ,
204
+ } ,
205
+ )
206
+ . collect ( ) ,
207
+ } ;
208
+
209
+ writeln ! ( output, "{enumm}" ) . unwrap ( ) ;
210
+ }
211
+ _ => ( ) ,
212
+ }
213
+ } ) ;
214
+
68
215
Ok ( ( ) )
69
216
}
0 commit comments