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