miden-mast-package 0.22.2

Package containing a compiled Miden MAST artifact with declared dependencies and exports
Documentation
use alloc::{collections::BTreeMap, sync::Arc, vec, vec::Vec};
use std::{fs, path::Path, println};

use miden_assembly_syntax::{
    Library,
    ast::{
        AttributeSet, Path as AstPath, PathBuf,
        types::{CallConv, FunctionType, Type},
    },
    library::{LibraryExport, ProcedureExport as LibraryProcedureExport},
    semver::Version,
};
use miden_core::{
    mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, MastNodeExt, MastNodeId},
    operations::Operation,
    serde::Serializable,
};

use super::{PackageId, TargetType};
use crate::{Package, PackageExport, PackageManifest, ProcedureExport as PackageProcedureExport};

fn build_forest() -> (MastForest, MastNodeId) {
    let mut forest = MastForest::new();
    let node_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new())
        .add_to_forest(&mut forest)
        .expect("failed to build basic block");
    forest.make_root(node_id);
    (forest, node_id)
}

fn absolute_path(name: &str) -> Arc<AstPath> {
    let path = PathBuf::new(name).expect("invalid path");
    let path = path.as_path().to_absolute().into_owned();
    Arc::from(path.into_boxed_path())
}

fn build_library(signature: Option<FunctionType>) -> Arc<Library> {
    let (forest, node_id) = build_forest();
    let path = absolute_path("test::proc");
    let mut export = LibraryProcedureExport::new(node_id, Arc::clone(&path));
    if let Some(signature) = signature {
        export = export.with_signature(signature);
    }

    let mut exports = BTreeMap::new();
    exports.insert(path, LibraryExport::Procedure(export));

    Arc::new(Library::new(Arc::new(forest), exports).expect("failed to build library"))
}

fn build_package(library: Arc<Library>, signature: FunctionType) -> Package {
    let path = absolute_path("test::proc");
    let node_id = library.get_export_node_id(path.as_ref());
    let digest = library.mast_forest()[node_id].digest();

    let export = PackageExport::Procedure(PackageProcedureExport {
        path: Arc::clone(&path),
        digest,
        signature: Some(signature),
        attributes: AttributeSet::default(),
    });

    let manifest = PackageManifest::new([export]).expect("seed package manifest should be valid");

    Package {
        name: PackageId::from("test_pkg"),
        version: Version::new(0, 0, 0),
        description: None,
        kind: TargetType::Library,
        mast: library,
        manifest,
        sections: Vec::new(),
    }
}

#[test]
#[ignore = "run manually to generate fuzz seeds"]
fn generate_fuzz_seeds() {
    fn write_seed(target: &str, name: &str, bytes: &[u8]) {
        let corpus_root =
            Path::new(env!("CARGO_MANIFEST_DIR")).join("../../miden-core-fuzz/corpus");
        let corpus_dir = corpus_root.join(target);
        fs::create_dir_all(&corpus_dir).expect("failed to create corpus directory");
        fs::write(corpus_dir.join(name), bytes).expect("failed to write seed");
        println!("Generated {}/{} ({} bytes)", target, name, bytes.len());
    }

    let library = build_library(None);
    write_seed("library_deserialize", "minimal_library.bin", &library.to_bytes());

    let signature = FunctionType::new(CallConv::Fast, [Type::Felt], [Type::Felt]);
    let library_with_signature = build_library(Some(signature.clone()));
    write_seed(
        "library_deserialize",
        "library_with_signature.bin",
        &library_with_signature.to_bytes(),
    );

    let package = build_package(library_with_signature, signature);
    write_seed("package_deserialize", "minimal_package.bin", &package.to_bytes());

    println!("\nSeed corpus generated in ../../miden-core-fuzz/corpus");
}