wnfs_unixfs_file/
types.rs1use crate::{codecs::Codec, parse_links, protobufs};
2use anyhow::{anyhow, Result};
3use bytes::Bytes;
4use libipld::Cid;
5use std::{io::Cursor, pin::Pin};
6use tokio::io::AsyncRead;
7use wnfs_common::BlockStore;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct Block {
11 codec: Codec,
12 data: Bytes,
13 links: Vec<Cid>,
14}
15
16impl Block {
17 pub fn new(codec: Codec, data: Bytes, links: Vec<Cid>) -> Self {
18 Self { codec, data, links }
19 }
20
21 pub fn codec(&self) -> &Codec {
22 &self.codec
23 }
24
25 pub fn data(&self) -> &Bytes {
26 &self.data
27 }
28
29 pub fn links(&self) -> &[Cid] {
30 &self.links
31 }
32
33 pub fn raw_data_size(&self) -> Option<u64> {
34 match self.codec {
35 Codec::Raw => Some(self.data.len() as u64),
36 _ => None,
37 }
38 }
39
40 pub async fn store(&self, store: &impl BlockStore) -> Result<Cid> {
41 Ok(store
42 .put_block(self.data.clone(), self.codec.into())
43 .await?)
44 }
45
46 pub fn validate(&self) -> Result<()> {
48 let expected_links = parse_links(self.codec, &self.data)?;
50 let mut actual_links = self.links.clone();
51 actual_links.sort();
52 actual_links.dedup();
58 anyhow::ensure!(expected_links == actual_links, "links do not match");
59 Ok(())
60 }
61
62 pub fn into_parts(self) -> (Codec, Bytes, Vec<Cid>) {
63 (self.codec, self.data, self.links)
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct Link {
69 pub cid: Cid,
70 pub name: Option<String>,
71 pub tsize: Option<u64>,
72}
73
74impl Link {
75 pub fn as_ref(&self) -> LinkRef<'_> {
76 LinkRef {
77 cid: self.cid,
78 name: self.name.as_deref(),
79 tsize: self.tsize,
80 }
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct LinkRef<'a> {
86 pub cid: Cid,
87 pub name: Option<&'a str>,
88 pub tsize: Option<u64>,
89}
90
91impl LinkRef<'_> {
92 pub fn to_owned(&self) -> Link {
93 Link {
94 cid: self.cid,
95 name: self.name.map(|t| t.to_string()),
96 tsize: self.tsize,
97 }
98 }
99}
100
101#[derive(Debug)]
102pub enum Links<'a> {
103 Leaf,
104 Node(PbLinks<'a>),
105}
106
107#[derive(Debug)]
108pub struct PbLinks<'a> {
109 i: usize,
110 outer: &'a protobufs::PbNode,
111}
112
113impl<'a> PbLinks<'a> {
114 pub fn new(outer: &'a protobufs::PbNode) -> Self {
115 PbLinks { i: 0, outer }
116 }
117}
118
119impl<'a> Iterator for Links<'a> {
120 type Item = Result<LinkRef<'a>>;
121
122 fn next(&mut self) -> Option<Self::Item> {
123 match self {
124 Links::Leaf => None,
125 Links::Node(links) => links.next(),
126 }
127 }
128
129 fn size_hint(&self) -> (usize, Option<usize>) {
130 match self {
131 Links::Leaf => (0, Some(0)),
132 Links::Node(links) => links.size_hint(),
133 }
134 }
135}
136
137impl<'a> Iterator for PbLinks<'a> {
138 type Item = Result<LinkRef<'a>>;
139
140 fn next(&mut self) -> Option<Self::Item> {
141 if self.i == self.outer.links.len() {
142 return None;
143 }
144
145 let l = &self.outer.links[self.i];
146 self.i += 1;
147
148 let res = l
149 .hash
150 .as_ref()
151 .ok_or_else(|| anyhow!("missing link"))
152 .and_then(|c| {
153 Ok(LinkRef {
154 cid: Cid::read_bytes(Cursor::new(c))?,
155 name: l.name.as_deref(),
156 tsize: l.tsize,
157 })
158 });
159
160 Some(res)
161 }
162
163 fn size_hint(&self) -> (usize, Option<usize>) {
164 (self.outer.links.len(), Some(self.outer.links.len()))
165 }
166}
167
168#[cfg(not(target_arch = "wasm32"))]
169pub type BoxAsyncRead<'a> = Pin<Box<dyn AsyncRead + Send + 'a>>;
170
171#[cfg(target_arch = "wasm32")]
172pub type BoxAsyncRead<'a> = Pin<Box<dyn AsyncRead + 'a>>;