Skip to main content

miden_mast_package/package/
serialization.rs

1//! The serialization format of `Package` is as follows:
2//!
3//! #### Header
4//! - `MAGIC_PACKAGE`, a 4-byte tag, followed by a NUL-byte, i.e. `b"\0"`
5//! - `VERSION`, a 3-byte semantic version number, 1 byte for each component, i.e. MAJ.MIN.PATCH
6//!
7//! #### Metadata
8//! - `name` (`String`)
9//! - `version` (optional, [`miden_assembly_syntax::Version`] serialized as a `String`)
10//! - `description` (optional, `String`)
11//! - `kind` (`u8`, see [`crate::PackageKind`])
12//!
13//! #### Code
14//! - `mast` (see [`crate::MastArtifact`])
15//!
16//! #### Manifest
17//! - `manifest` (see [`crate::PackageManifest`])
18//!
19//! #### Custom Sections
20//! - `sections` (a vector of zero or more [`crate::Section`])
21
22use 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    library::{FunctionTypeDeserializer, FunctionTypeSerializer},
34};
35use miden_core::{
36    Word,
37    program::Program,
38    serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
39};
40
41use super::{ConstantExport, PackageKind, ProcedureExport, TypeExport};
42use crate::{Dependency, MastArtifact, Package, PackageExport, PackageManifest, Section};
43
44// CONSTANTS
45// ================================================================================================
46
47/// Magic string for detecting that a file is serialized [`Package`]
48const MAGIC_PACKAGE: &[u8; 5] = b"MASP\0";
49
50/// Magic string indicating a Program artifact.
51const MAGIC_PROGRAM: &[u8; 4] = b"PRG\0";
52
53/// Magic string indicating a Library artifact.
54const MAGIC_LIBRARY: &[u8; 4] = b"LIB\0";
55
56/// The format version.
57///
58/// If future modifications are made to this format, the version should be incremented by 1.
59const VERSION: [u8; 3] = [3, 0, 0];
60
61// PACKAGE SERIALIZATION/DESERIALIZATION
62// ================================================================================================
63
64impl Serializable for Package {
65    fn write_into<W: ByteWriter>(&self, target: &mut W) {
66        // Write magic & version
67        target.write_bytes(MAGIC_PACKAGE);
68        target.write_bytes(&VERSION);
69
70        // Write package name
71        self.name.write_into(target);
72
73        // Write package version
74        self.version.as_ref().map(|v| v.to_string()).write_into(target);
75
76        // Write package description
77        self.description.write_into(target);
78
79        // Write package kind
80        target.write_u8(self.kind.into());
81
82        // Write MAST artifact
83        self.mast.write_into(target);
84
85        // Write manifest
86        self.manifest.write_into(target);
87
88        // Write custom sections
89        target.write_usize(self.sections.len());
90        for section in self.sections.iter() {
91            section.write_into(target);
92        }
93    }
94}
95
96impl Deserializable for Package {
97    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
98        // Read and validate magic & version
99        let magic: [u8; 5] = source.read_array()?;
100        if magic != *MAGIC_PACKAGE {
101            return Err(DeserializationError::InvalidValue(format!(
102                "invalid magic bytes. Expected '{MAGIC_PACKAGE:?}', got '{magic:?}'"
103            )));
104        }
105
106        let version: [u8; 3] = source.read_array()?;
107        if version != VERSION {
108            return Err(DeserializationError::InvalidValue(format!(
109                "unsupported version. Got '{version:?}', but only '{VERSION:?}' is supported"
110            )));
111        }
112
113        // Read package name
114        let name = String::read_from(source)?;
115
116        // Read package version
117        let version = Option::<String>::read_from(source)?;
118        let version = match version {
119            Some(version) => Some(
120                crate::Version::parse(&version)
121                    .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?,
122            ),
123            None => None,
124        };
125
126        // Read package description
127        let description = Option::<String>::read_from(source)?;
128
129        // Read package kind
130        let kind_tag = source.read_u8()?;
131        let kind = PackageKind::try_from(kind_tag)
132            .map_err(|e| DeserializationError::InvalidValue(e.to_string()))?;
133
134        // Read MAST artifact
135        let mast = MastArtifact::read_from(source)?;
136
137        // Read manifest
138        let manifest = PackageManifest::read_from(source)?;
139
140        // Read custom sections
141        let num_sections = source.read_usize()?;
142        let mut sections = Vec::with_capacity(num_sections);
143        for _ in 0..num_sections {
144            let section = Section::read_from(source)?;
145            sections.push(section);
146        }
147
148        Ok(Self {
149            name,
150            version,
151            description,
152            kind,
153            mast,
154            manifest,
155            sections,
156        })
157    }
158}
159
160// MAST ARTIFACT SERIALIZATION/DESERIALIZATION
161// ================================================================================================
162
163impl Serializable for MastArtifact {
164    fn write_into<W: ByteWriter>(&self, target: &mut W) {
165        match self {
166            Self::Executable(program) => {
167                target.write_bytes(MAGIC_PROGRAM);
168                program.write_into(target);
169            },
170            Self::Library(library) => {
171                target.write_bytes(MAGIC_LIBRARY);
172                library.write_into(target);
173            },
174        }
175    }
176}
177
178impl Deserializable for MastArtifact {
179    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
180        let tag: [u8; 4] = source.read_array()?;
181
182        if &tag == MAGIC_PROGRAM {
183            Program::read_from(source).map(Arc::new).map(MastArtifact::Executable)
184        } else if &tag == MAGIC_LIBRARY {
185            Library::read_from(source).map(Arc::new).map(MastArtifact::Library)
186        } else {
187            Err(DeserializationError::InvalidValue(format!(
188                "invalid MAST artifact tag: {:?}",
189                &tag
190            )))
191        }
192    }
193}
194
195// PACKAGE MANIFEST SERIALIZATION/DESERIALIZATION
196// ================================================================================================
197
198#[cfg(feature = "serde")]
199impl serde::Serialize for PackageManifest {
200    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
201    where
202        S: serde::Serializer,
203    {
204        use miden_assembly_syntax::Path;
205        use serde::ser::SerializeStruct;
206
207        struct PackageExports<'a>(&'a BTreeMap<Arc<Path>, PackageExport>);
208
209        impl serde::Serialize for PackageExports<'_> {
210            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
211            where
212                S: serde::Serializer,
213            {
214                use serde::ser::SerializeSeq;
215
216                let mut serializer = serializer.serialize_seq(Some(self.0.len()))?;
217                for value in self.0.values() {
218                    serializer.serialize_element(value)?;
219                }
220                serializer.end()
221            }
222        }
223
224        let mut serializer = serializer.serialize_struct("PackageManifest", 2)?;
225        serializer.serialize_field("exports", &PackageExports(&self.exports))?;
226        serializer.serialize_field("dependencies", &self.dependencies)?;
227        serializer.end()
228    }
229}
230
231#[cfg(feature = "serde")]
232impl<'de> serde::Deserialize<'de> for PackageManifest {
233    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
234    where
235        D: serde::Deserializer<'de>,
236    {
237        #[derive(serde::Deserialize)]
238        #[serde(field_identifier, rename_all = "lowercase")]
239        enum Field {
240            Exports,
241            Dependencies,
242        }
243
244        struct PackageManifestVisitor;
245
246        impl<'de> serde::de::Visitor<'de> for PackageManifestVisitor {
247            type Value = PackageManifest;
248
249            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
250                formatter.write_str("struct PackageManifest")
251            }
252
253            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
254            where
255                A: serde::de::SeqAccess<'de>,
256            {
257                let exports = seq
258                    .next_element::<Vec<PackageExport>>()?
259                    .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
260                let dependencies = seq
261                    .next_element::<Vec<Dependency>>()?
262                    .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
263                Ok(PackageManifest::new(exports).with_dependencies(dependencies))
264            }
265
266            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
267            where
268                A: serde::de::MapAccess<'de>,
269            {
270                let mut exports = None;
271                let mut dependencies = None;
272                while let Some(key) = map.next_key()? {
273                    match key {
274                        Field::Exports => {
275                            if exports.is_some() {
276                                return Err(serde::de::Error::duplicate_field("exports"));
277                            }
278                            exports = Some(map.next_value::<Vec<PackageExport>>()?);
279                        },
280                        Field::Dependencies => {
281                            if dependencies.is_some() {
282                                return Err(serde::de::Error::duplicate_field("dependencies"));
283                            }
284                            dependencies = Some(map.next_value::<Vec<Dependency>>()?);
285                        },
286                    }
287                }
288                let exports = exports.ok_or_else(|| serde::de::Error::missing_field("exports"))?;
289                let dependencies =
290                    dependencies.ok_or_else(|| serde::de::Error::missing_field("dependencies"))?;
291                Ok(PackageManifest::new(exports).with_dependencies(dependencies))
292            }
293        }
294
295        deserializer.deserialize_struct(
296            "PackageManifest",
297            &["exports", "dependencies"],
298            PackageManifestVisitor,
299        )
300    }
301}
302
303impl Serializable for PackageManifest {
304    fn write_into<W: ByteWriter>(&self, target: &mut W) {
305        // Write exports
306        target.write_usize(self.num_exports());
307        for export in self.exports() {
308            export.write_into(target);
309        }
310
311        // Write dependencies
312        target.write_usize(self.num_dependencies());
313        for dep in self.dependencies() {
314            dep.write_into(target);
315        }
316    }
317}
318
319impl Deserializable for PackageManifest {
320    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
321        // Read exports
322        let exports_len = source.read_usize()?;
323        let mut exports = BTreeMap::new();
324        for _ in 0..exports_len {
325            let export = PackageExport::read_from(source)?;
326            exports.insert(export.path().clone(), export);
327        }
328
329        // Read dependencies
330        let deps_len = source.read_usize()?;
331        let mut dependencies = Vec::with_capacity(deps_len);
332        for _ in 0..deps_len {
333            dependencies.push(Dependency::read_from(source)?);
334        }
335
336        Ok(Self { exports, dependencies })
337    }
338}
339
340// PACKAGE EXPORT SERIALIZATION/DESERIALIZATION
341// ================================================================================================
342impl Serializable for PackageExport {
343    fn write_into<W: ByteWriter>(&self, target: &mut W) {
344        target.write_u8(self.tag());
345        match self {
346            Self::Procedure(export) => export.write_into(target),
347            Self::Constant(export) => export.write_into(target),
348            Self::Type(export) => export.write_into(target),
349        }
350    }
351}
352
353impl Deserializable for PackageExport {
354    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
355        match source.read_u8()? {
356            1 => ProcedureExport::read_from(source).map(Self::Procedure),
357            2 => ConstantExport::read_from(source).map(Self::Constant),
358            3 => TypeExport::read_from(source).map(Self::Type),
359            invalid => Err(DeserializationError::InvalidValue(format!(
360                "unexpected PackageExport tag: '{invalid}'"
361            ))),
362        }
363    }
364}
365
366impl Serializable for ProcedureExport {
367    fn write_into<W: ByteWriter>(&self, target: &mut W) {
368        self.path.write_into(target);
369        self.digest.write_into(target);
370        match self.signature.as_ref() {
371            Some(sig) => {
372                target.write_bool(true);
373                FunctionTypeSerializer(sig).write_into(target);
374            },
375            None => {
376                target.write_bool(false);
377            },
378        }
379        self.attributes.write_into(target);
380    }
381}
382
383impl Deserializable for ProcedureExport {
384    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
385        let path = PathBuf::read_from(source)?.into_boxed_path().into();
386        let digest = Word::read_from(source)?;
387        let signature = if source.read_bool()? {
388            Some(FunctionTypeDeserializer::read_from(source)?.0)
389        } else {
390            None
391        };
392        let attributes = AttributeSet::read_from(source)?;
393        Ok(Self { path, digest, signature, attributes })
394    }
395}
396
397impl Serializable for ConstantExport {
398    fn write_into<W: ByteWriter>(&self, target: &mut W) {
399        self.path.write_into(target);
400        self.value.write_into(target);
401    }
402}
403
404impl Deserializable for ConstantExport {
405    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
406        let path = PathBuf::read_from(source)?.into_boxed_path().into();
407        let value = miden_assembly_syntax::ast::ConstantValue::read_from(source)?;
408        Ok(Self { path, value })
409    }
410}
411
412impl Serializable for TypeExport {
413    fn write_into<W: ByteWriter>(&self, target: &mut W) {
414        use miden_assembly_syntax::library::TypeSerializer;
415
416        self.path.write_into(target);
417        TypeSerializer(&self.ty).write_into(target);
418    }
419}
420
421impl Deserializable for TypeExport {
422    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
423        use miden_assembly_syntax::library::TypeDeserializer;
424
425        let path = PathBuf::read_from(source)?.into_boxed_path().into();
426        let ty = TypeDeserializer::read_from(source)?.0;
427        Ok(Self { path, ty })
428    }
429}