holochain_integrity_types/
record.rs1use std::borrow::Borrow;
4
5use crate::action::conversions::WrongActionError;
6use crate::action::ActionHashed;
7use crate::action::CreateLink;
8use crate::action::DeleteLink;
9use crate::entry_def::EntryVisibility;
10use crate::signature::Signature;
11use crate::Entry;
12use crate::{Action, ActionHashedContainer, ActionSequenceAndHash};
13use holo_hash::ActionHash;
14use holo_hash::HasHash;
15use holo_hash::HashableContent;
16use holo_hash::HoloHashOf;
17use holo_hash::HoloHashed;
18use holo_hash::PrimitiveHashType;
19use holochain_serialized_bytes::prelude::*;
20
21#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SerializedBytes)]
24pub struct Record<A = SignedActionHashed> {
25 pub signed_action: A,
27 pub entry: RecordEntry<Entry>,
30}
31
32impl<A> AsRef<A> for Record<A> {
33 fn as_ref(&self) -> &A {
34 &self.signed_action
35 }
36}
37
38impl ActionHashedContainer for Record {
39 fn action(&self) -> &Action {
40 self.action()
41 }
42
43 fn action_hash(&self) -> &ActionHash {
44 self.action_address()
45 }
46}
47
48impl ActionSequenceAndHash for Record {
49 fn action_seq(&self) -> u32 {
50 self.action().action_seq()
51 }
52
53 fn address(&self) -> &ActionHash {
54 self.action_address()
55 }
56}
57
58#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, SerializedBytes)]
61pub enum RecordEntry<E: Borrow<Entry> = Entry> {
62 Present(E),
64 Hidden,
67 NA,
70 NotStored,
75}
76
77impl<E: Borrow<Entry>> From<E> for RecordEntry<E> {
78 fn from(entry: E) -> Self {
79 RecordEntry::Present(entry)
80 }
81}
82
83impl<E: Borrow<Entry>> RecordEntry<E> {
84 pub fn new(vis: Option<&EntryVisibility>, maybe_entry: Option<E>) -> Self {
86 match (maybe_entry, vis) {
87 (Some(entry), Some(_)) => RecordEntry::Present(entry),
88 (None, Some(EntryVisibility::Private)) => RecordEntry::Hidden,
89 (None, None) => RecordEntry::NA,
90 (Some(_), None) => {
91 unreachable!("Entry is present for an action type which has no entry reference")
93 }
94 (None, Some(EntryVisibility::Public)) => RecordEntry::NotStored,
95 }
96 }
97
98 pub fn as_option(&self) -> Option<&E> {
103 if let RecordEntry::Present(ref entry) = self {
104 Some(entry)
105 } else {
106 None
107 }
108 }
109
110 pub fn into_option(self) -> Option<E> {
115 if let RecordEntry::Present(entry) = self {
116 Some(entry)
117 } else {
118 None
119 }
120 }
121
122 pub fn to_app_option<A: TryFrom<SerializedBytes, Error = SerializedBytesError>>(
129 &self,
130 ) -> Result<Option<A>, SerializedBytesError> {
131 match self.as_option().map(|e| e.borrow()) {
132 Some(Entry::App(eb)) => Ok(Some(A::try_from(SerializedBytes::from(eb.to_owned()))?)),
133 _ => Ok(None),
134 }
135 }
136
137 pub fn as_ref<'a>(&'a self) -> RecordEntry<&'a E>
139 where
140 &'a E: Borrow<Entry>,
141 {
142 match self {
143 RecordEntry::Present(ref e) => RecordEntry::Present(e),
144 RecordEntry::Hidden => RecordEntry::Hidden,
145 RecordEntry::NA => RecordEntry::NA,
146 RecordEntry::NotStored => RecordEntry::NotStored,
147 }
148 }
149
150 pub fn to_grant_option(&self) -> Option<crate::entry::CapGrantEntry> {
155 match self.as_option().map(|e| e.borrow()) {
156 Some(Entry::CapGrant(cap_grant_entry)) => Some(cap_grant_entry.to_owned()),
157 _ => None,
158 }
159 }
160
161 pub fn or_hidden(entry: Option<E>) -> Self {
163 entry.map(Self::Present).unwrap_or(Self::Hidden)
164 }
165
166 pub fn or_not_applicable(entry: Option<E>) -> Self {
168 entry.map(Self::Present).unwrap_or(Self::NA)
169 }
170
171 pub fn or_not_stored(entry: Option<E>) -> Self {
173 entry.map(Self::Present).unwrap_or(Self::NotStored)
174 }
175}
176
177pub type RecordEntryRef<'a> = RecordEntry<&'a Entry>;
179
180pub type SignedActionHashed = SignedHashed<Action>;
182
183impl AsRef<SignedActionHashed> for SignedActionHashed {
184 fn as_ref(&self) -> &SignedActionHashed {
185 self
186 }
187}
188
189#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
190pub struct SignedHashed<T>
192where
193 T: HashableContent,
194{
195 pub hashed: HoloHashed<T>,
197 pub signature: Signature,
199}
200
201impl Record {
202 pub fn new(signed_action: SignedActionHashed, maybe_entry: Option<Entry>) -> Self {
205 let maybe_visibility = signed_action.action().entry_visibility();
206 let entry = RecordEntry::new(maybe_visibility, maybe_entry);
207 Self {
208 signed_action,
209 entry,
210 }
211 }
212
213 pub fn signature(&self) -> &Signature {
215 self.signed_action.signature()
216 }
217
218 #[cfg(feature = "test_utils")]
223 pub fn as_action_mut(&mut self) -> &mut Action {
224 &mut self.signed_action.hashed.content
225 }
226
227 pub fn privatized(self) -> (Self, Option<Entry>) {
231 let (entry, hidden) = if let Some(EntryVisibility::Private) = self
232 .signed_action
233 .action()
234 .entry_data()
235 .map(|(_, entry_type)| entry_type.visibility())
236 {
237 match self.entry {
238 RecordEntry::Present(entry) => (RecordEntry::Hidden, Some(entry)),
239 other => (other, None),
240 }
241 } else {
242 (self.entry, None)
243 };
244 let privatized = Self {
245 signed_action: self.signed_action,
246 entry,
247 };
248 (privatized, hidden)
249 }
250
251 pub fn action_address(&self) -> &ActionHash {
253 self.signed_action.action_address()
254 }
255
256 pub fn action(&self) -> &Action {
258 self.signed_action.action()
259 }
260
261 pub fn action_hashed(&self) -> &ActionHashed {
263 &self.signed_action.hashed
264 }
265
266 pub fn entry(&self) -> &RecordEntry {
269 &self.entry
270 }
271}
272
273impl<A> Record<A> {
274 #[cfg(feature = "test_utils")]
279 pub fn as_entry_mut(&mut self) -> &mut RecordEntry {
280 &mut self.entry
281 }
282
283 pub fn into_inner(self) -> (A, RecordEntry) {
285 (self.signed_action, self.entry)
286 }
287
288 pub fn signed_action(&self) -> &A {
290 &self.signed_action
291 }
292}
293
294#[cfg(feature = "hashing")]
295impl<T> SignedHashed<T>
296where
297 T: HashableContent,
298 <T as holo_hash::HashableContent>::HashType: holo_hash::hash_type::HashTypeSync,
299{
300 pub fn new_unchecked(content: T, signature: Signature) -> Self {
303 let hashed = HoloHashed::from_content_sync(content);
304 Self { hashed, signature }
305 }
306}
307
308impl<T> std::hash::Hash for SignedHashed<T>
309where
310 T: HashableContent,
311{
312 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
313 self.signature.hash(state);
314 self.as_hash().hash(state);
315 }
316}
317
318impl<T> std::cmp::PartialEq for SignedHashed<T>
319where
320 T: HashableContent,
321{
322 fn eq(&self, other: &Self) -> bool {
323 self.hashed == other.hashed && self.signature == other.signature
324 }
325}
326
327impl<T> SignedHashed<T>
328where
329 T: HashableContent,
330{
331 pub fn into_inner(self) -> (HoloHashed<T>, Signature) {
333 (self.hashed, self.signature)
334 }
335
336 pub fn as_hash(&self) -> &HoloHashOf<T> {
338 &self.hashed.hash
339 }
340
341 pub fn with_presigned(hashed: HoloHashed<T>, signature: Signature) -> Self {
343 Self { hashed, signature }
344 }
345
346 pub fn signature(&self) -> &Signature {
348 &self.signature
349 }
350}
351
352impl SignedActionHashed {
353 pub fn action_address(&self) -> &ActionHash {
355 &self.hashed.hash
356 }
357
358 pub fn action(&self) -> &Action {
360 &self.hashed.content
361 }
362
363 pub fn raw_from_same_hash<T>(other: SignedHashed<T>) -> Self
367 where
368 T: Into<Action>,
369 T: HashableContent<HashType = holo_hash::hash_type::Action>,
370 {
371 let SignedHashed {
372 hashed: HoloHashed { content, hash },
373 signature,
374 } = other;
375 let action = content.into();
376 let hashed = ActionHashed::with_pre_hashed(action, hash);
377 Self { hashed, signature }
378 }
379}
380
381impl<C: HashableContent<HashType = T>, T: PrimitiveHashType> HashableContent for SignedHashed<C> {
382 type HashType = C::HashType;
383
384 fn hash_type(&self) -> Self::HashType {
385 T::new()
386 }
387
388 fn hashable_content(&self) -> holo_hash::HashableContentBytes {
389 holo_hash::HashableContentBytes::Prehashed39(self.hashed.as_hash().get_raw_39().to_vec())
390 }
391}
392
393impl<C: HashableContent> HasHash for SignedHashed<C> {
394 type HashType = C::HashType;
395
396 fn as_hash(&self) -> &HoloHashOf<C> {
397 self.hashed.as_hash()
398 }
399
400 fn into_hash(self) -> HoloHashOf<C> {
401 self.hashed.into_hash()
402 }
403}
404
405impl<T> From<SignedHashed<T>> for HoloHashed<T>
406where
407 T: HashableContent,
408{
409 fn from(sh: SignedHashed<T>) -> HoloHashed<T> {
410 sh.hashed
411 }
412}
413
414impl From<ActionHashed> for Action {
415 fn from(action_hashed: ActionHashed) -> Action {
416 action_hashed.into_content()
417 }
418}
419
420impl From<SignedActionHashed> for Action {
421 fn from(signed_action_hashed: SignedActionHashed) -> Action {
422 ActionHashed::from(signed_action_hashed).into()
423 }
424}
425
426impl From<Record> for Option<Entry> {
427 fn from(e: Record) -> Self {
428 e.entry.into_option()
429 }
430}
431
432impl TryFrom<Record> for CreateLink {
433 type Error = WrongActionError;
434 fn try_from(value: Record) -> Result<Self, Self::Error> {
435 value
436 .into_inner()
437 .0
438 .into_inner()
439 .0
440 .into_content()
441 .try_into()
442 }
443}
444
445impl TryFrom<Record> for DeleteLink {
446 type Error = WrongActionError;
447 fn try_from(value: Record) -> Result<Self, Self::Error> {
448 value
449 .into_inner()
450 .0
451 .into_inner()
452 .0
453 .into_content()
454 .try_into()
455 }
456}