Skip to main content

miden_assembly/project/
providers.rs

1mod masm;
2
3use miden_assembly_syntax::debuginfo::SourceManager;
4use miden_package_registry::PackageRegistryAndProvider;
5use miden_project::ProjectDependencyGraph;
6
7pub use self::masm::MasmSourceProvider;
8use super::*;
9
10/// This struct provides important context about the current target being assembled to
11/// implementations of the [ProjectSourceProvider] trait.
12pub struct TargetAssemblyContext<'a> {
13    /// The package manifest for the target being assembled
14    pub package: Arc<ProjectPackage>,
15    /// The resolved/canonicalized package manifest path
16    pub manifest_path: &'a std::path::Path,
17    /// The resolved/canonicalized path to the directory containing `manifest_path`
18    pub project_root: &'a std::path::Path,
19    /// The resolved/canonicalized path to the root source file of `target`
20    pub resolved_target_root: Box<std::path::Path>,
21    /// The target being assembled
22    pub target: &'a Target,
23    /// The build profile selected for this assembly session
24    pub profile: &'a Profile,
25    /// The dependency graph computed for this assembly session
26    pub dependency_graph: &'a ProjectDependencyGraph,
27    /// The current source manager
28    pub source_manager: Arc<dyn SourceManager>,
29    /// The current package store of the assembler
30    pub package_registry: &'a dyn PackageRegistryAndProvider,
31    /// The assembler-wide `warnings_as_errors` flag
32    pub warnings_as_errors: bool,
33}
34
35impl<'a> TargetAssemblyContext<'a> {
36    pub fn new(
37        package: Arc<ProjectPackage>,
38        manifest_path: &'a std::path::Path,
39        target: &'a Target,
40        profile: &'a Profile,
41        dependency_graph: &'a ProjectDependencyGraph,
42        package_registry: &'a dyn PackageRegistryAndProvider,
43        source_manager: Arc<dyn SourceManager>,
44    ) -> Result<Self, Report> {
45        let project_root = manifest_path.parent().ok_or_else(|| {
46            Report::msg(format!("manifest '{}' has no parent directory", manifest_path.display()))
47        })?;
48        let target_path = target.path.to_path().ok_or_else(|| {
49            Report::msg(format!(
50                "invalid target '{}': '{}' is not a valid file path",
51                target.name.inner(),
52                target.path
53            ))
54        })?;
55        let root_path = project_root.join(&target_path);
56        let root_path = root_path.canonicalize().map_err(|error| {
57            Report::msg(format!(
58                "failed to resolve target source '{}': {error}",
59                root_path.display()
60            ))
61        })?;
62        Ok(TargetAssemblyContext {
63            package,
64            manifest_path,
65            project_root,
66            resolved_target_root: root_path.into_boxed_path(),
67            target,
68            profile,
69            dependency_graph,
70            source_manager,
71            package_registry,
72            warnings_as_errors: false,
73        })
74    }
75
76    #[inline]
77    pub fn with_warnings_as_errors(&mut self, yes: bool) -> &mut Self {
78        self.warnings_as_errors = yes;
79        self
80    }
81}
82
83/// This trait provides source file inputs and package post-processing hooks for a Miden Assembly
84/// project, regardless of the source language it was derived from.
85///
86/// For Miden Assembly source projects this is straightforward, see [MasmSourceProvider].
87///
88/// For languages other than MASM, which require a compilation step to produce Miden Assembly AST
89/// from the source language prior to assembly, and may have differing means for providing package
90/// metadata (advice data, account component metadata, custom sections), this trait provides the
91/// necessary hooks so that the project assembler can request compilation of a project in source
92/// form on-demand. Implementors are given all available information needed to compile to MASM, and
93/// are expected to return requested artifacts to the project assembler.
94///
95/// Source providers are registered by the file type (i.e. file extension used by the source file)
96/// with the assembler when it is created. Only one source provider per-file-type is allowed.
97pub trait ProjectSourceProvider {
98    /// Returns the file extension this provider should be registered as handling, e.g. `rs`
99    fn file_type(&self) -> &'static str;
100    /// Called to request the compiled/parsed Miden Assembly AST corresponding to the current target
101    /// being assembled.
102    fn provide_sources(
103        &self,
104        context: &TargetAssemblyContext<'_>,
105    ) -> Result<ProjectSourceInputs, Report>;
106    /// Called to request the source files that are inputs to assembly of the current target, so
107    /// that source provenance hash for the target can be computed.
108    ///
109    /// It is expected that all source files that contribute to the build be included in the set
110    /// of source inputs returned, otherwise package identity for the assembled target will be
111    /// incomplete, and another instance of the same package may be used from the cache if the
112    /// source provenance appears unchanged, even when the artifacts produced would be different.
113    ///
114    /// For MASM packages, the above is already guaranteed - but for compilation of packages in
115    /// other languages, such as Rust, the toolchain invoking the assembler must ensure that all
116    /// build inputs are accounted for. Note that you _do not_ need to include the sources of
117    /// your Miden dependencies, and non-Miden dependencies can be accounted for by hashing a
118    /// dependency lock file if present (e.g. `Cargo.toml`).
119    fn provide_source_provenance(
120        &self,
121        context: &TargetAssemblyContext<'_>,
122    ) -> Result<ProjectSourceProvenanceInputs, Report>;
123
124    /// Called after a project target - whose sources were provided via this trait- has been
125    /// assembled to a package, so that the provider can do any language-specific post-processing
126    /// of the assembled package before it is frozen and submitted to the package cache/registry.
127    ///
128    /// The default implementation is a no-op.
129    ///
130    /// The `context` given is the same as given to [`ProjectSourceProvider::provide_sources`].
131    #[allow(unused_variables)]
132    fn post_process_package(
133        &self,
134        package: &mut MastPackage,
135        context: &TargetAssemblyContext<'_>,
136    ) -> Result<(), Report> {
137        Ok(())
138    }
139}