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)]
24#[cfg_attr(
25 feature = "fuzzing",
26 derive(arbitrary::Arbitrary, proptest_derive::Arbitrary)
27)]
28pub struct Record<A = SignedActionHashed> {
29 pub signed_action: A,
31 pub entry: RecordEntry<Entry>,
34}
35
36impl<A> AsRef<A> for Record<A> {
37 fn as_ref(&self) -> &A {
38 &self.signed_action
39 }
40}
41
42impl ActionHashedContainer for Record {
43 fn action(&self) -> &Action {
44 self.action()
45 }
46
47 fn action_hash(&self) -> &ActionHash {
48 self.action_address()
49 }
50}
51
52impl ActionSequenceAndHash for Record {
53 fn action_seq(&self) -> u32 {
54 self.action().action_seq()
55 }
56
57 fn address(&self) -> &ActionHash {
58 self.action_address()
59 }
60}
61
62#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, SerializedBytes)]
65#[cfg_attr(
66 feature = "fuzzing",
67 derive(arbitrary::Arbitrary, proptest_derive::Arbitrary)
68)]
69pub enum RecordEntry<E: Borrow<Entry> = Entry> {
70 Present(E),
72 Hidden,
75 NA,
78 NotStored,
83}
84
85impl<E: Borrow<Entry>> From<E> for RecordEntry<E> {
86 fn from(entry: E) -> Self {
87 RecordEntry::Present(entry)
88 }
89}
90
91impl<E: Borrow<Entry>> RecordEntry<E> {
92 pub fn new(vis: Option<&EntryVisibility>, maybe_entry: Option<E>) -> Self {
94 match (maybe_entry, vis) {
95 (Some(entry), Some(_)) => RecordEntry::Present(entry),
96 (None, Some(EntryVisibility::Private)) => RecordEntry::Hidden,
97 (None, None) => RecordEntry::NA,
98 (Some(_), None) => {
99 unreachable!("Entry is present for an action type which has no entry reference")
101 }
102 (None, Some(EntryVisibility::Public)) => RecordEntry::NotStored,
103 }
104 }
105
106 pub fn as_option(&self) -> Option<&E> {
111 if let RecordEntry::Present(ref entry) = self {
112 Some(entry)
113 } else {
114 None
115 }
116 }
117
118 pub fn into_option(self) -> Option<E> {
123 if let RecordEntry::Present(entry) = self {
124 Some(entry)
125 } else {
126 None
127 }
128 }
129
130 pub fn to_app_option<A: TryFrom<SerializedBytes, Error = SerializedBytesError>>(
137 &self,
138 ) -> Result<Option<A>, SerializedBytesError> {
139 match self.as_option().map(|e| e.borrow()) {
140 Some(Entry::App(eb)) => Ok(Some(A::try_from(SerializedBytes::from(eb.to_owned()))?)),
141 _ => Ok(None),
142 }
143 }
144
145 pub fn as_ref<'a>(&'a self) -> RecordEntry<&'a E>
147 where
148 &'a E: Borrow<Entry>,
149 {
150 match self {
151 RecordEntry::Present(ref e) => RecordEntry::Present(e),
152 RecordEntry::Hidden => RecordEntry::Hidden,
153 RecordEntry::NA => RecordEntry::NA,
154 RecordEntry::NotStored => RecordEntry::NotStored,
155 }
156 }
157
158 pub fn to_grant_option(&self) -> Option<crate::entry::CapGrantEntry> {
163 match self.as_option().map(|e| e.borrow()) {
164 Some(Entry::CapGrant(cap_grant_entry)) => Some(cap_grant_entry.to_owned()),
165 _ => None,
166 }
167 }
168
169 pub fn or_hidden(entry: Option<E>) -> Self {
171 entry.map(Self::Present).unwrap_or(Self::Hidden)
172 }
173
174 pub fn or_not_applicable(entry: Option<E>) -> Self {
176 entry.map(Self::Present).unwrap_or(Self::NA)
177 }
178
179 pub fn or_not_stored(entry: Option<E>) -> Self {
181 entry.map(Self::Present).unwrap_or(Self::NotStored)
182 }
183}
184
185pub type RecordEntryRef<'a> = RecordEntry<&'a Entry>;
187
188pub type SignedActionHashed = SignedHashed<Action>;
190
191impl AsRef<SignedActionHashed> for SignedActionHashed {
192 fn as_ref(&self) -> &SignedActionHashed {
193 self
194 }
195}
196
197#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
198pub struct SignedHashed<T>
200where
201 T: HashableContent,
202{
203 pub hashed: HoloHashed<T>,
205 pub signature: Signature,
207}
208
209impl Record {
210 pub fn new(signed_action: SignedActionHashed, maybe_entry: Option<Entry>) -> Self {
213 let maybe_visibility = signed_action.action().entry_visibility();
214 let entry = RecordEntry::new(maybe_visibility, maybe_entry);
215 Self {
216 signed_action,
217 entry,
218 }
219 }
220
221 pub fn signature(&self) -> &Signature {
223 self.signed_action.signature()
224 }
225
226 #[cfg(feature = "test_utils")]
231 pub fn as_action_mut(&mut self) -> &mut Action {
232 &mut self.signed_action.hashed.content
233 }
234
235 pub fn privatized(self) -> (Self, Option<Entry>) {
239 let (entry, hidden) = if let Some(EntryVisibility::Private) = self
240 .signed_action
241 .action()
242 .entry_data()
243 .map(|(_, entry_type)| entry_type.visibility())
244 {
245 match self.entry {
246 RecordEntry::Present(entry) => (RecordEntry::Hidden, Some(entry)),
247 other => (other, None),
248 }
249 } else {
250 (self.entry, None)
251 };
252 let privatized = Self {
253 signed_action: self.signed_action,
254 entry,
255 };
256 (privatized, hidden)
257 }
258
259 pub fn action_address(&self) -> &ActionHash {
261 self.signed_action.action_address()
262 }
263
264 pub fn action(&self) -> &Action {
266 self.signed_action.action()
267 }
268
269 pub fn action_hashed(&self) -> &ActionHashed {
271 &self.signed_action.hashed
272 }
273
274 pub fn entry(&self) -> &RecordEntry {
277 &self.entry
278 }
279}
280
281impl<A> Record<A> {
282 #[cfg(feature = "test_utils")]
287 pub fn as_entry_mut(&mut self) -> &mut RecordEntry {
288 &mut self.entry
289 }
290
291 pub fn into_inner(self) -> (A, RecordEntry) {
293 (self.signed_action, self.entry)
294 }
295
296 pub fn signed_action(&self) -> &A {
298 &self.signed_action
299 }
300}
301
302#[cfg(feature = "hashing")]
303impl<T> SignedHashed<T>
304where
305 T: HashableContent,
306 <T as holo_hash::HashableContent>::HashType: holo_hash::hash_type::HashTypeSync,
307{
308 pub fn new_unchecked(content: T, signature: Signature) -> Self {
311 let hashed = HoloHashed::from_content_sync(content);
312 Self { hashed, signature }
313 }
314}
315
316impl<T> std::hash::Hash for SignedHashed<T>
317where
318 T: HashableContent,
319{
320 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
321 self.signature.hash(state);
322 self.as_hash().hash(state);
323 }
324}
325
326impl<T> std::cmp::PartialEq for SignedHashed<T>
327where
328 T: HashableContent,
329{
330 fn eq(&self, other: &Self) -> bool {
331 self.hashed == other.hashed && self.signature == other.signature
332 }
333}
334
335impl<T> SignedHashed<T>
336where
337 T: HashableContent,
338{
339 pub fn into_inner(self) -> (HoloHashed<T>, Signature) {
341 (self.hashed, self.signature)
342 }
343
344 pub fn as_hash(&self) -> &HoloHashOf<T> {
346 &self.hashed.hash
347 }
348
349 pub fn with_presigned(hashed: HoloHashed<T>, signature: Signature) -> Self {
351 Self { hashed, signature }
352 }
353
354 pub fn signature(&self) -> &Signature {
356 &self.signature
357 }
358}
359
360impl SignedActionHashed {
361 pub fn action_address(&self) -> &ActionHash {
363 &self.hashed.hash
364 }
365
366 pub fn action(&self) -> &Action {
368 &self.hashed.content
369 }
370
371 pub fn raw_from_same_hash<T>(other: SignedHashed<T>) -> Self
375 where
376 T: Into<Action>,
377 T: HashableContent<HashType = holo_hash::hash_type::Action>,
378 {
379 let SignedHashed {
380 hashed: HoloHashed { content, hash },
381 signature,
382 } = other;
383 let action = content.into();
384 let hashed = ActionHashed::with_pre_hashed(action, hash);
385 Self { hashed, signature }
386 }
387}
388
389impl<C: HashableContent<HashType = T>, T: PrimitiveHashType> HashableContent for SignedHashed<C> {
390 type HashType = C::HashType;
391
392 fn hash_type(&self) -> Self::HashType {
393 T::new()
394 }
395
396 fn hashable_content(&self) -> holo_hash::HashableContentBytes {
397 holo_hash::HashableContentBytes::Prehashed39(self.hashed.as_hash().get_raw_39().to_vec())
398 }
399}
400
401impl<C: HashableContent> HasHash for SignedHashed<C> {
402 type HashType = C::HashType;
403
404 fn as_hash(&self) -> &HoloHashOf<C> {
405 self.hashed.as_hash()
406 }
407
408 fn into_hash(self) -> HoloHashOf<C> {
409 self.hashed.into_hash()
410 }
411}
412
413impl<T> From<SignedHashed<T>> for HoloHashed<T>
414where
415 T: HashableContent,
416{
417 fn from(sh: SignedHashed<T>) -> HoloHashed<T> {
418 sh.hashed
419 }
420}
421
422impl From<ActionHashed> for Action {
423 fn from(action_hashed: ActionHashed) -> Action {
424 action_hashed.into_content()
425 }
426}
427
428impl From<SignedActionHashed> for Action {
429 fn from(signed_action_hashed: SignedActionHashed) -> Action {
430 ActionHashed::from(signed_action_hashed).into()
431 }
432}
433
434impl From<Record> for Option<Entry> {
435 fn from(e: Record) -> Self {
436 e.entry.into_option()
437 }
438}
439
440impl TryFrom<Record> for CreateLink {
441 type Error = WrongActionError;
442 fn try_from(value: Record) -> Result<Self, Self::Error> {
443 value
444 .into_inner()
445 .0
446 .into_inner()
447 .0
448 .into_content()
449 .try_into()
450 }
451}
452
453impl TryFrom<Record> for DeleteLink {
454 type Error = WrongActionError;
455 fn try_from(value: Record) -> Result<Self, Self::Error> {
456 value
457 .into_inner()
458 .0
459 .into_inner()
460 .0
461 .into_content()
462 .try_into()
463 }
464}
465
466#[cfg(feature = "fuzzing")]
467impl<'a, T> arbitrary::Arbitrary<'a> for SignedHashed<T>
468where
469 T: HashableContent,
470 T: arbitrary::Arbitrary<'a>,
471 <T as holo_hash::HashableContent>::HashType: holo_hash::PrimitiveHashType,
472{
473 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
474 Ok(Self {
475 hashed: HoloHashed::<T>::arbitrary(u)?,
476 signature: Signature::arbitrary(u)?,
477 })
478 }
479}