1use std::collections::{VecDeque, HashMap};
2
3use cid::Cid;
4use ipld::raw::RawCodec;
5
6use crate::{reader::CarReader, Ipld, unixfs::{UnixFs, FileType}, error::CarError};
7
8fn walk<F>(
10 vecq: &mut VecDeque<Cid>,
11 reader: &mut impl CarReader,
12 list_f: &F
13) -> Result<(), CarError>
14where
15 F: Fn(&Cid, &str)
16{
17 let mut cache: HashMap<Cid, String> = HashMap::new();
18 let raw_code: u64 = RawCodec.into();
19 while let Some(file_cid) = vecq.pop_front() {
20 let codec = file_cid.codec();
21 let file_n = cache.get(&file_cid).map_or(file_cid.to_string(), |c| c.to_string());
22 list_f(&file_cid, &file_n);
23 if codec == raw_code {
26 continue;
27 }
28 let file_ipld: Ipld = reader.ipld(&file_cid)?;
29 if let m @ Ipld::Map(_) = file_ipld {
30 let unixfs: UnixFs = m.try_into()?;
31 match unixfs.file_type() {
32 FileType::Directory => {},
33 _=> continue,
34 }
35 for n in unixfs.links().into_iter() {
36 let cid = n.hash();
37 cache.insert(cid, file_n.clone() + "/" + n.name_ref());
38 vecq.push_back(cid);
39 }
40 }
41 }
42 Ok(())
43}
44
45pub fn list(reader: &mut impl CarReader) -> Result<(), CarError> {
47 list_call(reader, |_, file_n| println!("{file_n}"))
48}
49
50pub fn list_cid(reader: &mut impl CarReader) -> Result<(), CarError> {
52 list_call(reader, |cid, _| println!("{cid}"))
53}
54
55pub fn list_call<F>(
59 reader: &mut impl CarReader,
60 list_f: F
61) -> Result<(), CarError>
62where
63 F: Fn(&Cid, &str)
64{
65 let roots = reader.header().roots();
66 let mut queue: VecDeque<Cid> = VecDeque::new();
67 for r in roots.iter() {
68 queue.push_front(*r);
69 walk(&mut queue, reader, &list_f)?;
70 }
71 Ok(())
72}