use serde::{Deserialize, Serialize}; use sha2::Sha256; use std::{collections::HashMap, fmt::Display, hash, rc::Rc}; use crate::util::cjson; #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct StringHash(pub [u8; 32]); impl Display for StringHash { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&hex::encode(self.0)) } } impl std::fmt::Debug for StringHash { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "\"{}\"", self) } } impl Serialize for StringHash { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { hex::serialize(self.0, serializer) } } impl<'de> Deserialize<'de> for StringHash { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { Ok(StringHash(hex::deserialize(deserializer)?)) } } macro_rules! stringhash_newtype { ($id:ident) => { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] pub struct $id(pub StringHash); impl Display for $id { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } }; } pub type InputHasher = Sha256; stringhash_newtype!(InputHash); pub type DependencyHasher = Sha256; stringhash_newtype!(DependencyHash); pub type ArchiveHasher = Sha256; stringhash_newtype!(ArchiveHash); #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TaskID(pub String); impl Display for TaskID { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub struct TaskArgs(pub HashMap>); impl hash::Hash for TaskArgs { fn hash(&self, _state: &mut H) { // Don't do anything: Properly hashing the task args is likely to cost // much more performance than the hash collisions caused by TaskRefs // that only differ by the args } } #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum Dependency { Fetch { name: String, sha256: StringHash }, BuildTask { output: ArchiveHash }, TargetTask { output: ArchiveHash }, } impl Dependency { pub fn dependency_hash(&self) -> DependencyHash { DependencyHash(StringHash( cjson::digest::(self).unwrap().into(), )) } }