hugr_model/v0/binary/
write.rs1use std::io::Write;
2
3use crate::capnp::hugr_v0_capnp as hugr_capnp;
4use crate::v0 as model;
5use crate::v0::table;
6
7#[derive(Debug, derive_more::From, derive_more::Display, derive_more::Error)]
9#[non_exhaustive]
10pub enum WriteError {
11 EncodingError(capnp::Error),
13}
14
15macro_rules! write_list {
17 ($builder:expr, $init:ident, $write:expr, $list:expr) => {
18 let mut __list_builder = $builder.reborrow().$init($list.len() as _);
19 for (index, item) in $list.iter().enumerate() {
20 $write(__list_builder.reborrow().get(index as _), item);
21 }
22 };
23}
24
25pub fn write_to_writer(package: &table::Package, writer: impl Write) -> Result<(), WriteError> {
27 let mut message = capnp::message::Builder::new_default();
28 let builder = message.init_root();
29 write_package(builder, package);
30
31 Ok(capnp::serialize_packed::write_message(writer, &message)?)
32}
33
34#[must_use]
36pub fn write_to_vec(package: &table::Package) -> Vec<u8> {
37 let mut message = capnp::message::Builder::new_default();
38 let builder = message.init_root();
39 write_package(builder, package);
40
41 let mut output = Vec::new();
42 let _ = capnp::serialize_packed::write_message(&mut output, &message);
43 output
44}
45
46fn write_package(mut builder: hugr_capnp::package::Builder, package: &table::Package) {
47 write_list!(builder, init_modules, write_module, package.modules);
48}
49
50fn write_module(mut builder: hugr_capnp::module::Builder, module: &table::Module) {
51 builder.set_root(module.root.0);
52 write_list!(builder, init_nodes, write_node, module.nodes);
53 write_list!(builder, init_regions, write_region, module.regions);
54 write_list!(builder, init_terms, write_term, module.terms);
55}
56
57fn write_node(mut builder: hugr_capnp::node::Builder, node: &table::Node) {
58 write_operation(builder.reborrow().init_operation(), &node.operation);
59 let _ = builder.set_inputs(table::LinkIndex::unwrap_slice(node.inputs));
60 let _ = builder.set_outputs(table::LinkIndex::unwrap_slice(node.outputs));
61 let _ = builder.set_meta(table::TermId::unwrap_slice(node.meta));
62 let _ = builder.set_regions(table::RegionId::unwrap_slice(node.regions));
63 builder.set_signature(node.signature.map_or(0, |t| t.0 + 1));
64}
65
66fn write_operation(mut builder: hugr_capnp::operation::Builder, operation: &table::Operation) {
67 match operation {
68 table::Operation::Dfg => builder.set_dfg(()),
69 table::Operation::Cfg => builder.set_cfg(()),
70 table::Operation::Block => builder.set_block(()),
71 table::Operation::TailLoop => builder.set_tail_loop(()),
72 table::Operation::Conditional => builder.set_conditional(()),
73 table::Operation::Custom(operation) => builder.set_custom(operation.0),
74
75 table::Operation::DefineFunc(symbol) => {
76 let builder = builder.init_func_defn();
77 write_symbol(builder, symbol);
78 }
79 table::Operation::DeclareFunc(symbol) => {
80 let builder = builder.init_func_decl();
81 write_symbol(builder, symbol);
82 }
83
84 table::Operation::DefineAlias(symbol, value) => {
85 let mut builder = builder.init_alias_defn();
86 write_symbol(builder.reborrow().init_symbol(), symbol);
87 builder.set_value(value.0);
88 }
89 table::Operation::DeclareAlias(symbol) => {
90 let builder = builder.init_alias_decl();
91 write_symbol(builder, symbol);
92 }
93
94 table::Operation::DeclareConstructor(symbol) => {
95 let builder = builder.init_constructor_decl();
96 write_symbol(builder, symbol);
97 }
98 table::Operation::DeclareOperation(symbol) => {
99 let builder = builder.init_operation_decl();
100 write_symbol(builder, symbol);
101 }
102
103 table::Operation::Import { name } => {
104 builder.set_import(*name);
105 }
106
107 table::Operation::Invalid => builder.set_invalid(()),
108 }
109}
110
111fn write_symbol(mut builder: hugr_capnp::symbol::Builder, symbol: &table::Symbol) {
112 builder.set_name(symbol.name);
113 if let Some(vis) = symbol.visibility {
114 builder.set_visibility(match vis {
115 model::Visibility::Private => hugr_capnp::Visibility::Private,
116 model::Visibility::Public => hugr_capnp::Visibility::Public,
117 })
118 } write_list!(builder, init_params, write_param, symbol.params);
120 let _ = builder.set_constraints(table::TermId::unwrap_slice(symbol.constraints));
121 builder.set_signature(symbol.signature.0);
122}
123
124fn write_param(mut builder: hugr_capnp::param::Builder, param: &table::Param) {
125 builder.set_name(param.name);
126 builder.set_type(param.r#type.0);
127}
128
129fn write_region(mut builder: hugr_capnp::region::Builder, region: &table::Region) {
130 builder.set_kind(match region.kind {
131 model::RegionKind::DataFlow => hugr_capnp::RegionKind::DataFlow,
132 model::RegionKind::ControlFlow => hugr_capnp::RegionKind::ControlFlow,
133 model::RegionKind::Module => hugr_capnp::RegionKind::Module,
134 });
135
136 let _ = builder.set_sources(table::LinkIndex::unwrap_slice(region.sources));
137 let _ = builder.set_targets(table::LinkIndex::unwrap_slice(region.targets));
138 let _ = builder.set_children(table::NodeId::unwrap_slice(region.children));
139 let _ = builder.set_meta(table::TermId::unwrap_slice(region.meta));
140 builder.set_signature(region.signature.map_or(0, |t| t.0 + 1));
141
142 if let Some(scope) = ®ion.scope {
143 write_region_scope(builder.init_scope(), scope);
144 }
145}
146
147fn write_region_scope(mut builder: hugr_capnp::region_scope::Builder, scope: &table::RegionScope) {
148 builder.set_links(scope.links);
149 builder.set_ports(scope.ports);
150}
151
152fn write_term(mut builder: hugr_capnp::term::Builder, term: &table::Term) {
153 match term {
154 table::Term::Wildcard => builder.set_wildcard(()),
155 table::Term::Var(table::VarId(node, index)) => {
156 let mut builder = builder.init_variable();
157 builder.set_node(node.0);
158 builder.set_index(*index);
159 }
160
161 table::Term::Literal(value) => match value {
162 model::Literal::Str(value) => builder.set_string(value),
163 model::Literal::Nat(value) => builder.set_nat(*value),
164 model::Literal::Bytes(value) => builder.set_bytes(value),
165 model::Literal::Float(value) => builder.set_float(value.into_inner()),
166 },
167
168 table::Term::Func(region) => builder.set_func(region.0),
169 table::Term::Apply(symbol, args) => {
170 let mut builder = builder.init_apply();
171 builder.set_symbol(symbol.0);
172 let _ = builder.set_args(table::TermId::unwrap_slice(args));
173 }
174
175 table::Term::List(parts) => {
176 write_list!(builder, init_list, write_seq_part, parts);
177 }
178
179 table::Term::Tuple(parts) => {
180 write_list!(builder, init_tuple, write_seq_part, parts);
181 }
182 }
183}
184
185fn write_seq_part(mut builder: hugr_capnp::term::seq_part::Builder, part: &table::SeqPart) {
186 match part {
187 table::SeqPart::Item(term_id) => builder.set_item(term_id.0),
188 table::SeqPart::Splice(term_id) => builder.set_splice(term_id.0),
189 }
190}