prefix_file_tree/
builder.rs1use 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 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}