common/linked_data/
link.rs1use std::fmt::Display;
2
3use iroh::NodeAddr;
4use iroh_blobs::{ticket::BlobTicket, BlobFormat, Hash, HashAndFormat};
5use serde::{Deserialize, Serialize};
6
7use crate::crypto::PublicKey;
8
9use super::ipld::{Cid, LinkedData, Multihash, BLAKE3_HASH_CODE, LD_CBOR_CODEC, LD_RAW_CODEC};
10
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
14pub struct Link(Cid);
15
16impl Display for Link {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 write!(f, "{}", self.hash())
19 }
20}
21
22#[allow(clippy::doc_overindented_list_items)]
41#[allow(clippy::doc_lazy_continuation)]
42impl Default for Link {
43 fn default() -> Self {
44 let hash = Hash::from_bytes([0; 32]);
45 let mh = Multihash::wrap(BLAKE3_HASH_CODE, hash.as_bytes()).expect("valid blake3 hash");
46 Link(Cid::new_v1(LD_RAW_CODEC, mh))
47 }
48}
49
50impl From<Link> for Cid {
51 fn from(val: Link) -> Self {
52 val.0
53 }
54}
55
56impl From<Cid> for Link {
57 fn from(val: Cid) -> Self {
58 let hash = val.hash();
59 let code = hash.code();
60 let codec = val.codec();
61 if code != BLAKE3_HASH_CODE {
64 panic!("invalid hash code");
65 }
66 if codec != LD_RAW_CODEC && codec != LD_CBOR_CODEC {
68 panic!("unsupported codec");
69 }
70
71 Link(val)
72 }
73}
74
75impl From<Link> for LinkedData {
76 fn from(val: Link) -> Self {
77 LinkedData::Link(val.0)
78 }
79}
80
81impl From<Link> for HashAndFormat {
82 fn from(val: Link) -> Self {
83 HashAndFormat {
84 hash: val.hash(),
85 format: BlobFormat::Raw,
86 }
87 }
88}
89
90impl From<Link> for Hash {
91 fn from(val: Link) -> Self {
92 val.hash()
93 }
94}
95
96impl Link {
97 pub fn new(codec: u64, hash: Hash) -> Self {
99 let mh = Multihash::wrap(BLAKE3_HASH_CODE, hash.as_bytes()).expect("valid blake3 hash");
100 Link(Cid::new_v1(codec, mh))
101 }
102
103 pub fn codec(&self) -> u64 {
105 self.0.codec()
106 }
107
108 pub fn hash(&self) -> Hash {
110 let hash_digest = self.0.hash().digest();
111 let mut hash_bytes: [u8; 32] = [0; 32];
112 hash_bytes.copy_from_slice(hash_digest);
113 Hash::from_bytes(hash_bytes)
114 }
115
116 pub fn cid(&self) -> &Cid {
118 &self.0
119 }
120
121 pub fn ticket(&self, source: PublicKey, format: Option<BlobFormat>) -> BlobTicket {
125 let node_addr = NodeAddr::new(*source);
126 BlobTicket::new(node_addr, self.hash(), format.unwrap_or(BlobFormat::Raw))
127 }
128}