#![deny(missing_docs)]
#![warn(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]
#![warn(rust_2018_idioms)]
#![doc = concat!(
"Structured access to the output of `scarb metadata --format-version ",
env!("CARGO_PKG_VERSION_MAJOR"),
"`.
")]
use std::collections::{BTreeMap, HashMap};
use std::fmt;
use std::ops::Index;
use std::path::PathBuf;
use camino::{Utf8Path, Utf8PathBuf};
#[cfg(feature = "builder")]
use derive_builder::Builder;
use semver::{Version, VersionReq};
use serde::{Deserialize, Serialize};
#[cfg(feature = "command")]
pub use command::*;
pub use version_pin::*;
#[cfg(feature = "command")]
mod command;
mod version_pin;
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(transparent)]
pub struct PackageId {
pub repr: String,
}
impl From<String> for PackageId {
fn from(repr: String) -> Self {
Self { repr }
}
}
impl fmt::Display for PackageId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.repr, f)
}
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(transparent)]
pub struct SourceId {
pub repr: String,
}
impl From<String> for SourceId {
fn from(repr: String) -> Self {
Self { repr }
}
}
impl fmt::Display for SourceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.repr, f)
}
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(transparent)]
pub struct CompilationUnitId {
pub repr: String,
}
impl From<String> for CompilationUnitId {
fn from(repr: String) -> Self {
Self { repr }
}
}
impl fmt::Display for CompilationUnitId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.repr, f)
}
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(transparent)]
pub struct CompilationUnitComponentId {
pub repr: String,
}
impl From<String> for CompilationUnitComponentId {
fn from(repr: String) -> Self {
Self { repr }
}
}
impl fmt::Display for CompilationUnitComponentId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.repr, f)
}
}
fn current_profile_default() -> String {
"release".to_string()
}
fn profiles_default() -> Vec<String> {
vec!["release".to_string()]
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct Metadata {
#[cfg_attr(feature = "builder", builder(setter(skip)))]
pub version: VersionPin,
pub app_exe: Option<PathBuf>,
pub app_version_info: VersionInfo,
pub target_dir: Option<Utf8PathBuf>,
#[serde(default)]
pub runtime_manifest: Utf8PathBuf,
pub workspace: WorkspaceMetadata,
pub packages: Vec<PackageMetadata>,
pub compilation_units: Vec<CompilationUnitMetadata>,
#[serde(default = "current_profile_default")]
pub current_profile: String,
#[serde(default = "profiles_default")]
pub profiles: Vec<String>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct WorkspaceMetadata {
pub manifest_path: Utf8PathBuf,
pub root: Utf8PathBuf,
pub members: Vec<PackageId>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct PackageMetadata {
pub id: PackageId,
pub name: String,
pub version: Version,
#[serde(skip_serializing_if = "Option::is_none")]
pub edition: Option<String>,
pub source: SourceId,
pub manifest_path: Utf8PathBuf,
pub root: Utf8PathBuf,
pub dependencies: Vec<DependencyMetadata>,
pub targets: Vec<TargetMetadata>,
#[serde(flatten)]
pub manifest_metadata: ManifestMetadata,
#[serde(default)]
pub experimental_features: Vec<String>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum DepKind {
Dev,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct DependencyMetadata {
pub name: String,
pub version_req: VersionReq,
pub source: SourceId,
pub kind: Option<DepKind>,
pub features: Option<Vec<String>>,
pub default_features: Option<bool>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct TargetMetadata {
pub kind: String,
pub name: String,
pub source_path: Utf8PathBuf,
pub params: serde_json::Value,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct CompilationUnitMetadata {
pub id: CompilationUnitId,
pub package: PackageId,
pub target: TargetMetadata,
pub compiler_config: serde_json::Value,
#[serde(rename = "components_data")]
pub components: Vec<CompilationUnitComponentMetadata>,
#[serde(default)]
pub cairo_plugins: Vec<CompilationUnitCairoPluginMetadata>,
#[serde(default)]
pub cfg: Vec<Cfg>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct CompilationUnitComponentMetadata {
pub package: PackageId,
pub name: String,
pub source_path: Utf8PathBuf,
#[serde(default)]
pub cfg: Option<Vec<Cfg>>,
pub id: Option<CompilationUnitComponentId>,
pub discriminator: Option<String>,
pub dependencies: Option<Vec<CompilationUnitComponentDependencyMetadata>>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct CompilationUnitComponentDependencyMetadata {
pub id: CompilationUnitComponentId,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct CompilationUnitCairoPluginMetadata {
pub package: PackageId,
pub component_dependency_id: Option<CompilationUnitComponentId>,
pub prebuilt_allowed: Option<bool>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct ManifestMetadata {
pub authors: Option<Vec<String>>,
pub description: Option<String>,
pub documentation: Option<String>,
pub homepage: Option<String>,
pub keywords: Option<Vec<String>>,
pub license: Option<String>,
pub license_file: Option<String>,
pub readme: Option<String>,
pub repository: Option<String>,
pub urls: Option<BTreeMap<String, String>>,
pub tool: Option<BTreeMap<String, serde_json::Value>>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct VersionInfo {
pub version: Version,
pub commit_info: Option<CommitInfo>,
pub cairo: CairoVersionInfo,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct CairoVersionInfo {
pub version: Version,
pub commit_info: Option<CommitInfo>,
#[cfg_attr(feature = "builder", builder(default))]
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "builder", derive(Builder))]
#[cfg_attr(feature = "builder", builder(setter(into)))]
#[non_exhaustive]
pub struct CommitInfo {
pub short_commit_hash: String,
pub commit_hash: String,
pub commit_date: Option<String>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
pub enum Cfg {
KV(String, String),
Name(String),
}
impl Metadata {
pub fn get_package(&self, id: &PackageId) -> Option<&PackageMetadata> {
self.packages.iter().find(|p| p.id == *id)
}
pub fn is_builtin_plugin(&self, plugin: &CompilationUnitCairoPluginMetadata) -> Option<bool> {
self.get_package(&plugin.package)?
.targets
.iter()
.find(|&target| target.kind == "cairo-plugin")
.map(|target| {
target
.params
.get("builtin")
.and_then(|value| value.as_bool())
.unwrap_or_default()
})
}
pub fn get_compilation_unit(&self, id: &CompilationUnitId) -> Option<&CompilationUnitMetadata> {
self.compilation_units.iter().find(|p| p.id == *id)
}
}
impl<'a> Index<&'a PackageId> for Metadata {
type Output = PackageMetadata;
fn index(&self, idx: &'a PackageId) -> &Self::Output {
self.get_package(idx)
.unwrap_or_else(|| panic!("no package with this ID: {idx}"))
}
}
impl<'a> Index<&'a CompilationUnitId> for Metadata {
type Output = CompilationUnitMetadata;
fn index(&self, idx: &'a CompilationUnitId) -> &Self::Output {
self.get_compilation_unit(idx)
.unwrap_or_else(|| panic!("no compilation unit with this ID: {idx}"))
}
}
impl PackageMetadata {
pub fn tool_metadata(&self, tool_name: &str) -> Option<&serde_json::Value> {
self.manifest_metadata.tool.as_ref()?.get(tool_name)
}
}
impl TargetMetadata {
pub fn source_root(&self) -> &Utf8Path {
self.source_path
.parent()
.expect("Source path is guaranteed to point to a file.")
}
}
impl CompilationUnitComponentMetadata {
pub fn source_root(&self) -> &Utf8Path {
self.source_path
.parent()
.expect("Source path is guaranteed to point to a file.")
}
}
impl<'a> Index<&'a CompilationUnitComponentId> for CompilationUnitMetadata {
type Output = CompilationUnitComponentMetadata;
fn index(&self, idx: &'a CompilationUnitComponentId) -> &Self::Output {
self.components
.iter()
.find(|p| p.id.as_ref() == Some(idx))
.unwrap_or_else(|| panic!("no compilation unit with this ID: {idx}"))
}
}