use crate::entry_def::EntryVisibility;
use crate::header::conversions::WrongHeaderError;
use crate::header::CreateLink;
use crate::header::DeleteLink;
use crate::header::HeaderHashed;
use crate::signature::Signature;
use crate::Entry;
use crate::Header;
use holo_hash::hash_type;
use holo_hash::HasHash;
use holo_hash::HashableContent;
use holo_hash::HashableContentBytes;
use holo_hash::HeaderHash;
use holo_hash::HoloHashed;
use holochain_serialized_bytes::prelude::*;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes)]
pub struct Element {
signed_header: SignedHeaderHashed,
entry: ElementEntry,
}
impl Element {
pub fn new(signed_header: SignedHeaderHashed, maybe_entry: Option<Entry>) -> Self {
let maybe_visibilty = signed_header
.header()
.entry_data()
.map(|(_, entry_type)| entry_type.visibility());
let entry = match (maybe_entry, maybe_visibilty) {
(Some(entry), Some(_)) => ElementEntry::Present(entry),
(None, Some(EntryVisibility::Private)) => ElementEntry::Hidden,
(None, None) => ElementEntry::NotApplicable,
(Some(_), None) => {
unreachable!("Entry is present for a Header type which has no entry reference")
}
(None, Some(EntryVisibility::Public)) => ElementEntry::NotStored,
};
Self {
signed_header,
entry,
}
}
pub fn into_inner(self) -> (SignedHeaderHashed, ElementEntry) {
(self.signed_header, self.entry)
}
pub fn signed_header(&self) -> &SignedHeaderHashed {
&self.signed_header
}
pub fn signature(&self) -> &Signature {
self.signed_header.signature()
}
pub fn header_address(&self) -> &HeaderHash {
self.signed_header.header_address()
}
pub fn header(&self) -> &Header {
self.signed_header.header()
}
pub fn header_hashed(&self) -> &HeaderHashed {
self.signed_header.header_hashed()
}
pub fn entry(&self) -> &ElementEntry {
&self.entry
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SerializedBytes)]
pub enum ElementEntry {
Present(Entry),
Hidden,
NotApplicable,
NotStored,
}
impl ElementEntry {
pub fn as_option(&self) -> Option<&Entry> {
if let ElementEntry::Present(ref entry) = self {
Some(entry)
} else {
None
}
}
pub fn into_option(self) -> Option<Entry> {
if let ElementEntry::Present(entry) = self {
Some(entry)
} else {
None
}
}
pub fn to_app_option<A: TryFrom<SerializedBytes, Error = SerializedBytesError>>(
&self,
) -> Result<Option<A>, SerializedBytesError> {
match self.as_option() {
Some(Entry::App(eb)) => Ok(Some(A::try_from(SerializedBytes::from(eb.to_owned()))?)),
_ => Ok(None),
}
}
pub fn to_grant_option(&self) -> Option<crate::entry::CapGrantEntry> {
match self.as_option() {
Some(Entry::CapGrant(cap_grant_entry)) => Some(cap_grant_entry.to_owned()),
_ => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializedBytes)]
pub struct SignedHeader(pub Header, pub Signature);
impl SignedHeader {
pub fn header(&self) -> &Header {
&self.0
}
pub fn signature(&self) -> &Signature {
&self.1
}
}
impl HashableContent for SignedHeader {
type HashType = hash_type::Header;
fn hash_type(&self) -> Self::HashType {
hash_type::Header
}
fn hashable_content(&self) -> HashableContentBytes {
HashableContentBytes::Content(
(&self.0)
.try_into()
.expect("Could not serialize HashableContent"),
)
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct SignedHeaderHashed {
header: HeaderHashed,
signature: Signature,
}
#[allow(missing_docs)]
impl SignedHeaderHashed {
pub fn into_inner(self) -> (SignedHeader, HeaderHash) {
let (header, hash) = self.header.into_inner();
((header, self.signature).into(), hash)
}
pub fn as_hash(&self) -> &HeaderHash {
self.header.as_hash()
}
pub fn with_presigned(header: HeaderHashed, signature: Signature) -> Self {
Self { header, signature }
}
pub fn into_header_and_signature(self) -> (HeaderHashed, Signature) {
(self.header, self.signature)
}
pub fn header_address(&self) -> &HeaderHash {
self.header.as_hash()
}
pub fn header(&self) -> &Header {
&self.header
}
pub fn header_hashed(&self) -> &HeaderHashed {
&self.header
}
pub fn signature(&self) -> &Signature {
&self.signature
}
}
impl From<(Header, Signature)> for SignedHeader {
fn from((h, s): (Header, Signature)) -> Self {
Self(h, s)
}
}
impl From<SignedHeader> for (Header, Signature) {
fn from(s: SignedHeader) -> Self {
(s.0, s.1)
}
}
impl From<HoloHashed<SignedHeader>> for SignedHeaderHashed {
fn from(hashed: HoloHashed<SignedHeader>) -> SignedHeaderHashed {
let (signed_header, hash) = hashed.into_inner();
let SignedHeader(header, signature) = signed_header;
SignedHeaderHashed {
header: HeaderHashed::with_pre_hashed(header, hash),
signature,
}
}
}
impl From<SignedHeaderHashed> for HoloHashed<SignedHeader> {
fn from(shh: SignedHeaderHashed) -> HoloHashed<SignedHeader> {
let (signed_header, hash) = shh.into_inner();
HoloHashed::with_pre_hashed(signed_header, hash)
}
}
impl From<Element> for Option<Entry> {
fn from(e: Element) -> Self {
e.entry.into_option()
}
}
impl TryFrom<Element> for CreateLink {
type Error = WrongHeaderError;
fn try_from(value: Element) -> Result<Self, Self::Error> {
value
.into_inner()
.0
.into_header_and_signature()
.0
.into_content()
.try_into()
}
}
impl TryFrom<Element> for DeleteLink {
type Error = WrongHeaderError;
fn try_from(value: Element) -> Result<Self, Self::Error> {
value
.into_inner()
.0
.into_header_and_signature()
.0
.into_content()
.try_into()
}
}