aldrin_codegen/
rust.rs

1#[cfg(test)]
2mod test;
3
4pub mod names;
5
6use crate::error::Error;
7use crate::Options;
8use aldrin_parser::{ast, LinkResolver, Parser, ResolvedLink, Schema};
9use comrak::nodes::NodeValue;
10use comrak::options::BrokenLinkReference;
11use comrak::{Arena, Options as ComrakOptions, ResolvedReference};
12use diffy::Patch;
13use std::fmt::Write;
14use std::fs;
15use std::path::Path;
16use std::sync::Arc;
17
18const BOOL: &str = "::std::primitive::bool";
19const BOX: &str = "::std::boxed::Box";
20const CLONE: &str = "::std::clone::Clone";
21const DEBUG: &str = "::std::fmt::Debug";
22const DEFAULT: &str = "::std::default::Default";
23const EQ: &str = "::std::cmp::Eq";
24const F32: &str = "::std::primitive::f32";
25const F64: &str = "::std::primitive::f64";
26const HASH: &str = "::std::hash::Hash";
27const HASH_MAP: &str = "::std::collections::HashMap";
28const HASH_SET: &str = "::std::collections::HashSet";
29const I16: &str = "::std::primitive::i16";
30const I32: &str = "::std::primitive::i32";
31const I64: &str = "::std::primitive::i64";
32const I8: &str = "::std::primitive::i8";
33const OK: &str = "::std::result::Result::Ok";
34const OPTION: &str = "::std::option::Option";
35const ORD: &str = "::std::cmp::Ord";
36const PARTIAL_EQ: &str = "::std::cmp::PartialEq";
37const PARTIAL_ORD: &str = "::std::cmp::PartialOrd";
38const RESULT: &str = "::std::result::Result";
39const STR: &str = "::std::primitive::str";
40const STRING: &str = "::std::string::String";
41const U16: &str = "::std::primitive::u16";
42const U32: &str = "::std::primitive::u32";
43const U64: &str = "::std::primitive::u64";
44const U8: &str = "::std::primitive::u8";
45const VEC: &str = "::std::vec::Vec";
46
47#[derive(Debug, Clone)]
48#[non_exhaustive]
49pub struct RustOptions<'a> {
50    pub patches: Vec<&'a Path>,
51    pub introspection_if: Option<&'a str>,
52    pub krate: Option<&'a str>,
53}
54
55impl<'a> RustOptions<'a> {
56    pub fn new() -> Self {
57        RustOptions {
58            patches: Vec::new(),
59            introspection_if: None,
60            krate: None,
61        }
62    }
63
64    pub fn krate_or_default(&self) -> &'a str {
65        self.krate.unwrap_or("::aldrin")
66    }
67}
68
69impl Default for RustOptions<'_> {
70    fn default() -> Self {
71        RustOptions::new()
72    }
73}
74
75#[derive(Debug, Clone)]
76pub struct RustOutput {
77    pub module_name: String,
78    pub module_content: String,
79}
80
81pub(crate) fn generate(
82    parser: &Parser,
83    options: &Options,
84    rust_options: &RustOptions,
85) -> Result<RustOutput, Error> {
86    let schema = parser.main_schema();
87
88    let generator = RustGenerator {
89        parser,
90        schema,
91        options,
92        rust_options,
93        output: RustOutput {
94            module_name: schema.name().to_owned(),
95            module_content: String::new(),
96        },
97    };
98
99    generator.generate()
100}
101
102struct RustGenerator<'a> {
103    parser: &'a Parser,
104    schema: &'a Schema,
105    options: &'a Options,
106    rust_options: &'a RustOptions<'a>,
107    output: RustOutput,
108}
109
110macro_rules! code {
111    ($this:expr, $arg:literal) => {
112        write!($this.output.module_content, $arg).unwrap()
113    };
114}
115
116macro_rules! codeln {
117    ($this:expr) => {
118        writeln!($this.output.module_content).unwrap()
119    };
120
121    ($this:expr, $arg:literal) => {
122        writeln!($this.output.module_content, $arg).unwrap()
123    };
124}
125
126#[rustfmt::skip::macros(code, codeln)]
127impl RustGenerator<'_> {
128    fn generate(mut self) -> Result<RustOutput, Error> {
129        let (doc, _) = self.doc_string_inner(self.schema.doc(), 0);
130        if !doc.is_empty() {
131            codeln!(self, "{doc}");
132        }
133
134        for def in self.schema.definitions() {
135            self.definition(def);
136        }
137
138        if self.options.introspection {
139            let krate = self.rust_options.krate_or_default();
140            let name = names::register_introspection(self.schema.name());
141
142            if let Some(feature) = self.rust_options.introspection_if {
143                codeln!(self, "#[cfg(feature = \"{feature}\")]");
144            }
145
146            codeln!(self, "pub fn {name}(client: &{krate}::Handle) -> {RESULT}<(), {krate}::Error> {{");
147
148            for def in self.schema.definitions() {
149                self.register_introspection(def);
150            }
151
152            codeln!(self, "    {OK}(())");
153            codeln!(self, "}}");
154        }
155
156        for patch in &self.rust_options.patches {
157            self.patch(patch)?;
158        }
159
160        Ok(self.output)
161    }
162
163    fn patch(&mut self, patch: &Path) -> Result<(), Error> {
164        let patch = fs::read_to_string(patch)?;
165        let patch = Patch::from_str(&patch)?;
166        self.output.module_content = diffy::apply(&self.output.module_content, &patch)?;
167        Ok(())
168    }
169
170    fn definition(&mut self, def: &ast::Definition) {
171        match def {
172            ast::Definition::Struct(d) => self.struct_def(
173                d.name().value(),
174                d.doc(),
175                d.attributes(),
176                d.fields(),
177                d.fallback(),
178            ),
179
180            ast::Definition::Enum(e) => self.enum_def(
181                e.name().value(),
182                e.doc(),
183                e.attributes(),
184                e.variants(),
185                e.fallback(),
186            ),
187
188            ast::Definition::Service(s) => self.service_def(s),
189            ast::Definition::Const(c) => self.const_def(c),
190            ast::Definition::Newtype(n) => self.newtype_def(n),
191        }
192    }
193
194    fn struct_def(
195        &mut self,
196        name: &str,
197        doc: &[ast::DocString],
198        attrs: &[ast::Attribute],
199        fields: &[ast::StructField],
200        fallback: Option<&ast::StructFallback>,
201    ) {
202        let krate = self.rust_options.krate_or_default();
203        let ident = format!("r#{name}");
204        let attrs = RustAttributes::parse(attrs);
205        let num_required_fields = fields.iter().filter(|&f| f.required()).count();
206        let has_required_fields = num_required_fields > 0;
207        let schema_name = self.schema.name();
208        let additional_derives = attrs.additional_derives();
209
210        let (doc_comment, doc_alt) = self.doc_string(doc, 0);
211        code!(self, "{doc_comment}");
212
213        code!(self, "#[derive({DEBUG}, {CLONE}");
214
215        if !has_required_fields {
216            code!(self, ", {DEFAULT}");
217        }
218
219        code!(self, ", {krate}::Tag, {krate}::PrimaryTag, {krate}::RefType, {krate}::Serialize, {krate}::Deserialize");
220
221        if self.options.introspection && self.rust_options.introspection_if.is_none() {
222            code!(self, ", {krate}::Introspectable");
223        }
224
225        codeln!(self, "{additional_derives})]");
226
227        if self.options.introspection {
228            if let Some(feature) = self.rust_options.introspection_if {
229                codeln!(self, "#[cfg_attr(feature = \"{feature}\", derive({krate}::Introspectable))]");
230            }
231        }
232
233        code!(self, "#[aldrin(");
234        if let Some(krate) = self.rust_options.krate {
235            code!(self, "crate = {krate}::core, ");
236        }
237        codeln!(self, "schema = \"{schema_name}\", ref_type)]");
238
239        if doc_alt && self.options.introspection {
240            for doc in doc {
241                let doc = doc.value_inner();
242                codeln!(self, "#[aldrin(doc = \"{doc}\")]");
243            }
244        }
245
246        codeln!(self, "pub struct {ident} {{");
247        let mut first = true;
248        for field in fields {
249            let id = field.id().value();
250            let ident = format!("r#{}", field.name().value());
251            let ty = self.type_name(field.field_type());
252
253            if first {
254                first = false;
255            } else {
256                codeln!(self);
257            }
258
259            let (doc_comment, doc_alt) = self.doc_string(field.doc(), 4);
260            code!(self, "{doc_comment}");
261
262            if field.required() {
263                codeln!(self, "    #[aldrin(id = {id})]");
264            } else {
265                codeln!(self, "    #[aldrin(id = {id}, optional)]");
266            }
267
268            if doc_alt && self.options.introspection {
269                for doc in field.doc() {
270                    let doc = doc.value_inner();
271                    codeln!(self, "    #[aldrin(doc = \"{doc}\")]");
272                }
273            }
274
275            if field.required() {
276                codeln!(self, "    pub {ident}: {ty},");
277            } else {
278                codeln!(self, "    pub {ident}: {OPTION}<{ty}>,");
279            }
280        }
281        if let Some(fallback) = fallback {
282            if !first {
283                codeln!(self);
284            }
285
286            let (doc_comment, doc_alt) = self.doc_string(fallback.doc(), 4);
287            code!(self, "{doc_comment}");
288
289            codeln!(self, "    #[aldrin(fallback)]");
290
291            if doc_alt && self.options.introspection {
292                for doc in fallback.doc() {
293                    let doc = doc.value_inner();
294                    codeln!(self, "    #[aldrin(doc = \"{doc}\")]");
295                }
296            }
297
298            let ident = format!("r#{}", fallback.name().value());
299            codeln!(self, "    pub {ident}: {krate}::core::UnknownFields,");
300        }
301        codeln!(self, "}}");
302        codeln!(self);
303
304        if !has_required_fields {
305            codeln!(self, "impl {ident} {{");
306            codeln!(self, "    pub fn new() -> Self {{");
307            codeln!(self, "        <Self as {DEFAULT}>::default()");
308            codeln!(self, "    }}");
309            codeln!(self, "}}");
310            codeln!(self);
311        }
312    }
313
314    fn enum_def(
315        &mut self,
316        name: &str,
317        doc: &[ast::DocString],
318        attrs: &[ast::Attribute],
319        vars: &[ast::EnumVariant],
320        fallback: Option<&ast::EnumFallback>,
321    ) {
322        let ident = format!("r#{name}");
323        let krate = &self.rust_options.krate_or_default();
324        let schema_name = self.schema.name();
325        let attrs = RustAttributes::parse(attrs);
326        let additional_derives = attrs.additional_derives();
327
328        let (doc_comment, doc_alt) = self.doc_string(doc, 0);
329        code!(self, "{doc_comment}");
330
331        code!(self, "#[derive({DEBUG}, {CLONE}");
332        code!(self, ", {krate}::Tag, {krate}::PrimaryTag, {krate}::RefType, {krate}::Serialize, {krate}::Deserialize");
333
334        if self.options.introspection && self.rust_options.introspection_if.is_none() {
335            code!(self, ", {krate}::Introspectable");
336        }
337
338        codeln!(self, "{additional_derives})]");
339
340        if self.options.introspection {
341            if let Some(feature) = self.rust_options.introspection_if {
342                codeln!(self, "#[cfg_attr(feature = \"{feature}\", derive({krate}::Introspectable))]");
343            }
344        }
345
346        code!(self, "#[aldrin(");
347        if let Some(krate) = self.rust_options.krate {
348            code!(self, "crate = {krate}::core, ");
349        }
350        codeln!(self, "schema = \"{schema_name}\", ref_type)]");
351
352        if doc_alt && self.options.introspection {
353            for doc in doc {
354                let doc = doc.value_inner();
355                codeln!(self, "#[aldrin(doc = \"{doc}\")]");
356            }
357        }
358
359        codeln!(self, "pub enum {ident} {{");
360        let mut first = true;
361        for var in vars {
362            let id = var.id().value();
363            let ident = format!("r#{}", var.name().value());
364
365            if first {
366                first = false;
367            } else {
368                codeln!(self);
369            }
370
371            let (doc_comment, doc_alt) = self.doc_string(var.doc(), 4);
372            code!(self, "{doc_comment}");
373
374            codeln!(self, "    #[aldrin(id = {id})]");
375
376            if doc_alt && self.options.introspection {
377                for doc in var.doc() {
378                    let doc = doc.value_inner();
379                    codeln!(self, "    #[aldrin(doc = \"{doc}\")]");
380                }
381            }
382
383            if let Some(ty) = var.variant_type() {
384                let ty = self.type_name(ty);
385                codeln!(self, "    {ident}({ty}),");
386            } else {
387                codeln!(self, "    {ident},");
388            }
389        }
390        if let Some(fallback) = fallback {
391            if !first {
392                codeln!(self);
393            }
394
395            let (doc_comment, doc_alt) = self.doc_string(fallback.doc(), 4);
396            code!(self, "{doc_comment}");
397
398            codeln!(self, "    #[aldrin(fallback)]");
399
400            if doc_alt && self.options.introspection {
401                for doc in fallback.doc() {
402                    let doc = doc.value_inner();
403                    codeln!(self, "    #[aldrin(doc = \"{doc}\")]");
404                }
405            }
406
407            let ident = format!("r#{}", fallback.name().value());
408            codeln!(self, "    {ident}({krate}::core::UnknownVariant),");
409        }
410        codeln!(self, "}}");
411        codeln!(self);
412    }
413
414    fn service_def(&mut self, svc: &ast::ServiceDef) {
415        if !self.options.client && !self.options.server {
416            return;
417        }
418
419        let krate = self.rust_options.krate_or_default();
420        let schema = self.schema.name();
421        let svc_name = svc.name().value();
422        let ident = format!("r#{svc_name}");
423        let uuid = svc.uuid().value();
424        let version = svc.version().value();
425
426        codeln!(self, "{krate}::service! {{");
427
428        let (doc_comment, doc_alt) = self.doc_string(svc.doc(), 4);
429        code!(self, "{doc_comment}");
430
431        code!(self, "    #[aldrin(");
432
433        if let Some(krate) = self.rust_options.krate {
434            code!(self, "crate = {krate}, ");
435        }
436
437        code!(self, "schema = \"{schema}\"");
438
439        if !self.options.client {
440            code!(self, ", client = false");
441        }
442
443        if !self.options.server {
444            code!(self, ", server = false");
445        }
446
447        if self.options.introspection {
448            code!(self, ", introspection");
449        }
450
451        if let Some(feature) = self.rust_options.introspection_if {
452            code!(self, ", introspection_if = \"{feature}\"");
453        }
454
455        codeln!(self, ")]");
456
457        if doc_alt && self.options.introspection {
458            for doc in svc.doc() {
459                let doc = doc.value_inner();
460                codeln!(self, "    #[aldrin(doc = \"{doc}\")]");
461            }
462        }
463
464        codeln!(self, "    pub service {ident} {{");
465        codeln!(self, "        uuid = {krate}::core::ServiceUuid({krate}::private::uuid::uuid!(\"{uuid}\"));");
466        codeln!(self, "        version = {version};");
467
468        for item in svc.items() {
469            codeln!(self);
470
471            match item {
472                ast::ServiceItem::Function(func) => {
473                    let name = func.name().value();
474                    let ident = format!("r#{name}");
475                    let id = func.id().value();
476
477                    let (doc_comment, doc_alt) = self.doc_string(func.doc(), 8);
478                    code!(self, "{doc_comment}");
479
480                    if doc_alt && self.options.introspection {
481                        for doc in func.doc() {
482                            let doc = doc.value_inner();
483                            codeln!(self, "        #[aldrin(doc = \"{doc}\")]");
484                        }
485                    }
486
487                    code!(self, "        fn {ident} @ {id}");
488
489                    if let (None, Some(ok), None) = (func.args(), func.ok(), func.err()) {
490                        let ty = self.function_ok_type_name(svc_name, name, ok, true);
491                        codeln!(self, " = {ty};");
492                    } else if func.args().is_some() || func.ok().is_some() || func.err().is_some() {
493                        codeln!(self, " {{");
494
495                        if let Some(args) = func.args() {
496                            let ty = self.function_args_type_name(svc_name, name, args, true);
497                            codeln!(self, "            args = {ty};");
498                        }
499
500                        if let Some(ok) = func.ok() {
501                            let ty = self.function_ok_type_name(svc_name, name, ok, true);
502                            codeln!(self, "            ok = {ty};");
503                        }
504
505                        if let Some(err) = func.err() {
506                            let ty = self.function_err_type_name(svc_name, name, err, true);
507                            codeln!(self, "            err = {ty};");
508                        }
509
510                        codeln!(self, "        }}");
511                    } else {
512                        codeln!(self, ";");
513                    }
514                }
515
516                ast::ServiceItem::Event(ev) => {
517                    let name = ev.name().value();
518                    let ident = format!("r#{name}");
519                    let id = ev.id().value();
520
521                    let (doc_comment, doc_alt) = self.doc_string(ev.doc(), 8);
522                    code!(self, "{doc_comment}");
523
524                    if doc_alt && self.options.introspection {
525                        for doc in ev.doc() {
526                            let doc = doc.value_inner();
527                            codeln!(self, "        #[aldrin(doc = \"{doc}\")]");
528                        }
529                    }
530
531                    code!(self, "        event {ident} @ {id}");
532
533                    if let Some(ty) = ev.event_type() {
534                        let ty = self.event_args_type_name(svc_name, name, ty, true);
535                        code!(self, " = {ty}");
536                    }
537
538                    codeln!(self, ";");
539                }
540            }
541        }
542
543        if let Some(fallback) = svc.function_fallback() {
544            let name = fallback.name().value();
545            let ident = format!("r#{name}");
546
547            codeln!(self);
548
549            let (doc_comment, doc_alt) = self.doc_string(fallback.doc(), 8);
550            code!(self, "{doc_comment}");
551
552            if doc_alt && self.options.introspection {
553                for doc in fallback.doc() {
554                    let doc = doc.value_inner();
555                    codeln!(self, "        #[aldrin(doc = \"{doc}\")]");
556                }
557            }
558
559            codeln!(self, "        fn {ident} = {krate}::UnknownCall;");
560        }
561
562        if let Some(fallback) = svc.event_fallback() {
563            let name = fallback.name().value();
564            let ident = format!("r#{name}");
565
566            codeln!(self);
567
568            let (doc_comment, doc_alt) = self.doc_string(fallback.doc(), 8);
569            code!(self, "{doc_comment}");
570
571            if doc_alt && self.options.introspection {
572                for doc in fallback.doc() {
573                    let doc = doc.value_inner();
574                    codeln!(self, "        #[aldrin(doc = \"{doc}\")]");
575                }
576            }
577
578            codeln!(self, "        event {ident} = {krate}::UnknownEvent;");
579        }
580
581        codeln!(self, "    }}");
582        codeln!(self, "}}");
583        codeln!(self);
584
585        for item in svc.items() {
586            match item {
587                ast::ServiceItem::Function(func) => {
588                    let func_name = func.name().value();
589
590                    if let Some(args) = func.args() {
591                        match args.part_type() {
592                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
593                                &self.function_args_type_name(svc_name, func_name, args, false),
594                                s.doc(),
595                                s.attributes(),
596                                s.fields(),
597                                s.fallback(),
598                            ),
599
600                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
601                                &self.function_args_type_name(svc_name, func_name, args, false),
602                                e.doc(),
603                                e.attributes(),
604                                e.variants(),
605                                e.fallback(),
606                            ),
607
608                            ast::TypeNameOrInline::TypeName(_) => {}
609                        }
610                    }
611
612                    if let Some(ok) = func.ok() {
613                        match ok.part_type() {
614                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
615                                &self.function_ok_type_name(svc_name, func_name, ok, false),
616                                s.doc(),
617                                s.attributes(),
618                                s.fields(),
619                                s.fallback(),
620                            ),
621
622                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
623                                &self.function_ok_type_name(svc_name, func_name, ok, false),
624                                e.doc(),
625                                e.attributes(),
626                                e.variants(),
627                                e.fallback(),
628                            ),
629
630                            ast::TypeNameOrInline::TypeName(_) => {}
631                        }
632                    }
633
634                    if let Some(err) = func.err() {
635                        match err.part_type() {
636                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
637                                &self.function_err_type_name(svc_name, func_name, err, false),
638                                s.doc(),
639                                s.attributes(),
640                                s.fields(),
641                                s.fallback(),
642                            ),
643
644                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
645                                &self.function_err_type_name(svc_name, func_name, err, false),
646                                e.doc(),
647                                e.attributes(),
648                                e.variants(),
649                                e.fallback(),
650                            ),
651
652                            ast::TypeNameOrInline::TypeName(_) => {}
653                        }
654                    }
655                }
656
657                ast::ServiceItem::Event(ev) => {
658                    if let Some(ty) = ev.event_type() {
659                        let ev_name = ev.name().value();
660
661                        match ty {
662                            ast::TypeNameOrInline::Struct(s) => self.struct_def(
663                                &self.event_args_type_name(svc_name, ev_name, ty, false),
664                                s.doc(),
665                                s.attributes(),
666                                s.fields(),
667                                s.fallback(),
668                            ),
669
670                            ast::TypeNameOrInline::Enum(e) => self.enum_def(
671                                &self.event_args_type_name(svc_name, ev_name, ty, false),
672                                e.doc(),
673                                e.attributes(),
674                                e.variants(),
675                                e.fallback(),
676                            ),
677
678                            ast::TypeNameOrInline::TypeName(_) => {}
679                        }
680                    }
681                }
682            }
683        }
684    }
685
686    fn const_def(&mut self, const_def: &ast::ConstDef) {
687        let krate = self.rust_options.krate_or_default();
688        let name = const_def.name().value();
689
690        let (doc_comment, _) = self.doc_string(const_def.doc(), 0);
691        code!(self, "{doc_comment}");
692
693        match const_def.value() {
694            ast::ConstValue::U8(v) => {
695                let val = v.value();
696                codeln!(self, "pub const {name}: {U8} = {val};");
697            }
698
699            ast::ConstValue::I8(v) => {
700                let val = v.value();
701                codeln!(self, "pub const {name}: {I8} = {val};");
702            }
703
704            ast::ConstValue::U16(v) => {
705                let val = v.value();
706                codeln!(self, "pub const {name}: {U16} = {val};");
707            }
708
709            ast::ConstValue::I16(v) => {
710                let val = v.value();
711                codeln!(self, "pub const {name}: {I16} = {val};");
712            }
713
714            ast::ConstValue::U32(v) => {
715                let val = v.value();
716                codeln!(self, "pub const {name}: {U32} = {val};");
717            }
718
719            ast::ConstValue::I32(v) => {
720                let val = v.value();
721                codeln!(self, "pub const {name}: {I32} = {val};");
722            }
723
724            ast::ConstValue::U64(v) => {
725                let val = v.value();
726                codeln!(self, "pub const {name}: {U64} = {val};");
727            }
728
729            ast::ConstValue::I64(v) => {
730                let val = v.value();
731                codeln!(self, "pub const {name}: {I64} = {val};");
732            }
733
734            ast::ConstValue::String(v) => {
735                let val = v.value();
736                codeln!(self, "pub const {name}: &{STR} = {val};");
737            }
738
739            ast::ConstValue::Uuid(v) => {
740                let val = v.value();
741                codeln!(self, "pub const {name}: {krate}::private::uuid::Uuid = {krate}::private::uuid::uuid!(\"{val}\");");
742            }
743        };
744
745        codeln!(self);
746    }
747
748    fn newtype_def(&mut self, newtype_def: &ast::NewtypeDef) {
749        let krate = self.rust_options.krate_or_default();
750        let name = newtype_def.name().value();
751        let ident = format!("r#{name}");
752        let ty = self.type_name(newtype_def.target_type());
753        let schema_name = self.schema.name();
754        let additional_derives =
755            RustAttributes::parse(newtype_def.attributes()).additional_derives();
756        let (is_key_type, derive_default) =
757            self.newtype_properties(self.schema, newtype_def.target_type());
758
759        let (doc_comment, doc_alt) = self.doc_string(newtype_def.doc(), 0);
760        code!(self, "{doc_comment}");
761
762        code!(self, "#[derive({DEBUG}, {CLONE}");
763
764        if derive_default {
765            code!(self, ", {DEFAULT}");
766        }
767
768        if is_key_type {
769            code!(self, ", {PARTIAL_EQ}, {EQ}, {PARTIAL_ORD}, {ORD}, {HASH}");
770        }
771
772        code!(self, ", {krate}::Tag, {krate}::PrimaryTag, {krate}::RefType, {krate}::Serialize, {krate}::Deserialize");
773
774        if self.options.introspection && self.rust_options.introspection_if.is_none() {
775            code!(self, ", {krate}::Introspectable");
776        }
777
778        if is_key_type {
779            code!(self, ", {krate}::KeyTag, {krate}::PrimaryKeyTag, {krate}::SerializeKey, {krate}::DeserializeKey");
780        }
781
782        codeln!(self, "{additional_derives})]");
783
784        if self.options.introspection {
785            if let Some(feature) = self.rust_options.introspection_if {
786                codeln!(self, "#[cfg_attr(feature = \"{feature}\", derive({krate}::Introspectable))]");
787            }
788        }
789
790        code!(self, "#[aldrin(");
791        if let Some(krate) = self.rust_options.krate {
792            code!(self, "crate = {krate}::core, ");
793        }
794        codeln!(self, "newtype, schema = \"{schema_name}\", ref_type)]");
795
796        if doc_alt && self.options.introspection {
797            for doc in newtype_def.doc() {
798                let doc = doc.value_inner();
799                codeln!(self, "#[aldrin(doc = \"{doc}\")]");
800            }
801        }
802
803        codeln!(self, "pub struct {ident}(pub {ty});");
804        codeln!(self);
805    }
806
807    fn register_introspection(&mut self, def: &ast::Definition) {
808        match def {
809            def @ (ast::Definition::Struct(_)
810            | ast::Definition::Enum(_)
811            | ast::Definition::Newtype(_)) => {
812                let ident = format!("r#{}", def.name().value());
813                codeln!(self, "    client.register_introspection::<{ident}>()?;");
814            }
815
816            ast::Definition::Service(s) => {
817                if self.options.client || self.options.server {
818                    let ident = format!("r#{}", s.name().value());
819                    codeln!(self, "    client.register_introspection::<{ident}Introspection>()?;");
820                }
821            }
822
823            ast::Definition::Const(_) => {}
824        }
825    }
826
827    fn type_name(&self, ty: &ast::TypeName) -> String {
828        let krate = self.rust_options.krate_or_default();
829
830        match ty.kind() {
831            ast::TypeNameKind::Bool => BOOL.to_owned(),
832            ast::TypeNameKind::U8 => U8.to_owned(),
833            ast::TypeNameKind::I8 => I8.to_owned(),
834            ast::TypeNameKind::U16 => U16.to_owned(),
835            ast::TypeNameKind::I16 => I16.to_owned(),
836            ast::TypeNameKind::U32 => U32.to_owned(),
837            ast::TypeNameKind::I32 => I32.to_owned(),
838            ast::TypeNameKind::U64 => U64.to_owned(),
839            ast::TypeNameKind::I64 => I64.to_owned(),
840            ast::TypeNameKind::F32 => F32.to_owned(),
841            ast::TypeNameKind::F64 => F64.to_owned(),
842            ast::TypeNameKind::String => STRING.to_owned(),
843            ast::TypeNameKind::Uuid => format!("{krate}::private::uuid::Uuid"),
844            ast::TypeNameKind::ObjectId => format!("{krate}::core::ObjectId"),
845            ast::TypeNameKind::ServiceId => format!("{krate}::core::ServiceId"),
846            ast::TypeNameKind::Value => format!("{krate}::core::SerializedValue"),
847            ast::TypeNameKind::Option(ty) => format!("{OPTION}<{}>", self.type_name(ty)),
848            ast::TypeNameKind::Box(ty) => format!("{BOX}<{}>", self.type_name(ty)),
849
850            ast::TypeNameKind::Vec(ty) => match ty.kind() {
851                ast::TypeNameKind::U8 => format!("{krate}::core::Bytes"),
852                _ => format!("{VEC}<{}>", self.type_name(ty)),
853            },
854
855            ast::TypeNameKind::Bytes => format!("{krate}::core::Bytes"),
856
857            ast::TypeNameKind::Map(k, v) => {
858                format!("{HASH_MAP}<{}, {}>", self.type_name(k), self.type_name(v))
859            }
860
861            ast::TypeNameKind::Set(ty) => format!("{HASH_SET}<{}>", self.type_name(ty)),
862
863            ast::TypeNameKind::Sender(ty) => {
864                format!("{krate}::UnboundSender<{}>", self.type_name(ty))
865            }
866
867            ast::TypeNameKind::Receiver(ty) => {
868                format!("{krate}::UnboundReceiver<{}>", self.type_name(ty))
869            }
870
871            ast::TypeNameKind::Lifetime => format!("{krate}::LifetimeId"),
872            ast::TypeNameKind::Unit => "()".to_owned(),
873
874            ast::TypeNameKind::Result(ok, err) => {
875                format!("{RESULT}<{}, {}>", self.type_name(ok), self.type_name(err))
876            }
877
878            ast::TypeNameKind::Array(ty, len) => self.array_name(ty, len),
879            ast::TypeNameKind::Ref(ty) => self.named_ref_name(ty),
880        }
881    }
882
883    fn array_name(&self, ty: &ast::TypeName, len: &ast::ArrayLen) -> String {
884        match len.value() {
885            ast::ArrayLenValue::Literal(len) => {
886                format!("[{}; {}usize]", self.type_name(ty), len.value())
887            }
888
889            ast::ArrayLenValue::Ref(named_ref) => {
890                format!(
891                    "[{}; {} as usize]",
892                    self.type_name(ty),
893                    self.named_ref_name(named_ref)
894                )
895            }
896        }
897    }
898
899    fn named_ref_name(&self, ty: &ast::NamedRef) -> String {
900        match ty.kind() {
901            ast::NamedRefKind::Intern(ty) => format!("r#{}", ty.value()),
902            ast::NamedRefKind::Extern(m, ty) => format!("super::r#{}::r#{}", m.value(), ty.value()),
903        }
904    }
905
906    fn function_args_type_name(
907        &self,
908        svc_name: &str,
909        func_name: &str,
910        part: &ast::FunctionPart,
911        raw: bool,
912    ) -> String {
913        match part.part_type() {
914            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
915
916            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
917                if raw {
918                    format!("r#{}", names::function_args(svc_name, func_name))
919                } else {
920                    names::function_args(svc_name, func_name)
921                }
922            }
923        }
924    }
925
926    fn function_ok_type_name(
927        &self,
928        svc_name: &str,
929        func_name: &str,
930        part: &ast::FunctionPart,
931        raw: bool,
932    ) -> String {
933        match part.part_type() {
934            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
935
936            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
937                if raw {
938                    format!("r#{}", names::function_ok(svc_name, func_name))
939                } else {
940                    names::function_ok(svc_name, func_name)
941                }
942            }
943        }
944    }
945
946    fn function_err_type_name(
947        &self,
948        svc_name: &str,
949        func_name: &str,
950        part: &ast::FunctionPart,
951        raw: bool,
952    ) -> String {
953        match part.part_type() {
954            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
955
956            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
957                if raw {
958                    format!("r#{}", names::function_err(svc_name, func_name))
959                } else {
960                    names::function_err(svc_name, func_name)
961                }
962            }
963        }
964    }
965
966    fn event_args_type_name(
967        &self,
968        svc_name: &str,
969        ev_name: &str,
970        ev_type: &ast::TypeNameOrInline,
971        raw: bool,
972    ) -> String {
973        match ev_type {
974            ast::TypeNameOrInline::TypeName(ty) => self.type_name(ty),
975
976            ast::TypeNameOrInline::Struct(_) | ast::TypeNameOrInline::Enum(_) => {
977                if raw {
978                    format!("r#{}", names::event_args(svc_name, ev_name))
979                } else {
980                    names::event_args(svc_name, ev_name)
981                }
982            }
983        }
984    }
985
986    fn newtype_properties(&self, schema: &Schema, ty: &ast::TypeName) -> (bool, bool) {
987        match ty.kind() {
988            ast::TypeNameKind::U8
989            | ast::TypeNameKind::I8
990            | ast::TypeNameKind::U16
991            | ast::TypeNameKind::I16
992            | ast::TypeNameKind::U32
993            | ast::TypeNameKind::I32
994            | ast::TypeNameKind::U64
995            | ast::TypeNameKind::I64
996            | ast::TypeNameKind::String
997            | ast::TypeNameKind::Uuid => (true, false),
998
999            ast::TypeNameKind::Bool
1000            | ast::TypeNameKind::F32
1001            | ast::TypeNameKind::F64
1002            | ast::TypeNameKind::ObjectId
1003            | ast::TypeNameKind::ServiceId
1004            | ast::TypeNameKind::Value
1005            | ast::TypeNameKind::Option(_)
1006            | ast::TypeNameKind::Box(_)
1007            | ast::TypeNameKind::Vec(_)
1008            | ast::TypeNameKind::Bytes
1009            | ast::TypeNameKind::Map(_, _)
1010            | ast::TypeNameKind::Set(_)
1011            | ast::TypeNameKind::Sender(_)
1012            | ast::TypeNameKind::Receiver(_)
1013            | ast::TypeNameKind::Lifetime
1014            | ast::TypeNameKind::Unit
1015            | ast::TypeNameKind::Result(_, _)
1016            | ast::TypeNameKind::Array(_, _) => (false, false),
1017
1018            ast::TypeNameKind::Ref(ty) => {
1019                let (schema, name) = match ty.kind() {
1020                    ast::NamedRefKind::Intern(name) => (schema, name.value()),
1021
1022                    ast::NamedRefKind::Extern(schema, name) => {
1023                        if let Some(schema) = self.parser.get_schema(schema.value()) {
1024                            (schema, name.value())
1025                        } else {
1026                            return (false, false);
1027                        }
1028                    }
1029                };
1030
1031                let Some(def) = schema
1032                    .definitions()
1033                    .iter()
1034                    .find(|def| def.name().value() == name)
1035                else {
1036                    return (false, false);
1037                };
1038
1039                match def {
1040                    ast::Definition::Struct(struct_def) => {
1041                        let has_required_fields =
1042                            struct_def.fields().iter().any(ast::StructField::required);
1043
1044                        (false, !has_required_fields)
1045                    }
1046
1047                    ast::Definition::Newtype(newtype_def) => {
1048                        self.newtype_properties(schema, newtype_def.target_type())
1049                    }
1050
1051                    ast::Definition::Enum(_)
1052                    | ast::Definition::Service(_)
1053                    | ast::Definition::Const(_) => (false, false),
1054                }
1055            }
1056        }
1057    }
1058
1059    fn doc_string(&self, doc: &[ast::DocString], indent: usize) -> (String, bool) {
1060        self.doc_string_impl(doc, indent, "///")
1061    }
1062
1063    fn doc_string_inner(&self, doc: &[ast::DocString], indent: usize) -> (String, bool) {
1064        self.doc_string_impl(doc, indent, "//!")
1065    }
1066
1067    fn doc_string_impl(
1068        &self,
1069        doc: &[ast::DocString],
1070        indent: usize,
1071        style: &'static str,
1072    ) -> (String, bool) {
1073        const INDENT: &str = "        ";
1074
1075        debug_assert!(indent <= INDENT.len());
1076
1077        if doc.is_empty() {
1078            return (String::new(), false);
1079        }
1080
1081        let mut orig = String::new();
1082
1083        for doc in doc {
1084            orig.push_str(doc.value_inner());
1085            orig.push('\n');
1086        }
1087
1088        let with_links = self.rewrite_doc_links(&orig);
1089        let mut doc_string = String::new();
1090
1091        for line in with_links.lines() {
1092            doc_string.push_str(&INDENT[..indent]);
1093            doc_string.push_str(style);
1094
1095            if !line.is_empty() {
1096                doc_string.push(' ');
1097                doc_string.push_str(line);
1098            }
1099
1100            doc_string.push('\n');
1101        }
1102
1103        (doc_string, orig != with_links)
1104    }
1105
1106    fn rewrite_doc_links(&self, doc: &str) -> String {
1107        let resolver = LinkResolver::new(self.parser, self.schema);
1108
1109        let mut options = ComrakOptions::default();
1110        options.extension.footnotes = true;
1111        options.extension.strikethrough = true;
1112        options.extension.table = true;
1113        options.extension.tasklist = true;
1114        options.parse.smart = true;
1115
1116        options.parse.broken_link_callback = Some(Arc::new(move |link: BrokenLinkReference| {
1117            resolver
1118                .convert_broken_link_if_valid(link.original)
1119                .map(|link| ResolvedReference {
1120                    url: link.to_owned(),
1121                    title: String::new(),
1122                })
1123        }));
1124
1125        let arena = Arena::new();
1126        let root = comrak::parse_document(&arena, doc, &options);
1127
1128        for node in root.descendants() {
1129            let mut data = node.data.borrow_mut();
1130
1131            if let NodeValue::Link(ref mut link) = data.value {
1132                if let Some(new_link) = self.rewrite_doc_link(&link.url, resolver) {
1133                    link.url = new_link;
1134                }
1135            }
1136        }
1137
1138        let mut doc_string = String::new();
1139        comrak::format_commonmark(root, &options, &mut doc_string).unwrap();
1140        doc_string
1141    }
1142
1143    fn rewrite_doc_link(&self, link: &str, resolver: LinkResolver<'_>) -> Option<String> {
1144        let Ok(resolved) = resolver.resolve(link) else {
1145            return None;
1146        };
1147
1148        match resolved {
1149            ResolvedLink::Foreign => None,
1150
1151            ResolvedLink::Schema(schema) => {
1152                if schema.name() == resolver.schema().name() {
1153                    Some("self".to_owned())
1154                } else {
1155                    Some(format!("super::{}", schema.name()))
1156                }
1157            }
1158
1159            ResolvedLink::Struct(schema, struct_def) => Some(Self::doc_link_components(
1160                schema,
1161                resolver,
1162                &[struct_def.name().value()],
1163            )),
1164
1165            ResolvedLink::Field(schema, struct_def, field) => Some(Self::doc_link_components(
1166                schema,
1167                resolver,
1168                &[struct_def.name().value(), field.name().value()],
1169            )),
1170
1171            ResolvedLink::FallbackField(schema, struct_def, fallback) => {
1172                Some(Self::doc_link_components(
1173                    schema,
1174                    resolver,
1175                    &[struct_def.name().value(), fallback.name().value()],
1176                ))
1177            }
1178
1179            ResolvedLink::Enum(schema, enum_def) => Some(Self::doc_link_components(
1180                schema,
1181                resolver,
1182                &[enum_def.name().value()],
1183            )),
1184
1185            ResolvedLink::Variant(schema, enum_def, var) => Some(Self::doc_link_components(
1186                schema,
1187                resolver,
1188                &[enum_def.name().value(), var.name().value()],
1189            )),
1190
1191            ResolvedLink::FallbackVariant(schema, enum_def, fallback) => {
1192                Some(Self::doc_link_components(
1193                    schema,
1194                    resolver,
1195                    &[enum_def.name().value(), fallback.name().value()],
1196                ))
1197            }
1198
1199            ResolvedLink::Service(schema, svc) => {
1200                if self.options.client {
1201                    Some(Self::doc_link_components(
1202                        schema,
1203                        resolver,
1204                        &[&names::service_proxy(svc.name().value())],
1205                    ))
1206                } else if self.options.server {
1207                    Some(Self::doc_link_components(
1208                        schema,
1209                        resolver,
1210                        &[svc.name().value()],
1211                    ))
1212                } else {
1213                    None
1214                }
1215            }
1216
1217            ResolvedLink::Function(schema, svc, func) => {
1218                if self.options.client {
1219                    Some(Self::doc_link_components(
1220                        schema,
1221                        resolver,
1222                        &[
1223                            &names::service_proxy(svc.name().value()),
1224                            func.name().value(),
1225                        ],
1226                    ))
1227                } else if self.options.server {
1228                    Some(Self::doc_link_components(
1229                        schema,
1230                        resolver,
1231                        &[
1232                            &names::service_call(svc.name().value()),
1233                            &names::function_variant(func.name().value()),
1234                        ],
1235                    ))
1236                } else {
1237                    None
1238                }
1239            }
1240
1241            ResolvedLink::FunctionArgsStruct(schema, svc, func, _, _) => {
1242                if self.options.client || self.options.server {
1243                    Some(Self::doc_link_components(
1244                        schema,
1245                        resolver,
1246                        &[&names::function_args(
1247                            svc.name().value(),
1248                            func.name().value(),
1249                        )],
1250                    ))
1251                } else {
1252                    None
1253                }
1254            }
1255
1256            ResolvedLink::FunctionArgsField(schema, svc, func, _, _, field) => {
1257                if self.options.client || self.options.server {
1258                    Some(Self::doc_link_components(
1259                        schema,
1260                        resolver,
1261                        &[
1262                            &names::function_args(svc.name().value(), func.name().value()),
1263                            field.name().value(),
1264                        ],
1265                    ))
1266                } else {
1267                    None
1268                }
1269            }
1270
1271            ResolvedLink::FunctionArgsFallbackField(schema, svc, func, _, _, fallback) => {
1272                if self.options.client || self.options.server {
1273                    Some(Self::doc_link_components(
1274                        schema,
1275                        resolver,
1276                        &[
1277                            &names::function_args(svc.name().value(), func.name().value()),
1278                            fallback.name().value(),
1279                        ],
1280                    ))
1281                } else {
1282                    None
1283                }
1284            }
1285
1286            ResolvedLink::FunctionArgsEnum(schema, svc, func, _, _) => {
1287                if self.options.client || self.options.server {
1288                    Some(Self::doc_link_components(
1289                        schema,
1290                        resolver,
1291                        &[&names::function_args(
1292                            svc.name().value(),
1293                            func.name().value(),
1294                        )],
1295                    ))
1296                } else {
1297                    None
1298                }
1299            }
1300
1301            ResolvedLink::FunctionArgsVariant(schema, svc, func, _, _, var) => {
1302                if self.options.client || self.options.server {
1303                    Some(Self::doc_link_components(
1304                        schema,
1305                        resolver,
1306                        &[
1307                            &names::function_args(svc.name().value(), func.name().value()),
1308                            var.name().value(),
1309                        ],
1310                    ))
1311                } else {
1312                    None
1313                }
1314            }
1315
1316            ResolvedLink::FunctionArgsFallbackVariant(schema, svc, func, _, _, fallback) => {
1317                if self.options.client || self.options.server {
1318                    Some(Self::doc_link_components(
1319                        schema,
1320                        resolver,
1321                        &[
1322                            &names::function_args(svc.name().value(), func.name().value()),
1323                            fallback.name().value(),
1324                        ],
1325                    ))
1326                } else {
1327                    None
1328                }
1329            }
1330
1331            ResolvedLink::FunctionOkStruct(schema, svc, func, _, _) => {
1332                if self.options.client || self.options.server {
1333                    Some(Self::doc_link_components(
1334                        schema,
1335                        resolver,
1336                        &[&names::function_ok(svc.name().value(), func.name().value())],
1337                    ))
1338                } else {
1339                    None
1340                }
1341            }
1342
1343            ResolvedLink::FunctionOkField(schema, svc, func, _, _, field) => {
1344                if self.options.client || self.options.server {
1345                    Some(Self::doc_link_components(
1346                        schema,
1347                        resolver,
1348                        &[
1349                            &names::function_ok(svc.name().value(), func.name().value()),
1350                            field.name().value(),
1351                        ],
1352                    ))
1353                } else {
1354                    None
1355                }
1356            }
1357
1358            ResolvedLink::FunctionOkFallbackField(schema, svc, func, _, _, fallback) => {
1359                if self.options.client || self.options.server {
1360                    Some(Self::doc_link_components(
1361                        schema,
1362                        resolver,
1363                        &[
1364                            &names::function_ok(svc.name().value(), func.name().value()),
1365                            fallback.name().value(),
1366                        ],
1367                    ))
1368                } else {
1369                    None
1370                }
1371            }
1372
1373            ResolvedLink::FunctionOkEnum(schema, svc, func, _, _) => {
1374                if self.options.client || self.options.server {
1375                    Some(Self::doc_link_components(
1376                        schema,
1377                        resolver,
1378                        &[&names::function_ok(svc.name().value(), func.name().value())],
1379                    ))
1380                } else {
1381                    None
1382                }
1383            }
1384
1385            ResolvedLink::FunctionOkVariant(schema, svc, func, _, _, var) => {
1386                if self.options.client || self.options.server {
1387                    Some(Self::doc_link_components(
1388                        schema,
1389                        resolver,
1390                        &[
1391                            &names::function_ok(svc.name().value(), func.name().value()),
1392                            var.name().value(),
1393                        ],
1394                    ))
1395                } else {
1396                    None
1397                }
1398            }
1399
1400            ResolvedLink::FunctionOkFallbackVariant(schema, svc, func, _, _, fallback) => {
1401                if self.options.client || self.options.server {
1402                    Some(Self::doc_link_components(
1403                        schema,
1404                        resolver,
1405                        &[
1406                            &names::function_ok(svc.name().value(), func.name().value()),
1407                            fallback.name().value(),
1408                        ],
1409                    ))
1410                } else {
1411                    None
1412                }
1413            }
1414
1415            ResolvedLink::FunctionErrStruct(schema, svc, func, _, _) => {
1416                if self.options.client || self.options.server {
1417                    Some(Self::doc_link_components(
1418                        schema,
1419                        resolver,
1420                        &[&names::function_err(
1421                            svc.name().value(),
1422                            func.name().value(),
1423                        )],
1424                    ))
1425                } else {
1426                    None
1427                }
1428            }
1429
1430            ResolvedLink::FunctionErrField(schema, svc, func, _, _, field) => {
1431                if self.options.client || self.options.server {
1432                    Some(Self::doc_link_components(
1433                        schema,
1434                        resolver,
1435                        &[
1436                            &names::function_err(svc.name().value(), func.name().value()),
1437                            field.name().value(),
1438                        ],
1439                    ))
1440                } else {
1441                    None
1442                }
1443            }
1444
1445            ResolvedLink::FunctionErrFallbackField(schema, svc, func, _, _, fallback) => {
1446                if self.options.client || self.options.server {
1447                    Some(Self::doc_link_components(
1448                        schema,
1449                        resolver,
1450                        &[
1451                            &names::function_err(svc.name().value(), func.name().value()),
1452                            fallback.name().value(),
1453                        ],
1454                    ))
1455                } else {
1456                    None
1457                }
1458            }
1459
1460            ResolvedLink::FunctionErrEnum(schema, svc, func, _, _) => {
1461                if self.options.client || self.options.server {
1462                    Some(Self::doc_link_components(
1463                        schema,
1464                        resolver,
1465                        &[&names::function_err(
1466                            svc.name().value(),
1467                            func.name().value(),
1468                        )],
1469                    ))
1470                } else {
1471                    None
1472                }
1473            }
1474
1475            ResolvedLink::FunctionErrVariant(schema, svc, func, _, _, var) => {
1476                if self.options.client || self.options.server {
1477                    Some(Self::doc_link_components(
1478                        schema,
1479                        resolver,
1480                        &[
1481                            &names::function_err(svc.name().value(), func.name().value()),
1482                            var.name().value(),
1483                        ],
1484                    ))
1485                } else {
1486                    None
1487                }
1488            }
1489
1490            ResolvedLink::FunctionErrFallbackVariant(schema, svc, func, _, _, fallback) => {
1491                if self.options.client || self.options.server {
1492                    Some(Self::doc_link_components(
1493                        schema,
1494                        resolver,
1495                        &[
1496                            &names::function_err(svc.name().value(), func.name().value()),
1497                            fallback.name().value(),
1498                        ],
1499                    ))
1500                } else {
1501                    None
1502                }
1503            }
1504
1505            ResolvedLink::FunctionFallback(schema, svc, fallback) => {
1506                if self.options.server {
1507                    Some(Self::doc_link_components(
1508                        schema,
1509                        resolver,
1510                        &[
1511                            &names::service_call(svc.name().value()),
1512                            &names::function_variant(fallback.name().value()),
1513                        ],
1514                    ))
1515                } else {
1516                    None
1517                }
1518            }
1519
1520            ResolvedLink::Event(schema, svc, ev) => {
1521                if self.options.client {
1522                    Some(Self::doc_link_components(
1523                        schema,
1524                        resolver,
1525                        &[
1526                            &names::service_event(svc.name().value()),
1527                            &names::event_variant(ev.name().value()),
1528                        ],
1529                    ))
1530                } else if self.options.server {
1531                    Some(Self::doc_link_components(
1532                        schema,
1533                        resolver,
1534                        &[svc.name().value(), ev.name().value()],
1535                    ))
1536                } else {
1537                    None
1538                }
1539            }
1540
1541            ResolvedLink::EventStruct(schema, svc, ev, _) => {
1542                if self.options.client || self.options.server {
1543                    Some(Self::doc_link_components(
1544                        schema,
1545                        resolver,
1546                        &[&names::event_args(svc.name().value(), ev.name().value())],
1547                    ))
1548                } else {
1549                    None
1550                }
1551            }
1552
1553            ResolvedLink::EventField(schema, svc, ev, _, field) => {
1554                if self.options.client || self.options.server {
1555                    Some(Self::doc_link_components(
1556                        schema,
1557                        resolver,
1558                        &[
1559                            &names::event_args(svc.name().value(), ev.name().value()),
1560                            field.name().value(),
1561                        ],
1562                    ))
1563                } else {
1564                    None
1565                }
1566            }
1567
1568            ResolvedLink::EventFallbackField(schema, svc, ev, _, fallback) => {
1569                if self.options.client || self.options.server {
1570                    Some(Self::doc_link_components(
1571                        schema,
1572                        resolver,
1573                        &[
1574                            &names::event_args(svc.name().value(), ev.name().value()),
1575                            fallback.name().value(),
1576                        ],
1577                    ))
1578                } else {
1579                    None
1580                }
1581            }
1582
1583            ResolvedLink::EventEnum(schema, svc, ev, _) => {
1584                if self.options.client || self.options.server {
1585                    Some(Self::doc_link_components(
1586                        schema,
1587                        resolver,
1588                        &[&names::event_args(svc.name().value(), ev.name().value())],
1589                    ))
1590                } else {
1591                    None
1592                }
1593            }
1594
1595            ResolvedLink::EventVariant(schema, svc, ev, _, var) => {
1596                if self.options.client || self.options.server {
1597                    Some(Self::doc_link_components(
1598                        schema,
1599                        resolver,
1600                        &[
1601                            &names::event_args(svc.name().value(), ev.name().value()),
1602                            var.name().value(),
1603                        ],
1604                    ))
1605                } else {
1606                    None
1607                }
1608            }
1609
1610            ResolvedLink::EventFallbackVariant(schema, svc, ev, _, fallback) => {
1611                if self.options.client || self.options.server {
1612                    Some(Self::doc_link_components(
1613                        schema,
1614                        resolver,
1615                        &[
1616                            &names::event_args(svc.name().value(), ev.name().value()),
1617                            fallback.name().value(),
1618                        ],
1619                    ))
1620                } else {
1621                    None
1622                }
1623            }
1624
1625            ResolvedLink::EventFallback(schema, svc, fallback) => {
1626                if self.options.client {
1627                    Some(Self::doc_link_components(
1628                        schema,
1629                        resolver,
1630                        &[
1631                            &names::service_event(svc.name().value()),
1632                            &names::event_variant(fallback.name().value()),
1633                        ],
1634                    ))
1635                } else {
1636                    None
1637                }
1638            }
1639
1640            ResolvedLink::Const(schema, const_def) => Some(Self::doc_link_components(
1641                schema,
1642                resolver,
1643                &[const_def.name().value()],
1644            )),
1645
1646            ResolvedLink::Newtype(schema, newtype) => Some(Self::doc_link_components(
1647                schema,
1648                resolver,
1649                &[newtype.name().value()],
1650            )),
1651        }
1652    }
1653
1654    fn doc_link_base(schema: &Schema, resolver: LinkResolver) -> String {
1655        if schema.name() == resolver.schema().name() {
1656            String::new()
1657        } else {
1658            format!("super::{}::", schema.name())
1659        }
1660    }
1661
1662    fn doc_link_components(schema: &Schema, resolver: LinkResolver, components: &[&str]) -> String {
1663        let mut link = Self::doc_link_base(schema, resolver);
1664
1665        for (i, component) in components.iter().enumerate() {
1666            if i > 0 {
1667                link.push_str("::");
1668            }
1669
1670            link.push_str(component);
1671        }
1672
1673        link
1674    }
1675}
1676
1677struct RustAttributes {
1678    impl_copy: bool,
1679    impl_partial_eq: bool,
1680    impl_eq: bool,
1681    impl_partial_ord: bool,
1682    impl_ord: bool,
1683    impl_hash: bool,
1684}
1685
1686impl RustAttributes {
1687    fn new() -> Self {
1688        Self {
1689            impl_copy: false,
1690            impl_partial_eq: false,
1691            impl_eq: false,
1692            impl_partial_ord: false,
1693            impl_ord: false,
1694            impl_hash: false,
1695        }
1696    }
1697
1698    fn parse(attrs: &[ast::Attribute]) -> Self {
1699        let mut res = Self::new();
1700
1701        for attr in attrs {
1702            if attr.name().value() != "rust" {
1703                continue;
1704            }
1705
1706            for opt in attr.options() {
1707                match opt.value() {
1708                    "impl_copy" => res.impl_copy = true,
1709                    "impl_partial_eq" => res.impl_partial_eq = true,
1710                    "impl_eq" => res.impl_eq = true,
1711                    "impl_partial_ord" => res.impl_partial_ord = true,
1712                    "impl_ord" => res.impl_ord = true,
1713                    "impl_hash" => res.impl_hash = true,
1714                    _ => {}
1715                }
1716            }
1717        }
1718
1719        res
1720    }
1721
1722    fn additional_derives(&self) -> String {
1723        let mut derives = String::new();
1724
1725        if self.impl_copy {
1726            derives.push_str(", ::std::marker::Copy");
1727        }
1728
1729        if self.impl_partial_eq {
1730            derives.push_str(", ");
1731            derives.push_str(PARTIAL_EQ);
1732        }
1733
1734        if self.impl_eq {
1735            derives.push_str(", ");
1736            derives.push_str(EQ);
1737        }
1738
1739        if self.impl_partial_ord {
1740            derives.push_str(", ");
1741            derives.push_str(PARTIAL_ORD);
1742        }
1743
1744        if self.impl_ord {
1745            derives.push_str(", ");
1746            derives.push_str(ORD);
1747        }
1748
1749        if self.impl_hash {
1750            derives.push_str(", ");
1751            derives.push_str(HASH);
1752        }
1753
1754        derives
1755    }
1756}