Skip to content

Commit

Permalink
feature: add miden-package crate with Package type to represent
Browse files Browse the repository at this point in the history
compiled Miden program/library.
  • Loading branch information
greenhat committed Nov 19, 2024
1 parent eda4a01 commit 84ea102
Show file tree
Hide file tree
Showing 17 changed files with 885 additions and 0 deletions.
53 changes: 53 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"assembly",
"core",
"miden",
"package",
"processor",
"prover",
"stdlib",
Expand Down
5 changes: 5 additions & 0 deletions assembly/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ doctest = false
default = ["std"]
std = ["aho-corasick/std", "miette/fancy", "miette/std", "thiserror/std", "vm-core/std"]
testing = ["dep:regex"]
serde = [
"dep:serde",
"smallvec/serde",
]

[dependencies]
aho-corasick = { version = "1.1", default-features = false }
Expand All @@ -37,6 +41,7 @@ unicode-width = { version = "0.2", features = ["no_std"] }
vm-core = { package = "miden-core", path = "../core", version = "0.11", default-features = false, features = [
"diagnostics",
] }
serde = { version = "1.0.208", features = ["alloc", "rc", "serde_derive"], optional = true }

[dev-dependencies]
pretty_assertions = "1.4"
Expand Down
35 changes: 35 additions & 0 deletions assembly/src/ast/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,38 @@ impl FromStr for Ident {
Ok(Self { span: SourceSpan::default(), name })
}
}

#[cfg(feature = "serde")]
impl serde::Serialize for Ident {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.as_str().serialize(serializer)
}
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Ident {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct IdentVisitor;
impl serde::de::Visitor<'_> for IdentVisitor {
type Value = Ident;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("ident")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Ident::new_unchecked(Span::unknown(Arc::from(v))))
}
}
deserializer.deserialize_str(IdentVisitor)
}
}
17 changes: 17 additions & 0 deletions core/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ impl ToElements for Vec<u64> {
}
}

// TODO(denysz): add roundtrip proptest
impl ToElements for &[u8] {
fn to_elements(&self) -> Vec<Felt> {
self.chunks(4)
.map(|chunk| {
if chunk.len() < 4 {
let mut bytes = [0; 4];
bytes[..chunk.len()].copy_from_slice(chunk);
Felt::new(u32::from_le_bytes(bytes) as u64)
} else {
Felt::new(u32::from_le_bytes(chunk.try_into().unwrap()) as u64)
}
})
.collect()
}
}

// INTO BYTES
// ================================================================================================

Expand Down
31 changes: 31 additions & 0 deletions package/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "miden-package"
version = "0.11.0"
description = "Miden VM package"
documentation = "https://docs.rs/miden-package/0.10.5"
readme = "README.md"
categories = ["compilers", "no-std"]
keywords = ["package", "language", "miden"]
license.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true
rust-version.workspace = true
edition.workspace = true

[lib]
bench = false
doctest = false

[dependencies]
vm-core = { package = "miden-core", path = "../core", version = "0.11", default-features = false }
# processor = { package = "miden-processor", path = "../processor", version = "0.11", default-features = false }
assembly = { package = "miden-assembly", path = "../assembly", version = "0.11", default-features = false, features = [
"serde",
] }
serde = { version = "1.0.208", features = ["alloc", "rc", "serde_derive"] }
serde_bytes = "0.11.15"
serde_repr = "0.1.19"
bitcode = { version = "0.6.3", default-features = false, features = ["serde"] }

[dev-dependencies]
7 changes: 7 additions & 0 deletions package/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Overview

TBD

## Binary Format

TBD
57 changes: 57 additions & 0 deletions package/src/de.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use alloc::{fmt, sync::Arc};

use assembly::Library;
use vm_core::{utils::Deserializable, Program};

use crate::{package::MastArtifact, Digest};

/// Deserialize a [Digest] from a byte array
pub fn deserialize_digest<'de, D>(deserializer: D) -> Result<Digest, D::Error>
where
D: serde::Deserializer<'de>,
{
const DIGEST_BYTES: usize = 32;

let bytes: [u8; DIGEST_BYTES] = serde_bytes::deserialize(deserializer)?;

Digest::try_from(bytes).map_err(serde::de::Error::custom)
}

/// Deserialize a [MastArtifact] from a byte array
pub fn deserialize_mast<'de, D>(deserializer: D) -> Result<MastArtifact, D::Error>
where
D: serde::Deserializer<'de>,
{
struct MastArtifactVisitor;

impl serde::de::Visitor<'_> for MastArtifactVisitor {
type Value = MastArtifact;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("mast artifact")
}

fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if let Some(bytes) = v.strip_prefix(b"PRG\0") {
Program::read_from_bytes(bytes)
.map(Arc::new)
.map(MastArtifact::Executable)
.map_err(serde::de::Error::custom)
} else if let Some(bytes) = v.strip_prefix(b"LIB\0") {
Library::read_from_bytes(bytes)
.map(Arc::new)
.map(MastArtifact::Library)
.map_err(serde::de::Error::custom)
} else {
Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Bytes(v.get(0..4).unwrap_or(v)),
&"expected valid mast artifact type tag",
))
}
}
}
deserializer.deserialize_bytes(MastArtifactVisitor)
}
67 changes: 67 additions & 0 deletions package/src/dep/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use alloc::string::String;

use serde::{Deserialize, Serialize};

use super::{de, se};
use crate::Digest;

pub(crate) mod resolver;

/// A system library identifier
#[derive(
Debug, Copy, Clone, PartialEq, Eq, serde_repr::Serialize_repr, serde_repr::Deserialize_repr,
)]
#[repr(u8)]
pub enum SystemLibraryId {
/// The standard library
Stdlib,
/// The base library
Miden,
}

impl core::str::FromStr for SystemLibraryId {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
// Compiler uses "std" and "base" to identify the standard and base libraries
// respectively. We also accept "stdlib" and "miden" as aliases for these libraries.
"std" | "stdlib" => Ok(Self::Stdlib),
"base" | "miden" => Ok(Self::Miden),
_ => Err(()),
}
}
}

/// The name of a dependency
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DependencyName {
/// The dependency is a system library
System(SystemLibraryId),
/// The dependency is a user library with the given name
User(String),
}

impl From<String> for DependencyName {
fn from(s: String) -> Self {
if let Ok(id) = s.parse() {
DependencyName::System(id)
} else {
DependencyName::User(s)
}
}
}

/// A package dependency
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Dependency {
/// The name of the dependency.
/// Serves as a human-readable identifier for the dependency and a search hint for the resolver
pub name: DependencyName,
/// The digest of the dependency.
/// Serves as an ultimate source of truth for identifying the dependency.
#[serde(
serialize_with = "se::serialize_digest",
deserialize_with = "de::deserialize_digest"
)]
pub digest: Digest,
}
Loading

0 comments on commit 84ea102

Please sign in to comment.