aldrin_codegen/
rust.rs

1#[cfg(test)]
2mod test;
3
4use crate::error::Error;
5use crate::Options;
6use aldrin_parser::{ast, Parsed, Schema};
7use diffy::Patch;
8use heck::ToUpperCamelCase;
9use std::fmt::Write;
10use std::fs;
11use std::path::Path;
12
13const BOOL: &str = "::std::primitive::bool";
14const BOX: &str = "::std::boxed::Box";
15const CLONE: &str = "::std::clone::Clone";
16const DEBUG: &str = "::std::fmt::Debug";
17const DEFAULT: &str = "::std::default::Default";
18const F32: &str = "::std::primitive::f32";
19const F64: &str = "::std::primitive::f64";
20const HASH_MAP: &str = "::std::collections::HashMap";
21const HASH_SET: &str = "::std::collections::HashSet";
22const I16: &str = "::std::primitive::i16";
23const I32: &str = "::std::primitive::i32";
24const I64: &str = "::std::primitive::i64";
25const I8: &str = "::std::primitive::i8";
26const OK: &str = "::std::result::Result::Ok";
27const OPTION: &str = "::std::option::Option";
28const RESULT: &str = "::std::result::Result";
29const STR: &str = "::std::primitive::str";
30const STRING: &str = "::std::string::String";
31const U16: &str = "::std::primitive::u16";
32const U32: &str = "::std::primitive::u32";
33const U64: &str = "::std::primitive::u64";
34const U8: &str = "::std::primitive::u8";
35const VEC: &str = "::std::vec::Vec";
36
37#[derive(Debug, Clone)]
38#[non_exhaustive]
39pub struct RustOptions<'a> {
40    pub patches: Vec<&'a Path>,
41    pub introspection_if: Option<&'a str>,
42    pub krate: &'a str,
43}
44
45impl RustOptions<'_> {
46    pub fn new() -> Self {
47        RustOptions {
48            patches: Vec::new(),
49            introspection_if: None,
50            krate: "::aldrin",
51        }
52    }
53}
54
55impl Default for RustOptions<'_> {
56    fn default() -> Self {
57        RustOptions::new()
58    }
59}
60
61#[derive(Debug, Clone)]
62pub struct RustOutput {
63    pub module_name: String,
64    pub module_content: String,
65}
66
67pub(crate) fn generate(
68    parsed: &Parsed,
69    options: &Options,
70    rust_options: &RustOptions,
71) -> Result<RustOutput, Error> {
72    let schema = parsed.main_schema();
73
74    let generator = RustGenerator {
75        schema,
76        options,
77        rust_options,
78        output: RustOutput {
79            module_name: schema.name().to_owned(),
80            module_content: String::new(),
81        },
82    };
83
84    generator.generate()
85}
86
87struct RustGenerator<'a> {
88    schema: &'a Schema,
89    options: &'a Options,
90    rust_options: &'a RustOptions<'a>,
91    output: RustOutput,
92}
93
94macro_rules! code {
95    ($this:expr, $arg:literal) => {
96        write!($this.output.module_content, $arg).unwrap()
97    };
98}
99
100macro_rules! codeln {
101    ($this:expr) => {
102        writeln!($this.output.module_content).unwrap()
103    };
104
105    ($this:expr, $arg:literal) => {
106        writeln!($this.output.module_content, $arg).unwrap()
107    };
108}
109
110#[rustfmt::skip::macros(code, codeln)]
111impl RustGenerator<'_> {
112    fn generate(mut self) -> Result<RustOutput, Error> {
113        for def in self.schema.definitions() {
114            self.definition(def);
115        }
116
117        if self.options.introspection {
118            let krate = self.rust_options.krate;
119
120            if let Some(feature) = self.rust_options.introspection_if {
121                codeln!(self, "#[cfg(feature = \"{feature}\")]");
122            }
123
124            codeln!(self, "pub fn register_introspection(client: &{krate}::Handle) -> {RESULT}<(), {krate}::Error> {{");
125
126            for def in self.schema.definitions() {
127                self.register_introspection(def);
128            }
129
130            codeln!(self, "    {OK}(())");
131            codeln!(self, "}}");
132        }
133
134        for patch in &self.rust_options.patches {
135            self.patch(patch)?;
136        }
137
138        Ok(self.output)
139    }
140
141    fn patch(&mut self, patch: &Path) -> Result<(), Error> {
142        let patch = fs::read_to_string(patch)?;
143        let patch = Patch::from_str(&patch)?;
144        self.output.module_content = diffy::apply(&self.output.module_content, &patch)?;
145        Ok(())
146    }
147
148    fn definition(&mut self, def: &ast::Definition) {
149        match def {
150            ast::Definition::Struct(d) => self.struct_def(
151                d.name().value(),
152                Some(d.attributes()),
153                d.fields(),
154                d.fallback(),
155            ),
156
157            ast::Definition::Enum(e) => self.enum_def(
158                e.name().value(),
159                Some(e.attributes()),
160                e.variants(),
161                e.fallback(),
162            ),
163
164            ast::Definition::Service(s) => self.service_def(s),
165            ast::Definition::Const(c) => self.const_def(c),
166        }
167    }
168
169    fn struct_def(
170        &mut self,
171        name: &str,
172        attrs: Option<&[ast::Attribute]>,
173        fields: &[ast::StructField],
174        fallback: Option<&ast::Ident>,
175    ) {
176        let krate = self.rust_options.krate;
177        let ident = format!("r#{name}");
178        let attrs = attrs
179            .map(RustAttributes::parse)
180            .unwrap_or_else(RustAttributes::new);
181        let num_required_fields = fields.iter().filter(|&f| f.required()).count();
182        let has_required_fields = num_required_fields > 0;
183        let schema_name = self.schema.name();
184        let additional_derives = attrs.additional_derives();
185
186        let derive_default = if has_required_fields {
187            String::new()
188        } else {
189            format!(", {DEFAULT}")
190        };
191
192        let derive_introspectable =
193            if self.options.introspection && self.rust_options.introspection_if.is_none() {
194                format!(", {krate}::Introspectable")
195            } else {
196                String::new()
197            };
198
199        codeln!(self, "#[derive({DEBUG}, {CLONE}{derive_default}, {krate}::Serialize, {krate}::Deserialize, {krate}::AsSerializeArg{derive_introspectable}{additional_derives})]");
200
201        if self.options.introspection {
202            if let Some(feature) = self.rust_options.introspection_if {
203                codeln!(self, "#[cfg_attr(feature = \"{feature}\", derive({krate}::Introspectable))]");
204            }
205        }
206
207        codeln!(self, "#[aldrin(crate = \"{krate}::core\", schema = \"{schema_name}\")]");
208        codeln!(self, "pub struct {ident} {{");
209        let mut first = true;
210        for field in fields {
211            let id = field.id().value();
212            let ident = format!("r#{}", field.name().value());
213            let ty = self.type_name(field.field_type());
214
215            if first {
216                first = false;
217            } else {
218                codeln!(self);
219            }
220
221            if field.required() {
222                codeln!(self, "    #[aldrin(id = {id})]");
223                codeln!(self, "    pub {ident}: {ty},");
224            } else {
225                codeln!(self, "    #[aldrin(id = {id}, optional)]");
226                codeln!(self, "    pub {ident}: {OPTION}<{ty}>,");
227            }
228        }
229        if let Some(fallback) = fallback {
230            if !first {
231                codeln!(self);
232            }
233
234            let ident = format!("r#{}", fallback.value());
235            codeln!(self, "    #[aldrin(fallback)]");
236            codeln!(self, "    pub {ident}: {krate}::core::UnknownFields,");
237        }
238        codeln!(self, "}}");
239        codeln!(self);
240
241        if !has_required_fields {
242            codeln!(self, "impl {ident} {{");
243            codeln!(self, "    pub fn new() -> Self {{");
244            codeln!(self, "        <Self as {DEFAULT}>::default()");
245            codeln!(self, "    }}");
246            codeln!(self, "}}");
247            codeln!(self);
248        }
249    }
250
251    fn enum_def(
252        &mut self,
253        name: &str,
254        attrs: Option<&[ast::Attribute]>,
255        vars: &[ast::EnumVariant],
256        fallback: Option<&ast::Ident>,
257    ) {
258        let ident = format!("r#{name}");
259        let krate = &self.rust_options.krate;
260        let schema_name = self.schema.name();
261
262        let attrs = attrs
263            .map(RustAttributes::parse)
264            .unwrap_or_else(RustAttributes::new);
265        let additional_derives = attrs.additional_derives();
266
267        let derive_introspectable =
268            if self.options.introspection && self.rust_options.introspection_if.is_none() {
269                format!(", {krate}::Introspectable")
270            } else {
271                String::new()
272            };
273
274        codeln!(self, "#[derive({DEBUG}, {CLONE}, {krate}::Serialize, {krate}::Deserialize, {krate}::AsSerializeArg{derive_introspectable}{additional_derives})]");
275
276        if self.options.introspection {
277            if let Some(feature) = self.rust_options.introspection_if {
278                codeln!(self, "#[cfg_attr(feature = \"{feature}\", derive({krate}::Introspectable))]");
279            }
280        }
281
282        codeln!(self, "#[aldrin(crate = \"{krate}::core\", schema = \"{schema_name}\")]");
283        codeln!(self, "pub enum {ident} {{");
284        let mut first = true;
285        for var in vars {
286            let id = var.id().value();
287            let ident = format!("r#{}", var.name().value());
288
289            if first {
290                first = false;
291            } else {
292                codeln!(self);
293            }
294
295            codeln!(self, "    #[aldrin(id = {id})]");
296            if let Some(ty) = var.variant_type() {
297                let ty = self.type_name(ty);
298                codeln!(self, "    {ident}({ty}),");
299            } else {
300                codeln!(self, "    {ident},");
301            }
302        }
303        if let Some(fallback) = fallback {
304            if !first {
305                codeln!(self);
306            }
307
308            let ident = format!("r#{}", fallback.value());
309            codeln!(self, "    #[aldrin(fallback)]");
310            codeln!(self, "    {ident}({krate}::core::UnknownVariant),");
311        }
312        codeln!(self, "}}");
313        codeln!(self);
314    }
315
316    fn service_def(&mut self, svc: &ast::ServiceDef) {
317        if !self.options.client && !self.options.server {
318            return;
319        }
320
321        let krate = self.rust_options.krate;
322        let schema = self.schema.name();
323        let svc_name = svc.name().value();
324        let ident = format!("r#{svc_name}");
325        let uuid = svc.uuid().value();
326        let version = svc.version().value();
327
328        codeln!(self, "{krate}::service! {{");
329
330        code!(self, "    #[aldrin(crate = \"{krate}\", schema = \"{schema}\"");
331
332        if !self.options.client {
333            code!(self, ", no_client");
334        }
335
336        if !self.options.server {
337            code!(self, ", no_server");
338        }
339
340        if self.options.introspection {
341            code!(self, ", introspection");
342        }
343
344        if let Some(feature) = self.rust_options.introspection_if {
345            code!(self, ", introspection_if = \"{feature}\"");
346        }
347
348        codeln!(self, ")]");
349
350        codeln!(self, "    pub service {ident} {{");
351        codeln!(self, "        uuid = {krate}::core::ServiceUuid({krate}::private::uuid::uuid!(\"{uuid}\"));");
352        codeln!(self, "        version = {version};");
353
354        for item in svc.items() {
355            codeln!(self);
356
357            match item {
358                ast::ServiceItem::Function(func) => {
359                    let name = func.name().value();
360                    let ident = format!("r#{name}");
361                    let id = func.id().value();
362
363                    code!(self, "        fn {ident} @ {id}");
364
365                    if let (None, Some(ok), None) = (func.args(), func.ok(), func.err()) {
366                        let ty = self.function_ok_type_name(svc_name, name, ok, true);
367                        codeln!(self, " = {ty};");
368                    } else if func.args().is_some() || func.ok().is_some() || func.err().is_some() {
369                        codeln!(self, " {{");
370
371                        if let Some(args) = func.args() {
372                            let ty = self.function_args_type_name(svc_name, name, args, true);
373                            codeln!(self, "            args = {ty};");
374                        }
375
376                        if let Some(ok) = func.ok() {
377                            let ty = self.function_ok_type_name(svc_name, name, ok, true);
378                            codeln!(self, "            ok = {ty};");
379                        }
380
381                        if let Some(err) = func.err() {
382                            let ty = self.function_err_type_name(svc_name, name, err, true);
383                            codeln!(self, "            err = {ty};");
384                        }
385
386                        codeln!(self, "        }}");
387                    } else {
388                        codeln!(self, ";");
389                    }
390                }
391
392                ast::ServiceItem::Event(ev) => {
393                    let name = ev.name().value();
394                    let ident = format!("r#{name}");
395                    let id = ev.id().value();
396
397                    code!(self, "        event {ident} @ {id}");
398
399                    if let Some(ty) = ev.event_type() {
400                        let ty = self.event_variant_type(svc_name, name, ty, true);
401                        code!(self, " = {ty}");
402                    }
403
404                    codeln!(self, ";");
405                }
406            }
407        }
408
409        if let Some(fallback) = svc.function_fallback() {
410            let name = fallback.name().value();
411            let ident = format!("r#{name}");
412
413            codeln!(self);
414            codeln!(self, "        fn {ident} = {krate}::UnknownCall;");
415        }
416
417        if let Some(fallback) = svc.event_fallback() {
418            let name = fallback.name().value();
419            let ident = format!("r#{name}");
420
421            codeln!(self);
422            codeln!(self, "        event {ident} = {krate}::UnknownEvent;");
423        }
424
425        codeln!(self, "    }}");
426        codeln!(self, "}}");
427        codeln!(self);
428
429        for item in svc.items() {
430            match item {
431                ast::ServiceItem::Function(func) => {
432                    let func_name = func.name().value();
433
434                    if let Some(args) = func.args() {
435                        match args.part_type() {
436                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
437                                &self.function_args_type_name(svc_name, func_name, args, false),
438                                None,
439                                s.fields(),
440                                s.fallback(),
441                            ),
442
443                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
444                                &self.function_args_type_name(svc_name, func_name, args, false),
445                                None,
446                                e.variants(),
447                                e.fallback(),
448                            ),
449
450                            ast::TypeNameOrInline::TypeName(_) => {}
451                        }
452                    }
453
454                    if let Some(ok) = func.ok() {
455                        match ok.part_type() {
456                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
457                                &self.function_ok_type_name(svc_name, func_name, ok, false),
458                                None,
459                                s.fields(),
460                                s.fallback(),
461                            ),
462
463                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
464                                &self.function_ok_type_name(svc_name, func_name, ok, false),
465                                None,
466                                e.variants(),
467                                e.fallback(),
468                            ),
469
470                            ast::TypeNameOrInline::TypeName(_) => {}
471                        }
472                    }
473
474                    if let Some(err) = func.err() {
475                        match err.part_type() {
476                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
477                                &self.function_err_type_name(svc_name, func_name, err, false),
478                                None,
479                                s.fields(),
480                                s.fallback(),
481                            ),
482
483                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
484                                &self.function_err_type_name(svc_name, func_name, err, false),
485                                None,
486                                e.variants(),
487                                e.fallback(),
488                            ),
489
490                            ast::TypeNameOrInline::TypeName(_) => {}
491                        }
492                    }
493                }
494
495                ast::ServiceItem::Event(ev) => {
496                    if let Some(ty) = ev.event_type() {
497                        let ev_name = ev.name().value();
498
499                        match ty {
500                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
501                                &self.event_variant_type(svc_name, ev_name, ty, false),
502                                None,
503                                s.fields(),
504                                s.fallback(),
505                            ),
506
507                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
508                                &self.event_variant_type(svc_name, ev_name, ty, false),
509                                None,
510                                e.variants(),
511                                e.fallback(),
512                            ),
513
514                            ast::TypeNameOrInline::TypeName(_) => {}
515                        }
516                    }
517                }
518            }
519        }
520    }
521
522    fn const_def(&mut self, const_def: &ast::ConstDef) {
523        let krate = self.rust_options.krate;
524        let name = const_def.name().value();
525
526        match const_def.value() {
527            ast::ConstValue::U8(v) => {
528                let val = v.value();
529                codeln!(self, "pub const {name}: {U8} = {val};");
530            }
531
532            ast::ConstValue::I8(v) => {
533                let val = v.value();
534                codeln!(self, "pub const {name}: {I8} = {val};");
535            }
536
537            ast::ConstValue::U16(v) => {
538                let val = v.value();
539                codeln!(self, "pub const {name}: {U16} = {val};");
540            }
541
542            ast::ConstValue::I16(v) => {
543                let val = v.value();
544                codeln!(self, "pub const {name}: {I16} = {val};");
545            }
546
547            ast::ConstValue::U32(v) => {
548                let val = v.value();
549                codeln!(self, "pub const {name}: {U32} = {val};");
550            }
551
552            ast::ConstValue::I32(v) => {
553                let val = v.value();
554                codeln!(self, "pub const {name}: {I32} = {val};");
555            }
556
557            ast::ConstValue::U64(v) => {
558                let val = v.value();
559                codeln!(self, "pub const {name}: {U64} = {val};");
560            }
561
562            ast::ConstValue::I64(v) => {
563                let val = v.value();
564                codeln!(self, "pub const {name}: {I64} = {val};");
565            }
566
567            ast::ConstValue::String(v) => {
568                let val = v.value();
569                codeln!(self, "pub const {name}: &{STR} = \"{val}\";");
570            }
571
572            ast::ConstValue::Uuid(v) => {
573                let val = v.value();
574                codeln!(self, "pub const {name}: {krate}::private::uuid::Uuid = {krate}::private::uuid::uuid!(\"{val}\");");
575            }
576        };
577
578        codeln!(self);
579    }
580
581    fn register_introspection(&mut self, def: &ast::Definition) {
582        match def {
583            ast::Definition::Struct(d) => {
584                let ident = format!("r#{}", d.name().value());
585                codeln!(self, "    client.register_introspection::<{ident}>()?;");
586            }
587
588            ast::Definition::Enum(e) => {
589                let ident = format!("r#{}", e.name().value());
590                codeln!(self, "    client.register_introspection::<{ident}>()?;");
591            }
592
593            ast::Definition::Service(s) => {
594                if self.options.client || self.options.server {
595                    let ident = format!("r#{}", s.name().value());
596                    codeln!(self, "    client.register_introspection::<{ident}Introspection>()?;");
597                }
598            }
599
600            ast::Definition::Const(_) => {}
601        }
602    }
603
604    fn type_name(&self, ty: &ast::TypeName) -> String {
605        let krate = self.rust_options.krate;
606
607        match ty.kind() {
608            ast::TypeNameKind::Bool => BOOL.to_owned(),
609            ast::TypeNameKind::U8 => U8.to_owned(),
610            ast::TypeNameKind::I8 => I8.to_owned(),
611            ast::TypeNameKind::U16 => U16.to_owned(),
612            ast::TypeNameKind::I16 => I16.to_owned(),
613            ast::TypeNameKind::U32 => U32.to_owned(),
614            ast::TypeNameKind::I32 => I32.to_owned(),
615            ast::TypeNameKind::U64 => U64.to_owned(),
616            ast::TypeNameKind::I64 => I64.to_owned(),
617            ast::TypeNameKind::F32 => F32.to_owned(),
618            ast::TypeNameKind::F64 => F64.to_owned(),
619            ast::TypeNameKind::String => STRING.to_owned(),
620            ast::TypeNameKind::Uuid => format!("{krate}::private::uuid::Uuid"),
621            ast::TypeNameKind::ObjectId => format!("{krate}::core::ObjectId"),
622            ast::TypeNameKind::ServiceId => format!("{krate}::core::ServiceId"),
623            ast::TypeNameKind::Value => format!("{krate}::core::SerializedValue"),
624            ast::TypeNameKind::Option(ty) => format!("{OPTION}<{}>", self.type_name(ty)),
625            ast::TypeNameKind::Box(ty) => format!("{BOX}<{}>", self.type_name(ty)),
626
627            ast::TypeNameKind::Vec(ty) => match ty.kind() {
628                ast::TypeNameKind::U8 => format!("{krate}::core::Bytes"),
629                _ => format!("{VEC}<{}>", self.type_name(ty)),
630            },
631
632            ast::TypeNameKind::Bytes => format!("{krate}::core::Bytes"),
633
634            ast::TypeNameKind::Map(k, v) => format!(
635                "{HASH_MAP}<{}, {}>",
636                self.key_type_name(k),
637                self.type_name(v)
638            ),
639
640            ast::TypeNameKind::Set(ty) => format!("{HASH_SET}<{}>", self.key_type_name(ty)),
641
642            ast::TypeNameKind::Sender(ty) => {
643                format!("{krate}::UnboundSender<{}>", self.type_name(ty))
644            }
645
646            ast::TypeNameKind::Receiver(ty) => {
647                format!("{krate}::UnboundReceiver<{}>", self.type_name(ty))
648            }
649
650            ast::TypeNameKind::Lifetime => format!("{krate}::LifetimeId"),
651            ast::TypeNameKind::Unit => "()".to_owned(),
652
653            ast::TypeNameKind::Result(ok, err) => {
654                format!("{RESULT}<{}, {}>", self.type_name(ok), self.type_name(err))
655            }
656
657            ast::TypeNameKind::Array(ty, len) => self.array_name(ty, len),
658            ast::TypeNameKind::Ref(ty) => self.named_ref_name(ty),
659        }
660    }
661
662    fn array_name(&self, ty: &ast::TypeName, len: &ast::ArrayLen) -> String {
663        match len.value() {
664            ast::ArrayLenValue::Literal(len) => {
665                format!("[{}; {}usize]", self.type_name(ty), len.value())
666            }
667
668            ast::ArrayLenValue::Ref(named_ref) => {
669                format!(
670                    "[{}; {} as usize]",
671                    self.type_name(ty),
672                    self.named_ref_name(named_ref)
673                )
674            }
675        }
676    }
677
678    fn named_ref_name(&self, ty: &ast::NamedRef) -> String {
679        match ty.kind() {
680            ast::NamedRefKind::Intern(ty) => format!("r#{}", ty.value().to_owned()),
681            ast::NamedRefKind::Extern(m, ty) => format!("super::r#{}::r#{}", m.value(), ty.value()),
682        }
683    }
684
685    fn function_args_type_name(
686        &self,
687        svc_name: &str,
688        func_name: &str,
689        part: &ast::FunctionPart,
690        raw: bool,
691    ) -> String {
692        match part.part_type() {
693            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
694
695            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
696                if raw {
697                    format!("r#{svc_name}{}Args", func_name.to_upper_camel_case())
698                } else {
699                    format!("{svc_name}{}Args", func_name.to_upper_camel_case())
700                }
701            }
702        }
703    }
704
705    fn function_ok_type_name(
706        &self,
707        svc_name: &str,
708        func_name: &str,
709        part: &ast::FunctionPart,
710        raw: bool,
711    ) -> String {
712        match part.part_type() {
713            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
714
715            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
716                if raw {
717                    format!("r#{svc_name}{}Ok", func_name.to_upper_camel_case())
718                } else {
719                    format!("{svc_name}{}Ok", func_name.to_upper_camel_case())
720                }
721            }
722        }
723    }
724
725    fn function_err_type_name(
726        &self,
727        svc_name: &str,
728        func_name: &str,
729        part: &ast::FunctionPart,
730        raw: bool,
731    ) -> String {
732        match part.part_type() {
733            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
734
735            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
736                if raw {
737                    format!("r#{svc_name}{}Error", func_name.to_upper_camel_case())
738                } else {
739                    format!("{svc_name}{}Error", func_name.to_upper_camel_case())
740                }
741            }
742        }
743    }
744
745    fn event_variant_type(
746        &self,
747        svc_name: &str,
748        ev_name: &str,
749        ev_type: &ast::TypeNameOrInline,
750        raw: bool,
751    ) -> String {
752        match ev_type {
753            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
754
755            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
756                if raw {
757                    format!("r#{svc_name}{}Event", service_event_variant(ev_name))
758                } else {
759                    format!("{svc_name}{}Event", service_event_variant(ev_name))
760                }
761            }
762        }
763    }
764
765    fn key_type_name(&self, ty: &ast::KeyTypeName) -> String {
766        let krate = self.rust_options.krate;
767
768        match ty.kind() {
769            ast::KeyTypeNameKind::U8 => U8.to_owned(),
770            ast::KeyTypeNameKind::I8 => I8.to_owned(),
771            ast::KeyTypeNameKind::U16 => U16.to_owned(),
772            ast::KeyTypeNameKind::I16 => I16.to_owned(),
773            ast::KeyTypeNameKind::U32 => U32.to_owned(),
774            ast::KeyTypeNameKind::I32 => I32.to_owned(),
775            ast::KeyTypeNameKind::U64 => U64.to_owned(),
776            ast::KeyTypeNameKind::I64 => I64.to_owned(),
777            ast::KeyTypeNameKind::String => STRING.to_owned(),
778            ast::KeyTypeNameKind::Uuid => format!("{krate}::private::uuid::Uuid"),
779        }
780    }
781}
782
783fn service_event_variant(ev_name: &str) -> String {
784    ev_name.to_upper_camel_case()
785}
786
787struct RustAttributes {
788    impl_copy: bool,
789    impl_partial_eq: bool,
790    impl_eq: bool,
791    impl_partial_ord: bool,
792    impl_ord: bool,
793    impl_hash: bool,
794}
795
796impl RustAttributes {
797    fn new() -> Self {
798        Self {
799            impl_copy: false,
800            impl_partial_eq: false,
801            impl_eq: false,
802            impl_partial_ord: false,
803            impl_ord: false,
804            impl_hash: false,
805        }
806    }
807
808    fn parse(attrs: &[ast::Attribute]) -> Self {
809        let mut res = Self::new();
810
811        for attr in attrs {
812            if attr.name().value() != "rust" {
813                continue;
814            }
815
816            for opt in attr.options() {
817                match opt.value() {
818                    "impl_copy" => res.impl_copy = true,
819                    "impl_partial_eq" => res.impl_partial_eq = true,
820                    "impl_eq" => res.impl_eq = true,
821                    "impl_partial_ord" => res.impl_partial_ord = true,
822                    "impl_ord" => res.impl_ord = true,
823                    "impl_hash" => res.impl_hash = true,
824                    _ => {}
825                }
826            }
827        }
828
829        res
830    }
831
832    fn additional_derives(&self) -> String {
833        let mut derives = String::new();
834
835        if self.impl_copy {
836            derives.push_str(", ::std::marker::Copy");
837        }
838
839        if self.impl_partial_eq {
840            derives.push_str(", ::std::cmp::PartialEq");
841        }
842
843        if self.impl_eq {
844            derives.push_str(", ::std::cmp::Eq");
845        }
846
847        if self.impl_partial_ord {
848            derives.push_str(", ::std::cmp::PartialOrd");
849        }
850
851        if self.impl_ord {
852            derives.push_str(", ::std::cmp::Ord");
853        }
854
855        if self.impl_hash {
856            derives.push_str(", ::std::hash::Hash");
857        }
858
859        derives
860    }
861}