prefix_file_tree/
builder.rs

1use std::ops::Range;
2use std::path::PathBuf;
3
4use crate::{constraint, scheme};
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
7pub enum Error {
8    #[error("Inconsistent prefix part lengths")]
9    InconsistentPrefixPartLengths {
10        prefix_part_lengths_total: usize,
11        length_constraint: constraint::Length,
12    },
13}
14
15#[derive(Clone, Debug, Eq, PartialEq)]
16pub struct TreeBuilder<S> {
17    base: PathBuf,
18    length_constraint: Option<crate::constraint::Length>,
19    extension_constraint: Option<crate::constraint::Extension>,
20    prefix_part_lengths: Option<Vec<usize>>,
21    scheme: S,
22}
23
24impl TreeBuilder<crate::scheme::Identity> {
25    pub(crate) const fn new(base: PathBuf) -> Self {
26        Self {
27            base,
28            length_constraint: None,
29            extension_constraint: None,
30            prefix_part_lengths: None,
31            scheme: scheme::Identity,
32        }
33    }
34}
35
36impl<S> TreeBuilder<S> {
37    pub fn build(self) -> Result<crate::Tree<S>, Error> {
38        let tree = self.into_tree();
39
40        match tree.length_constraint {
41            Some(length_constraint) => {
42                let prefix_part_lengths_total =
43                    tree.prefix_part_lengths.iter().copied().sum::<usize>();
44
45                match length_constraint {
46                    constraint::Length::Fixed(length) | constraint::Length::Range(_, length) => {
47                        if prefix_part_lengths_total <= length {
48                            Ok(tree)
49                        } else {
50                            Err(Error::InconsistentPrefixPartLengths {
51                                prefix_part_lengths_total,
52                                length_constraint,
53                            })
54                        }
55                    }
56                }
57            }
58            None => Ok(tree),
59        }
60    }
61
62    /// Internal unvalidated conversion.
63    fn into_tree(self) -> crate::Tree<S> {
64        crate::Tree {
65            base: self.base,
66            length_constraint: self.length_constraint,
67            extension_constraint: self.extension_constraint,
68            prefix_part_lengths: self.prefix_part_lengths.unwrap_or_default(),
69            scheme: self.scheme,
70        }
71    }
72
73    #[must_use]
74    pub fn with_fixed_length(self, length: usize) -> Self {
75        Self {
76            base: self.base,
77            length_constraint: Some(length.into()),
78            extension_constraint: self.extension_constraint,
79            prefix_part_lengths: self.prefix_part_lengths,
80            scheme: self.scheme,
81        }
82    }
83
84    #[must_use]
85    pub fn with_length_range(self, range: Range<usize>) -> Self {
86        Self {
87            base: self.base,
88            length_constraint: Some(range.into()),
89            extension_constraint: self.extension_constraint,
90            prefix_part_lengths: self.prefix_part_lengths,
91            scheme: self.scheme,
92        }
93    }
94
95    #[must_use]
96    pub fn with_prefix_part_lengths<T: AsRef<[usize]>>(self, prefix_part_lengths: T) -> Self {
97        Self {
98            base: self.base,
99            length_constraint: self.length_constraint,
100            extension_constraint: self.extension_constraint,
101            prefix_part_lengths: Some(prefix_part_lengths.as_ref().to_vec()),
102            scheme: self.scheme,
103        }
104    }
105
106    #[must_use]
107    pub fn with_scheme<T: crate::scheme::Scheme>(self, scheme: T) -> TreeBuilder<T> {
108        let length_constraint = T::fixed_length().map_or(self.length_constraint, |fixed_length| {
109            Some(fixed_length.into())
110        });
111
112        TreeBuilder {
113            base: self.base,
114            length_constraint,
115            extension_constraint: self.extension_constraint,
116            prefix_part_lengths: self.prefix_part_lengths,
117            scheme,
118        }
119    }
120}