use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::fmt;
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
pub enum ContractArtifactKind {
MigrationInventory,
SurfaceClientManifest,
GeneratedClientTree,
ApplicationManifest,
DeploymentPlan,
ClientProgramDescriptor,
ResolvedDeployment,
}
impl ContractArtifactKind {
pub const ALL: [Self; 7] = [
Self::MigrationInventory,
Self::SurfaceClientManifest,
Self::GeneratedClientTree,
Self::ApplicationManifest,
Self::DeploymentPlan,
Self::ClientProgramDescriptor,
Self::ResolvedDeployment,
];
pub const fn as_str(self) -> &'static str {
match self {
Self::MigrationInventory => "migration_inventory",
Self::SurfaceClientManifest => "surface_client_manifest",
Self::GeneratedClientTree => "generated_client_tree",
Self::ApplicationManifest => "application_manifest",
Self::DeploymentPlan => "deployment_plan",
Self::ClientProgramDescriptor => "client_program_descriptor",
Self::ResolvedDeployment => "resolved_deployment",
}
}
pub fn parse(value: &str) -> Option<Self> {
Self::ALL.into_iter().find(|kind| kind.as_str() == value)
}
}
impl fmt::Display for ContractArtifactKind {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ArtifactIdentity {
pub kind: ContractArtifactKind,
pub value: String,
}
impl ArtifactIdentity {
pub fn new(kind: ContractArtifactKind, value: impl Into<String>) -> Self {
Self {
kind,
value: value.into(),
}
}
pub fn from_canonical_bytes(kind: ContractArtifactKind, bytes: &[u8]) -> Self {
Self::new(kind, canonical_digest(bytes))
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ArtifactProvenance {
pub sources: std::collections::BTreeSet<String>,
pub generator: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_revision: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub glob_limit: Option<usize>,
}
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ArtifactPredecessor {
#[serde(alias = "entry")]
pub entry_id: String,
pub identity: ArtifactIdentity,
}
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(deny_unknown_fields)]
pub struct EnvironmentPolicyReference {
pub identity: String,
pub name: String,
pub reference: String,
}
fn hex_digest(bytes: &[u8]) -> String {
let digest = Sha256::digest(bytes);
digest.iter().map(|byte| format!("{byte:02x}")).collect()
}
pub(crate) fn canonical_digest(bytes: &[u8]) -> String {
format!("sha256:{}", hex_digest(bytes))
}