miden_mast_package/package/
mod.rs1mod kind;
2mod manifest;
3mod section;
4mod serialization;
5
6use alloc::{format, string::String, sync::Arc, vec::Vec};
7
8use miden_assembly_syntax::{Library, Report, ast::QualifiedProcedureName};
9pub use miden_assembly_syntax::{Version, VersionError};
10use miden_core::{Program, Word};
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14pub use self::{
15 kind::{InvalidPackageKindError, PackageKind},
16 manifest::{ConstantExport, PackageExport, PackageManifest, ProcedureExport, TypeExport},
17 section::{InvalidSectionIdError, Section, SectionId},
18};
19use crate::MastArtifact;
20
21#[derive(Debug, Clone, Eq, PartialEq)]
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27pub struct Package {
28 pub name: String,
30 #[cfg_attr(feature = "serde", serde(default))]
32 pub version: Option<Version>,
33 #[cfg_attr(feature = "serde", serde(default))]
35 pub description: Option<String>,
36 pub kind: PackageKind,
38 pub mast: MastArtifact,
40 pub manifest: PackageManifest,
43 #[cfg_attr(feature = "serde", serde(default))]
46 pub sections: Vec<Section>,
47}
48
49impl Package {
50 pub fn digest(&self) -> Word {
52 self.mast.digest()
53 }
54
55 pub fn into_mast_artifact(self) -> MastArtifact {
57 self.mast
58 }
59
60 pub fn is_program(&self) -> bool {
62 matches!(self.mast, MastArtifact::Executable(_))
63 }
64
65 pub fn is_library(&self) -> bool {
67 matches!(self.mast, MastArtifact::Library(_))
68 }
69
70 pub fn unwrap_program(&self) -> Arc<Program> {
72 match self.mast {
73 MastArtifact::Executable(ref prog) => Arc::clone(prog),
74 _ => panic!("expected package to contain a program, but got a library"),
75 }
76 }
77
78 pub fn unwrap_library(&self) -> Arc<Library> {
80 match self.mast {
81 MastArtifact::Library(ref lib) => Arc::clone(lib),
82 _ => panic!("expected package to contain a library, but got an executable"),
83 }
84 }
85
86 pub fn make_executable(&self, entrypoint: &QualifiedProcedureName) -> Result<Self, Report> {
89 let MastArtifact::Library(ref library) = self.mast else {
90 return Err(Report::msg("expected library but got an executable"));
91 };
92
93 let module = library
94 .module_infos()
95 .find(|info| info.path() == entrypoint.namespace())
96 .ok_or_else(|| {
97 Report::msg(format!(
98 "invalid entrypoint: library does not contain a module named '{}'",
99 entrypoint.namespace()
100 ))
101 })?;
102 if let Some(digest) = module.get_procedure_digest_by_name(entrypoint.name()) {
103 let node_id = library.mast_forest().find_procedure_root(digest).ok_or_else(|| {
104 Report::msg(
105 "invalid entrypoint: malformed library - procedure exported, but digest has \
106 no node in the forest",
107 )
108 })?;
109
110 Ok(Self {
111 name: self.name.clone(),
112 version: self.version.clone(),
113 description: self.description.clone(),
114 kind: PackageKind::Executable,
115 mast: MastArtifact::Executable(Arc::new(Program::new(
116 library.mast_forest().clone(),
117 node_id,
118 ))),
119 manifest: PackageManifest::new(
120 self.manifest
121 .get_procedures_by_digest(&digest)
122 .cloned()
123 .map(PackageExport::Procedure),
124 )
125 .with_dependencies(self.manifest.dependencies().cloned()),
126 sections: self.sections.clone(),
127 })
128 } else {
129 Err(Report::msg(format!(
130 "invalid entrypoint: library does not export '{entrypoint}'"
131 )))
132 }
133 }
134}