use super::zome;
use crate::prelude::*;
#[cfg(feature = "full-dna-def")]
use crate::zome::error::ZomeError;
#[cfg(feature = "full-dna-def")]
use holo_hash::*;
pub type IntegrityZomes = Vec<(ZomeName, zome::IntegrityZomeDef)>;
pub type CoordinatorZomes = Vec<(ZomeName, zome::CoordinatorZomeDef)>;
pub type NetworkSeed = String;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, SerializedBytes)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "full-dna-def", derive(derive_builder::Builder))]
#[cfg_attr(feature = "full-dna-def", builder(public))]
pub struct DnaDef {
#[cfg_attr(
feature = "full-dna-def",
builder(default = "\"Generated DnaDef\".to_string()")
)]
pub name: String,
pub network_seed: String,
#[cfg_attr(feature = "full-dna-def", builder(default = "().try_into().unwrap()"))]
pub properties: SerializedBytes,
#[cfg_attr(feature = "full-dna-def", builder(default = "Timestamp::now()"))]
pub origin_time: Timestamp,
pub integrity_zomes: IntegrityZomes,
pub coordinator_zomes: CoordinatorZomes,
}
#[derive(Serialize, Debug, PartialEq, Eq)]
struct DnaDefHash<'a> {
name: &'a String,
network_seed: &'a String,
properties: &'a SerializedBytes,
integrity_zomes: &'a IntegrityZomes,
}
#[cfg(feature = "test_utils")]
impl DnaDef {
pub fn unique_from_zomes(
integrity: Vec<IntegrityZome>,
coordinator: Vec<CoordinatorZome>,
) -> DnaDef {
let integrity = integrity.into_iter().map(|z| z.into_inner()).collect();
let coordinator = coordinator.into_iter().map(|z| z.into_inner()).collect();
DnaDefBuilder::default()
.integrity_zomes(integrity)
.coordinator_zomes(coordinator)
.random_network_seed()
.build()
.unwrap()
}
}
impl DnaDef {
pub fn all_zomes(&self) -> impl Iterator<Item = (&ZomeName, &zome::ZomeDef)> {
self.integrity_zomes
.iter()
.map(|(n, def)| (n, def.as_any_zome_def()))
.chain(
self.coordinator_zomes
.iter()
.map(|(n, def)| (n, def.as_any_zome_def())),
)
}
}
#[cfg(feature = "full-dna-def")]
impl DnaDef {
pub fn get_integrity_zome(
&self,
zome_name: &ZomeName,
) -> Result<zome::IntegrityZome, ZomeError> {
self.integrity_zomes
.iter()
.find(|(name, _)| name == zome_name)
.cloned()
.map(|(name, def)| IntegrityZome::new(name, def))
.ok_or_else(|| ZomeError::ZomeNotFound(format!("Zome '{}' not found", &zome_name,)))
}
pub fn is_integrity_zome(&self, zome_name: &ZomeName) -> bool {
self.integrity_zomes
.iter()
.any(|(name, _)| name == zome_name)
}
pub fn get_coordinator_zome(
&self,
zome_name: &ZomeName,
) -> Result<zome::CoordinatorZome, ZomeError> {
self.coordinator_zomes
.iter()
.find(|(name, _)| name == zome_name)
.cloned()
.map(|(name, def)| CoordinatorZome::new(name, def))
.ok_or_else(|| ZomeError::ZomeNotFound(format!("Zome '{}' not found", &zome_name,)))
}
pub fn get_zome(&self, zome_name: &ZomeName) -> Result<zome::Zome, ZomeError> {
self.integrity_zomes
.iter()
.find(|(name, _)| name == zome_name)
.cloned()
.map(|(name, def)| Zome::new(name, def.erase_type()))
.or_else(|| {
self.coordinator_zomes
.iter()
.find(|(name, _)| name == zome_name)
.cloned()
.map(|(name, def)| Zome::new(name, def.erase_type()))
})
.ok_or_else(|| ZomeError::ZomeNotFound(format!("Zome '{}' not found", &zome_name,)))
}
pub fn get_all_coordinators(&self) -> Vec<zome::CoordinatorZome> {
self.coordinator_zomes
.iter()
.cloned()
.map(|(name, def)| CoordinatorZome::new(name, def))
.collect()
}
pub fn get_wasm_zome(&self, zome_name: &ZomeName) -> Result<&zome::WasmZome, ZomeError> {
self.all_zomes()
.find(|(name, _)| *name == zome_name)
.map(|(_, def)| def)
.ok_or_else(|| ZomeError::ZomeNotFound(format!("Zome '{}' not found", &zome_name,)))
.and_then(|def| {
if let ZomeDef::Wasm(wasm_zome) = def {
Ok(wasm_zome)
} else {
Err(ZomeError::NonWasmZome(zome_name.clone()))
}
})
}
pub fn modify_phenotype(&self, network_seed: NetworkSeed, properties: SerializedBytes) -> Self {
let mut clone = self.clone();
clone.properties = properties;
clone.network_seed = network_seed;
clone
}
pub fn topology(&self, cutoff: std::time::Duration) -> kitsune_p2p_dht::spacetime::Topology {
kitsune_p2p_dht::spacetime::Topology::standard(self.origin_time, cutoff)
}
}
#[cfg(feature = "full-dna-def")]
pub fn random_network_seed() -> String {
nanoid::nanoid!()
}
#[cfg(feature = "full-dna-def")]
impl DnaDefBuilder {
pub fn random_network_seed(&mut self) -> &mut Self {
self.network_seed = Some(random_network_seed());
self
}
}
#[cfg(feature = "full-dna-def")]
pub type DnaDefHashed = HoloHashed<DnaDef>;
#[cfg(feature = "full-dna-def")]
impl HashableContent for DnaDef {
type HashType = holo_hash::hash_type::Dna;
fn hash_type(&self) -> Self::HashType {
holo_hash::hash_type::Dna::new()
}
fn hashable_content(&self) -> HashableContentBytes {
let hash = DnaDefHash {
name: &self.name,
network_seed: &self.network_seed,
properties: &self.properties,
integrity_zomes: &self.integrity_zomes,
};
HashableContentBytes::Content(
holochain_serialized_bytes::UnsafeBytes::from(
holochain_serialized_bytes::encode(&hash)
.expect("Could not serialize HashableContent"),
)
.into(),
)
}
}