p2panda_core/operation/
operation.rs1use std::borrow::Borrow;
4
5use crate::hash::Hash;
6use crate::identity::VerifyingKey;
7use crate::logs::SeqNum;
8use crate::operation::{AnyHeader, AnyOperation, Body, Header, HeaderError, PayloadSize};
9use crate::traits::{Chain, Digest, Extensions, Offchain, Provenance};
10
11pub type RawOperation = (Vec<u8>, Option<Vec<u8>>);
13
14#[derive(Clone, Debug)]
16pub struct Operation<E = ()> {
17 pub hash: Hash,
18 pub header: Header<E>,
19 pub body: Option<Body>,
20}
21
22impl<E> Operation<E>
23where
24 E: Extensions,
25{
26 pub fn from_parts(header: Header<E>, body: Option<Body>) -> Self {
31 Self {
32 hash: header.hash(),
33 header,
34 body,
35 }
36 }
37}
38
39impl<E> PartialEq for Operation<E> {
40 fn eq(&self, other: &Self) -> bool {
41 self.hash.eq(&other.hash)
42 }
43}
44
45impl<E> Eq for Operation<E> {}
46
47impl<E> Borrow<Header<E>> for Operation<E> {
48 fn borrow(&self) -> &Header<E> {
49 &self.header
50 }
51}
52
53#[allow(clippy::non_canonical_partial_ord_impl)]
54impl<E> PartialOrd for Operation<E> {
55 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
56 Some(self.hash.cmp(&other.hash))
57 }
58}
59
60impl<E> Ord for Operation<E> {
61 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
62 self.hash.cmp(&other.hash)
63 }
64}
65
66impl<E> Digest<Hash> for Operation<E> {
67 fn hash(&self) -> Hash {
68 self.hash
69 }
70}
71
72impl<E> Provenance<VerifyingKey> for Operation<E>
73where
74 E: Extensions,
75{
76 fn author(&self) -> VerifyingKey {
77 self.header.verifying_key
78 }
79
80 fn verify(&self) -> bool {
81 self.header.verify()
82 }
83}
84
85impl<E> Chain<Hash> for Operation<E> {
86 fn backlink(&self) -> Option<Hash> {
87 self.header.backlink
88 }
89
90 fn seq_num(&self) -> SeqNum {
91 self.header.seq_num
92 }
93}
94
95impl<E> Offchain<Hash> for Operation<E> {
96 fn payload(&self) -> Option<&Body> {
97 self.body.as_ref()
98 }
99
100 fn payload_hash(&self) -> Option<Hash> {
101 self.header.payload_hash
102 }
103
104 fn payload_size(&self) -> PayloadSize {
105 self.header.payload_size
106 }
107}
108
109impl<E> TryFrom<AnyOperation> for Operation<E>
110where
111 E: Extensions,
112{
113 type Error = HeaderError;
114
115 fn try_from(any_operation: AnyOperation) -> Result<Self, Self::Error> {
116 let header: Header<E> = any_operation.header.try_into()?;
117 Ok(Operation {
118 header,
119 body: any_operation.body,
120 hash: any_operation.hash,
121 })
122 }
123}
124
125impl<E> TryFrom<(AnyHeader, Option<Body>)> for Operation<E>
126where
127 E: Extensions,
128{
129 type Error = HeaderError;
130
131 fn try_from(value: (AnyHeader, Option<Body>)) -> Result<Self, Self::Error> {
132 let (any_header, body) = value;
133
134 let hash = any_header.hash();
136
137 let header: Header<E> = any_header.try_into()?;
140
141 Ok(Operation { header, body, hash })
142 }
143}