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