1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
use std::{
    collections::VecDeque,
    io::{self, Write},
};

use cid::Cid;

use crate::{error::CarError, reader::CarReader, unixfs::UnixFs, Ipld};

/// write ipld to output
/// `file_cid` is the file cid to write
/// `output` is the out the file write to.
pub fn ipld_write(
    reader: &mut impl CarReader,
    cid: Cid,
    output: &mut impl Write,
) -> Result<(), CarError> 
{
    let mut vecq = VecDeque::new();
    vecq.push_back(cid);
    ipld_write_inner(reader, &mut vecq, output)
}

/// write ipld to output
/// `file_cid` is the file cid to write
/// `output` is the out the file write to.
fn ipld_write_inner(
    reader: &mut impl CarReader,
    vecq: &mut VecDeque<Cid>,
    output: &mut impl Write,
) -> Result<(), CarError> {
    while let Some(file_cid) = vecq.pop_front() {
        let file_ipld: Ipld = reader.ipld(&file_cid).unwrap();

        match file_ipld {
            Ipld::Bytes(b) => {
                output.write_all(&b[..])?;
            }
            m @ Ipld::Map(_) => {
                let unix_fs: Result<UnixFs, CarError> = (file_cid, m).try_into();
                let ufs = unix_fs?;
                for link in ufs.links().iter() {
                    vecq.push_back(link.hash);
                }
            }
            _ => {}
        };
    }
    Ok(())
}

pub fn cat_ipld(reader: &mut impl CarReader, file_cid: Cid) -> Result<(), CarError> {
    let mut stdout = io::stdout();
    let mut vecq = VecDeque::new();
    vecq.push_back(file_cid);
    ipld_write_inner(reader, &mut vecq, &mut stdout)
}