ipfs_unixfs/dir/
builder.rs

1use cid::Cid;
2use core::fmt;
3
4mod dir_builder;
5use dir_builder::DirBuilder;
6
7mod iter;
8pub use iter::{OwnedTreeNode, PostOrderIterator, TreeNode};
9
10mod buffered;
11pub use buffered::BufferingTreeBuilder;
12
13mod custom_pb;
14use custom_pb::CustomFlatUnixFs;
15
16enum Entry {
17    Leaf(Leaf),
18    Directory(DirBuilder),
19}
20
21impl fmt::Debug for Entry {
22    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
23        use Entry::*;
24
25        match self {
26            Leaf(leaf) => write!(fmt, "Leaf {{ {:?} }}", leaf),
27            Directory(_) => write!(fmt, "DirBuilder {{ .. }}"),
28        }
29    }
30}
31
32impl Entry {
33    fn as_dir_builder(&mut self) -> Result<&mut DirBuilder, ()> {
34        use Entry::*;
35        match self {
36            Directory(ref mut d) => Ok(d),
37            _ => Err(()),
38        }
39    }
40}
41
42struct Leaf {
43    link: Cid,
44    total_size: u64,
45}
46
47impl fmt::Debug for Leaf {
48    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(fmt, "{}, {}", self.link, self.total_size)
50    }
51}
52
53/// Configuration for customizing how the tree is built.
54#[derive(Debug, Clone)]
55pub struct TreeOptions {
56    block_size_limit: Option<u64>,
57    wrap_with_directory: bool,
58}
59
60impl Default for TreeOptions {
61    fn default() -> Self {
62        TreeOptions {
63            // this is just a guess; our bitswap message limit is a bit more
64            block_size_limit: Some(512 * 1024),
65            wrap_with_directory: false,
66        }
67    }
68}
69
70impl TreeOptions {
71    /// Overrides the default directory block size limit. If the size limit is set to `None`, no
72    /// directory will be too large.
73    pub fn block_size_limit(&mut self, limit: Option<u64>) {
74        self.block_size_limit = limit;
75    }
76
77    /// When true, allow multiple top level entries, otherwise error on the second entry.
78    /// Defaults to false.
79    pub fn wrap_with_directory(&mut self) {
80        self.wrap_with_directory = true;
81    }
82}
83
84/// Tree building failure cases.
85#[derive(Debug)]
86pub enum TreeBuildingFailed {
87    /// The given full path started with a slash; paths in the `/add` convention are not rooted.
88    RootedPath(String),
89    /// The given full path contained an empty segment.
90    RepeatSlashesInPath(String),
91    /// The given full path ends in slash.
92    PathEndsInSlash(String),
93    /// If the `BufferingTreeBuilder` was created without `TreeOptions` with the option
94    /// `wrap_with_directory` enabled, then there can be only a single element at the root.
95    TooManyRootLevelEntries,
96    /// The given full path had already been added.
97    DuplicatePath(String),
98    /// The given full path had already been added as a link to an opaque entry.
99    LeafAsDirectory(String),
100}
101
102impl fmt::Display for TreeBuildingFailed {
103    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
104        use TreeBuildingFailed::*;
105
106        match self {
107            RootedPath(s) => write!(fmt, "path is rooted: {:?}", s),
108            RepeatSlashesInPath(s) => write!(fmt, "path contains repeat slashes: {:?}", s),
109            PathEndsInSlash(s) => write!(fmt, "path ends in a slash: {:?}", s),
110            TooManyRootLevelEntries => write!(
111                fmt,
112                "multiple root level entries while configured wrap_with_directory = false"
113            ),
114            // TODO: perhaps we should allow adding two leafs with the same Cid?
115            DuplicatePath(s) => write!(fmt, "path exists already: {:?}", s),
116            LeafAsDirectory(s) => write!(
117                fmt,
118                "attempted to use already added leaf as a subdirectory: {:?}",
119                s
120            ),
121        }
122    }
123}
124
125impl std::error::Error for TreeBuildingFailed {}
126
127/// Failure cases for `PostOrderIterator` creating the tree dag-pb nodes.
128#[derive(Debug)]
129pub enum TreeConstructionFailed {
130    /// Failed to serialize the protobuf node for the directory
131    Protobuf(quick_protobuf::Error),
132    /// The resulting directory would be too large and HAMT sharding is yet to be implemented or
133    /// denied.
134    TooLargeBlock(u64),
135}
136
137impl fmt::Display for TreeConstructionFailed {
138    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
139        use TreeConstructionFailed::*;
140
141        match self {
142            Protobuf(e) => write!(fmt, "serialization failed: {}", e),
143            TooLargeBlock(size) => write!(fmt, "attempted to create block of {} bytes", size),
144        }
145    }
146}
147
148impl std::error::Error for TreeConstructionFailed {}
149
150#[derive(Debug)]
151struct NamedLeaf(String, Cid, u64);