miden_mast_package/package/
serialization.rs1use alloc::{
23 collections::BTreeMap,
24 format,
25 string::{String, ToString},
26 sync::Arc,
27 vec::Vec,
28};
29
30use miden_assembly_syntax::{
31 Library,
32 ast::{AttributeSet, PathBuf},
33};
34use miden_core::{
35 Word,
36 program::Program,
37 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
38};
39
40use super::{ConstantExport, PackageKind, ProcedureExport, TypeExport};
41use crate::{Dependency, MastArtifact, Package, PackageExport, PackageManifest, Section};
42
43const MAGIC_PACKAGE: &[u8; 5] = b"MASP\0";
48
49const MAGIC_PROGRAM: &[u8; 4] = b"PRG\0";
51
52const MAGIC_LIBRARY: &[u8; 4] = b"LIB\0";
54
55const VERSION: [u8; 3] = [3, 0, 0];
59
60impl Serializable for Package {
64 fn write_into<W: ByteWriter>(&self, target: &mut W) {
65 target.write_bytes(MAGIC_PACKAGE);
67 target.write_bytes(&VERSION);
68
69 self.name.write_into(target);
71
72 self.version.as_ref().map(|v| v.to_string()).write_into(target);
74
75 self.description.write_into(target);
77
78 target.write_u8(self.kind.into());
80
81 self.mast.write_into(target);
83
84 self.manifest.write_into(target);
86
87 target.write_usize(self.sections.len());
89 for section in self.sections.iter() {
90 section.write_into(target);
91 }
92 }
93}
94
95impl Deserializable for Package {
96 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
97 let magic: [u8; 5] = source.read_array()?;
99 if magic != *MAGIC_PACKAGE {
100 return Err(DeserializationError::InvalidValue(format!(
101 "invalid magic bytes. Expected '{MAGIC_PACKAGE:?}', got '{magic:?}'"
102 )));
103 }
104
105 let version: [u8; 3] = source.read_array()?;
106 if version != VERSION {
107 return Err(DeserializationError::InvalidValue(format!(
108 "unsupported version. Got '{version:?}', but only '{VERSION:?}' is supported"
109 )));
110 }
111
112 let name = String::read_from(source)?;
114
115 let version = Option::<String>::read_from(source)?;
117 let version = match version {
118 Some(version) => Some(
119 crate::Version::parse(&version)
120 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?,
121 ),
122 None => None,
123 };
124
125 let description = Option::<String>::read_from(source)?;
127
128 let kind_tag = source.read_u8()?;
130 let kind = PackageKind::try_from(kind_tag)
131 .map_err(|e| DeserializationError::InvalidValue(e.to_string()))?;
132
133 let mast = MastArtifact::read_from(source)?;
135
136 let manifest = PackageManifest::read_from(source)?;
138
139 let sections = Vec::<Section>::read_from(source)?;
141
142 Ok(Self {
143 name,
144 version,
145 description,
146 kind,
147 mast,
148 manifest,
149 sections,
150 })
151 }
152}
153
154impl Serializable for MastArtifact {
158 fn write_into<W: ByteWriter>(&self, target: &mut W) {
159 match self {
160 Self::Executable(program) => {
161 target.write_bytes(MAGIC_PROGRAM);
162 program.write_into(target);
163 },
164 Self::Library(library) => {
165 target.write_bytes(MAGIC_LIBRARY);
166 library.write_into(target);
167 },
168 }
169 }
170}
171
172impl Deserializable for MastArtifact {
173 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
174 let tag: [u8; 4] = source.read_array()?;
175
176 if &tag == MAGIC_PROGRAM {
177 Program::read_from(source).map(Arc::new).map(MastArtifact::Executable)
178 } else if &tag == MAGIC_LIBRARY {
179 Library::read_from(source).map(Arc::new).map(MastArtifact::Library)
180 } else {
181 Err(DeserializationError::InvalidValue(format!(
182 "invalid MAST artifact tag: {:?}",
183 &tag
184 )))
185 }
186 }
187}
188
189#[cfg(feature = "serde")]
193impl serde::Serialize for PackageManifest {
194 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
195 where
196 S: serde::Serializer,
197 {
198 use miden_assembly_syntax::Path;
199 use serde::ser::SerializeStruct;
200
201 struct PackageExports<'a>(&'a BTreeMap<Arc<Path>, PackageExport>);
202
203 impl serde::Serialize for PackageExports<'_> {
204 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
205 where
206 S: serde::Serializer,
207 {
208 use serde::ser::SerializeSeq;
209
210 let mut serializer = serializer.serialize_seq(Some(self.0.len()))?;
211 for value in self.0.values() {
212 serializer.serialize_element(value)?;
213 }
214 serializer.end()
215 }
216 }
217
218 let mut serializer = serializer.serialize_struct("PackageManifest", 2)?;
219 serializer.serialize_field("exports", &PackageExports(&self.exports))?;
220 serializer.serialize_field("dependencies", &self.dependencies)?;
221 serializer.end()
222 }
223}
224
225#[cfg(feature = "serde")]
226impl<'de> serde::Deserialize<'de> for PackageManifest {
227 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
228 where
229 D: serde::Deserializer<'de>,
230 {
231 #[derive(serde::Deserialize)]
232 #[serde(field_identifier, rename_all = "lowercase")]
233 enum Field {
234 Exports,
235 Dependencies,
236 }
237
238 struct PackageManifestVisitor;
239
240 impl<'de> serde::de::Visitor<'de> for PackageManifestVisitor {
241 type Value = PackageManifest;
242
243 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
244 formatter.write_str("struct PackageManifest")
245 }
246
247 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
248 where
249 A: serde::de::SeqAccess<'de>,
250 {
251 let exports = seq
252 .next_element::<Vec<PackageExport>>()?
253 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
254 let dependencies = seq
255 .next_element::<Vec<Dependency>>()?
256 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
257 Ok(PackageManifest::new(exports).with_dependencies(dependencies))
258 }
259
260 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
261 where
262 A: serde::de::MapAccess<'de>,
263 {
264 let mut exports = None;
265 let mut dependencies = None;
266 while let Some(key) = map.next_key()? {
267 match key {
268 Field::Exports => {
269 if exports.is_some() {
270 return Err(serde::de::Error::duplicate_field("exports"));
271 }
272 exports = Some(map.next_value::<Vec<PackageExport>>()?);
273 },
274 Field::Dependencies => {
275 if dependencies.is_some() {
276 return Err(serde::de::Error::duplicate_field("dependencies"));
277 }
278 dependencies = Some(map.next_value::<Vec<Dependency>>()?);
279 },
280 }
281 }
282 let exports = exports.ok_or_else(|| serde::de::Error::missing_field("exports"))?;
283 let dependencies =
284 dependencies.ok_or_else(|| serde::de::Error::missing_field("dependencies"))?;
285 Ok(PackageManifest::new(exports).with_dependencies(dependencies))
286 }
287 }
288
289 deserializer.deserialize_struct(
290 "PackageManifest",
291 &["exports", "dependencies"],
292 PackageManifestVisitor,
293 )
294 }
295}
296
297impl Serializable for PackageManifest {
298 fn write_into<W: ByteWriter>(&self, target: &mut W) {
299 target.write_usize(self.num_exports());
301 for export in self.exports() {
302 export.write_into(target);
303 }
304
305 target.write_usize(self.num_dependencies());
307 for dep in self.dependencies() {
308 dep.write_into(target);
309 }
310 }
311}
312
313impl Deserializable for PackageManifest {
314 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
315 let exports_len = source.read_usize()?;
317 let mut exports = BTreeMap::new();
318 for _ in 0..exports_len {
319 let export = PackageExport::read_from(source)?;
320 exports.insert(export.path().clone(), export);
321 }
322
323 let dependencies = Vec::<Dependency>::read_from(source)?;
325
326 Ok(Self { exports, dependencies })
327 }
328}
329
330impl Serializable for PackageExport {
333 fn write_into<W: ByteWriter>(&self, target: &mut W) {
334 target.write_u8(self.tag());
335 match self {
336 Self::Procedure(export) => export.write_into(target),
337 Self::Constant(export) => export.write_into(target),
338 Self::Type(export) => export.write_into(target),
339 }
340 }
341}
342
343impl Deserializable for PackageExport {
344 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
345 match source.read_u8()? {
346 1 => ProcedureExport::read_from(source).map(Self::Procedure),
347 2 => ConstantExport::read_from(source).map(Self::Constant),
348 3 => TypeExport::read_from(source).map(Self::Type),
349 invalid => Err(DeserializationError::InvalidValue(format!(
350 "unexpected PackageExport tag: '{invalid}'"
351 ))),
352 }
353 }
354}
355
356impl Serializable for ProcedureExport {
357 fn write_into<W: ByteWriter>(&self, target: &mut W) {
358 self.path.write_into(target);
359 self.digest.write_into(target);
360 match self.signature.as_ref() {
361 Some(sig) => {
362 target.write_bool(true);
363 sig.write_into(target);
364 },
365 None => {
366 target.write_bool(false);
367 },
368 }
369 self.attributes.write_into(target);
370 }
371}
372
373impl Deserializable for ProcedureExport {
374 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
375 use miden_assembly_syntax::ast::types::FunctionType;
376 let path = PathBuf::read_from(source)?.into_boxed_path().into();
377 let digest = Word::read_from(source)?;
378 let signature = if source.read_bool()? {
379 Some(FunctionType::read_from(source)?)
380 } else {
381 None
382 };
383 let attributes = AttributeSet::read_from(source)?;
384 Ok(Self { path, digest, signature, attributes })
385 }
386}
387
388impl Serializable for ConstantExport {
389 fn write_into<W: ByteWriter>(&self, target: &mut W) {
390 self.path.write_into(target);
391 self.value.write_into(target);
392 }
393}
394
395impl Deserializable for ConstantExport {
396 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
397 let path = PathBuf::read_from(source)?.into_boxed_path().into();
398 let value = miden_assembly_syntax::ast::ConstantValue::read_from(source)?;
399 Ok(Self { path, value })
400 }
401}
402
403impl Serializable for TypeExport {
404 fn write_into<W: ByteWriter>(&self, target: &mut W) {
405 self.path.write_into(target);
406 self.ty.write_into(target);
407 }
408}
409
410impl Deserializable for TypeExport {
411 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
412 use miden_assembly_syntax::ast::types::Type;
413 let path = PathBuf::read_from(source)?.into_boxed_path().into();
414 let ty = Type::read_from(source)?;
415 Ok(Self { path, ty })
416 }
417}
418
419#[cfg(test)]
420mod tests {
421 use alloc::{
422 collections::BTreeMap,
423 string::{String, ToString},
424 sync::Arc,
425 vec,
426 vec::Vec,
427 };
428
429 use miden_assembly_syntax::{
430 Library,
431 ast::{AttributeSet, Path as AstPath, PathBuf},
432 library::{LibraryExport, ProcedureExport as LibraryProcedureExport},
433 };
434 use miden_core::{
435 mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, MastNodeExt, MastNodeId},
436 operations::Operation,
437 serde::{
438 BudgetedReader, ByteWriter, Deserializable, DeserializationError, Serializable,
439 SliceReader,
440 },
441 };
442
443 use super::{
444 MAGIC_PACKAGE, MastArtifact, Package, PackageExport, PackageKind, PackageManifest, VERSION,
445 };
446 use crate::package::manifest::ProcedureExport as PackageProcedureExport;
447
448 fn build_forest() -> (MastForest, MastNodeId) {
449 let mut forest = MastForest::new();
450 let node_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new())
451 .add_to_forest(&mut forest)
452 .expect("failed to build basic block");
453 forest.make_root(node_id);
454 (forest, node_id)
455 }
456
457 fn absolute_path(name: &str) -> Arc<AstPath> {
458 let path = PathBuf::new(name).expect("invalid path");
459 let path = path.as_path().to_absolute().into_owned();
460 Arc::from(path.into_boxed_path())
461 }
462
463 fn build_library() -> Library {
464 let (forest, node_id) = build_forest();
465 let path = absolute_path("test::proc");
466 let export = LibraryProcedureExport::new(node_id, Arc::clone(&path));
467
468 let mut exports = BTreeMap::new();
469 exports.insert(path, LibraryExport::Procedure(export));
470
471 Library::new(Arc::new(forest), exports).expect("failed to build library")
472 }
473
474 fn build_package() -> Package {
475 let library = build_library();
476 let path = absolute_path("test::proc");
477 let node_id = library.get_export_node_id(path.as_ref());
478 let digest = library.mast_forest()[node_id].digest();
479
480 let export = PackageExport::Procedure(PackageProcedureExport {
481 path: Arc::clone(&path),
482 digest,
483 signature: None,
484 attributes: AttributeSet::default(),
485 });
486
487 let manifest = PackageManifest::new([export]);
488
489 Package {
490 name: String::from("test_pkg"),
491 version: None,
492 description: None,
493 kind: PackageKind::Library,
494 mast: MastArtifact::Library(Arc::new(library)),
495 manifest,
496 sections: Vec::new(),
497 }
498 }
499
500 fn package_bytes_with_sections_count(count: usize) -> Vec<u8> {
501 let package = build_package();
502 let mut bytes = Vec::new();
503
504 bytes.write_bytes(MAGIC_PACKAGE);
505 bytes.write_bytes(&VERSION);
506 package.name.write_into(&mut bytes);
507 package.version.as_ref().map(|v| v.to_string()).write_into(&mut bytes);
508 package.description.write_into(&mut bytes);
509 bytes.write_u8(package.kind.into());
510 package.mast.write_into(&mut bytes);
511 package.manifest.write_into(&mut bytes);
512 bytes.write_usize(count);
513
514 bytes
515 }
516
517 #[test]
518 fn package_manifest_rejects_over_budget_dependencies() {
519 let mut bytes = Vec::new();
520 bytes.write_usize(0);
521 bytes.write_usize(2);
522
523 let mut reader = BudgetedReader::new(SliceReader::new(&bytes), 2);
524 let err = PackageManifest::read_from(&mut reader).unwrap_err();
525 assert!(matches!(err, DeserializationError::InvalidValue(_)));
526 }
527
528 #[test]
529 fn package_rejects_over_budget_sections() {
530 let bytes = package_bytes_with_sections_count(2);
531 let mut reader = BudgetedReader::new(SliceReader::new(&bytes), bytes.len());
532 let err = Package::read_from(&mut reader).unwrap_err();
533 assert!(matches!(err, DeserializationError::InvalidValue(_)));
534 }
535}