Skip to main content

miden_mast_package/package/serialization/
mod.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` ([`miden_assembly_syntax::Version`] serialized as a `String`)
10//! - `description` (optional, `String`)
11//! - `kind` (`u8`, see [`crate::TargetType`])
12//!
13//! #### Code
14//! - `mast` (see [`miden_assembly_syntax::Library`])
15//!
16//! #### Manifest
17//! - `manifest` (see [`crate::PackageManifest`])
18//!
19//! #### Custom Sections
20//! - `sections` (a vector of zero or more [`crate::Section`])
21//!
22//! #### Reader trust policy
23//!
24//! Package deserialization has two independently important trust decisions:
25//!
26//! - whether the embedded [`MastForest`] must be recomputed and validated;
27//! - whether package-owned debug sections may be exposed to callers.
28//!
29//! [`Package::read_from`] and [`Package::read_from_bytes`] are the normal untrusted readers. They
30//! validate the embedded MAST forest and package-owned debug information before returning the
31//! package. Use them for bytes received across a trust boundary.
32//!
33//! [`Package::read_from_trusted`] and [`Package::read_from_bytes_trusted`] are for local
34//! files/cache entries controlled by the same trusted build or execution system. They preserve
35//! package-owned debug sections and skip embedded MAST and manifest cross-check validation.
36//!
37//! Embedded kernel package bytes are stored in the opaque `kernel` custom section. Decoding an
38//! embedded kernel through the package API uses the untrusted reader, so nested package-owned debug
39//! information is validated and retained under the same policy.
40
41use alloc::{
42    format,
43    string::{String, ToString},
44    sync::Arc,
45    vec::Vec,
46};
47
48use miden_assembly_syntax::ast::{self, AttributeSet, PathBuf};
49use miden_core::{
50    Word,
51    mast::{MastForest, MastNodeExt, MastNodeId, UntrustedMastForest},
52    serde::{
53        BudgetedReader, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
54        SliceReader,
55    },
56};
57
58use super::{
59    ConstantExport, PackageId, PackageModule, PackageSubmodule, ProcedureExport, TargetType,
60    TypeExport,
61};
62use crate::{
63    Dependency, ManifestValidationError, Package, PackageExport, PackageManifest, Section,
64    debug_info::DebugSourceNodeId,
65};
66
67#[cfg(test)]
68mod tests;
69
70// CONSTANTS
71// ================================================================================================
72
73/// Magic string for detecting that a file is serialized [`Package`]
74const MAGIC_PACKAGE: &[u8; 5] = b"MASP\0";
75
76/// The format version.
77///
78/// If future modifications are made to this format, the version should be incremented by 1.
79const VERSION: [u8; 3] = [7, 0, 0];
80
81/// Byte-read budget multiplier for package deserialization from a byte slice.
82///
83/// The budget is intentionally finite to reject malicious length prefixes, but larger than the
84/// source length because collection deserialization uses conservative per-element size estimates.
85const PACKAGE_BYTE_READ_BUDGET_MULTIPLIER: usize = 64;
86
87// PACKAGE SERIALIZATION/DESERIALIZATION
88// ================================================================================================
89
90impl Package {
91    #[doc(hidden)]
92    pub fn write_header_into<W: ByteWriter>(&self, target: &mut W) {
93        // Write magic & version
94        target.write_bytes(MAGIC_PACKAGE);
95        target.write_bytes(&VERSION);
96
97        // Write package name
98        self.name.write_into(target);
99
100        // Write package version
101        self.version.to_string().write_into(target);
102
103        // Write package description
104        self.description.write_into(target);
105
106        // Write package kind
107        target.write_u8(self.kind.into());
108    }
109
110    #[doc(hidden)]
111    pub fn write_trailer_into<W: ByteWriter>(&self, target: &mut W) {
112        // Write manifest
113        self.manifest.write_into(target);
114
115        // Write custom sections
116        target.write_usize(self.sections.len());
117        for section in self.sections.iter() {
118            section.write_into(target);
119        }
120    }
121
122    /// Reads a package from trusted storage without validating the embedded MAST forest.
123    ///
124    /// # Trust boundary
125    ///
126    /// This skips embedded MAST and manifest cross-check validation and trusts serialized node
127    /// digests. Use it for a package written and retained by the same trusted system, such as a
128    /// local build cache.
129    ///
130    /// Do not use this for user-controlled packages, network input, or any other package that
131    /// crosses a trust boundary. Use [`Package::read_from`] for those inputs.
132    #[track_caller]
133    pub fn read_from_trusted<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
134        let header = Self::read_header_from(source)?;
135        let mast_forest = Self::read_mast_forest(source, false)?;
136        Self::read_from_with_header_and_mast(source, header, mast_forest, false, false)
137    }
138
139    /// Reads package bytes from trusted storage without validating the embedded MAST forest.
140    ///
141    /// # Trust boundary
142    ///
143    /// This skips embedded MAST and manifest cross-check validation and trusts serialized node
144    /// digests. Use it for a package written and retained by the same trusted system, such as a
145    /// local build cache. This method still applies the finite byte-read budget used by
146    /// [`Package::read_from_bytes`].
147    ///
148    /// Do not use this for user-controlled packages, network input, or any other package that
149    /// crosses a trust boundary. Use [`Package::read_from_bytes`] for those inputs.
150    #[track_caller]
151    pub fn read_from_bytes_trusted(bytes: &[u8]) -> Result<Self, DeserializationError> {
152        let budget = bytes.len().saturating_mul(PACKAGE_BYTE_READ_BUDGET_MULTIPLIER);
153        let mut reader = BudgetedReader::new(SliceReader::new(bytes), budget);
154        Self::read_from_trusted(&mut reader)
155    }
156
157    #[track_caller]
158    fn read_mast_forest<R: ByteReader>(
159        source: &mut R,
160        validate_mast_forest: bool,
161    ) -> Result<Arc<MastForest>, DeserializationError> {
162        if validate_mast_forest {
163            UntrustedMastForest::read_from(source)?.validate().map_err(|err| {
164                DeserializationError::InvalidValue(format!(
165                    "library contains an invalid untrusted MAST forest: {err}"
166                ))
167            })
168        } else {
169            MastForest::read_from(source)
170        }
171        .map(Arc::new)
172    }
173}
174
175impl Serializable for Package {
176    fn write_into<W: ByteWriter>(&self, target: &mut W) {
177        self.write_header_into(target);
178
179        // Write MAST artifact
180        self.mast.write_into(target);
181
182        self.write_trailer_into(target);
183    }
184}
185
186struct PackageHeader {
187    name: PackageId,
188    version: crate::Version,
189    description: Option<String>,
190    kind: TargetType,
191}
192
193impl Package {
194    fn read_header_from<R: ByteReader>(
195        source: &mut R,
196    ) -> Result<PackageHeader, DeserializationError> {
197        // Read and validate magic & version
198        let magic: [u8; 5] = source.read_array()?;
199        if magic != *MAGIC_PACKAGE {
200            return Err(DeserializationError::InvalidValue(format!(
201                "invalid magic bytes. Expected '{MAGIC_PACKAGE:?}', got '{magic:?}'"
202            )));
203        }
204
205        let version: [u8; 3] = source.read_array()?;
206        if version != VERSION {
207            return Err(DeserializationError::InvalidValue(format!(
208                "unsupported version. Got '{version:?}', but only '{VERSION:?}' is supported"
209            )));
210        }
211
212        // Read package name
213        let name = PackageId::read_from(source)?;
214
215        // Read package version
216        let version = String::read_from(source)?
217            .parse::<crate::Version>()
218            .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
219
220        // Read package description
221        let description = Option::<String>::read_from(source)?;
222
223        // Read package kind
224        let kind_tag = source.read_u8()?;
225        let kind = TargetType::try_from(kind_tag)
226            .map_err(|e| DeserializationError::InvalidValue(e.to_string()))?;
227
228        Ok(PackageHeader { name, version, description, kind })
229    }
230
231    fn read_from_with_header_and_mast<R: ByteReader>(
232        source: &mut R,
233        header: PackageHeader,
234        mast: Arc<MastForest>,
235        validate_manifest: bool,
236        validate_debug_sections: bool,
237    ) -> Result<Self, DeserializationError> {
238        let PackageHeader { name, version, description, kind } = header;
239
240        // Read manifest
241        let manifest = if validate_manifest {
242            PackageManifest::read_from_safe(source, &mast)?
243        } else {
244            PackageManifest::read_from_trusted(source, &mast)?
245        };
246
247        // Read custom sections
248        let sections = Vec::<Section>::read_from(source)?;
249
250        let package = Self {
251            name,
252            version,
253            description,
254            kind,
255            mast,
256            manifest,
257            sections,
258            debug_sections_trusted: true,
259        };
260
261        if validate_debug_sections {
262            package.debug_info().map_err(|err| {
263                DeserializationError::InvalidValue(format!(
264                    "package contains invalid debug information: {err}"
265                ))
266            })?;
267        }
268
269        if validate_manifest {
270            package
271                .interface_commitment()
272                .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
273        }
274
275        Ok(package)
276    }
277}
278
279impl Deserializable for Package {
280    /// Reads and validates a package from potentially adversarial input.
281    ///
282    /// This validates the embedded MAST forest, manifest references, and package-owned debug
283    /// information before returning. The caller's [`ByteReader`] controls the resource budget. For
284    /// a byte slice, prefer [`Package::read_from_bytes`], which applies a finite byte-read budget.
285    /// Use [`Package::read_from_trusted`] for packages written and retained by the same trusted
286    /// system when repeating these checks is unnecessary.
287    #[track_caller]
288    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
289        let header = Self::read_header_from(source)?;
290
291        // Read MAST artifact
292        let mast = Self::read_mast_forest(source, true)?;
293
294        Self::read_from_with_header_and_mast(source, header, mast, true, true)
295    }
296
297    /// Reads and validates a package from a potentially adversarial byte slice.
298    ///
299    /// This is the recommended reader for untrusted package bytes. It applies a finite byte-read
300    /// budget and validates the embedded MAST forest, manifest references, and package-owned debug
301    /// information. Use [`Package::read_from_bytes_trusted`] for packages written and retained by
302    /// the same trusted system when repeating these checks is unnecessary.
303    #[track_caller]
304    fn read_from_bytes(bytes: &[u8]) -> Result<Self, DeserializationError> {
305        let budget = bytes.len().saturating_mul(PACKAGE_BYTE_READ_BUDGET_MULTIPLIER);
306        let mut reader = BudgetedReader::new(SliceReader::new(bytes), budget);
307        Self::read_from(&mut reader)
308    }
309}
310
311// PACKAGE MANIFEST SERIALIZATION/DESERIALIZATION
312// ================================================================================================
313
314impl Serializable for PackageManifest {
315    fn write_into<W: ByteWriter>(&self, target: &mut W) {
316        // Write exports
317        target.write_usize(self.num_exports());
318        for export in self.exports() {
319            export.write_into(target);
320        }
321
322        // Write module surfaces
323        target.write_usize(self.num_modules());
324        for module in self.modules() {
325            module.write_into(target);
326        }
327
328        // Write dependencies
329        target.write_usize(self.num_dependencies());
330        for dep in self.dependencies() {
331            dep.write_into(target);
332        }
333
334        // Write entrypoint
335        if let Some(entrypoint) = self.entrypoint.as_ref() {
336            target.write_bool(true);
337            entrypoint.write_into(target);
338        } else {
339            target.write_bool(false);
340        }
341    }
342}
343
344impl PackageManifest {
345    pub fn read_from_trusted<R: ByteReader>(
346        source: &mut R,
347        mast: &MastForest,
348    ) -> Result<Self, DeserializationError> {
349        // Read exports
350        let exports_len = source.read_usize()?;
351        let max_exports = source.max_alloc(PackageExport::min_serialized_size());
352        if exports_len > max_exports {
353            return Err(DeserializationError::InvalidValue(format!(
354                "requested {exports_len} elements but reader can provide at most {max_exports}"
355            )));
356        }
357        let mut exports = Vec::with_capacity(exports_len);
358        for _ in 0..exports_len {
359            exports.push(PackageExport::read_from_trusted(source, mast)?);
360        }
361
362        // Read module surfaces
363        let modules_len = source.read_usize()?;
364        let max_modules = source.max_alloc(PackageModule::min_serialized_size());
365        if modules_len > max_modules {
366            return Err(DeserializationError::InvalidValue(format!(
367                "requested {modules_len} elements but reader can provide at most {max_modules}"
368            )));
369        }
370        let modules = source.read_many_iter(modules_len)?.collect::<Result<Vec<_>, _>>()?;
371
372        // Read dependencies
373        let dependencies = Vec::<Dependency>::read_from(source)?;
374
375        // Read entrypoint
376        let entrypoint = if source.read_bool()? {
377            Some(PathBuf::read_from(source).map(Arc::<ast::Path>::from)?)
378        } else {
379            None
380        };
381
382        PackageManifest::new(exports)
383            .and_then(|manifest| manifest.with_modules(modules))
384            .and_then(|manifest| manifest.with_dependencies(dependencies))
385            .and_then(|manifest| {
386                if let Some(entrypoint) = entrypoint {
387                    manifest.with_entrypoint(entrypoint)
388                } else {
389                    Ok(manifest)
390                }
391            })
392            .map_err(|error| DeserializationError::InvalidValue(error.to_string()))
393    }
394
395    pub fn read_from_safe<R: ByteReader>(
396        source: &mut R,
397        mast: &MastForest,
398    ) -> Result<Self, DeserializationError> {
399        // Read exports
400        let exports_len = source.read_usize()?;
401        let max_exports = source.max_alloc(PackageExport::min_serialized_size());
402        if exports_len > max_exports {
403            return Err(DeserializationError::InvalidValue(format!(
404                "requested {exports_len} elements but reader can provide at most {max_exports}"
405            )));
406        }
407        let mut exports = Vec::with_capacity(exports_len);
408        for _ in 0..exports_len {
409            exports.push(PackageExport::read_from_safe(source, mast)?);
410        }
411
412        // Read module surfaces
413        let modules_len = source.read_usize()?;
414        let max_modules = source.max_alloc(PackageModule::min_serialized_size());
415        if modules_len > max_modules {
416            return Err(DeserializationError::InvalidValue(format!(
417                "requested {modules_len} elements but reader can provide at most {max_modules}"
418            )));
419        }
420        let modules = source.read_many_iter(modules_len)?.collect::<Result<Vec<_>, _>>()?;
421
422        // Read dependencies
423        let dependencies = Vec::<Dependency>::read_from(source)?;
424
425        // Read entrypoint
426        let entrypoint = if source.read_bool()? {
427            Some(PathBuf::read_from(source).map(Arc::<ast::Path>::from)?)
428        } else {
429            None
430        };
431
432        PackageManifest::new(exports)
433            .and_then(|manifest| manifest.with_modules(modules))
434            .and_then(|manifest| manifest.with_dependencies(dependencies))
435            .and_then(|manifest| {
436                if let Some(entrypoint) = entrypoint {
437                    manifest.with_entrypoint(entrypoint)
438                } else {
439                    Ok(manifest)
440                }
441            })
442            .map_err(|error| DeserializationError::InvalidValue(error.to_string()))
443    }
444}
445
446impl Deserializable for PackageManifest {
447    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
448        // Read exports
449        let exports_len = source.read_usize()?;
450        let exports = source.read_many_iter(exports_len)?.collect::<Result<Vec<_>, _>>()?;
451
452        // Read module surfaces
453        let modules_len = source.read_usize()?;
454        let modules = source.read_many_iter(modules_len)?.collect::<Result<Vec<_>, _>>()?;
455
456        // Read dependencies
457        let dependencies = Vec::<Dependency>::read_from(source)?;
458
459        // Read entrypoint
460        let entrypoint = if source.read_bool()? {
461            Some(PathBuf::read_from(source).map(Arc::<ast::Path>::from)?)
462        } else {
463            None
464        };
465
466        PackageManifest::new(exports)
467            .and_then(|manifest| manifest.with_modules(modules))
468            .and_then(|manifest| manifest.with_dependencies(dependencies))
469            .and_then(|manifest| {
470                if let Some(entrypoint) = entrypoint {
471                    manifest.with_entrypoint(entrypoint)
472                } else {
473                    Ok(manifest)
474                }
475            })
476            .map_err(|error| DeserializationError::InvalidValue(error.to_string()))
477    }
478}
479
480// PACKAGE MODULE SURFACE SERIALIZATION/DESERIALIZATION
481// ================================================================================================
482
483impl Serializable for PackageModule {
484    fn write_into<W: ByteWriter>(&self, target: &mut W) {
485        self.path.write_into(target);
486        target.write_usize(self.submodules.len());
487        for submodule in self.submodules.iter() {
488            submodule.write_into(target);
489        }
490    }
491}
492
493impl Deserializable for PackageModule {
494    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
495        let path = PathBuf::read_from(source)?.into_boxed_path().into();
496        let submodules = Vec::<PackageSubmodule>::read_from(source)?;
497        Ok(Self { path, submodules })
498    }
499}
500
501impl Serializable for PackageSubmodule {
502    fn write_into<W: ByteWriter>(&self, target: &mut W) {
503        self.name.write_into(target);
504    }
505}
506
507impl Deserializable for PackageSubmodule {
508    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
509        let name = ast::Ident::read_from(source)?;
510        Ok(Self { name })
511    }
512}
513
514// PACKAGE EXPORT SERIALIZATION/DESERIALIZATION
515// ================================================================================================
516
517impl Serializable for PackageExport {
518    fn write_into<W: ByteWriter>(&self, target: &mut W) {
519        target.write_u8(self.tag());
520        match self {
521            Self::Procedure(export) => export.write_into(target),
522            Self::Constant(export) => export.write_into(target),
523            Self::Type(export) => export.write_into(target),
524        }
525    }
526}
527
528impl PackageExport {
529    pub fn read_from_trusted<R: ByteReader>(
530        source: &mut R,
531        mast: &MastForest,
532    ) -> Result<Self, DeserializationError> {
533        match source.read_u8()? {
534            1 => ProcedureExport::read_from_trusted(source, mast).map(Self::Procedure),
535            2 => ConstantExport::read_from(source).map(Self::Constant),
536            3 => TypeExport::read_from(source).map(Self::Type),
537            invalid => Err(DeserializationError::InvalidValue(format!(
538                "unexpected PackageExport tag: '{invalid}'"
539            ))),
540        }
541    }
542
543    pub fn read_from_safe<R: ByteReader>(
544        source: &mut R,
545        mast: &MastForest,
546    ) -> Result<Self, DeserializationError> {
547        match source.read_u8()? {
548            1 => ProcedureExport::read_from_safe(source, mast).map(Self::Procedure),
549            2 => ConstantExport::read_from(source).map(Self::Constant),
550            3 => TypeExport::read_from(source).map(Self::Type),
551            invalid => Err(DeserializationError::InvalidValue(format!(
552                "unexpected PackageExport tag: '{invalid}'"
553            ))),
554        }
555    }
556}
557
558impl Deserializable for PackageExport {
559    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
560        match source.read_u8()? {
561            1 => ProcedureExport::read_from(source).map(Self::Procedure),
562            2 => ConstantExport::read_from(source).map(Self::Constant),
563            3 => TypeExport::read_from(source).map(Self::Type),
564            invalid => Err(DeserializationError::InvalidValue(format!(
565                "unexpected PackageExport tag: '{invalid}'"
566            ))),
567        }
568    }
569}
570
571impl Serializable for ProcedureExport {
572    fn write_into<W: ByteWriter>(&self, target: &mut W) {
573        self.path.write_into(target);
574        if let Some(node_id) = self.node {
575            target.write_bool(true);
576            target.write_u32(node_id.into());
577        } else {
578            target.write_bool(false);
579        }
580        if let Some(source_node) = self.source_node {
581            target.write_bool(true);
582            source_node.write_into(target);
583        } else {
584            target.write_bool(false);
585        }
586        self.digest.write_into(target);
587        match self.signature.as_ref() {
588            Some(sig) => {
589                target.write_bool(true);
590                sig.write_into(target);
591            },
592            None => {
593                target.write_bool(false);
594            },
595        }
596        self.attributes.write_into(target);
597    }
598}
599
600impl ProcedureExport {
601    pub fn read_from_trusted<R: ByteReader>(
602        source: &mut R,
603        mast: &MastForest,
604    ) -> Result<Self, DeserializationError> {
605        use miden_assembly_syntax::ast::types::FunctionType;
606        let path = PathBuf::read_from(source)?.into_boxed_path().into();
607        let node = if source.read_bool()? {
608            Some(MastNodeId::from_u32_safe(source.read_u32()?, mast)?)
609        } else {
610            None
611        };
612        let source_node = if source.read_bool()? {
613            Some(DebugSourceNodeId::read_from(source)?)
614        } else {
615            None
616        };
617        let digest = Word::read_from(source)?;
618        let signature = if source.read_bool()? {
619            Some(FunctionType::read_from(source)?)
620        } else {
621            None
622        };
623        let attributes = AttributeSet::read_from(source)?;
624        Ok(Self {
625            path,
626            node,
627            source_node,
628            digest,
629            signature,
630            attributes,
631        })
632    }
633
634    pub fn read_from_safe<R: ByteReader>(
635        source: &mut R,
636        mast: &MastForest,
637    ) -> Result<Self, DeserializationError> {
638        use miden_assembly_syntax::ast::types::FunctionType;
639        let path = PathBuf::read_from(source)?.into_boxed_path().into();
640        let node = if source.read_bool()? {
641            let node_id = MastNodeId::from_u32_safe(source.read_u32()?, mast)?;
642            if !mast.is_procedure_root(node_id) {
643                return Err(DeserializationError::InvalidValue(
644                    ManifestValidationError::InvalidProcedureExport { path }.to_string(),
645                ));
646            }
647            Some(node_id)
648        } else {
649            None
650        };
651        let source_node = if source.read_bool()? {
652            Some(DebugSourceNodeId::read_from(source)?)
653        } else {
654            None
655        };
656        let digest = Word::read_from(source)?;
657        // Ensure that the digest associated with `node` matches the provided digest
658        if let Some(node) = node
659            && digest != mast[node].digest()
660        {
661            return Err(DeserializationError::InvalidValue(
662                ManifestValidationError::InvalidProcedureExport { path }.to_string(),
663            ));
664        }
665        let signature = if source.read_bool()? {
666            Some(FunctionType::read_from(source)?)
667        } else {
668            None
669        };
670        let attributes = AttributeSet::read_from(source)?;
671        Ok(Self {
672            path,
673            node,
674            source_node,
675            digest,
676            signature,
677            attributes,
678        })
679    }
680}
681
682impl Deserializable for ProcedureExport {
683    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
684        use miden_assembly_syntax::ast::types::FunctionType;
685        let path = PathBuf::read_from(source)?.into_boxed_path().into();
686        let node = if source.read_bool()? {
687            Some(MastNodeId::new_unchecked(source.read_u32()?))
688        } else {
689            None
690        };
691        let source_node = if source.read_bool()? {
692            Some(DebugSourceNodeId::read_from(source)?)
693        } else {
694            None
695        };
696        let digest = Word::read_from(source)?;
697        let signature = if source.read_bool()? {
698            Some(FunctionType::read_from(source)?)
699        } else {
700            None
701        };
702        let attributes = AttributeSet::read_from(source)?;
703        Ok(Self {
704            path,
705            node,
706            source_node,
707            digest,
708            signature,
709            attributes,
710        })
711    }
712}
713
714impl Serializable for ConstantExport {
715    fn write_into<W: ByteWriter>(&self, target: &mut W) {
716        self.path.write_into(target);
717        self.value.write_into(target);
718    }
719}
720
721impl Deserializable for ConstantExport {
722    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
723        let path = PathBuf::read_from(source)?.into_boxed_path().into();
724        let value = ast::ConstantValue::read_from(source)?;
725        Ok(Self { path, value })
726    }
727}
728
729impl Serializable for TypeExport {
730    fn write_into<W: ByteWriter>(&self, target: &mut W) {
731        self.path.write_into(target);
732        self.ty.write_into(target);
733    }
734}
735
736impl Deserializable for TypeExport {
737    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
738        use miden_assembly_syntax::ast::types::Type;
739        let path = PathBuf::read_from(source)?.into_boxed_path().into();
740        let ty = Type::read_from(source)?;
741        Ok(Self { path, ty })
742    }
743}