Skip to main content

capnpc/
codegen.rs

1// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
2// Licensed under the MIT License:
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21
22use std::collections;
23use std::collections::{HashMap, HashSet};
24use std::path::{Path, PathBuf};
25
26use capnp::schema_capnp;
27use capnp::Error;
28
29use self::FormattedText::{BlankLine, Branch, Indent, Line};
30use crate::codegen_types::{do_branding, Leaf, RustNodeInfo, RustTypeInfo, TypeParameterTexts};
31use crate::convert_io_err;
32use crate::pointer_constants::generate_pointer_constant;
33
34/// An invocation of the capnpc-rust code generation plugin.
35pub struct CodeGenerationCommand {
36    output_directory: PathBuf,
37    default_parent_module: Vec<String>,
38    raw_code_generator_request_path: Option<PathBuf>,
39    capnp_root: String,
40    crates_provide_map: HashMap<u64, String>,
41}
42
43impl Default for CodeGenerationCommand {
44    fn default() -> Self {
45        Self {
46            output_directory: PathBuf::new(),
47            default_parent_module: Vec::new(),
48            raw_code_generator_request_path: None,
49            capnp_root: "::capnp".into(),
50            crates_provide_map: HashMap::new(),
51        }
52    }
53}
54
55impl CodeGenerationCommand {
56    /// Creates a new code generation command with default options.
57    pub fn new() -> Self {
58        Self::default()
59    }
60
61    /// Sets the output directory.
62    pub fn output_directory<P>(&mut self, path: P) -> &mut Self
63    where
64        P: AsRef<Path>,
65    {
66        self.output_directory = path.as_ref().to_path_buf();
67        self
68    }
69
70    /// Sets the default parent module, indicating the scope in your crate where you will
71    /// add the generated code.
72    ///
73    /// This option can be overridden by the `parentModule` annotation defined in `rust.capnp`.
74    pub fn default_parent_module(&mut self, default_parent_module: Vec<String>) -> &mut Self {
75        self.default_parent_module = default_parent_module;
76        self
77    }
78
79    /// Sets the root path for referencing things in the `capnp` crate from the generated
80    /// code. Usually this is `::capnp`. When we bootstrap schema.capnp we set this to `crate`.
81    /// If you are renaming the `capnp` crate when importing it, then you probably want to set
82    /// this value.
83    pub fn capnp_root(&mut self, capnp_root: &str) -> &mut Self {
84        self.capnp_root = capnp_root.into();
85        self
86    }
87
88    /// Sets the raw code generator request output path.
89    pub fn raw_code_generator_request_path<P>(&mut self, path: P) -> &mut Self
90    where
91        P: AsRef<Path>,
92    {
93        self.raw_code_generator_request_path = Some(path.as_ref().to_path_buf());
94        self
95    }
96
97    /// Sets the crate provides map.
98    ///
99    /// # Arguments
100    ///
101    /// - `map` - A map from capnp file id to the crate name that provides the
102    ///   corresponding generated code.
103    ///
104    /// See [`crate::CompilerCommand::crate_provides`] for more details.
105    pub fn crates_provide_map(&mut self, map: HashMap<u64, String>) -> &mut Self {
106        self.crates_provide_map = map;
107        self
108    }
109
110    /// Generates Rust code according to a `schema_capnp::code_generator_request` read from `inp`.
111    pub fn run<T>(&mut self, inp: T) -> ::capnp::Result<()>
112    where
113        T: std::io::Read,
114    {
115        use capnp::serialize;
116        use std::io::Write;
117
118        let message = serialize::read_message(inp, capnp::message::ReaderOptions::new())?;
119
120        let ctx = GeneratorContext::new_from_code_generation_command(self, &message)?;
121
122        for requested_file in ctx.request.get_requested_files()? {
123            let id = requested_file.get_id();
124            let mut filepath = self.output_directory.to_path_buf();
125            let requested = ::std::path::PathBuf::from(requested_file.get_filename()?.to_str()?);
126            filepath.push(requested);
127            if let Some(parent) = filepath.parent() {
128                ::std::fs::create_dir_all(parent).map_err(convert_io_err)?;
129            }
130
131            let root_name = path_to_stem_string(&filepath)?.replace('-', "_");
132            filepath.set_file_name(format!("{root_name}_capnp.rs"));
133
134            let capnp_version = match ctx.request.get_capnp_version() {
135                Ok(version) => format!(
136                    "{}.{}.{}",
137                    version.get_major(),
138                    version.get_minor(),
139                    version.get_micro()
140                ),
141                Err(_) => "<unknown>".to_owned(),
142            };
143
144            let lines =
145                Branch(vec![
146                Line(
147                    "// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler."
148                        .to_string(),
149                ),
150                line("// DO NOT EDIT."),
151                Line(format!("// source: {}", requested_file.get_filename()?.to_str()?)),
152                Line(format!("// capnp binary version: {}", capnp_version)),
153                Line(format!("// capnpc crate version: {}", env!("CARGO_PKG_VERSION"))),
154                BlankLine,
155                generate_node(&ctx, id, &root_name)?,
156            ]);
157
158            let text = stringify(&lines);
159
160            let previous_text = ::std::fs::read(&filepath);
161            if previous_text.is_ok() && previous_text.unwrap() == text.as_bytes() {
162                // File is unchanged. Do not write it so that builds with the
163                // output as part of the source work in read-only filesystems
164                // and so timestamp-based build systems and watchers do not get
165                // confused.
166                continue;
167            }
168
169            // It would be simpler to use the ? operator instead of a pattern match, but then the error message
170            // would not include `filepath`.
171            match ::std::fs::File::create(&filepath) {
172                Ok(mut writer) => {
173                    writer.write_all(text.as_bytes()).map_err(convert_io_err)?;
174                }
175                Err(e) => {
176                    let _ = writeln!(
177                        &mut ::std::io::stderr(),
178                        "could not open file {filepath:?} for writing: {e}"
179                    );
180                    return Err(convert_io_err(e));
181                }
182            }
183        }
184
185        if let Some(raw_code_generator_request) = &self.raw_code_generator_request_path {
186            let raw_code_generator_request_file =
187                ::std::fs::File::create(raw_code_generator_request).map_err(convert_io_err)?;
188            serialize::write_message_segments(
189                raw_code_generator_request_file,
190                &message.into_segments(),
191            )?;
192        }
193
194        Ok(())
195    }
196}
197
198pub struct GeneratorContext<'a> {
199    pub request: schema_capnp::code_generator_request::Reader<'a>,
200    pub node_map: collections::hash_map::HashMap<u64, schema_capnp::node::Reader<'a>>,
201    pub scope_map: collections::hash_map::HashMap<u64, Vec<String>>,
202
203    /// Map from node ID to the node ID of its parent scope. This is equal to node.scope_id
204    /// for all nodes except for autogenerated interface Param and Result structs;
205    /// those have scope_id set to 0. See the comment on paramStructType in schema.capnp.
206    pub node_parents: collections::hash_map::HashMap<u64, u64>,
207
208    /// Root path for referencing things in the `capnp` crate from the generated code.
209    pub capnp_root: String,
210}
211
212impl<'a> GeneratorContext<'a> {
213    pub fn new(
214        message: &'a capnp::message::Reader<capnp::serialize::OwnedSegments>,
215    ) -> ::capnp::Result<GeneratorContext<'a>> {
216        GeneratorContext::new_from_code_generation_command(&Default::default(), message)
217    }
218
219    fn new_from_code_generation_command(
220        code_generation_command: &CodeGenerationCommand,
221        message: &'a capnp::message::Reader<capnp::serialize::OwnedSegments>,
222    ) -> ::capnp::Result<GeneratorContext<'a>> {
223        let mut default_parent_module_scope = vec!["crate".to_string()];
224        default_parent_module_scope
225            .extend_from_slice(&code_generation_command.default_parent_module[..]);
226
227        let mut ctx = GeneratorContext {
228            request: message.get_root()?,
229            node_map: collections::hash_map::HashMap::<u64, schema_capnp::node::Reader<'a>>::new(),
230            scope_map: collections::hash_map::HashMap::<u64, Vec<String>>::new(),
231            node_parents: collections::hash_map::HashMap::new(),
232            capnp_root: code_generation_command.capnp_root.clone(),
233        };
234
235        let crates_provide = &code_generation_command.crates_provide_map;
236
237        for node in ctx.request.get_nodes()? {
238            ctx.node_map.insert(node.get_id(), node);
239            ctx.node_parents.insert(node.get_id(), node.get_scope_id());
240        }
241
242        // Fix up "anonymous" method params and results scopes.
243        for node in ctx.request.get_nodes()? {
244            if let Ok(schema_capnp::node::Interface(interface_reader)) = node.which() {
245                for method in interface_reader.get_methods()? {
246                    let param_struct_type = method.get_param_struct_type();
247                    if ctx.node_parents.get(&param_struct_type) == Some(&0) {
248                        ctx.node_parents.insert(param_struct_type, node.get_id());
249                    }
250                    let result_struct_type = method.get_result_struct_type();
251                    if ctx.node_parents.get(&result_struct_type) == Some(&0) {
252                        ctx.node_parents.insert(result_struct_type, node.get_id());
253                    }
254                }
255            }
256        }
257
258        for requested_file in ctx.request.get_requested_files()? {
259            let id = requested_file.get_id();
260
261            for import in requested_file.get_imports()? {
262                let importpath = ::std::path::Path::new(import.get_name()?.to_str()?);
263                let root_name: String = format!(
264                    "{}_capnp",
265                    path_to_stem_string(importpath)?.replace('-', "_")
266                );
267                let parent_module_scope = if let Some(krate) = crates_provide.get(&import.get_id())
268                {
269                    vec![format!("::{krate}")]
270                } else {
271                    default_parent_module_scope.clone()
272                };
273
274                ctx.populate_scope_map(
275                    parent_module_scope,
276                    root_name,
277                    NameKind::Verbatim,
278                    import.get_id(),
279                )?;
280            }
281
282            let root_name = path_to_stem_string(requested_file.get_filename()?.to_str()?)?;
283            let root_mod = format!("{}_capnp", root_name.replace('-', "_"));
284            ctx.populate_scope_map(
285                default_parent_module_scope.clone(),
286                root_mod,
287                NameKind::Verbatim,
288                id,
289            )?;
290        }
291        Ok(ctx)
292    }
293
294    fn get_last_name(&self, id: u64) -> ::capnp::Result<&str> {
295        match self.scope_map.get(&id) {
296            None => Err(Error::failed(format!("node not found: {id}"))),
297            Some(v) => match v.last() {
298                None => Err(Error::failed(format!("node has no scope: {id}"))),
299                Some(n) => Ok(n),
300            },
301        }
302    }
303
304    fn populate_scope_map(
305        &mut self,
306        mut ancestor_scope_names: Vec<String>,
307        mut current_node_name: String,
308        current_name_kind: NameKind,
309        node_id: u64,
310    ) -> ::capnp::Result<()> {
311        // unused nodes in imported files might be omitted from the node map
312        let Some(&node_reader) = self.node_map.get(&node_id) else {
313            return Ok(());
314        };
315
316        for annotation in node_reader.get_annotations()? {
317            if annotation.get_id() == NAME_ANNOTATION_ID {
318                current_node_name = name_annotation_value(annotation)?.to_string();
319            } else if annotation.get_id() == PARENT_MODULE_ANNOTATION_ID {
320                let head = ancestor_scope_names[0].clone();
321                ancestor_scope_names.clear();
322                ancestor_scope_names.push(head);
323                ancestor_scope_names.append(&mut get_parent_module(annotation)?);
324            }
325        }
326
327        let mut scope_names = ancestor_scope_names;
328        scope_names.push(capnp_name_to_rust_name(
329            &current_node_name,
330            current_name_kind,
331        ));
332
333        self.scope_map.insert(node_id, scope_names.clone());
334
335        let nested_nodes = node_reader.get_nested_nodes()?;
336        for nested_node in nested_nodes {
337            let nested_node_id = nested_node.get_id();
338            match self.node_map.get(&nested_node_id) {
339                None => {}
340                Some(node_reader) => match node_reader.which() {
341                    Ok(schema_capnp::node::Enum(_enum_reader)) => {
342                        self.populate_scope_map(
343                            scope_names.clone(),
344                            nested_node.get_name()?.to_string()?,
345                            NameKind::Verbatim,
346                            nested_node_id,
347                        )?;
348                    }
349                    _ => {
350                        self.populate_scope_map(
351                            scope_names.clone(),
352                            nested_node.get_name()?.to_string()?,
353                            NameKind::Module,
354                            nested_node_id,
355                        )?;
356                    }
357                },
358            }
359        }
360
361        if let Ok(schema_capnp::node::Struct(struct_reader)) = node_reader.which() {
362            let fields = struct_reader.get_fields()?;
363            for field in fields {
364                if let Ok(schema_capnp::field::Group(group)) = field.which() {
365                    self.populate_scope_map(
366                        scope_names.clone(),
367                        get_field_name(field)?.to_string(),
368                        NameKind::Module,
369                        group.get_type_id(),
370                    )?;
371                }
372            }
373        }
374
375        Ok(())
376    }
377
378    pub fn get_qualified_module(&self, type_id: u64) -> String {
379        self.scope_map[&type_id].join("::")
380    }
381}
382
383/// Like `format!(...)`, but adds a `capnp=ctx.capnp_root` argument.
384macro_rules! fmt(
385    ($ctx:ident, $($arg:tt)*) => ( format!($($arg)*, capnp=$ctx.capnp_root) )
386);
387
388pub(crate) use fmt;
389
390fn path_to_stem_string<P: AsRef<::std::path::Path>>(path: P) -> ::capnp::Result<String> {
391    if let Some(stem) = path.as_ref().file_stem() {
392        stem.to_owned()
393            .into_string()
394            .map_err(|os_string| Error::failed(format!("bad filename: {os_string:?}")))
395    } else {
396        Err(Error::failed(format!(
397            "file has no stem: {:?}",
398            path.as_ref()
399        )))
400    }
401}
402
403fn snake_to_upper_case(s: &str) -> String {
404    let mut result_chars: Vec<char> = Vec::new();
405    for c in s.chars() {
406        if c == '_' {
407            result_chars.push('_');
408        } else {
409            result_chars.push(c.to_ascii_uppercase());
410        }
411    }
412    result_chars.into_iter().collect()
413}
414
415fn camel_to_snake_case(s: &str) -> String {
416    let mut result_chars: Vec<char> = Vec::new();
417    let mut first_char = true;
418    for c in s.chars() {
419        if c.is_uppercase() && !first_char {
420            result_chars.push('_');
421        }
422        result_chars.push(c.to_ascii_lowercase());
423        first_char = false;
424    }
425    result_chars.into_iter().collect()
426}
427
428fn capitalize_first_letter(s: &str) -> String {
429    let mut result_chars: Vec<char> = Vec::new();
430    for c in s.chars() {
431        result_chars.push(c)
432    }
433    result_chars[0] = result_chars[0].to_ascii_uppercase();
434    result_chars.into_iter().collect()
435}
436
437/// Formats a u64 into a string representation of the hex value, with
438/// separating underscores. Used instead of simple hex formatting to prevent
439/// clippy warnings in autogenerated code. This is loosely based off of
440/// similar functionality in the `separator` crate.
441fn format_u64(value: u64) -> String {
442    let hex = format!("{value:#x}");
443    let mut separated = hex[0..2].to_string();
444    let mut place = hex.len() - 2;
445    let mut later_loop = false;
446
447    for ch in hex[2..].chars() {
448        if later_loop && place % 4 == 0 {
449            separated.push('_');
450        }
451
452        separated.push(ch);
453        later_loop = true;
454        place -= 1;
455    }
456
457    separated
458}
459
460#[test]
461fn test_camel_to_snake_case() {
462    assert_eq!(camel_to_snake_case("fooBar"), "foo_bar".to_string());
463    assert_eq!(camel_to_snake_case("FooBar"), "foo_bar".to_string());
464    assert_eq!(camel_to_snake_case("fooBarBaz"), "foo_bar_baz".to_string());
465    assert_eq!(camel_to_snake_case("FooBarBaz"), "foo_bar_baz".to_string());
466    assert_eq!(camel_to_snake_case("helloWorld"), "hello_world".to_string());
467    assert_eq!(camel_to_snake_case("HelloWorld"), "hello_world".to_string());
468    assert_eq!(camel_to_snake_case("uint32Id"), "uint32_id".to_string());
469
470    assert_eq!(camel_to_snake_case("fooBar_"), "foo_bar_".to_string());
471}
472
473#[derive(PartialEq, Clone)]
474pub enum FormattedText {
475    Indent(Box<FormattedText>),
476    Branch(Vec<FormattedText>),
477    Line(String),
478    BlankLine,
479}
480
481impl From<Vec<FormattedText>> for FormattedText {
482    fn from(value: Vec<FormattedText>) -> Self {
483        Branch(value)
484    }
485}
486
487pub fn indent(inner: impl Into<FormattedText>) -> FormattedText {
488    Indent(Box::new(inner.into()))
489}
490
491pub fn line(inner: impl ToString) -> FormattedText {
492    Line(inner.to_string())
493}
494
495fn to_lines(ft: &FormattedText, indent: usize) -> Vec<String> {
496    match ft {
497        Indent(ft) => to_lines(ft, indent + 1),
498        Branch(fts) => fts.iter().flat_map(|ft| to_lines(ft, indent)).collect(),
499        Line(s) => {
500            let mut s1: String = " ".repeat(indent * 4);
501            s1.push_str(s);
502            vec![s1.to_string()]
503        }
504        BlankLine => vec!["".to_string()],
505    }
506}
507
508fn stringify(ft: &FormattedText) -> String {
509    let mut result = to_lines(ft, 0).join("\n");
510    result.push('\n');
511    result
512}
513
514const RUST_KEYWORDS: &[&str] = &[
515    "abstract", "alignof", "as", "be", "become", "box", "break", "const", "continue", "crate",
516    "do", "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let",
517    "loop", "macro", "match", "mod", "move", "mut", "offsetof", "once", "override", "priv", "proc",
518    "pub", "pure", "ref", "return", "self", "sizeof", "static", "struct", "super", "trait", "true",
519    "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
520];
521
522fn module_name(camel_case: &str) -> String {
523    let mut name = camel_to_snake_case(camel_case);
524    if RUST_KEYWORDS.contains(&&*name) {
525        name.push('_');
526    }
527    name
528}
529
530// Annotation IDs, as defined in rust.capnp.
531const NAME_ANNOTATION_ID: u64 = 0xc2fe4c6d100166d0;
532const PARENT_MODULE_ANNOTATION_ID: u64 = 0xabee386cd1450364;
533const OPTION_ANNOTATION_ID: u64 = 0xabfef22c4ee1964e;
534
535// StreamResult type ID, as defined in stream.capnp.
536const STREAM_RESULT_ID: u64 = 0x995f9a3377c0b16e;
537
538fn name_annotation_value(annotation: schema_capnp::annotation::Reader<'_>) -> capnp::Result<&str> {
539    if let schema_capnp::value::Text(t) = annotation.get_value()?.which()? {
540        let name = t?.to_str()?;
541        for c in name.chars() {
542            if !(c == '_' || c.is_alphanumeric()) {
543                return Err(capnp::Error::failed(
544                    "rust.name annotation value must only contain alphanumeric characters and '_'"
545                        .to_string(),
546                ));
547            }
548        }
549        Ok(name)
550    } else {
551        Err(capnp::Error::failed(
552            "expected rust.name annotation value to be of type Text".to_string(),
553        ))
554    }
555}
556
557fn get_field_name(field: schema_capnp::field::Reader<'_>) -> capnp::Result<&str> {
558    for annotation in field.get_annotations()? {
559        if annotation.get_id() == NAME_ANNOTATION_ID {
560            return name_annotation_value(annotation);
561        }
562    }
563    Ok(field.get_name()?.to_str()?)
564}
565
566fn get_enumerant_name(enumerant: schema_capnp::enumerant::Reader<'_>) -> capnp::Result<&str> {
567    for annotation in enumerant.get_annotations()? {
568        if annotation.get_id() == NAME_ANNOTATION_ID {
569            return name_annotation_value(annotation);
570        }
571    }
572    Ok(enumerant.get_name()?.to_str()?)
573}
574
575fn get_parent_module(annotation: schema_capnp::annotation::Reader) -> capnp::Result<Vec<String>> {
576    if let schema_capnp::value::Text(t) = annotation.get_value()?.which()? {
577        let module = t?.to_str()?;
578        Ok(module.split("::").map(|x| x.to_string()).collect())
579    } else {
580        Err(capnp::Error::failed(
581            "expected rust.parentModule annotation value to be of type Text".to_string(),
582        ))
583    }
584}
585#[derive(Clone, Copy)]
586enum NameKind {
587    // convert camel case to snake case, and avoid Rust keywords
588    Module,
589
590    // don't modify
591    Verbatim,
592}
593
594fn capnp_name_to_rust_name(capnp_name: &str, name_kind: NameKind) -> String {
595    match name_kind {
596        NameKind::Module => module_name(capnp_name),
597        NameKind::Verbatim => capnp_name.to_string(),
598    }
599}
600
601fn is_option_field(field: schema_capnp::field::Reader) -> capnp::Result<bool> {
602    use capnp::schema_capnp::*;
603
604    let enabled = field
605        .get_annotations()?
606        .iter()
607        .any(|a| a.get_id() == OPTION_ANNOTATION_ID);
608
609    if enabled {
610        let supported = match field.which()? {
611            field::Which::Group(_) => false,
612            field::Which::Slot(field) => {
613                let ty = field.get_type()?;
614                ty.is_pointer()? && !matches!(ty.which()?, type_::Interface(_))
615            }
616        };
617        if !supported {
618            return Err(capnp::Error::failed(
619                "$Rust.option annotation only supported on pointer fields (support for optional interfaces isn't implemented yet)".to_string(),
620            ));
621        }
622    }
623
624    Ok(enabled)
625}
626
627fn prim_default(value: &schema_capnp::value::Reader) -> ::capnp::Result<Option<String>> {
628    use capnp::schema_capnp::value;
629    match value.which()? {
630        value::Bool(false)
631        | value::Int8(0)
632        | value::Int16(0)
633        | value::Int32(0)
634        | value::Int64(0)
635        | value::Uint8(0)
636        | value::Uint16(0)
637        | value::Uint32(0)
638        | value::Uint64(0) => Ok(None),
639
640        value::Bool(true) => Ok(Some("true".to_string())),
641        value::Int8(i) => Ok(Some(i.to_string())),
642        value::Int16(i) => Ok(Some(i.to_string())),
643        value::Int32(i) => Ok(Some(i.to_string())),
644        value::Int64(i) => Ok(Some(i.to_string())),
645        value::Uint8(i) => Ok(Some(i.to_string())),
646        value::Uint16(i) => Ok(Some(i.to_string())),
647        value::Uint32(i) => Ok(Some(i.to_string())),
648        value::Uint64(i) => Ok(Some(i.to_string())),
649        value::Float32(f) => match f.classify() {
650            ::std::num::FpCategory::Zero => Ok(None),
651            _ => Ok(Some(format!("{}u32", f.to_bits()))),
652        },
653        value::Float64(f) => match f.classify() {
654            ::std::num::FpCategory::Zero => Ok(None),
655            _ => Ok(Some(format!("{}u64", f.to_bits()))),
656        },
657        _ => Err(Error::failed(
658            "Non-primitive value found where primitive was expected.".to_string(),
659        )),
660    }
661}
662
663// Gets the full list ordered of generic parameters for a node. Outer scopes come first.
664fn get_params(ctx: &GeneratorContext, mut node_id: u64) -> ::capnp::Result<Vec<String>> {
665    let mut result = Vec::new();
666
667    while node_id != 0 {
668        let node = ctx.node_map[&node_id];
669        let parameters = node.get_parameters()?;
670
671        for parameter in parameters.into_iter().rev() {
672            result.push(parameter.get_name()?.to_str()?.into());
673        }
674
675        node_id = node.get_scope_id();
676    }
677
678    result.reverse();
679    Ok(result)
680}
681
682//
683// Returns (type, getter body, default_decl)
684//
685pub fn getter_text(
686    ctx: &GeneratorContext,
687    field: &schema_capnp::field::Reader,
688    is_reader: bool,
689    is_fn: bool,
690) -> ::capnp::Result<(String, FormattedText, Option<FormattedText>)> {
691    use capnp::schema_capnp::*;
692
693    match field.which()? {
694        field::Group(group) => {
695            let params = get_params(ctx, group.get_type_id())?;
696            let params_string = if params.is_empty() {
697                "".to_string()
698            } else {
699                format!(",{}", params.join(","))
700            };
701
702            let the_mod = ctx.get_qualified_module(group.get_type_id());
703
704            let mut result_type = if is_reader {
705                format!("{the_mod}::Reader<'a{params_string}>")
706            } else {
707                format!("{the_mod}::Builder<'a{params_string}>")
708            };
709
710            if is_fn {
711                result_type = format!("-> {result_type}");
712            }
713
714            let getter_code = if is_reader {
715                line("self.reader.into()")
716            } else {
717                line("self.builder.into()")
718            };
719
720            Ok((result_type, getter_code, None))
721        }
722        field::Slot(reg_field) => {
723            let mut default_decl = None;
724            let offset = reg_field.get_offset() as usize;
725            let module_string = if is_reader { "Reader" } else { "Builder" };
726            let module = if is_reader {
727                Leaf::Reader("'a")
728            } else {
729                Leaf::Builder("'a")
730            };
731            let member = camel_to_snake_case(module_string);
732
733            fn primitive_case<T: PartialEq + ::std::fmt::Display>(
734                typ: &str,
735                member: &str,
736                offset: usize,
737                default: T,
738                zero: T,
739            ) -> String {
740                if default == zero {
741                    format!("self.{member}.get_data_field::<{typ}>({offset})")
742                } else {
743                    format!("self.{member}.get_data_field_mask::<{typ}>({offset}, {default})")
744                }
745            }
746
747            let raw_type = reg_field.get_type()?;
748            let inner_type = raw_type.type_string(ctx, module)?;
749            let default_value = reg_field.get_default_value()?;
750            let default = default_value.which()?;
751            let default_name = format!(
752                "DEFAULT_{}",
753                snake_to_upper_case(&camel_to_snake_case(get_field_name(*field)?))
754            );
755            let should_get_option = is_option_field(*field)?;
756
757            let typ = if should_get_option {
758                format!("Option<{inner_type}>")
759            } else {
760                inner_type
761            };
762
763            let (is_fallible, mut result_type) = match raw_type.which()? {
764                type_::Enum(_) => (
765                    true,
766                    fmt!(ctx, "::core::result::Result<{typ},{capnp}::NotInSchema>"),
767                ),
768                type_::AnyPointer(_) if !raw_type.is_parameter()? => (false, typ.clone()),
769                type_::Interface(_) => (
770                    true,
771                    fmt!(
772                        ctx,
773                        "{capnp}::Result<{}>",
774                        raw_type.type_string(ctx, Leaf::Client)?
775                    ),
776                ),
777                _ if raw_type.is_prim()? => (false, typ.clone()),
778                _ => (true, fmt!(ctx, "{capnp}::Result<{typ}>")),
779            };
780
781            if is_fn {
782                result_type = if result_type == "()" {
783                    "".to_string()
784                } else {
785                    format!("-> {result_type}")
786                }
787            }
788
789            let getter_fragment = match (raw_type.which()?, default) {
790                (type_::Void(()), value::Void(())) => {
791                    if is_fn {
792                        "".to_string()
793                    } else {
794                        "()".to_string()
795                    }
796                }
797                (type_::Bool(()), value::Bool(b)) => {
798                    if b {
799                        format!("self.{member}.get_bool_field_mask({offset}, true)")
800                    } else {
801                        format!("self.{member}.get_bool_field({offset})")
802                    }
803                }
804                (type_::Int8(()), value::Int8(i)) => primitive_case(&typ, &member, offset, i, 0),
805                (type_::Int16(()), value::Int16(i)) => primitive_case(&typ, &member, offset, i, 0),
806                (type_::Int32(()), value::Int32(i)) => primitive_case(&typ, &member, offset, i, 0),
807                (type_::Int64(()), value::Int64(i)) => primitive_case(&typ, &member, offset, i, 0),
808                (type_::Uint8(()), value::Uint8(i)) => primitive_case(&typ, &member, offset, i, 0),
809                (type_::Uint16(()), value::Uint16(i)) => {
810                    primitive_case(&typ, &member, offset, i, 0)
811                }
812                (type_::Uint32(()), value::Uint32(i)) => {
813                    primitive_case(&typ, &member, offset, i, 0)
814                }
815                (type_::Uint64(()), value::Uint64(i)) => {
816                    primitive_case(&typ, &member, offset, i, 0)
817                }
818                (type_::Float32(()), value::Float32(f)) => {
819                    primitive_case(&typ, &member, offset, f.to_bits(), 0)
820                }
821                (type_::Float64(()), value::Float64(f)) => {
822                    primitive_case(&typ, &member, offset, f.to_bits(), 0)
823                }
824                (type_::Enum(_), value::Enum(d)) => {
825                    if d == 0 {
826                        format!("::core::convert::TryFrom::try_from(self.{member}.get_data_field::<u16>({offset}))")
827                    } else {
828                        format!(
829                                "::core::convert::TryFrom::try_from(self.{member}.get_data_field_mask::<u16>({offset}, {d}))")
830                    }
831                }
832
833                (type_::Text(()), value::Text(_))
834                | (type_::Data(()), value::Data(_))
835                | (type_::List(_), value::List(_))
836                | (type_::Struct(_), value::Struct(_)) => {
837                    let default = if reg_field.get_had_explicit_default() {
838                        default_decl = Some(crate::pointer_constants::word_array_declaration(
839                            ctx,
840                            &default_name,
841                            ::capnp::raw::get_struct_pointer_section(default_value).get(0),
842                            crate::pointer_constants::WordArrayDeclarationOptions { public: true },
843                        )?);
844                        format!("::core::option::Option::Some(&_private::{default_name}[..])")
845                    } else {
846                        "::core::option::Option::None".to_string()
847                    };
848
849                    if is_reader {
850                        fmt!(ctx,
851                            "{capnp}::traits::FromPointerReader::get_from_pointer(&self.{member}.get_pointer_field({offset}), {default})")
852                    } else {
853                        fmt!(ctx,"{capnp}::traits::FromPointerBuilder::get_from_pointer(self.{member}.get_pointer_field({offset}), {default})")
854                    }
855                }
856
857                (type_::Interface(_), value::Interface(_)) => {
858                    fmt!(ctx,"match self.{member}.get_pointer_field({offset}).get_capability() {{ ::core::result::Result::Ok(c) => ::core::result::Result::Ok({capnp}::capability::FromClientHook::new(c)), ::core::result::Result::Err(e) => ::core::result::Result::Err(e)}}")
859                }
860                (type_::AnyPointer(_), value::AnyPointer(_)) => {
861                    if !raw_type.is_parameter()? {
862                        fmt!(ctx,"{capnp}::any_pointer::{module_string}::new(self.{member}.get_pointer_field({offset}))")
863                    } else if is_reader {
864                        fmt!(ctx,"{capnp}::traits::FromPointerReader::get_from_pointer(&self.{member}.get_pointer_field({offset}), ::core::option::Option::None)")
865                    } else {
866                        fmt!(ctx,"{capnp}::traits::FromPointerBuilder::get_from_pointer(self.{member}.get_pointer_field({offset}), ::core::option::Option::None)")
867                    }
868                }
869                _ => return Err(Error::failed("default value was of wrong type".to_string())),
870            };
871
872            let getter_code = if should_get_option {
873                Branch(vec![
874                    Line(format!(
875                        "if self.{member}.is_pointer_field_null({offset}) {{"
876                    )),
877                    indent(Line(
878                        if is_fallible {
879                            "core::result::Result::Ok(core::option::Option::None)"
880                        } else {
881                            "::core::option::Option::None"
882                        }
883                        .to_string(),
884                    )),
885                    Line("} else {".to_string()),
886                    indent(Line(if is_fallible {
887                        format!("{getter_fragment}.map(::core::option::Option::Some)")
888                    } else {
889                        format!("::core::option::Option::Some({getter_fragment})")
890                    })),
891                    Line("}".to_string()),
892                ])
893            } else {
894                Line(getter_fragment)
895            };
896
897            Ok((result_type, getter_code, default_decl))
898        }
899    }
900}
901
902fn zero_fields_of_group(
903    ctx: &GeneratorContext,
904    node_id: u64,
905    clear: &mut bool,
906) -> ::capnp::Result<FormattedText> {
907    use capnp::schema_capnp::{field, node, type_};
908    match ctx.node_map[&node_id].which()? {
909        node::Struct(st) => {
910            let mut result = Vec::new();
911            if st.get_discriminant_count() != 0 {
912                result.push(Line(format!(
913                    "self.builder.set_data_field::<u16>({}, 0);",
914                    st.get_discriminant_offset()
915                )));
916            }
917            let fields = st.get_fields()?;
918            for field in fields {
919                match field.which()? {
920                    field::Group(group) => {
921                        result.push(zero_fields_of_group(ctx, group.get_type_id(), clear)?);
922                    }
923                    field::Slot(slot) => {
924                        let typ = slot.get_type()?.which()?;
925                        match typ {
926                            type_::Void(()) => {}
927                            type_::Bool(()) => {
928                                let line = Line(format!(
929                                    "self.builder.set_bool_field({}, false);",
930                                    slot.get_offset()
931                                ));
932                                // PERF could dedup more efficiently
933                                if !result.contains(&line) {
934                                    result.push(line)
935                                }
936                            }
937                            type_::Int8(())
938                            | type_::Int16(())
939                            | type_::Int32(())
940                            | type_::Int64(())
941                            | type_::Uint8(())
942                            | type_::Uint16(())
943                            | type_::Uint32(())
944                            | type_::Uint64(())
945                            | type_::Float32(())
946                            | type_::Float64(()) => {
947                                let line = Line(format!(
948                                    "self.builder.set_data_field::<{0}>({1}, 0{0});",
949                                    slot.get_type()?.type_string(ctx, Leaf::Builder("'a"))?,
950                                    slot.get_offset()
951                                ));
952                                // PERF could dedup more efficiently
953                                if !result.contains(&line) {
954                                    result.push(line)
955                                }
956                            }
957                            type_::Enum(_) => {
958                                let line = Line(format!(
959                                    "self.builder.set_data_field::<u16>({}, 0u16);",
960                                    slot.get_offset()
961                                ));
962                                // PERF could dedup more efficiently
963                                if !result.contains(&line) {
964                                    result.push(line)
965                                }
966                            }
967                            type_::Struct(_)
968                            | type_::List(_)
969                            | type_::Text(())
970                            | type_::Data(())
971                            | type_::AnyPointer(_)
972                            | type_::Interface(_) => {
973                                // Is this the right thing to do for interfaces?
974                                let line = Line(format!(
975                                    "self.builder.reborrow().get_pointer_field({}).clear();",
976                                    slot.get_offset()
977                                ));
978                                *clear = true;
979                                // PERF could dedup more efficiently
980                                if !result.contains(&line) {
981                                    result.push(line)
982                                }
983                            }
984                        }
985                    }
986                }
987            }
988            Ok(Branch(result))
989        }
990        _ => Err(Error::failed(
991            "zero_fields_of_group() expected a struct".to_string(),
992        )),
993    }
994}
995
996fn generate_setter(
997    ctx: &GeneratorContext,
998    discriminant_offset: u32,
999    styled_name: &str,
1000    field: &schema_capnp::field::Reader,
1001) -> ::capnp::Result<FormattedText> {
1002    use capnp::schema_capnp::*;
1003
1004    let mut setter_interior = Vec::new();
1005    let mut setter_param = "value".to_string();
1006    let mut initter_interior = Vec::new();
1007    let mut initter_mut = false;
1008    let mut initn_interior = Vec::new();
1009    let mut initter_params = Vec::new();
1010
1011    let discriminant_value = field.get_discriminant_value();
1012    if discriminant_value != field::NO_DISCRIMINANT {
1013        setter_interior.push(Line(format!(
1014            "self.builder.set_data_field::<u16>({}, {});",
1015            discriminant_offset as usize, discriminant_value as usize
1016        )));
1017        let init_discrim = Line(format!(
1018            "self.builder.set_data_field::<u16>({}, {});",
1019            discriminant_offset as usize, discriminant_value as usize
1020        ));
1021        initter_interior.push(init_discrim.clone());
1022        initn_interior.push(init_discrim);
1023    }
1024
1025    let mut return_result = false;
1026    let mut result = Vec::new();
1027
1028    let (maybe_reader_type, maybe_builder_type): (Option<String>, Option<String>) = match field
1029        .which()?
1030    {
1031        field::Group(group) => {
1032            let params = get_params(ctx, group.get_type_id())?;
1033            let params_string = if params.is_empty() {
1034                "".to_string()
1035            } else {
1036                format!(",{}", params.join(","))
1037            };
1038
1039            let the_mod = ctx.get_qualified_module(group.get_type_id());
1040
1041            initter_interior.push(zero_fields_of_group(
1042                ctx,
1043                group.get_type_id(),
1044                &mut initter_mut,
1045            )?);
1046
1047            initter_interior.push(line("self.builder.into()"));
1048
1049            (None, Some(format!("{the_mod}::Builder<'a{params_string}>")))
1050        }
1051        field::Slot(reg_field) => {
1052            let offset = reg_field.get_offset() as usize;
1053            let typ = reg_field.get_type()?;
1054            match typ.which().expect("unrecognized type") {
1055                type_::Void(()) => {
1056                    setter_param = "_value".to_string();
1057                    (Some("()".to_string()), None)
1058                }
1059                type_::Bool(()) => {
1060                    match prim_default(&reg_field.get_default_value()?)? {
1061                        None => {
1062                            setter_interior.push(Line(format!(
1063                                "self.builder.set_bool_field({offset}, value);"
1064                            )));
1065                        }
1066                        Some(s) => {
1067                            setter_interior.push(Line(format!(
1068                                "self.builder.set_bool_field_mask({offset}, value, {s});"
1069                            )));
1070                        }
1071                    }
1072                    (Some("bool".to_string()), None)
1073                }
1074                _ if typ.is_prim()? => {
1075                    let tstr = typ.type_string(ctx, Leaf::Reader("'a"))?;
1076                    match prim_default(&reg_field.get_default_value()?)? {
1077                        None => {
1078                            setter_interior.push(Line(format!(
1079                                "self.builder.set_data_field::<{tstr}>({offset}, value);"
1080                            )));
1081                        }
1082                        Some(s) => {
1083                            setter_interior.push(Line(format!(
1084                                "self.builder.set_data_field_mask::<{tstr}>({offset}, value, {s});"
1085                            )));
1086                        }
1087                    };
1088                    (Some(tstr), None)
1089                }
1090                type_::Text(()) => {
1091                    // The text::Reader impl of SetterInput never fails, so we can unwrap().
1092                    setter_interior.push(Line(fmt!(ctx,
1093                        "{capnp}::traits::SetterInput::set_pointer_builder(self.builder.reborrow().get_pointer_field({offset}), value, false).unwrap()"
1094                    )));
1095                    initter_interior.push(Line(format!(
1096                        "self.builder.get_pointer_field({offset}).init_text(size)"
1097                    )));
1098                    initter_params.push("size: u32");
1099                    (
1100                        Some(fmt!(
1101                            ctx,
1102                            "impl {capnp}::traits::SetterInput<{capnp}::text::Owned>"
1103                        )),
1104                        Some(fmt!(ctx, "{capnp}::text::Builder<'a>")),
1105                    )
1106                }
1107                type_::Data(()) => {
1108                    setter_interior.push(Line(format!(
1109                        "self.builder.reborrow().get_pointer_field({offset}).set_data(value);"
1110                    )));
1111                    initter_interior.push(Line(format!(
1112                        "self.builder.get_pointer_field({offset}).init_data(size)"
1113                    )));
1114                    initter_params.push("size: u32");
1115                    (
1116                        Some(fmt!(ctx, "{capnp}::data::Reader<'_>")),
1117                        Some(fmt!(ctx, "{capnp}::data::Builder<'a>")),
1118                    )
1119                }
1120                type_::List(ls) => {
1121                    let et = ls.get_element_type()?;
1122                    return_result = true;
1123                    setter_interior.push(
1124                        Line(fmt!(ctx,"{capnp}::traits::SetterInput::set_pointer_builder(self.builder.reborrow().get_pointer_field({offset}), value, false)")));
1125
1126                    initter_params.push("size: u32");
1127                    initter_interior.push(
1128                        Line(fmt!(ctx,"{capnp}::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field({offset}), size)")));
1129
1130                    let mr = match et.which()? {
1131                        type_::Void(())
1132                        | type_::Bool(())
1133                        | type_::Int8(())
1134                        | type_::Int16(())
1135                        | type_::Int32(())
1136                        | type_::Int64(())
1137                        | type_::Uint8(())
1138                        | type_::Uint16(())
1139                        | type_::Uint32(())
1140                        | type_::Uint64(())
1141                        | type_::Float32(())
1142                        | type_::Float64(())
1143                        | type_::Enum(_)
1144                        | type_::Text(()) => {
1145                            // There are multiple SetterInput impls.
1146                            fmt!(
1147                                ctx,
1148                                "impl {capnp}::traits::SetterInput<{}>",
1149                                reg_field.get_type()?.type_string(ctx, Leaf::Owned)?
1150                            )
1151                        }
1152                        _ => reg_field.get_type()?.type_string(ctx, Leaf::Reader("'_"))?,
1153                    };
1154
1155                    (
1156                        Some(mr),
1157                        Some(
1158                            reg_field
1159                                .get_type()?
1160                                .type_string(ctx, Leaf::Builder("'a"))?,
1161                        ),
1162                    )
1163                }
1164                type_::Enum(e) => {
1165                    let id = e.get_type_id();
1166                    let the_mod = ctx.get_qualified_module(id);
1167                    if !reg_field.get_had_explicit_default() {
1168                        setter_interior.push(Line(format!(
1169                            "self.builder.set_data_field::<u16>({offset}, value as u16);"
1170                        )));
1171                    } else {
1172                        match reg_field.get_default_value()?.which()? {
1173                            schema_capnp::value::Enum(d) => {
1174                                setter_interior.push(Line(format!(
1175                                    "self.builder.set_data_field_mask::<u16>({offset}, value as u16, {d});"
1176                                )));
1177                            }
1178                            _ => return Err(Error::failed("enum default not an Enum".to_string())),
1179                        }
1180                    };
1181                    (Some(the_mod), None)
1182                }
1183                type_::Struct(_) => {
1184                    return_result = true;
1185                    initter_interior.push(
1186                      Line(fmt!(ctx,"{capnp}::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field({offset}), 0)")));
1187                    setter_interior.push(
1188                        Line(fmt!(ctx,"{capnp}::traits::SetterInput::set_pointer_builder(self.builder.reborrow().get_pointer_field({offset}), value, false)")));
1189
1190                    (
1191                        Some(typ.type_string(ctx, Leaf::Reader("'_"))?),
1192                        Some(typ.type_string(ctx, Leaf::Builder("'a"))?),
1193                    )
1194                }
1195                type_::Interface(_) => {
1196                    setter_interior.push(Line(format!(
1197                        "self.builder.reborrow().get_pointer_field({offset}).set_capability(value.client.hook);"
1198                    )));
1199                    (Some(typ.type_string(ctx, Leaf::Client)?), None)
1200                }
1201                type_::AnyPointer(_) => {
1202                    if typ.is_parameter()? {
1203                        initter_interior.push(Line(fmt!(ctx,"{capnp}::any_pointer::Builder::new(self.builder.get_pointer_field({offset})).init_as()")));
1204                        setter_interior.push(Line(fmt!(ctx,"{capnp}::traits::SetterInput::set_pointer_builder(self.builder.reborrow().get_pointer_field({offset}), value, false)")));
1205                        return_result = true;
1206
1207                        let builder_type = typ.type_string(ctx, Leaf::Builder("'a"))?;
1208
1209                        result.push(line("#[inline]"));
1210                        result.push(Line(format!(
1211                            "pub fn initn_{styled_name}(self, length: u32) -> {builder_type} {{"
1212                        )));
1213                        result.push(indent(initn_interior));
1214                        result.push(indent(
1215                            Line(fmt!(ctx,"{capnp}::any_pointer::Builder::new(self.builder.get_pointer_field({offset})).initn_as(length)")))
1216                        );
1217                        result.push(line("}"));
1218
1219                        (
1220                            Some(fmt!(
1221                                ctx,
1222                                "impl {capnp}::traits::SetterInput<{}>",
1223                                typ.type_string(ctx, Leaf::Owned)?
1224                            )),
1225                            Some(builder_type),
1226                        )
1227                    } else {
1228                        initter_interior.push(Line(fmt!(ctx,"let mut result = {capnp}::any_pointer::Builder::new(self.builder.get_pointer_field({offset}));")));
1229                        initter_interior.push(line("result.clear();"));
1230                        initter_interior.push(line("result"));
1231                        (None, Some(fmt!(ctx, "{capnp}::any_pointer::Builder<'a>")))
1232                    }
1233                }
1234                _ => return Err(Error::failed("unrecognized type".to_string())),
1235            }
1236        }
1237    };
1238    if let Some(reader_type) = maybe_reader_type {
1239        let return_type = if return_result {
1240            fmt!(ctx, "-> {capnp}::Result<()>")
1241        } else {
1242            "".into()
1243        };
1244        result.push(line("#[inline]"));
1245        result.push(Line(format!(
1246            "pub fn set_{styled_name}(&mut self, {setter_param}: {reader_type}) {return_type} {{"
1247        )));
1248        result.push(indent(setter_interior));
1249        result.push(line("}"));
1250    }
1251    if let Some(builder_type) = maybe_builder_type {
1252        result.push(line("#[inline]"));
1253        let args = initter_params.join(", ");
1254        let mutable = if initter_mut { "mut " } else { "" };
1255        result.push(Line(format!(
1256            "pub fn init_{styled_name}({mutable}self, {args}) -> {builder_type} {{"
1257        )));
1258        result.push(indent(initter_interior));
1259        result.push(line("}"));
1260    }
1261    Ok(Branch(result))
1262}
1263
1264fn used_params_of_group(
1265    ctx: &GeneratorContext,
1266    group_id: u64,
1267    used_params: &mut HashSet<String>,
1268) -> capnp::Result<()> {
1269    let node = ctx.node_map[&group_id];
1270    match node.which()? {
1271        schema_capnp::node::Struct(st) => {
1272            for field in st.get_fields()? {
1273                match field.which()? {
1274                    schema_capnp::field::Group(group) => {
1275                        used_params_of_group(ctx, group.get_type_id(), used_params)?;
1276                    }
1277                    schema_capnp::field::Slot(slot) => {
1278                        used_params_of_type(ctx, slot.get_type()?, used_params)?;
1279                    }
1280                }
1281            }
1282            Ok(())
1283        }
1284        _ => Err(Error::failed("not a group".to_string())),
1285    }
1286}
1287
1288fn used_params_of_type(
1289    ctx: &GeneratorContext,
1290    ty: schema_capnp::type_::Reader,
1291    used_params: &mut HashSet<String>,
1292) -> capnp::Result<()> {
1293    use capnp::schema_capnp::type_;
1294    match ty.which()? {
1295        type_::List(ls) => {
1296            let et = ls.get_element_type()?;
1297            used_params_of_type(ctx, et, used_params)?;
1298        }
1299        type_::Enum(e) => {
1300            let node_id = e.get_type_id();
1301            let brand = e.get_brand()?;
1302            used_params_of_brand(ctx, node_id, brand, used_params)?;
1303        }
1304        type_::Struct(s) => {
1305            let node_id = s.get_type_id();
1306            let brand = s.get_brand()?;
1307            used_params_of_brand(ctx, node_id, brand, used_params)?;
1308        }
1309        type_::Interface(i) => {
1310            let node_id = i.get_type_id();
1311            let brand = i.get_brand()?;
1312            used_params_of_brand(ctx, node_id, brand, used_params)?;
1313        }
1314
1315        type_::AnyPointer(ap) => {
1316            if let type_::any_pointer::Parameter(def) = ap.which()? {
1317                let the_struct = &ctx.node_map[&def.get_scope_id()];
1318                let parameters = the_struct.get_parameters()?;
1319                let parameter = parameters.get(u32::from(def.get_parameter_index()));
1320                let parameter_name = parameter.get_name()?.to_str()?;
1321                used_params.insert(parameter_name.to_string());
1322            }
1323        }
1324        _ => (),
1325    }
1326    Ok(())
1327}
1328
1329fn used_params_of_brand(
1330    ctx: &GeneratorContext,
1331    node_id: u64,
1332    brand: schema_capnp::brand::Reader,
1333    used_params: &mut HashSet<String>,
1334) -> capnp::Result<()> {
1335    use schema_capnp::brand;
1336    let scopes = brand.get_scopes()?;
1337    let mut brand_scopes = HashMap::new();
1338    for scope in scopes {
1339        brand_scopes.insert(scope.get_scope_id(), scope);
1340    }
1341    let brand_scopes = brand_scopes; // freeze
1342    let mut current_node_id = node_id;
1343    loop {
1344        let Some(current_node) = ctx.node_map.get(&current_node_id) else {
1345            break;
1346        };
1347        let params = current_node.get_parameters()?;
1348        match brand_scopes.get(&current_node_id) {
1349            None => (),
1350            Some(scope) => match scope.which()? {
1351                brand::scope::Inherit(()) => {
1352                    for param in params {
1353                        used_params.insert(param.get_name()?.to_string()?);
1354                    }
1355                }
1356                brand::scope::Bind(bindings_list_opt) => {
1357                    let bindings_list = bindings_list_opt?;
1358                    assert_eq!(bindings_list.len(), params.len());
1359                    for binding in bindings_list {
1360                        match binding.which()? {
1361                            brand::binding::Unbound(()) => (),
1362                            brand::binding::Type(t) => {
1363                                used_params_of_type(ctx, t?, used_params)?;
1364                            }
1365                        }
1366                    }
1367                }
1368            },
1369        }
1370        current_node_id = current_node.get_scope_id();
1371    }
1372    Ok(())
1373}
1374
1375// return (the 'Which' enum, the 'which()' accessor, typedef, default_decls)
1376fn generate_union(
1377    ctx: &GeneratorContext,
1378    discriminant_offset: u32,
1379    fields: &[schema_capnp::field::Reader],
1380    is_reader: bool,
1381    params: &TypeParameterTexts,
1382) -> ::capnp::Result<(
1383    FormattedText,
1384    FormattedText,
1385    FormattedText,
1386    Vec<FormattedText>,
1387)> {
1388    use capnp::schema_capnp::*;
1389
1390    fn new_ty_param(ty_params: &mut Vec<String>) -> String {
1391        let result = format!("A{}", ty_params.len());
1392        ty_params.push(result.clone());
1393        result
1394    }
1395
1396    let mut getter_interior = Vec::new();
1397    let mut interior = Vec::new();
1398    let mut enum_interior = Vec::new();
1399    let mut default_decls = Vec::new();
1400
1401    let mut ty_params = Vec::new();
1402    let mut ty_args = Vec::new();
1403
1404    let mut used_params: HashSet<String> = HashSet::new();
1405
1406    let doffset = discriminant_offset as usize;
1407
1408    for field in fields {
1409        let dvalue = field.get_discriminant_value() as usize;
1410
1411        let field_name = get_field_name(*field)?;
1412        let enumerant_name = capitalize_first_letter(field_name);
1413
1414        let (ty, get, maybe_default_decl) = getter_text(ctx, field, is_reader, false)?;
1415        if let Some(default_decl) = maybe_default_decl {
1416            default_decls.push(default_decl)
1417        }
1418
1419        getter_interior.push(Branch(vec![
1420            Line(format!("{dvalue} => {{")),
1421            indent(Line(format!(
1422                "::core::result::Result::Ok({}(",
1423                enumerant_name.clone()
1424            ))),
1425            indent(indent(get)),
1426            indent(line("))")),
1427            line("}"),
1428        ]));
1429
1430        let ty1 = match field.which() {
1431            Ok(field::Group(group)) => {
1432                used_params_of_group(ctx, group.get_type_id(), &mut used_params)?;
1433                ty_args.push(ty);
1434                new_ty_param(&mut ty_params)
1435            }
1436            Ok(field::Slot(reg_field)) => {
1437                let fty = reg_field.get_type()?;
1438                used_params_of_type(ctx, fty, &mut used_params)?;
1439                match fty.which() {
1440                    Ok(
1441                        type_::Text(())
1442                        | type_::Data(())
1443                        | type_::List(_)
1444                        | type_::Struct(_)
1445                        | type_::AnyPointer(_),
1446                    ) => {
1447                        ty_args.push(ty);
1448                        new_ty_param(&mut ty_params)
1449                    }
1450                    Ok(type_::Interface(_)) => ty,
1451                    _ => ty,
1452                }
1453            }
1454            _ => ty,
1455        };
1456
1457        enum_interior.push(Line(format!("{enumerant_name}({ty1}),")));
1458    }
1459
1460    let enum_name = format!(
1461        "Which{}",
1462        if !ty_params.is_empty() {
1463            format!("<{}>", ty_params.join(","))
1464        } else {
1465            "".to_string()
1466        }
1467    );
1468
1469    getter_interior.push(Line(fmt!(
1470        ctx,
1471        "x => ::core::result::Result::Err({capnp}::NotInSchema(x))"
1472    )));
1473
1474    interior.push(Branch(vec![
1475        Line(format!("pub enum {enum_name} {{")),
1476        indent(enum_interior),
1477        line("}"),
1478    ]));
1479
1480    let result = Branch(interior);
1481
1482    let field_name = if is_reader { "reader" } else { "builder" };
1483
1484    let concrete_type = format!(
1485        "Which{}{}",
1486        if is_reader { "Reader" } else { "Builder" },
1487        if !ty_params.is_empty() {
1488            format!(
1489                "<'a,{}>",
1490                params
1491                    .expanded_list
1492                    .iter()
1493                    .filter(|s: &&String| used_params.contains(*s))
1494                    .cloned()
1495                    .collect::<Vec<String>>()
1496                    .join(",")
1497            )
1498        } else {
1499            "".to_string()
1500        }
1501    );
1502
1503    let typedef = Line(format!(
1504        "pub type {concrete_type} = Which{};",
1505        if !ty_args.is_empty() {
1506            format!("<{}>", ty_args.join(","))
1507        } else {
1508            "".to_string()
1509        }
1510    ));
1511
1512    let getter_result = Branch(vec![
1513        line("#[inline]"),
1514        Line(fmt!(ctx,
1515            "pub fn which(self) -> ::core::result::Result<{concrete_type}, {capnp}::NotInSchema> {{"
1516        )),
1517        indent(vec![
1518            Line(format!(
1519                "match self.{field_name}.get_data_field::<u16>({doffset}) {{"
1520            )),
1521            indent(getter_interior),
1522            line("}"),
1523        ]),
1524        line("}"),
1525    ]);
1526
1527    // TODO set_which() for builders?
1528
1529    Ok((result, getter_result, typedef, default_decls))
1530}
1531
1532fn generate_haser(
1533    discriminant_offset: u32,
1534    styled_name: &str,
1535    field: &schema_capnp::field::Reader,
1536    is_reader: bool,
1537) -> ::capnp::Result<FormattedText> {
1538    use capnp::schema_capnp::*;
1539
1540    let mut result = Vec::new();
1541    let mut interior = Vec::new();
1542    let member = if is_reader { "reader" } else { "builder" };
1543
1544    let discriminant_value = field.get_discriminant_value();
1545    if discriminant_value != field::NO_DISCRIMINANT {
1546        interior.push(Line(format!(
1547            "if self.{}.get_data_field::<u16>({}) != {} {{ return false; }}",
1548            member, discriminant_offset as usize, discriminant_value as usize
1549        )));
1550    }
1551    match field.which() {
1552        Err(_) | Ok(field::Group(_)) => {}
1553        Ok(field::Slot(reg_field)) => match reg_field.get_type()?.which()? {
1554            type_::Text(())
1555            | type_::Data(())
1556            | type_::List(_)
1557            | type_::Struct(_)
1558            | type_::Interface(_)
1559            | type_::AnyPointer(_) => {
1560                if is_reader {
1561                    interior.push(Line(format!(
1562                        "!self.{member}.get_pointer_field({}).is_null()",
1563                        reg_field.get_offset()
1564                    )));
1565                } else {
1566                    interior.push(Line(format!(
1567                        "!self.{member}.is_pointer_field_null({})",
1568                        reg_field.get_offset()
1569                    )));
1570                }
1571                result.push(line("#[inline]"));
1572                result.push(Line(format!("pub fn has_{styled_name}(&self) -> bool {{")));
1573                result.push(indent(interior));
1574                result.push(line("}"));
1575            }
1576            _ => {}
1577        },
1578    }
1579
1580    Ok(Branch(result))
1581}
1582
1583fn generate_pipeline_getter(
1584    ctx: &GeneratorContext,
1585    field: schema_capnp::field::Reader,
1586) -> ::capnp::Result<FormattedText> {
1587    use capnp::schema_capnp::{field, type_};
1588
1589    let name = get_field_name(field)?;
1590
1591    match field.which()? {
1592        field::Group(group) => {
1593            let params = get_params(ctx, group.get_type_id())?;
1594            let params_string = if params.is_empty() {
1595                "".to_string()
1596            } else {
1597                format!("<{}>", params.join(","))
1598            };
1599
1600            let the_mod = ctx.get_qualified_module(group.get_type_id());
1601            Ok(Branch(vec![
1602                Line(format!(
1603                    "pub fn get_{}(&self) -> {}::Pipeline{} {{",
1604                    camel_to_snake_case(name),
1605                    the_mod,
1606                    params_string
1607                )),
1608                indent(Line(fmt!(
1609                    ctx,
1610                    "{capnp}::capability::FromTypelessPipeline::new(self._typeless.noop())"
1611                ))),
1612                line("}"),
1613            ]))
1614        }
1615        field::Slot(reg_field) => {
1616            let typ = reg_field.get_type()?;
1617            match typ.which()? {
1618                type_::Struct(_) | type_::AnyPointer(_) => {
1619                    Ok(Branch(vec![
1620                        Line(format!("pub fn get_{}(&self) -> {} {{", camel_to_snake_case(name), typ.type_string(ctx, Leaf::Pipeline)?)),
1621                        indent(Line(fmt!(ctx,"{capnp}::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field({}))", reg_field.get_offset()))),
1622                        line("}")
1623                    ]))
1624                }
1625                type_::Interface(_) => {
1626                    Ok(Branch(vec![
1627                        Line(format!("pub fn get_{}(&self) -> {} {{", camel_to_snake_case(name), typ.type_string(ctx, Leaf::Client)?)),
1628                        indent(Line(fmt!(ctx,"{capnp}::capability::FromClientHook::new(self._typeless.get_pointer_field({}).as_cap())", reg_field.get_offset()))),
1629                        line("}")
1630                    ]))
1631                }
1632                _ => {
1633                    Ok(Branch(Vec::new()))
1634                }
1635            }
1636        }
1637    }
1638}
1639
1640fn generate_get_field_types(
1641    ctx: &GeneratorContext,
1642    node_reader: schema_capnp::node::Reader,
1643) -> ::capnp::Result<FormattedText> {
1644    use capnp::schema_capnp::field;
1645    let st = match node_reader.which()? {
1646        schema_capnp::node::Struct(st) => st,
1647        _ => return Err(Error::failed("not a struct".into())),
1648    };
1649    let mut branches = vec![];
1650    for (index, field) in st.get_fields()?.iter().enumerate() {
1651        match field.which()? {
1652            field::Slot(slot) => {
1653                let raw_type = slot.get_type()?;
1654                let typ = raw_type.type_string(ctx, Leaf::Owned)?;
1655                branches.push(Line(fmt!(
1656                    ctx,
1657                    "{} => <{} as {capnp}::introspect::Introspect>::introspect(),",
1658                    index,
1659                    typ
1660                )));
1661            }
1662            field::Group(group) => {
1663                let params = get_params(ctx, group.get_type_id())?;
1664                let params_string = if params.is_empty() {
1665                    "".to_string()
1666                } else {
1667                    format!("<{}>", params.join(","))
1668                };
1669
1670                let the_mod = ctx.get_qualified_module(group.get_type_id());
1671
1672                let typ = format!("{the_mod}::Owned{params_string}");
1673                branches.push(Line(fmt!(
1674                    ctx,
1675                    "{} => <{} as {capnp}::introspect::Introspect>::introspect(),",
1676                    index,
1677                    typ
1678                )));
1679            }
1680        }
1681    }
1682    let body = if branches.is_empty() {
1683        Line(fmt!(
1684            ctx,
1685            "{capnp}::introspect::panic_invalid_field_index(index)"
1686        ))
1687    } else {
1688        branches.push(Line(fmt!(
1689            ctx,
1690            "_ => {capnp}::introspect::panic_invalid_field_index(index),"
1691        )));
1692        Branch(vec![
1693            Line("match index {".into()),
1694            indent(branches),
1695            Line("}".into()),
1696        ])
1697    };
1698    if !node_reader.get_is_generic() {
1699        Ok(Branch(vec![
1700            Line(fmt!(
1701                ctx,
1702                "pub fn get_field_types(index: u16) -> {capnp}::introspect::Type {{"
1703            )),
1704            indent(body),
1705            Line("}".into()),
1706        ]))
1707    } else {
1708        let params = node_reader.parameters_texts(ctx);
1709        Ok(Branch(vec![
1710            Line(fmt!(
1711                ctx,
1712                "pub fn get_field_types<{0}>(index: u16) -> {capnp}::introspect::Type {1} {{",
1713                params.params,
1714                params.where_clause
1715            )),
1716            indent(body),
1717            Line("}".into()),
1718        ]))
1719    }
1720}
1721
1722fn annotation_branch(
1723    ctx: &GeneratorContext,
1724    annotation: schema_capnp::annotation::Reader,
1725    child_index: Option<u16>,
1726    index: u32,
1727) -> ::capnp::Result<FormattedText> {
1728    use capnp::schema_capnp::node;
1729    let id = annotation.get_id();
1730    let annotation_decl = ctx.node_map[&id];
1731    let node::Annotation(a) = annotation_decl.which()? else {
1732        return Err(Error::failed("not an annotation node".into()));
1733    };
1734    if annotation_decl.get_is_generic() {
1735        let brand = annotation.get_brand()?;
1736        let the_mod = ctx.get_qualified_module(id);
1737        let func = do_branding(ctx, id, brand, Leaf::GetType, &the_mod)?;
1738        Ok(Line(format!("({child_index:?}, {index}) => {func}(),")))
1739    } else {
1740        // Avoid referring to the annotation in the generated code, so that users can import
1741        // annotation schemas like `c++.capnp` or `rust.capnp` without needing to generate code
1742        // for them, as long as the annotations are not generic.
1743        let ty = a.get_type()?;
1744        Ok(Line(fmt!(
1745            ctx,
1746            "({child_index:?}, {index}) => <{} as {capnp}::introspect::Introspect>::introspect(),",
1747            ty.type_string(ctx, Leaf::Owned)?
1748        )))
1749    }
1750}
1751
1752fn generate_get_annotation_types(
1753    ctx: &GeneratorContext,
1754    node_reader: schema_capnp::node::Reader,
1755) -> ::capnp::Result<FormattedText> {
1756    use capnp::schema_capnp::node;
1757
1758    let mut branches = vec![];
1759
1760    for (idx, annotation) in node_reader.get_annotations()?.iter().enumerate() {
1761        branches.push(annotation_branch(ctx, annotation, None, idx as u32)?);
1762    }
1763
1764    match node_reader.which()? {
1765        node::Struct(s) => {
1766            for (fidx, field) in s.get_fields()?.iter().enumerate() {
1767                for (idx, annotation) in field.get_annotations()?.iter().enumerate() {
1768                    branches.push(annotation_branch(
1769                        ctx,
1770                        annotation,
1771                        Some(fidx as u16),
1772                        idx as u32,
1773                    )?);
1774                }
1775            }
1776        }
1777        node::Enum(e) => {
1778            for (fidx, enumerant) in e.get_enumerants()?.iter().enumerate() {
1779                for (idx, annotation) in enumerant.get_annotations()?.iter().enumerate() {
1780                    branches.push(annotation_branch(
1781                        ctx,
1782                        annotation,
1783                        Some(fidx as u16),
1784                        idx as u32,
1785                    )?);
1786                }
1787            }
1788        }
1789        _ => (),
1790    }
1791
1792    let body = if branches.is_empty() {
1793        Line(fmt!(
1794            ctx,
1795            "{capnp}::introspect::panic_invalid_annotation_indices(child_index, index)"
1796        ))
1797    } else {
1798        branches.push(Line(fmt!(
1799            ctx,
1800            "_ => {capnp}::introspect::panic_invalid_annotation_indices(child_index, index),"
1801        )));
1802        indent(vec![
1803            Line("match (child_index, index) {".into()),
1804            indent(branches),
1805            Line("}".into()),
1806        ])
1807    };
1808
1809    if !node_reader.get_is_generic() {
1810        Ok(Branch(vec![
1811            Line(fmt!(ctx,"pub fn get_annotation_types(child_index: Option<u16>, index: u32) -> {capnp}::introspect::Type {{")),
1812            indent(body),
1813            Line("}".into()),
1814        ]))
1815    } else {
1816        let params = node_reader.parameters_texts(ctx);
1817        Ok(Branch(vec![
1818            Line(fmt!(ctx,
1819                "pub fn get_annotation_types<{0}>(child_index: Option<u16>, index: u32) -> {capnp}::introspect::Type {1} {{",
1820                params.params, params.where_clause
1821            )),
1822            indent(body),
1823            Line("}".into()),
1824        ]))
1825    }
1826}
1827
1828fn generate_members_by_discriminant(
1829    node_reader: schema_capnp::node::Reader,
1830) -> ::capnp::Result<FormattedText> {
1831    use capnp::schema_capnp::field;
1832    let st = match node_reader.which()? {
1833        schema_capnp::node::Struct(st) => st,
1834        _ => return Err(Error::failed("not a struct".into())),
1835    };
1836
1837    let mut union_member_indexes = vec![];
1838    let mut nonunion_member_indexes = vec![];
1839    for (index, field) in st.get_fields()?.iter().enumerate() {
1840        let disc = field.get_discriminant_value();
1841        if disc == field::NO_DISCRIMINANT {
1842            nonunion_member_indexes.push(index);
1843        } else {
1844            union_member_indexes.push((disc, index));
1845        }
1846    }
1847    union_member_indexes.sort();
1848
1849    let mut nonunion_string: String = "pub static NONUNION_MEMBERS : &[u16] = &[".into();
1850    for idx in 0..nonunion_member_indexes.len() {
1851        nonunion_string += &format!("{}", nonunion_member_indexes[idx]);
1852        if idx + 1 < nonunion_member_indexes.len() {
1853            nonunion_string += ",";
1854        }
1855    }
1856    nonunion_string += "];";
1857
1858    let mut members_by_disc: String = "pub static MEMBERS_BY_DISCRIMINANT : &[u16] = &[".into();
1859    for idx in 0..union_member_indexes.len() {
1860        let (disc, index) = union_member_indexes[idx];
1861        assert_eq!(idx, disc as usize);
1862        members_by_disc += &format!("{index}");
1863        if idx + 1 < union_member_indexes.len() {
1864            members_by_disc += ",";
1865        }
1866    }
1867    members_by_disc += "];";
1868    Ok(Branch(vec![Line(nonunion_string), Line(members_by_disc)]))
1869}
1870
1871fn generate_members_by_name(
1872    node_reader: schema_capnp::node::Reader,
1873) -> ::capnp::Result<FormattedText> {
1874    let st = match node_reader.which()? {
1875        schema_capnp::node::Struct(st) => st,
1876        _ => return Err(Error::failed("not a struct".into())),
1877    };
1878
1879    let mut members_by_name = Vec::new();
1880    for (index, field) in st.get_fields()?.iter().enumerate() {
1881        if let Ok(name) = get_field_name(field) {
1882            members_by_name.push((name, index));
1883        }
1884    }
1885    members_by_name.sort_by_key(|k| k.0);
1886
1887    let mut members_by_name_string: String = "pub static MEMBERS_BY_NAME : &[u16] = &[".into();
1888    for (i, (_, index)) in members_by_name.iter().enumerate() {
1889        members_by_name_string += &format!("{}", *index);
1890        if i + 1 < members_by_name.len() {
1891            members_by_name_string += ",";
1892        }
1893    }
1894    members_by_name_string += "];";
1895
1896    Ok(Branch(vec![Line(members_by_name_string)]))
1897}
1898
1899// We need this to work around the fact that Rust does not allow typedefs
1900// with unused type parameters.
1901fn get_ty_params_of_brand(
1902    ctx: &GeneratorContext,
1903    brand: schema_capnp::brand::Reader,
1904) -> ::capnp::Result<String> {
1905    let mut acc = HashSet::new();
1906    get_ty_params_of_brand_helper(ctx, &mut acc, brand)?;
1907    let mut result = String::new();
1908    for (scope_id, parameter_index) in acc.into_iter() {
1909        let node = ctx.node_map[&scope_id];
1910        let p = node.get_parameters()?.get(u32::from(parameter_index));
1911        result.push_str(p.get_name()?.to_str()?);
1912        result.push(',');
1913    }
1914
1915    Ok(result)
1916}
1917
1918fn get_ty_params_of_type_helper(
1919    ctx: &GeneratorContext,
1920    accumulator: &mut HashSet<(u64, u16)>,
1921    typ: schema_capnp::type_::Reader,
1922) -> ::capnp::Result<()> {
1923    use capnp::schema_capnp::type_;
1924    match typ.which()? {
1925        type_::Void(())
1926        | type_::Bool(())
1927        | type_::Int8(())
1928        | type_::Int16(())
1929        | type_::Int32(())
1930        | type_::Int64(())
1931        | type_::Uint8(())
1932        | type_::Uint16(())
1933        | type_::Uint32(())
1934        | type_::Uint64(())
1935        | type_::Float32(())
1936        | type_::Float64(())
1937        | type_::Text(_)
1938        | type_::Data(_) => {}
1939        type_::AnyPointer(p) => {
1940            match p.which()? {
1941                type_::any_pointer::Unconstrained(_) => (),
1942                type_::any_pointer::Parameter(p) => {
1943                    accumulator.insert((p.get_scope_id(), p.get_parameter_index()));
1944                }
1945                type_::any_pointer::ImplicitMethodParameter(_) => {
1946                    // XXX
1947                }
1948            }
1949        }
1950        type_::List(list) => {
1951            get_ty_params_of_type_helper(ctx, accumulator, list.get_element_type()?)?
1952        }
1953        type_::Enum(e) => {
1954            get_ty_params_of_brand_helper(ctx, accumulator, e.get_brand()?)?;
1955        }
1956        type_::Struct(s) => {
1957            get_ty_params_of_brand_helper(ctx, accumulator, s.get_brand()?)?;
1958        }
1959        type_::Interface(interf) => {
1960            get_ty_params_of_brand_helper(ctx, accumulator, interf.get_brand()?)?;
1961        }
1962    }
1963    Ok(())
1964}
1965
1966fn get_ty_params_of_brand_helper(
1967    ctx: &GeneratorContext,
1968    accumulator: &mut HashSet<(u64, u16)>,
1969    brand: schema_capnp::brand::Reader,
1970) -> ::capnp::Result<()> {
1971    for scope in brand.get_scopes()? {
1972        let scope_id = scope.get_scope_id();
1973        match scope.which()? {
1974            schema_capnp::brand::scope::Bind(bind) => {
1975                for binding in bind? {
1976                    match binding.which()? {
1977                        schema_capnp::brand::binding::Unbound(()) => {}
1978                        schema_capnp::brand::binding::Type(t) => {
1979                            get_ty_params_of_type_helper(ctx, accumulator, t?)?
1980                        }
1981                    }
1982                }
1983            }
1984            schema_capnp::brand::scope::Inherit(()) => {
1985                let parameters = ctx.node_map[&scope_id].get_parameters()?;
1986                for idx in 0..parameters.len() {
1987                    accumulator.insert((scope_id, idx as u16));
1988                }
1989            }
1990        }
1991    }
1992    Ok(())
1993}
1994
1995fn generate_node(
1996    ctx: &GeneratorContext,
1997    node_id: u64,
1998    node_name: &str,
1999) -> ::capnp::Result<FormattedText> {
2000    use capnp::schema_capnp::*;
2001
2002    let mut output: Vec<FormattedText> = Vec::new();
2003    let mut nested_output: Vec<FormattedText> = Vec::new();
2004
2005    let node_reader = &ctx.node_map[&node_id];
2006    let nested_nodes = node_reader.get_nested_nodes()?;
2007    for nested_node in nested_nodes {
2008        let id = nested_node.get_id();
2009        nested_output.push(generate_node(ctx, id, ctx.get_last_name(id)?)?);
2010    }
2011
2012    match node_reader.which()? {
2013        node::File(()) => {
2014            output.push(Branch(nested_output));
2015        }
2016        node::Struct(struct_reader) => {
2017            let params = node_reader.parameters_texts(ctx);
2018            output.push(BlankLine);
2019
2020            let is_generic = node_reader.get_is_generic();
2021            if is_generic {
2022                output.push(Line(format!(
2023                    "pub mod {} {{ /* {} */",
2024                    node_name,
2025                    params.expanded_list.join(",")
2026                )));
2027            } else {
2028                output.push(Line(format!("pub mod {node_name} {{")));
2029            }
2030            let bracketed_params = if params.params.is_empty() {
2031                "".to_string()
2032            } else {
2033                format!("<{}>", params.params)
2034            };
2035
2036            let mut preamble = Vec::new();
2037            let mut builder_members = Vec::new();
2038            let mut reader_members = Vec::new();
2039            let mut union_fields = Vec::new();
2040            let mut which_enums = Vec::new();
2041            let mut pipeline_impl_interior = Vec::new();
2042            let mut private_mod_interior = Vec::new();
2043
2044            let data_size = struct_reader.get_data_word_count();
2045            let pointer_size = struct_reader.get_pointer_count();
2046            let discriminant_count = struct_reader.get_discriminant_count();
2047            let discriminant_offset = struct_reader.get_discriminant_offset();
2048
2049            private_mod_interior.push(crate::pointer_constants::node_word_array_declaration(
2050                ctx,
2051                "ENCODED_NODE",
2052                *node_reader,
2053                crate::pointer_constants::WordArrayDeclarationOptions { public: true },
2054            )?);
2055
2056            private_mod_interior.push(generate_get_field_types(ctx, *node_reader)?);
2057            private_mod_interior.push(generate_get_annotation_types(ctx, *node_reader)?);
2058
2059            // `static` instead of `const` so that this has a fixed memory address
2060            // and we can check equality of `RawStructSchema` values by comparing pointers.
2061            private_mod_interior.push(Branch(vec![
2062                Line(fmt!(ctx, "pub static ARENA: {capnp}::private::arena::GeneratedCodeArena = {capnp}::private::arena::GeneratedCodeArena::new(&ENCODED_NODE);")),
2063                Line(fmt!(ctx,"pub static RAW_SCHEMA: {capnp}::introspect::RawStructSchema = {capnp}::introspect::RawStructSchema::new(")),
2064                indent(vec![
2065                    Line("&ARENA,".into()),
2066                    Line("NONUNION_MEMBERS,".into()),
2067                    Line("MEMBERS_BY_DISCRIMINANT,".into()),
2068                    Line("MEMBERS_BY_NAME".into()),
2069                ]),
2070                Line(");".into()),
2071            ]));
2072
2073            private_mod_interior.push(generate_members_by_discriminant(*node_reader)?);
2074            private_mod_interior.push(generate_members_by_name(*node_reader)?);
2075
2076            let mut has_pointer_field = false;
2077            let fields = struct_reader.get_fields()?;
2078            for field in fields {
2079                let name = get_field_name(field)?;
2080                let styled_name = camel_to_snake_case(name);
2081
2082                let discriminant_value = field.get_discriminant_value();
2083                let is_union_field = discriminant_value != field::NO_DISCRIMINANT;
2084
2085                match field.which()? {
2086                    field::Slot(s) => match s.get_type()?.which()? {
2087                        type_::Text(())
2088                        | type_::Data(())
2089                        | type_::List(_)
2090                        | type_::Struct(_)
2091                        | type_::Interface(_)
2092                        | type_::AnyPointer(_) => has_pointer_field = true,
2093                        _ => (),
2094                    },
2095                    field::Group(_) => has_pointer_field = true,
2096                }
2097
2098                if !is_union_field {
2099                    pipeline_impl_interior.push(generate_pipeline_getter(ctx, field)?);
2100                    let (ty, get, default_decl) = getter_text(ctx, &field, true, true)?;
2101                    if let Some(default) = default_decl {
2102                        private_mod_interior.push(default.clone());
2103                    }
2104                    reader_members.push(Branch(vec![
2105                        line("#[inline]"),
2106                        Line(format!("pub fn get_{styled_name}(self) {ty} {{")),
2107                        indent(get),
2108                        line("}"),
2109                    ]));
2110
2111                    let (ty_b, get_b, _) = getter_text(ctx, &field, false, true)?;
2112                    builder_members.push(Branch(vec![
2113                        line("#[inline]"),
2114                        Line(format!("pub fn get_{styled_name}(self) {ty_b} {{")),
2115                        indent(get_b),
2116                        line("}"),
2117                    ]));
2118                } else {
2119                    union_fields.push(field);
2120                }
2121
2122                builder_members.push(generate_setter(
2123                    ctx,
2124                    discriminant_offset,
2125                    &styled_name,
2126                    &field,
2127                )?);
2128
2129                reader_members.push(generate_haser(
2130                    discriminant_offset,
2131                    &styled_name,
2132                    &field,
2133                    true,
2134                )?);
2135                builder_members.push(generate_haser(
2136                    discriminant_offset,
2137                    &styled_name,
2138                    &field,
2139                    false,
2140                )?);
2141
2142                if let Ok(field::Group(group)) = field.which() {
2143                    let id = group.get_type_id();
2144                    let text = generate_node(ctx, id, ctx.get_last_name(id)?)?;
2145                    nested_output.push(text);
2146                }
2147            }
2148
2149            if discriminant_count > 0 {
2150                let (which_enums1, union_getter, typedef, mut default_decls) =
2151                    generate_union(ctx, discriminant_offset, &union_fields, true, &params)?;
2152                which_enums.push(which_enums1);
2153                which_enums.push(typedef);
2154                reader_members.push(union_getter);
2155
2156                private_mod_interior.append(&mut default_decls);
2157
2158                let (_, union_getter, typedef, _) =
2159                    generate_union(ctx, discriminant_offset, &union_fields, false, &params)?;
2160                which_enums.push(typedef);
2161                builder_members.push(union_getter);
2162
2163                let mut reexports = String::new();
2164                reexports.push_str("pub use self::Which::{");
2165                let mut whichs = Vec::new();
2166                for f in &union_fields {
2167                    whichs.push(capitalize_first_letter(get_field_name(*f)?));
2168                }
2169                reexports.push_str(&whichs.join(","));
2170                reexports.push_str("};");
2171                preamble.push(Line(reexports));
2172                preamble.push(BlankLine);
2173            }
2174
2175            let builder_struct_size =
2176                Branch(vec![
2177                    Line(fmt!(ctx,"impl <{0}> {capnp}::traits::HasStructSize for Builder<'_,{0}> {1} {{",
2178                                 params.params, params.where_clause)),
2179                                 indent(Line(
2180                        fmt!(ctx,"const STRUCT_SIZE: {capnp}::private::layout::StructSize = {capnp}::private::layout::StructSize {{ data: {}, pointers: {} }};", data_size as usize, pointer_size as usize))),
2181                   line("}")]);
2182
2183            private_mod_interior.push(Line(format!(
2184                "pub const TYPE_ID: u64 = {};",
2185                format_u64(node_id)
2186            )));
2187
2188            let from_pointer_builder_impl =
2189                Branch(vec![
2190                    Line(fmt!(ctx,"impl <'a,{0}> {capnp}::traits::FromPointerBuilder<'a> for Builder<'a,{0}> {1} {{", params.params, params.where_clause)),
2191                    indent(vec![
2192                        Line(fmt!(ctx,"fn init_pointer(builder: {capnp}::private::layout::PointerBuilder<'a>, _size: u32) -> Self {{")),
2193                        indent(Line(fmt!(ctx,"builder.init_struct(<Self as {capnp}::traits::HasStructSize>::STRUCT_SIZE).into()"))),
2194                        line("}"),
2195                        Line(fmt!(ctx,"fn get_from_pointer(builder: {capnp}::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [{capnp}::Word]>) -> {capnp}::Result<Self> {{")),
2196                        indent(Line(fmt!(ctx,"::core::result::Result::Ok(builder.get_struct(<Self as {capnp}::traits::HasStructSize>::STRUCT_SIZE, default)?.into())"))),
2197                        line("}")
2198                    ]),
2199                    line("}"),
2200                    BlankLine]);
2201
2202            let accessors = vec![
2203                Branch(preamble),
2204                (if !is_generic {
2205                    Branch(vec![
2206                        Line("#[derive(Copy, Clone)]".into()),
2207                        line("pub struct Owned(());"),
2208                        Line(fmt!(ctx,"impl {capnp}::introspect::Introspect for Owned {{ fn introspect() -> {capnp}::introspect::Type {{ {capnp}::introspect::TypeVariant::Struct({capnp}::introspect::RawBrandedStructSchema {{ generic: &_private::RAW_SCHEMA, field_types: _private::get_field_types, annotation_types: _private::get_annotation_types }}).into() }} }}")),
2209                        Line(fmt!(ctx, "impl {capnp}::traits::Owned for Owned {{ type Reader<'a> = Reader<'a>; type Builder<'a> = Builder<'a>; }}")),
2210                        Line(fmt!(ctx,"impl {capnp}::traits::OwnedStruct for Owned {{ type Reader<'a> = Reader<'a>; type Builder<'a> = Builder<'a>; }}")),
2211                        Line(fmt!(ctx,"impl {capnp}::traits::Pipelined for Owned {{ type Pipeline = Pipeline; }}"))
2212                    ])
2213                } else {
2214                    Branch(vec![
2215                        Line("#[derive(Copy, Clone)]".into()),
2216                        Line(format!("pub struct Owned<{}> {{", params.params)),
2217                            indent(Line(params.phantom_data_type.clone())),
2218                        line("}"),
2219                        Line(fmt!(ctx,"impl <{0}> {capnp}::introspect::Introspect for Owned <{0}> {1} {{ fn introspect() -> {capnp}::introspect::Type {{ {capnp}::introspect::TypeVariant::Struct({capnp}::introspect::RawBrandedStructSchema {{ generic: &_private::RAW_SCHEMA, field_types: _private::get_field_types::<{0}>, annotation_types: _private::get_annotation_types::<{0}> }}).into() }} }}",
2220                            params.params, params.where_clause)),
2221                        Line(fmt!(ctx,"impl <{0}> {capnp}::traits::Owned for Owned <{0}> {1} {{ type Reader<'a> = Reader<'a, {0}>; type Builder<'a> = Builder<'a, {0}>; }}",
2222                            params.params, params.where_clause)),
2223                        Line(fmt!(ctx,"impl <{0}> {capnp}::traits::OwnedStruct for Owned <{0}> {1} {{ type Reader<'a> = Reader<'a, {0}>; type Builder<'a> = Builder<'a, {0}>; }}",
2224                            params.params, params.where_clause)),
2225                        Line(fmt!(ctx,"impl <{0}> {capnp}::traits::Pipelined for Owned<{0}> {1} {{ type Pipeline = Pipeline{2}; }}",
2226                            params.params, params.where_clause, bracketed_params)),
2227                    ])
2228                }),
2229                BlankLine,
2230                (if !is_generic {
2231                    Line(fmt!(ctx,"pub struct Reader<'a> {{ reader: {capnp}::private::layout::StructReader<'a> }}"))
2232                } else {
2233                    Branch(vec![
2234                        Line(format!("pub struct Reader<'a,{}> {} {{", params.params, params.where_clause)),
2235                        indent(vec![
2236                            Line(fmt!(ctx,"reader: {capnp}::private::layout::StructReader<'a>,")),
2237                            Line(params.phantom_data_type.clone()),
2238                        ]),
2239                        line("}")
2240                    ])
2241                }),
2242                // Manually implement Copy/Clone because `derive` only kicks in if all of
2243                // the parameters are known to implement Copy/Clone.
2244                Branch(vec![
2245                    Line(format!("impl <{0}> ::core::marker::Copy for Reader<'_,{0}> {1} {{}}",
2246                                 params.params, params.where_clause)),
2247                    Line(format!("impl <{0}> ::core::clone::Clone for Reader<'_,{0}> {1} {{",
2248                                 params.params, params.where_clause)),
2249                    indent(Line("fn clone(&self) -> Self { *self }".into())),
2250                    Line("}".into())]),
2251                BlankLine,
2252                Branch(vec![
2253                        Line(fmt!(ctx,"impl <{0}> {capnp}::traits::HasTypeId for Reader<'_,{0}> {1} {{",
2254                            params.params, params.where_clause)),
2255                        indent(vec![line("const TYPE_ID: u64 = _private::TYPE_ID;")]),
2256                    line("}")]),
2257                Line(fmt!(ctx,"impl <'a,{0}> ::core::convert::From<{capnp}::private::layout::StructReader<'a>> for Reader<'a,{0}> {1} {{",
2258                            params.params, params.where_clause)),
2259                indent(vec![
2260                    Line(fmt!(ctx,"fn from(reader: {capnp}::private::layout::StructReader<'a>) -> Self {{")),
2261                    indent(Line(format!("Self {{ reader, {} }}", params.phantom_data_value))),
2262                    line("}")
2263                ]),
2264                line("}"),
2265                BlankLine,
2266                Line(fmt!(ctx,"impl <'a,{0}> ::core::convert::From<Reader<'a,{0}>> for {capnp}::dynamic_value::Reader<'a> {1} {{",
2267                            params.params, params.where_clause)),
2268                indent(vec![
2269                    Line(format!("fn from(reader: Reader<'a,{0}>) -> Self {{", params.params)),
2270                    indent(Line(fmt!(ctx,"Self::Struct({capnp}::dynamic_struct::Reader::new(reader.reader, {capnp}::schema::StructSchema::new({capnp}::introspect::RawBrandedStructSchema {{ generic: &_private::RAW_SCHEMA, field_types: _private::get_field_types::<{0}>, annotation_types: _private::get_annotation_types::<{0}>}})))", params.params))),
2271                    line("}")
2272                ]),
2273                line("}"),
2274                BlankLine,
2275                Line(format!("impl <{0}> ::core::fmt::Debug for Reader<'_,{0}> {1} {{",
2276                            params.params, params.where_clause)),
2277                indent(vec![
2278                    Line("fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::result::Result<(), ::core::fmt::Error> {".into()),
2279                    indent(Line(fmt!(ctx,"core::fmt::Debug::fmt(&::core::convert::Into::<{capnp}::dynamic_value::Reader<'_>>::into(*self), f)"))),
2280                    line("}")
2281                ]),
2282                line("}"),
2283
2284                BlankLine,
2285
2286                Line(fmt!(ctx,"impl <'a,{0}> {capnp}::traits::FromPointerReader<'a> for Reader<'a,{0}> {1} {{",
2287                    params.params, params.where_clause)),
2288                indent(vec![
2289                    Line(fmt!(ctx,"fn get_from_pointer(reader: &{capnp}::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [{capnp}::Word]>) -> {capnp}::Result<Self> {{")),
2290                    indent(line("::core::result::Result::Ok(reader.get_struct(default)?.into())")),
2291                    line("}")
2292                ]),
2293                line("}"),
2294                BlankLine,
2295                Line(fmt!(ctx,"impl <'a,{0}> {capnp}::traits::IntoInternalStructReader<'a> for Reader<'a,{0}> {1} {{",
2296                            params.params, params.where_clause)),
2297                indent(vec![
2298                    Line(fmt!(ctx,"fn into_internal_struct_reader(self) -> {capnp}::private::layout::StructReader<'a> {{")),
2299                    indent(line("self.reader")),
2300                    line("}")
2301                ]),
2302                line("}"),
2303                BlankLine,
2304                Line(fmt!(ctx,"impl <'a,{0}> {capnp}::traits::Imbue<'a> for Reader<'a,{0}> {1} {{",
2305                    params.params, params.where_clause)),
2306                indent(vec![
2307                    Line(fmt!(ctx,"fn imbue(&mut self, cap_table: &'a {capnp}::private::layout::CapTable) {{")),
2308                    indent(Line(fmt!(ctx,"self.reader.imbue({capnp}::private::layout::CapTableReader::Plain(cap_table))"))),
2309                    line("}")
2310                ]),
2311                line("}"),
2312                BlankLine,
2313                if has_pointer_field { // we do this to keep clippy happy
2314                    Line(format!("impl <'a,{0}> Reader<'a,{0}> {1} {{", params.params, params.where_clause))
2315                } else {
2316                    Line(format!("impl <{0}> Reader<'_,{0}> {1} {{", params.params, params.where_clause))
2317                },
2318                indent(vec![
2319                        Line(format!("pub fn reborrow(&self) -> Reader<'_,{}> {{",params.params)),
2320                        indent(line("Self { .. *self }")),
2321                        line("}"),
2322                        BlankLine,
2323                        Line(fmt!(ctx,"pub fn total_size(&self) -> {capnp}::Result<{capnp}::MessageSize> {{")),
2324                        indent(line("self.reader.total_size()")),
2325                        line("}")]),
2326                indent(reader_members),
2327                line("}"),
2328                BlankLine,
2329                (if !is_generic {
2330                    Line(fmt!(ctx,"pub struct Builder<'a> {{ builder: {capnp}::private::layout::StructBuilder<'a> }}"))
2331                } else {
2332                    Branch(vec![
2333                        Line(format!("pub struct Builder<'a,{}> {} {{",
2334                                     params.params, params.where_clause)),
2335                            indent(vec![
2336                            Line(fmt!(ctx, "builder: {capnp}::private::layout::StructBuilder<'a>,")),
2337                            Line(params.phantom_data_type.clone()),
2338                        ]),
2339                        line("}")
2340                    ])
2341                }),
2342                builder_struct_size,
2343                Branch(vec![
2344                    Line(fmt!(ctx,"impl <{0}> {capnp}::traits::HasTypeId for Builder<'_,{0}> {1} {{",
2345                                 params.params, params.where_clause)),
2346                    indent(vec![
2347                        line("const TYPE_ID: u64 = _private::TYPE_ID;")]),
2348                    line("}")
2349                ]),
2350                Line(fmt!(ctx,
2351                    "impl <'a,{0}> ::core::convert::From<{capnp}::private::layout::StructBuilder<'a>> for Builder<'a,{0}> {1} {{",
2352                    params.params, params.where_clause)),
2353                indent(vec![
2354                        Line(fmt!(ctx,"fn from(builder: {capnp}::private::layout::StructBuilder<'a>) -> Self {{")),
2355                        indent(Line(format!("Self {{ builder, {} }}", params.phantom_data_value))),
2356                        line("}")
2357                ]),
2358                line("}"),
2359                BlankLine,
2360                Line(fmt!(ctx,"impl <'a,{0}> ::core::convert::From<Builder<'a,{0}>> for {capnp}::dynamic_value::Builder<'a> {1} {{",
2361                            params.params, params.where_clause)),
2362                indent(vec![
2363                        Line(format!("fn from(builder: Builder<'a,{0}>) -> Self {{", params.params)),
2364                        indent(Line(fmt!(ctx,"Self::Struct({capnp}::dynamic_struct::Builder::new(builder.builder, {capnp}::schema::StructSchema::new({capnp}::introspect::RawBrandedStructSchema {{ generic: &_private::RAW_SCHEMA, field_types: _private::get_field_types::<{0}>, annotation_types: _private::get_annotation_types::<{0}>}})))", params.params))),
2365                        line("}")
2366                ]),
2367                line("}"),
2368                BlankLine,
2369
2370                Line(fmt!(ctx,"impl <'a,{0}> {capnp}::traits::ImbueMut<'a> for Builder<'a,{0}> {1} {{",
2371                             params.params, params.where_clause)),
2372                indent(vec![
2373                        Line(fmt!(ctx,"fn imbue_mut(&mut self, cap_table: &'a mut {capnp}::private::layout::CapTable) {{")),
2374                        indent(Line(fmt!(ctx,"self.builder.imbue({capnp}::private::layout::CapTableBuilder::Plain(cap_table))"))),
2375                        line("}")]),
2376                line("}"),
2377                BlankLine,
2378
2379                from_pointer_builder_impl,
2380                Line(fmt!(ctx,
2381                    "impl <{0}> {capnp}::traits::SetterInput<Owned<{0}>> for Reader<'_,{0}> {1} {{",
2382                    params.params, params.where_clause)),
2383                indent(Line(fmt!(ctx,"fn set_pointer_builder(mut pointer: {capnp}::private::layout::PointerBuilder<'_>, value: Self, canonicalize: bool) -> {capnp}::Result<()> {{ pointer.set_struct(&value.reader, canonicalize) }}"))),
2384                line("}"),
2385                BlankLine,
2386                Line(format!("impl <'a,{0}> Builder<'a,{0}> {1} {{", params.params, params.where_clause)),
2387                indent(vec![
2388                        Line(format!("pub fn into_reader(self) -> Reader<'a,{}> {{", params.params)),
2389                        indent(line("self.builder.into_reader().into()")),
2390                        line("}"),
2391                        Line(format!("pub fn reborrow(&mut self) -> Builder<'_,{}> {{", params.params)),
2392                        (if !is_generic {
2393                            indent(line("Builder { builder: self.builder.reborrow() }"))
2394                        } else {
2395                            indent(line("Builder { builder: self.builder.reborrow(), ..*self }"))
2396                        }),
2397                        line("}"),
2398                        Line(format!("pub fn reborrow_as_reader(&self) -> Reader<'_,{}> {{", params.params)),
2399                        indent(line("self.builder.as_reader().into()")),
2400                        line("}"),
2401
2402                        BlankLine,
2403                        Line(fmt!(ctx,"pub fn total_size(&self) -> {capnp}::Result<{capnp}::MessageSize> {{")),
2404                        indent(line("self.builder.as_reader().total_size()")),
2405                        line("}")
2406                        ]),
2407                indent(builder_members),
2408                line("}"),
2409                BlankLine,
2410                (if is_generic {
2411                    Branch(vec![
2412                        Line(format!("pub struct Pipeline{bracketed_params} {{")),
2413                        indent(vec![
2414                            Line(fmt!(ctx,"_typeless: {capnp}::any_pointer::Pipeline,")),
2415                            Line(params.phantom_data_type),
2416                        ]),
2417                        line("}")
2418                    ])
2419                } else {
2420                    Line(fmt!(ctx,"pub struct Pipeline {{ _typeless: {capnp}::any_pointer::Pipeline }}"))
2421                }),
2422                Line(fmt!(ctx,"impl{bracketed_params} {capnp}::capability::FromTypelessPipeline for Pipeline{bracketed_params} {{")),
2423                indent(vec![
2424                        Line(fmt!(ctx,"fn new(typeless: {capnp}::any_pointer::Pipeline) -> Self {{")),
2425                        indent(Line(format!("Self {{ _typeless: typeless, {} }}", params.phantom_data_value))),
2426                        line("}")]),
2427                line("}"),
2428                Line(format!("impl{0} Pipeline{0} {1} {{", bracketed_params,
2429                             params.pipeline_where_clause)),
2430                indent(pipeline_impl_interior),
2431                line("}"),
2432                line("mod _private {"),
2433                indent(private_mod_interior),
2434                line("}"),
2435            ];
2436
2437            output.push(indent(vec![
2438                Branch(accessors),
2439                Branch(which_enums),
2440                Branch(nested_output),
2441            ]));
2442            output.push(line("}"));
2443        }
2444
2445        node::Enum(enum_reader) => {
2446            let last_name = ctx.get_last_name(node_id)?;
2447            let name_as_mod = module_name(last_name);
2448            output.push(BlankLine);
2449
2450            let mut members = Vec::new();
2451            let mut match_branches = Vec::new();
2452            let enumerants = enum_reader.get_enumerants()?;
2453            for (ii, enumerant) in enumerants.into_iter().enumerate() {
2454                let enumerant = capitalize_first_letter(get_enumerant_name(enumerant)?);
2455                members.push(Line(format!("{enumerant} = {ii},")));
2456                match_branches.push(Line(format!(
2457                    "{ii} => ::core::result::Result::Ok(Self::{enumerant}),"
2458                )));
2459            }
2460            match_branches.push(Line(fmt!(
2461                ctx,
2462                "n => ::core::result::Result::Err({capnp}::NotInSchema(n)),"
2463            )));
2464
2465            output.push(Branch(vec![
2466                line("#[repr(u16)]"),
2467                line("#[derive(Clone, Copy, Debug, PartialEq, Eq)]"),
2468                Line(format!("pub enum {last_name} {{")),
2469                indent(members),
2470                line("}"),
2471            ]));
2472
2473            output.push(BlankLine);
2474            output.push(Branch(vec![
2475                Line(fmt!(ctx,
2476                    "impl {capnp}::introspect::Introspect for {last_name} {{"
2477                )),
2478                indent(Line(fmt!(ctx,
2479                    "fn introspect() -> {capnp}::introspect::Type {{ {capnp}::introspect::TypeVariant::Enum({capnp}::introspect::RawEnumSchema {{ encoded_node: &{0}::ENCODED_NODE, annotation_types: {0}::get_annotation_types }}).into() }}", name_as_mod))),
2480                Line("}".into()),
2481            ]));
2482
2483            output.push(Branch(vec![
2484                Line(fmt!(ctx,"impl ::core::convert::From<{last_name}> for {capnp}::dynamic_value::Reader<'_> {{")),
2485                indent(Line(fmt!(ctx,
2486                    "fn from(e: {last_name}) -> Self {{ {capnp}::dynamic_value::Enum::new(e.into(), {capnp}::introspect::RawEnumSchema {{ encoded_node: &{0}::ENCODED_NODE, annotation_types: {0}::get_annotation_types }}.into()).into() }}", name_as_mod ))),
2487                Line("}".into())
2488            ]));
2489
2490            output.push(Branch(vec![
2491                Line(format!(
2492                    "impl ::core::convert::TryFrom<u16> for {last_name} {{"
2493                )),
2494                indent(Line(
2495                    fmt!(ctx,"type Error = {capnp}::NotInSchema;"),
2496                )),
2497                indent(vec![
2498                    Line(
2499                        format!("fn try_from(value: u16) -> ::core::result::Result<Self, <{last_name} as ::core::convert::TryFrom<u16>>::Error> {{")
2500                    ),
2501                    indent(vec![
2502                        line("match value {"),
2503                        indent(match_branches),
2504                        line("}"),
2505                    ]),
2506                    line("}"),
2507                ]),
2508                line("}"),
2509                Line(format!("impl From<{last_name}> for u16 {{")),
2510                indent(line("#[inline]")),
2511                indent(Line(format!(
2512                    "fn from(x: {last_name}) -> u16 {{ x as u16 }}"
2513                ))),
2514                line("}"),
2515            ]));
2516
2517            output.push(Branch(vec![
2518                Line(fmt!(
2519                    ctx,
2520                    "impl {capnp}::traits::HasTypeId for {last_name} {{"
2521                )),
2522                indent(Line(format!(
2523                    "const TYPE_ID: u64 = {}u64;",
2524                    format_u64(node_id)
2525                ))),
2526                line("}"),
2527            ]));
2528
2529            output.push(Branch(vec![
2530                Line(format!("mod {name_as_mod} {{")),
2531                Branch(vec![
2532                    crate::pointer_constants::node_word_array_declaration(
2533                        ctx,
2534                        "ENCODED_NODE",
2535                        *node_reader,
2536                        crate::pointer_constants::WordArrayDeclarationOptions { public: true },
2537                    )?,
2538                    generate_get_annotation_types(ctx, *node_reader)?,
2539                ]),
2540                Line("}".into()),
2541            ]));
2542        }
2543
2544        node::Interface(interface) => {
2545            let params = node_reader.parameters_texts(ctx);
2546            output.push(BlankLine);
2547
2548            let is_generic = node_reader.get_is_generic();
2549
2550            let names = &ctx.scope_map[&node_id];
2551            let mut client_impl_interior = Vec::new();
2552            let mut server_interior = Vec::new();
2553            let mut mod_interior = Vec::new();
2554            let mut dispatch_arms = Vec::new();
2555            let mut private_mod_interior = Vec::new();
2556
2557            let bracketed_params = if params.params.is_empty() {
2558                "".to_string()
2559            } else {
2560                format!("<{}>", params.params)
2561            };
2562
2563            private_mod_interior.push(Line(format!(
2564                "pub const TYPE_ID: u64 = {};",
2565                format_u64(node_id)
2566            )));
2567
2568            mod_interior.push(line("#![allow(unused_variables)]"));
2569
2570            let methods = interface.get_methods()?;
2571            for (ordinal, method) in methods.into_iter().enumerate() {
2572                let name = method.get_name()?.to_str()?;
2573
2574                let param_id = method.get_param_struct_type();
2575                let param_node = &ctx.node_map[&param_id];
2576                let (param_scopes, params_ty_params) = if param_node.get_scope_id() == 0 {
2577                    let mut names = names.clone();
2578                    let local_name = module_name(&format!("{name}Params"));
2579                    nested_output.push(generate_node(ctx, param_id, &local_name)?);
2580                    names.push(local_name);
2581                    (names, params.params.clone())
2582                } else {
2583                    (
2584                        ctx.scope_map[&param_node.get_id()].clone(),
2585                        get_ty_params_of_brand(ctx, method.get_param_brand()?)?,
2586                    )
2587                };
2588                let param_type = do_branding(
2589                    ctx,
2590                    param_id,
2591                    method.get_param_brand()?,
2592                    Leaf::Owned,
2593                    &param_scopes.join("::"),
2594                )?;
2595
2596                mod_interior.push(Line(fmt!(
2597                    ctx,
2598                    "pub type {}Params<{}> = {capnp}::capability::Params<{}>;",
2599                    capitalize_first_letter(name),
2600                    params_ty_params,
2601                    param_type
2602                )));
2603
2604                let result_id = method.get_result_struct_type();
2605                if result_id != STREAM_RESULT_ID {
2606                    dispatch_arms.push(
2607                        Line(fmt!(ctx,
2608                                  "{ordinal} => {capnp}::capability::DispatchCallResult::new({capnp}::capability::Promise::from_future(<_T as Server{bracketed_params}>::{}(this, {capnp}::private::capability::internal_get_typed_params(params), {capnp}::private::capability::internal_get_typed_results(results))), false),",
2609                                  module_name(name))));
2610
2611                    let result_node = &ctx.node_map[&result_id];
2612                    let (result_scopes, results_ty_params) = if result_node.get_scope_id() == 0 {
2613                        let mut names = names.clone();
2614                        let local_name = module_name(&format!("{name}Results"));
2615                        nested_output.push(generate_node(ctx, result_id, &local_name)?);
2616                        names.push(local_name);
2617                        (names, params.params.clone())
2618                    } else {
2619                        (
2620                            ctx.scope_map[&result_node.get_id()].clone(),
2621                            get_ty_params_of_brand(ctx, method.get_result_brand()?)?,
2622                        )
2623                    };
2624                    let result_type = do_branding(
2625                        ctx,
2626                        result_id,
2627                        method.get_result_brand()?,
2628                        Leaf::Owned,
2629                        &result_scopes.join("::"),
2630                    )?;
2631                    mod_interior.push(Line(fmt!(
2632                        ctx,
2633                        "pub type {}Results<{}> = {capnp}::capability::Results<{}>;",
2634                        capitalize_first_letter(name),
2635                        results_ty_params,
2636                        result_type
2637                    )));
2638                    server_interior.push(
2639                        Line(fmt!(ctx,
2640                                  "fn {}(self: {capnp}::capability::Rc<Self>, _: {}Params<{}>, _: {}Results<{}>) -> impl ::core::future::Future<Output = Result<(), {capnp}::Error>> + 'static {{ ::core::future::ready(Err({capnp}::Error::unimplemented(\"method {}::Server::{} not implemented\".to_string()))) }}",
2641                                  module_name(name),
2642                                  capitalize_first_letter(name), params_ty_params,
2643                                  capitalize_first_letter(name), results_ty_params,
2644                                  node_name, module_name(name)
2645                        )));
2646
2647                    client_impl_interior.push(Line(fmt!(
2648                        ctx,
2649                        "pub fn {}_request(&self) -> {capnp}::capability::Request<{},{}> {{",
2650                        camel_to_snake_case(name),
2651                        param_type,
2652                        result_type
2653                    )));
2654
2655                    client_impl_interior.push(indent(Line(format!(
2656                        "self.client.new_call(_private::TYPE_ID, {ordinal}, ::core::option::Option::None)"
2657                    ))));
2658                    client_impl_interior.push(line("}"));
2659                } else {
2660                    // It's a streaming method.
2661                    dispatch_arms.push(
2662                        Line(fmt!(ctx,
2663                                  "{ordinal} => {capnp}::capability::DispatchCallResult::new({capnp}::capability::Promise::from_future(<_T as Server{bracketed_params}>::{}(this, {capnp}::private::capability::internal_get_typed_params(params))), true),",
2664
2665                                  module_name(name))));
2666
2667                    server_interior.push(
2668                        Line(fmt!(ctx,
2669                                  "fn {}(self: {capnp}::capability::Rc<Self>, _: {}Params<{}>) -> impl ::core::future::Future<Output = Result<(), {capnp}::Error>> + 'static {{ ::core::future::ready(Err({capnp}::Error::unimplemented(\"method {}::Server::{} not implemented\".to_string()))) }}",
2670                                  module_name(name),
2671                                  capitalize_first_letter(name), params_ty_params,
2672                                  node_name, module_name(name)
2673                        )));
2674                    client_impl_interior.push(Line(fmt!(
2675                        ctx,
2676                        "pub fn {}_request(&self) -> {capnp}::capability::StreamingRequest<{}> {{",
2677                        camel_to_snake_case(name),
2678                        param_type
2679                    )));
2680                    client_impl_interior.push(indent(Line(format!(
2681                        "self.client.new_streaming_call(_private::TYPE_ID, {ordinal}, ::core::option::Option::None)"
2682                    ))));
2683
2684                    client_impl_interior.push(line("}"));
2685                }
2686
2687                method.get_annotations()?;
2688            }
2689
2690            let mut base_dispatch_arms = Vec::new();
2691
2692            let server_base = {
2693                let mut base_traits = Vec::new();
2694
2695                fn find_super_interfaces<'a>(
2696                    interface: schema_capnp::node::interface::Reader<'a>,
2697                    all_extends: &mut Vec<
2698                        <schema_capnp::superclass::Owned as capnp::traits::OwnedStruct>::Reader<'a>,
2699                    >,
2700                    ctx: &GeneratorContext<'a>,
2701                ) -> ::capnp::Result<()> {
2702                    let extends = interface.get_superclasses()?;
2703                    for superclass in extends {
2704                        if let node::Interface(interface) =
2705                            ctx.node_map[&superclass.get_id()].which()?
2706                        {
2707                            find_super_interfaces(interface, all_extends, ctx)?;
2708                        }
2709                        all_extends.push(superclass);
2710                    }
2711                    Ok(())
2712                }
2713
2714                let mut extends = Vec::new();
2715                find_super_interfaces(interface, &mut extends, ctx)?;
2716                for interface in &extends {
2717                    let type_id = interface.get_id();
2718                    let brand = interface.get_brand()?;
2719                    let the_mod = ctx.get_qualified_module(type_id);
2720
2721                    base_dispatch_arms.push(Line(format!(
2722                        "0x{type_id:x} => {}::dispatch_call_internal(self.server, method_id, params, results),",
2723                        do_branding(
2724                            ctx, type_id, brand, Leaf::ServerDispatch, &the_mod)?)));
2725                    base_traits.push(do_branding(ctx, type_id, brand, Leaf::Server, &the_mod)?);
2726                }
2727
2728                // Defining that the server itself should always be 'static makes
2729                // bounds easier down the line.
2730                if !extends.is_empty() {
2731                    format!(": {} + 'static", base_traits.join(" + "))
2732                } else {
2733                    ": 'static".to_string()
2734                }
2735            };
2736
2737            mod_interior.push(BlankLine);
2738            mod_interior.push(Line(format!("pub struct Client{bracketed_params} {{")));
2739            mod_interior.push(indent(Line(fmt!(
2740                ctx,
2741                "pub client: {capnp}::capability::Client,"
2742            ))));
2743            if is_generic {
2744                mod_interior.push(indent(Line(params.phantom_data_type.clone())));
2745            }
2746            mod_interior.push(line("}"));
2747            mod_interior.push(
2748                Branch(vec![
2749                    Line(fmt!(ctx,"impl {bracketed_params} {capnp}::capability::FromClientHook for Client{bracketed_params} {{")),
2750                    indent(Line(fmt!(ctx,"fn new(hook: Box<{capnp}::capability::DynClientHook>) -> Self {{"))),
2751                    indent(indent(Line(fmt!(ctx,"Self {{ client: {capnp}::capability::Client::new(hook), {} }}", params.phantom_data_value)))),
2752                    indent(line("}")),
2753                    indent(Line(fmt!(ctx,"fn into_client_hook(self) -> Box<{capnp}::capability::DynClientHook> {{"))),
2754                    indent(indent(line("self.client.hook"))),
2755                    indent(line("}")),
2756                    indent(Line(fmt!(ctx,"fn as_client_hook(&self) -> &{capnp}::capability::DynClientHook {{"))),
2757                    indent(indent(line("&*self.client.hook"))),
2758                    indent(line("}")),
2759                    line("}")]));
2760
2761            mod_interior.push(if !is_generic {
2762                Branch(vec![
2763                    Line("#[derive(Copy, Clone)]".into()),
2764                    line("pub struct Owned(());"),
2765                    Line(fmt!(ctx,"impl {capnp}::introspect::Introspect for Owned {{ fn introspect() -> {capnp}::introspect::Type {{ {capnp}::introspect::TypeVariant::Capability.into() }} }}")),
2766                    line("impl ::capnp::traits::Owned for Owned { type Reader<'a> = Client; type Builder<'a> = Client; }"),
2767                    Line(fmt!(ctx,"impl {capnp}::traits::Pipelined for Owned {{ type Pipeline = Client; }}"))])
2768            } else {
2769                Branch(vec![
2770                    Line("#[derive(Copy, Clone)]".into()),
2771                    Line(format!("pub struct Owned<{}> {} {{", params.params, params.where_clause)),
2772                    indent(Line(params.phantom_data_type.clone())),
2773                    line("}"),
2774                    Line(fmt!(ctx,
2775                              "impl <{0}> {capnp}::introspect::Introspect for Owned <{0}> {1} {{ fn introspect() -> {capnp}::introspect::Type {{ {capnp}::introspect::TypeVariant::Capability.into() }} }}",
2776                              params.params, params.where_clause)),
2777                    Line(fmt!(ctx,
2778                        "impl <{0}> {capnp}::traits::Owned for Owned <{0}> {1} {{ type Reader<'a> = Client<{0}>; type Builder<'a> = Client<{0}>; }}",
2779                        params.params, params.where_clause)),
2780                    Line(fmt!(ctx,
2781                        "impl <{0}> {capnp}::traits::Pipelined for Owned <{0}> {1} {{ type Pipeline = Client{2}; }}",
2782                        params.params, params.where_clause, bracketed_params))])
2783            });
2784
2785            mod_interior.push(Branch(vec![
2786                Line(fmt!(ctx,"impl <'a,{0}> {capnp}::traits::FromPointerReader<'a> for Client<{0}> {1} {{",
2787                    params.params, params.where_clause)),
2788                indent(vec![
2789                        Line(fmt!(ctx,"fn get_from_pointer(reader: &{capnp}::private::layout::PointerReader<'a>, _default: ::core::option::Option<&'a [{capnp}::Word]>) -> {capnp}::Result<Self> {{")),
2790                        indent(Line(fmt!(ctx,"::core::result::Result::Ok({capnp}::capability::FromClientHook::new(reader.get_capability()?))"))),
2791                        line("}")]),
2792                line("}")]));
2793
2794            mod_interior.push(Branch(vec![
2795                Line(fmt!(ctx,"impl <'a,{0}> {capnp}::traits::FromPointerBuilder<'a> for Client<{0}> {1} {{",
2796                             params.params, params.where_clause)),
2797                indent(vec![
2798                            Line(fmt!(ctx,"fn init_pointer(_builder: {capnp}::private::layout::PointerBuilder<'a>, _size: u32) -> Self {{")),
2799                            indent(line("unimplemented!()")),
2800                            line("}"),
2801                            Line(fmt!(ctx,"fn get_from_pointer(builder: {capnp}::private::layout::PointerBuilder<'a>, _default: ::core::option::Option<&'a [{capnp}::Word]>) -> {capnp}::Result<Self> {{")),
2802                            indent(Line(fmt!(ctx,"::core::result::Result::Ok({capnp}::capability::FromClientHook::new(builder.get_capability()?))"))),
2803                            line("}")]),
2804                line("}"),
2805                BlankLine]));
2806
2807            mod_interior.push(Branch(vec![
2808                Line(fmt!(ctx,
2809                    "impl <{0}> {capnp}::traits::SetterInput<Owned<{0}>> for Client<{0}> {1} {{",
2810                    params.params, params.where_clause)),
2811                indent(vec![
2812                            Line(fmt!(ctx,"fn set_pointer_builder(mut pointer: {capnp}::private::layout::PointerBuilder<'_>, from: Self, _canonicalize: bool) -> {capnp}::Result<()> {{")),
2813                            indent(Line("pointer.set_capability(from.client.hook);".to_string())),
2814                            indent(Line("::core::result::Result::Ok(())".to_string())),
2815                            line("}")
2816                        ]
2817                ),
2818                line("}")]));
2819
2820            mod_interior.push(Branch(vec![
2821                Line(fmt!(ctx,
2822                    "impl {bracketed_params} {capnp}::traits::HasTypeId for Client{bracketed_params} {{"
2823                )),
2824                indent(Line(
2825                    "const TYPE_ID: u64 = _private::TYPE_ID;".to_string(),
2826                )),
2827                line("}"),
2828            ]));
2829
2830            mod_interior.push(Branch(vec![
2831                Line(format!(
2832                    "impl {bracketed_params} Clone for Client{bracketed_params} {{"
2833                )),
2834                indent(line("fn clone(&self) -> Self {")),
2835                indent(indent(Line(format!(
2836                    "Self {{ client: self.client.clone(), {} }}",
2837                    params.phantom_data_value
2838                )))),
2839                indent(line("}")),
2840                line("}"),
2841            ]));
2842
2843            mod_interior.push(Branch(vec![
2844                Line(format!(
2845                    "impl {bracketed_params} Client{bracketed_params} {{"
2846                )),
2847                indent(client_impl_interior),
2848                line("}"),
2849            ]));
2850
2851            mod_interior.push(Branch(vec![
2852                Line(format!(
2853                    "pub trait Server<{}> {} {} {{",
2854                    params.params, server_base, params.where_clause
2855                )),
2856                indent(server_interior),
2857                line("}"),
2858            ]));
2859
2860            mod_interior.push(Branch(vec![
2861                Line(format!(
2862                    "pub struct ServerDispatch<_T,{}> {{",
2863                    params.params
2864                )),
2865                indent(line(fmt!(ctx, "pub server: {capnp}::capability::Rc<_T>,"))),
2866                indent(if is_generic {
2867                    vec![Line(params.phantom_data_type.clone())]
2868                } else {
2869                    vec![]
2870                }),
2871                line("}"),
2872            ]));
2873
2874            mod_interior.push(Branch(vec![
2875                Line(
2876                    fmt!(ctx,"impl <_S: Server{1} + 'static, {0}> {capnp}::capability::FromServer<_S> for Client{1} {2}  {{",
2877                            params.params, bracketed_params, params.where_clause_with_static)),
2878                indent(vec![
2879                    Line(format!("type Dispatch = ServerDispatch<_S, {}>;", params.params)),
2880                    Line(fmt!(ctx, "fn from_server(s: {capnp}::capability::Rc<_S>) -> ServerDispatch<_S, {}> {{", params.params)),
2881                    indent(Line(format!("ServerDispatch {{ server: s, {} }}", params.phantom_data_value))),
2882                    line("}"),
2883                ]),
2884                line("}"),
2885            ]));
2886
2887            mod_interior.push(
2888                Branch(vec![
2889                    (if is_generic {
2890                        Line(format!("impl <{}, _T: Server{}> ::core::ops::Deref for ServerDispatch<_T,{}> {} {{", params.params, bracketed_params, params.params, params.where_clause))
2891                    } else {
2892                        line("impl <_T: Server> ::core::ops::Deref for ServerDispatch<_T> {")
2893                    }),
2894                    indent(line("type Target = _T;")),
2895                    indent(line("fn deref(&self) -> &_T { &self.server}")),
2896                    line("}"),
2897                    ]));
2898
2899            mod_interior.push(
2900                Branch(vec![
2901                    (if is_generic {
2902                        Line(format!("impl <{}, _T: Server{}> ::core::clone::Clone for ServerDispatch<_T,{}> {} {{", params.params, bracketed_params, params.params, params.where_clause))
2903                    } else {
2904                        line("impl <_T: Server> ::core::clone::Clone for ServerDispatch<_T> {")
2905                    }),
2906                    indent(line(
2907                        format!("fn clone(&self) -> Self {{ Self {{ server: self.server.clone(), {} }} }}", params.phantom_data_value))),
2908                    line("}"),
2909                    ]));
2910
2911            mod_interior.push(
2912                Branch(vec![
2913                    (if is_generic {
2914                        Line(fmt!(ctx,"impl <{}, _T: Server{}> {capnp}::capability::Server for ServerDispatch<_T,{}> {} {{", params.params, bracketed_params, params.params, params.where_clause_with_static))
2915                    } else {
2916                        Line(fmt!(ctx,"impl <_T: Server> {capnp}::capability::Server for ServerDispatch<_T> {{"))
2917                    }),
2918                    indent(Line(fmt!(ctx,"fn dispatch_call(self, interface_id: u64, method_id: u16, params: {capnp}::capability::Params<{capnp}::any_pointer::Owned>, results: {capnp}::capability::Results<{capnp}::any_pointer::Owned>) -> {capnp}::capability::DispatchCallResult {{"))),
2919                    indent(indent(line("match interface_id {"))),
2920                    indent(indent(indent(line("_private::TYPE_ID => Self::dispatch_call_internal(self.server, method_id, params, results),")))),
2921                    indent(indent(indent(base_dispatch_arms))),
2922                    indent(indent(indent(Line(fmt!(ctx,"_ => {{ {capnp}::capability::DispatchCallResult::new({capnp}::capability::Promise::err({capnp}::Error::unimplemented(\"Method not implemented.\".to_string())), false) }}"))))),
2923                    indent(indent(line("}"))),
2924                    indent(line("}")),
2925
2926                    indent(Line(fmt!(ctx, "fn as_ptr(&self) -> usize {{ {capnp}::capability::Rc::as_ptr(&self.server) as usize }}"))),
2927
2928                    line("}")]));
2929
2930            mod_interior.push(
2931                Branch(vec![
2932                    (if is_generic {
2933                        Line(format!("impl <{}, _T: Server{}> ServerDispatch<_T,{}> {} {{", params.params, bracketed_params, params.params, params.where_clause_with_static))
2934                    } else {
2935                        line("impl <_T :Server> ServerDispatch<_T> {")
2936                    }),
2937
2938                    indent(Line(fmt!(ctx,"pub fn dispatch_call_internal(this: {capnp}::capability::Rc<_T>, method_id: u16, params: {capnp}::capability::Params<{capnp}::any_pointer::Owned>, results: {capnp}::capability::Results<{capnp}::any_pointer::Owned>) -> {capnp}::capability::DispatchCallResult {{"))),
2939                    indent(indent(line("match method_id {"))),
2940                    indent(indent(indent(dispatch_arms))),
2941                    indent(indent(indent(Line(fmt!(ctx,"_ => {{ {capnp}::capability::DispatchCallResult::new({capnp}::capability::Promise::err({capnp}::Error::unimplemented(\"Method not implemented.\".to_string())), false) }}"))))),
2942                    indent(indent(line("}"))),
2943                    indent(line("}")),
2944                    line("}")]));
2945
2946            mod_interior.push(Branch(vec![
2947                line("pub mod _private {"),
2948                indent(private_mod_interior),
2949                line("}"),
2950            ]));
2951
2952            mod_interior.push(Branch(vec![Branch(nested_output)]));
2953
2954            output.push(BlankLine);
2955            if is_generic {
2956                output.push(Line(format!(
2957                    "pub mod {} {{ /* ({}) */",
2958                    node_name,
2959                    params.expanded_list.join(",")
2960                )));
2961            } else {
2962                output.push(Line(format!("pub mod {node_name} {{")));
2963            }
2964            output.push(indent(mod_interior));
2965            output.push(line("}"));
2966        }
2967
2968        node::Const(c) => {
2969            let styled_name = snake_to_upper_case(ctx.get_last_name(node_id)?);
2970
2971            let typ = c.get_type()?;
2972            let formatted_text = match (typ.which()?, c.get_value()?.which()?) {
2973                (type_::Void(()), value::Void(())) => {
2974                    Line(format!("pub const {styled_name}: () = ();"))
2975                }
2976                (type_::Bool(()), value::Bool(b)) => {
2977                    Line(format!("pub const {styled_name}: bool = {b};"))
2978                }
2979                (type_::Int8(()), value::Int8(i)) => {
2980                    Line(format!("pub const {styled_name}: i8 = {i};"))
2981                }
2982                (type_::Int16(()), value::Int16(i)) => {
2983                    Line(format!("pub const {styled_name}: i16 = {i};"))
2984                }
2985                (type_::Int32(()), value::Int32(i)) => {
2986                    Line(format!("pub const {styled_name}: i32 = {i};"))
2987                }
2988                (type_::Int64(()), value::Int64(i)) => {
2989                    Line(format!("pub const {styled_name}: i64 = {i};"))
2990                }
2991                (type_::Uint8(()), value::Uint8(i)) => {
2992                    Line(format!("pub const {styled_name}: u8 = {i};"))
2993                }
2994                (type_::Uint16(()), value::Uint16(i)) => {
2995                    Line(format!("pub const {styled_name}: u16 = {i};"))
2996                }
2997                (type_::Uint32(()), value::Uint32(i)) => {
2998                    Line(format!("pub const {styled_name}: u32 = {i};"))
2999                }
3000                (type_::Uint64(()), value::Uint64(i)) => {
3001                    Line(format!("pub const {styled_name}: u64 = {i};"))
3002                }
3003
3004                (type_::Float32(()), value::Float32(f)) => {
3005                    let literal = match f.classify() {
3006                        std::num::FpCategory::Nan => "f32::NAN".into(),
3007                        std::num::FpCategory::Infinite => {
3008                            if f.is_sign_positive() {
3009                                "f32::INFINITY".into()
3010                            } else {
3011                                "f32::NEG_INFINITY".into()
3012                            }
3013                        }
3014                        _ => format!("{f:e}"),
3015                    };
3016                    Line(format!("pub const {styled_name}: f32 = {literal};"))
3017                }
3018
3019                (type_::Float64(()), value::Float64(f)) => {
3020                    let literal = match f.classify() {
3021                        std::num::FpCategory::Nan => "f64::NAN".into(),
3022                        std::num::FpCategory::Infinite => {
3023                            if f.is_sign_positive() {
3024                                "f64::INFINITY".into()
3025                            } else {
3026                                "f64::NEG_INFINITY".into()
3027                            }
3028                        }
3029                        _ => format!("{f:e}"),
3030                    };
3031                    Line(format!("pub const {styled_name}: f64 = {literal};"))
3032                }
3033
3034                (type_::Enum(e), value::Enum(v)) => {
3035                    if let Some(node) = ctx.node_map.get(&e.get_type_id()) {
3036                        match node.which()? {
3037                            node::Enum(e) => {
3038                                let enumerants = e.get_enumerants()?;
3039                                if let Some(enumerant) = enumerants.try_get(u32::from(v)) {
3040                                    let variant =
3041                                        capitalize_first_letter(get_enumerant_name(enumerant)?);
3042                                    let type_string = typ.type_string(ctx, Leaf::Owned)?;
3043                                    Line(format!(
3044                                        "pub const {}: {} = {}::{};",
3045                                        styled_name, &type_string, &type_string, variant
3046                                    ))
3047                                } else {
3048                                    return Err(Error::failed(format!(
3049                                        "enumerant out of range: {v}"
3050                                    )));
3051                                }
3052                            }
3053                            _ => {
3054                                return Err(Error::failed(format!(
3055                                    "bad enum type ID: {}",
3056                                    e.get_type_id()
3057                                )));
3058                            }
3059                        }
3060                    } else {
3061                        return Err(Error::failed(format!(
3062                            "bad enum type ID: {}",
3063                            e.get_type_id()
3064                        )));
3065                    }
3066                }
3067
3068                (type_::Text(()), value::Text(t)) => Line(format!(
3069                    "pub const {styled_name}: &str = {:?};",
3070                    t?.to_str()?
3071                )),
3072                (type_::Data(()), value::Data(d)) => {
3073                    Line(format!("pub const {styled_name}: &[u8] = &{:?};", d?))
3074                }
3075
3076                (type_::List(_), value::List(v)) => {
3077                    generate_pointer_constant(ctx, &styled_name, typ, v)?
3078                }
3079                (type_::Struct(_), value::Struct(v)) => {
3080                    generate_pointer_constant(ctx, &styled_name, typ, v)?
3081                }
3082
3083                (type_::Interface(_t), value::Interface(())) => {
3084                    return Err(Error::unimplemented("interface constants".to_string()));
3085                }
3086                (type_::AnyPointer(_), value::AnyPointer(_pr)) => {
3087                    return Err(Error::unimplemented("anypointer constants".to_string()));
3088                }
3089
3090                _ => {
3091                    return Err(Error::failed("type does not match value".to_string()));
3092                }
3093            };
3094
3095            output.push(formatted_text);
3096        }
3097
3098        node::Annotation(annotation_reader) => {
3099            let is_generic = node_reader.get_is_generic();
3100            let params = node_reader.parameters_texts(ctx);
3101            let last_name = ctx.get_last_name(node_id)?;
3102            let mut interior = vec![];
3103            interior.push(Line(format!("pub const ID: u64 = 0x{node_id:x};")));
3104
3105            let ty = annotation_reader.get_type()?;
3106            if !is_generic {
3107                interior.push(Line(fmt!(ctx,
3108                    "pub fn get_type() -> {capnp}::introspect::Type {{ <{} as {capnp}::introspect::Introspect>::introspect() }}", ty.type_string(ctx, Leaf::Owned)?)));
3109            } else {
3110                interior.push(Line(fmt!(ctx,"pub fn get_type<{0}>() -> {capnp}::introspect::Type {1} {{ <{2} as {capnp}::introspect::Introspect>::introspect() }}", params.params, params.where_clause, ty.type_string(ctx, Leaf::Owned)?)));
3111            }
3112            output.push(Branch(vec![
3113                Line(format!("pub mod {last_name} {{")),
3114                indent(interior),
3115                Line("}".into()),
3116            ]));
3117        }
3118    }
3119
3120    Ok(Branch(output))
3121}
3122
3123// TODO: make indent take Into<FormattedText>, impl Into<FormattedText> for vec (branch)