macroonz_compiler/recipe/
encode.rs1use super::types::{ProjectionStanding, RecipeRelationPayload, RecipeShellContent};
4use super::{Recipe, RecipeRelationRequirements, RecipeRole, RecipeTransitionEffect};
5use crate::identity::{encode_bytes, encode_length};
6use crate::kind::{CanonicalContent, Role};
7
8impl CanonicalContent for Recipe {
9 fn encode_content_into(&self, into: &mut Vec<u8>) {
10 encode_bytes(self.module_name().as_bytes(), into);
11 encode_bytes(&self.module_head().canonical_bytes(), into);
12 encode_bytes(&self.authored_body().canonical_bytes(), into);
13 encode_length(self.vocabularies().count(), into);
14 for vocabulary in self.vocabularies() {
15 encode_bytes(vocabulary.name().as_bytes(), into);
16 encode_length(vocabulary.members().count(), into);
17 for member in vocabulary.members().members() {
18 encode_bytes(member.spelling().as_bytes(), into);
19 }
20 }
21 encode_length(self.relations().count(), into);
22 for relation in self.relations() {
23 encode_bytes(relation.name().as_bytes(), into);
24 encode_bytes(relation.left_vocabulary().as_bytes(), into);
25 encode_bytes(relation.right_vocabulary().as_bytes(), into);
26 encode_bytes(relation.payload_kind().name().as_bytes(), into);
27 encode_length(relation.row_count(), into);
28 for row in relation.rows() {
29 encode_bytes(row.left().as_bytes(), into);
30 encode_bytes(row.right().as_bytes(), into);
31 encode_relation_payload(row.payload(), into);
32 }
33 encode_relation_requirements(relation.requirements(), into);
34 }
35 encode_length(self.codecs().count(), into);
36 for codec in self.codecs() {
37 encode_bytes(codec.name().as_bytes(), into);
38 encode_bytes(&codec.content().canonical_content_bytes(), into);
39 }
40 encode_optional_name(
41 self.transition_relation().map(super::RecipeRelation::name),
42 into,
43 );
44 for role in RecipeRole::ALL {
45 encode_bytes(role.name().as_bytes(), into);
46 match self.standing(*role) {
47 ProjectionStanding::NotRequested => into.push(0),
48 ProjectionStanding::Generated(lowering) => {
49 into.push(1);
50 encode_lowering(lowering, into);
51 }
52 ProjectionStanding::FeatureUnavailable => into.push(2),
53 ProjectionStanding::TargetUnavailable => into.push(3),
54 }
55 encode_bytes(role.destination().name().as_bytes(), into);
56 encode_evidence(self.evidence(*role), into);
57 }
58 match self.support() {
59 None => into.push(0),
60 Some(address) => {
61 into.push(1);
62 encode_bytes(address.spelling().as_bytes(), into);
63 }
64 }
65 }
66}
67
68fn encode_relation_payload(payload: &RecipeRelationPayload, into: &mut Vec<u8>) {
69 match payload {
70 RecipeRelationPayload::Unlabeled => into.push(0),
71 RecipeRelationPayload::Path(path) => {
72 into.push(1);
73 encode_bytes(&path.canonical_bytes(), into);
74 }
75 RecipeRelationPayload::ExactRust(exact) => {
76 into.push(2);
77 encode_bytes(&exact.canonical_bytes(), into);
78 }
79 RecipeRelationPayload::Transition { target, effect, .. } => {
80 into.push(3);
81 encode_bytes(target.as_bytes(), into);
82 match effect {
83 RecipeTransitionEffect::Path(path) => {
84 into.push(0);
85 encode_bytes(&path.canonical_bytes(), into);
86 }
87 RecipeTransitionEffect::ExactRust {
88 target_binding,
89 body,
90 } => {
91 into.push(1);
92 target_binding.encode_into(into);
93 encode_bytes(&body.canonical_bytes(), into);
94 }
95 }
96 }
97 }
98}
99
100fn encode_relation_requirements(requirements: &RecipeRelationRequirements, into: &mut Vec<u8>) {
101 encode_optional_name(
102 requirements
103 .empty()
104 .map(crate::relation::EmptyPosture::name),
105 into,
106 );
107 encode_optional_name(
108 requirements
109 .repetition()
110 .map(crate::relation::RepetitionPosture::name),
111 into,
112 );
113 encode_optional_name(
114 requirements
115 .left_membership()
116 .map(crate::relation::MembershipPosture::name),
117 into,
118 );
119 encode_optional_name(
120 requirements
121 .right_membership()
122 .map(crate::relation::MembershipPosture::name),
123 into,
124 );
125 encode_optional_name(
126 requirements
127 .left_completeness()
128 .map(crate::relation::CompletenessPosture::name),
129 into,
130 );
131 encode_optional_name(
132 requirements
133 .right_completeness()
134 .map(crate::relation::CompletenessPosture::name),
135 into,
136 );
137 encode_optional_name(
138 requirements
139 .density()
140 .map(crate::relation::DensityPosture::name),
141 into,
142 );
143 encode_optional_name(
144 requirements
145 .absence()
146 .map(crate::relation::AbsencePosture::name),
147 into,
148 );
149 encode_optional_name(
150 requirements
151 .self_relation()
152 .map(crate::relation::SelfRelationPosture::name),
153 into,
154 );
155 encode_optional_name(
156 requirements
157 .cycle()
158 .map(crate::relation::CyclePosture::name),
159 into,
160 );
161}
162
163fn encode_lowering(lowering: &super::EffectiveProjection, into: &mut Vec<u8>) {
164 encode_bytes(lowering.source().name().as_bytes(), into);
165 encode_optional_name(lowering.name(), into);
166 encode_optional_name(lowering.subject(), into);
167 match lowering.dispatch_bindings() {
168 None => into.push(0),
169 Some([state, event]) => {
170 into.push(1);
171 encode_bytes(state.as_bytes(), into);
172 encode_bytes(event.as_bytes(), into);
173 }
174 }
175 let relation_tables = lowering.relation_tables().collect::<Vec<_>>();
176 encode_length(relation_tables.len(), into);
177 for table in relation_tables {
178 encode_bytes(table.relation().as_bytes(), into);
179 encode_bytes(table.function().as_bytes(), into);
180 encode_bytes(table.source().name().as_bytes(), into);
181 match table.exact_rust() {
182 None => into.push(0),
183 Some(exact) => {
184 into.push(1);
185 encode_bytes(&exact.canonical_bytes(), into);
186 }
187 }
188 }
189 let Some(exact) = lowering.exact_rust() else {
190 return;
191 };
192 encode_bytes(&exact.canonical_bytes(), into);
193}
194
195fn encode_evidence(evidence: Option<&super::RecipeEvidence>, into: &mut Vec<u8>) {
196 let Some(evidence) = evidence else {
197 into.push(0);
198 return;
199 };
200 into.push(1);
201 encode_optional_name(evidence.target().map(super::EvidenceTarget::name), into);
202 encode_bytes(&evidence.body().canonical_bytes(), into);
203}
204
205fn encode_optional_name(name: Option<&str>, into: &mut Vec<u8>) {
206 match name {
207 None => into.push(0),
208 Some(name) => {
209 into.push(1);
210 encode_bytes(name.as_bytes(), into);
211 }
212 }
213}
214
215impl CanonicalContent for RecipeShellContent {
216 fn encode_content_into(&self, into: &mut Vec<u8>) {
217 encode_bytes(self.recipe.as_bytes(), into);
218 match self.support {
219 None => into.push(0),
220 Some(support) => {
221 into.push(1);
222 encode_bytes(support.as_bytes(), into);
223 }
224 }
225 }
226}