1use std::{collections::BTreeMap, fs::read_to_string, path::Path};
97
98use heck::{ToSnakeCase, ToUpperCamelCase};
99use parser::{parse_string, AnyType, PrimitiveType, StructField};
100use proc_macro2::{Ident, Span, TokenStream};
101use quote::quote;
102
103mod parser;
104
105#[derive(Clone, Copy, Debug, Eq, PartialEq)]
107pub struct Config {}
108
109impl Default for Config {
110 fn default() -> Self {
111 Self {}
112 }
113}
114
115fn ident_from_string(s: &String) -> Ident {
116 Ident::new(s, Span::call_site())
117}
118
119#[derive(Clone, Copy)]
120struct Caps {
121 eq: bool,
122 hash: bool,
123}
124
125impl Caps {
126 const ALL: Caps = Caps {
127 eq: true,
128 hash: true,
129 };
130 const NONE: Caps = Caps {
131 eq: false,
132 hash: false,
133 };
134 fn and(self, other: Caps) -> Caps {
135 Caps {
136 eq: self.eq && other.eq,
137 hash: self.hash && other.hash,
138 }
139 }
140 fn derive_tokens(self) -> TokenStream {
141 match (self.eq, self.hash) {
142 (true, true) => quote! { , Eq, Hash },
143 (true, false) => quote! { , Eq },
144 (false, true) => quote! { , Hash },
145 (false, false) => quote! {},
146 }
147 }
148}
149
150pub fn bare_schema(schema_path: &Path, _config: Config) -> proc_macro2::TokenStream {
157 let file = read_to_string(schema_path).unwrap();
158 let mut schema_generator = SchemaGenerator {
159 global_output: Default::default(),
160 user_type_registry: parse_string(&file),
161 };
162
163 for (name, user_type) in &schema_generator.user_type_registry.clone() {
164 schema_generator.gen_user_type(&name, &user_type);
165 }
166
167 schema_generator.complete()
168}
169
170struct SchemaGenerator {
171 global_output: Vec<TokenStream>,
172 user_type_registry: BTreeMap<String, AnyType>,
173}
174
175impl SchemaGenerator {
176 fn complete(self) -> TokenStream {
179 let SchemaGenerator { global_output, .. } = self;
180 quote! {
181 #[allow(unused_imports)]
182 use serde::{Serialize, Deserialize};
183 #[allow(unused_imports)]
184 use serde_bare::{Uint, Int};
185
186 #(#global_output)*
187 }
188 }
189
190 fn gen_user_type(&mut self, name: &String, t: &AnyType) {
195 #[allow(unused_assignments)]
196 use AnyType::*;
197 let def = match t {
198 Primitive(p) => {
199 let def = gen_primative_type_def(p);
200 let ident = ident_from_string(name);
201 quote! {
202 pub type #ident = #def;
203 }
204 }
205 List { inner, length } => {
206 let def = self.gen_list(name, inner.as_ref(), length);
207 let ident = ident_from_string(name);
208 quote! {
209 pub type #ident = #def;
210 }
211 }
212 Struct(fields) => {
213 self.gen_struct(name, fields);
214 TokenStream::new()
216 }
217 Map { key, value } => {
218 let map_def = self.gen_map(name, key.as_ref(), value.as_ref());
219 let ident = ident_from_string(name);
220 quote! {
221 pub type #ident = #map_def;
222 }
223 }
224 Optional(inner) => {
225 let inner_def = self.dispatch_type(name, inner);
226 let ident = ident_from_string(name);
227 quote! {
228 pub type #ident = #inner_def;
229 }
230 }
231 TypeReference(reference) => {
232 panic!("Type reference is not valid as a top level definition: {reference}")
233 }
234 Enum(members) => {
235 self.gen_enum(name, members);
236 TokenStream::new()
238 }
239 Union(members) => {
240 self.gen_union(name, members);
241 TokenStream::new()
243 }
244 };
245 self.global_output.push(def);
246 }
247
248 fn caps_of(&self, t: &AnyType) -> Caps {
249 match t {
250 AnyType::Primitive(p) => match p {
251 PrimitiveType::F32 | PrimitiveType::F64 => Caps::NONE,
252 PrimitiveType::UInt | PrimitiveType::Int => Caps {
253 eq: true,
254 hash: false,
255 },
256 _ => Caps::ALL,
257 },
258 AnyType::List { inner, .. } => self.caps_of(inner),
259 AnyType::Optional(inner) => self.caps_of(inner),
260 AnyType::Map { key, value } => Caps {
261 eq: self.caps_of(key).eq && self.caps_of(value).eq,
262 hash: false,
263 },
264 AnyType::Struct(fields) => fields
265 .iter()
266 .map(|f| self.caps_of(&f.type_r))
267 .fold(Caps::ALL, Caps::and),
268 AnyType::Union(members) => members
269 .iter()
270 .map(|m| self.caps_of(m))
271 .fold(Caps::ALL, Caps::and),
272 AnyType::Enum(_) => Caps::ALL,
273 AnyType::TypeReference(name) => match self.user_type_registry.get(name) {
274 Some(t) => self.caps_of(t),
275 None => Caps::ALL,
276 },
277 }
278 }
279
280 fn is_bytes_type(&self, t: &AnyType) -> bool {
285 match t {
286 AnyType::Primitive(PrimitiveType::Data(size)) => match size {
287 Some(size) => *size > MAX_INLINE_DATA_LEN,
289 None => true,
290 },
291 AnyType::Optional(inner) => self.is_bytes_type(inner),
292 AnyType::TypeReference(name) => match self.user_type_registry.get(name) {
293 Some(t) => self.is_bytes_type(t),
294 None => false,
295 },
296 AnyType::Primitive(_)
297 | AnyType::List { .. }
298 | AnyType::Struct(_)
299 | AnyType::Enum(_)
300 | AnyType::Map { .. }
301 | AnyType::Union(_) => false,
302 }
303 }
304
305 fn dispatch_type(&mut self, name: &String, any_type: &AnyType) -> TokenStream {
306 match any_type {
307 AnyType::Primitive(p) => gen_primative_type_def(p),
308 AnyType::List { inner, length } => self.gen_list(name, inner.as_ref(), length),
309 AnyType::Struct(fields) => self.gen_struct(name, fields),
310 AnyType::Enum(members) => self.gen_enum(name, members),
311 AnyType::Map { key, value } => self.gen_map(name, key.as_ref(), value.as_ref()),
312 AnyType::Union(members) => self.gen_union(name, members),
313 AnyType::Optional(inner) => self.gen_option(name, inner),
314 AnyType::TypeReference(i) => {
315 let ident = ident_from_string(i);
316 quote! { #ident }
317 }
318 }
319 }
320
321 fn gen_map(&mut self, name: &String, key: &AnyType, value: &AnyType) -> TokenStream {
322 let key_def = self.dispatch_type(name, key);
323 let val_def = self.dispatch_type(name, value);
324 quote! {
325 std::collections::HashMap<#key_def, #val_def>
326 }
327 }
328
329 fn gen_list(
330 &mut self,
331 name: &String,
332 inner_type: &AnyType,
333 size: &Option<usize>,
334 ) -> TokenStream {
335 let inner_def = self.dispatch_type(name, inner_type);
336 match *size {
337 Some(size) if size <= 32 => quote! {
338 [#inner_def; #size]
339 },
340 _ => quote! {
341 Vec<#inner_def>
342 },
343 }
344 }
345
346 fn gen_struct(&mut self, name: &String, fields: &Vec<StructField>) -> TokenStream {
347 let extra = fields
348 .iter()
349 .map(|f| self.caps_of(&f.type_r))
350 .fold(Caps::ALL, Caps::and)
351 .derive_tokens();
352 let fields_clone = fields.clone();
354 let fields_gen = self.gen_struct_field(name, fields_clone);
355 self.gen_anonymous(name, |ident| {
356 quote! {
357 #[derive(Serialize, Deserialize, PartialEq, Debug, Clone #extra)]
358 pub struct #ident {
359 #(#fields_gen),*
360 }
361 }
362 })
363 }
364
365 fn gen_union(&mut self, name: &String, members: &Vec<AnyType>) -> TokenStream {
366 let mut members_def: Vec<TokenStream> = Vec::with_capacity(members.len());
367 for (i, member) in members.iter().enumerate() {
368 let is_void_type = match member {
370 AnyType::TypeReference(i) if self.user_type_registry.get(i).is_some() => {
371 let reference = self.user_type_registry.get(i).unwrap();
372 matches!(reference, AnyType::Primitive(PrimitiveType::Void))
373 }
374 _ => false,
375 };
376
377 #[allow(unused_assignments)]
381 let mut member_def = TokenStream::new();
382 member_def = match member {
383 AnyType::Struct(fields) => {
384 let fields_defs = self.gen_struct_field(name, fields.clone());
385 quote! {
386 {
387 #(#fields_defs),*
388 }
389 }
390 }
391 AnyType::TypeReference(i) if is_void_type => {
392 let inner_def = ident_from_string(i);
393 quote! {
395 #inner_def
396 }
397 }
398 _ => {
399 let bytes_attr = if self.is_bytes_type(member) {
400 quote! { #[serde(with = "serde_bytes")] }
401 } else {
402 quote! {}
403 };
404 let inner_def = self.dispatch_type(&format!("{name}Member{i}"), member);
405 quote! {
407 #bytes_attr
408 #inner_def(#inner_def)
409 }
410 }
411 };
412 members_def.push(member_def);
413 }
414 let extra = members
415 .iter()
416 .map(|m| self.caps_of(m))
417 .fold(Caps::ALL, Caps::and)
418 .derive_tokens();
419 self.gen_anonymous(name, |ident| {
420 quote! {
421 #[derive(Serialize, Deserialize, PartialEq, Debug, Clone #extra)]
422 pub enum #ident {
423 #(#members_def),*
424 }
425 }
426 })
427 }
428
429 fn gen_option(&mut self, name: &String, inner: &AnyType) -> TokenStream {
430 let inner_def = self.dispatch_type(name, inner);
431 quote! {
432 Option<#inner_def>
433 }
434 }
435
436 fn gen_struct_field(
437 &mut self,
438 struct_name: &String,
439 fields: Vec<StructField>,
440 ) -> Vec<TokenStream> {
441 let mut fields_gen: Vec<TokenStream> = Vec::with_capacity(fields.len());
442 for StructField { name, type_r } in fields {
443 let name = name.to_snake_case();
444 let bytes_attr = if self.is_bytes_type(&type_r) {
445 quote! { #[serde(with = "serde_bytes")] }
446 } else {
447 quote! {}
448 };
449 #[allow(unused_assignments)]
450 let field_gen = self.dispatch_type(&format!("{struct_name}{name}"), &type_r);
451 let ident = ident_from_string(&name);
452 fields_gen.push(quote! {
453 #bytes_attr
454 pub #ident: #field_gen
455 })
456 }
457 fields_gen
458 }
459
460 fn gen_enum(&mut self, name: &String, members: &Vec<(String, Option<usize>)>) -> TokenStream {
461 let member_defs = members.iter().map(|(name, val)| {
462 let ident = ident_from_string(&name.to_upper_camel_case());
463 if let Some(val) = val {
464 quote! {
465 #ident = #val
466 }
467 } else {
468 quote! {
469 #ident
470 }
471 }
472 });
473 self.gen_anonymous(name, |ident| {
474 quote! {
475 #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, PartialOrd, Clone)]
476 #[repr(usize)]
477 pub enum #ident {
478 #(#member_defs),*
479 }
480 }
481 })
482 }
483
484 fn gen_anonymous(
489 &mut self,
490 name: &String,
491 inner: impl FnOnce(Ident) -> TokenStream,
492 ) -> TokenStream {
493 let ident = ident_from_string(name);
494 self.global_output.push(inner(ident.clone()));
495 quote! {
496 #ident
497 }
498 }
499}
500
501const MAX_INLINE_DATA_LEN: usize = 32;
503
504fn gen_primative_type_def(p: &PrimitiveType) -> TokenStream {
505 use PrimitiveType::*;
506 match p {
507 UInt => quote! { Uint },
508 U64 => quote! { u64 },
509 U32 => quote! { u32 },
510 U16 => quote! { u16 },
511 U8 => quote! { u8 },
512 Int => quote! { Int },
513 I64 => quote! { i64 },
514 I32 => quote! { i32 },
515 I16 => quote! { i16 },
516 I8 => quote! { i8 },
517 F64 => quote! { f64 },
518 F32 => quote! { f32 },
519 Str => quote! { String },
520 Data(s) => match s {
521 Some(size) if *size <= MAX_INLINE_DATA_LEN => quote! { [u8; #size] },
522 _ => quote! { Vec<u8> },
523 },
524 Void => quote! { () },
525 Bool => quote! { bool },
526 }
527}