blockless_car/utils/
cat.rs

1use std::{
2    collections::VecDeque,
3    io::{self, Write},
4    str::FromStr,
5};
6
7use cid::Cid;
8
9use crate::{error::CarError, reader::CarReader, unixfs::UnixFs, Ipld};
10
11/// write ipld to output
12/// `file_cid` is the file cid to write
13/// `output` is the out the file write to.
14pub fn ipld_write(
15    reader: &mut impl CarReader,
16    cid: Cid,
17    output: &mut impl Write,
18) -> Result<(), CarError> {
19    let mut vecq = VecDeque::new();
20    vecq.push_back(cid);
21    ipld_write_inner(reader, &mut vecq, output)
22}
23
24/// write ipld to output
25/// `file_cid` is the file cid to write
26/// `output` is the out the file write to.
27fn ipld_write_inner(
28    reader: &mut impl CarReader,
29    vecq: &mut VecDeque<Cid>,
30    output: &mut impl Write,
31) -> Result<(), CarError> {
32    while let Some(file_cid) = vecq.pop_front() {
33        let file_ipld: Ipld = reader.ipld(&file_cid).unwrap();
34
35        match file_ipld {
36            Ipld::Bytes(b) => {
37                output.write_all(&b[..])?;
38            }
39            m @ Ipld::Map(_) => {
40                let unix_fs: Result<UnixFs, CarError> = (file_cid, m).try_into();
41                let ufs = unix_fs?;
42                for link in ufs.links().iter() {
43                    vecq.push_back(link.hash);
44                }
45            }
46            _ => {}
47        };
48    }
49    Ok(())
50}
51
52#[inline(always)]
53pub fn cat_ipld_str(reader: &mut impl CarReader, cid: &str) -> Result<(), CarError> {
54    let cid = Cid::from_str(cid).map_err(|e| CarError::Parsing(e.to_string()))?;
55    cat_ipld(reader, cid)
56}
57
58pub fn cat_ipld(reader: &mut impl CarReader, file_cid: Cid) -> Result<(), CarError> {
59    let mut stdout = io::stdout();
60    let mut vecq = VecDeque::new();
61    vecq.push_back(file_cid);
62    ipld_write_inner(reader, &mut vecq, &mut stdout)
63}