postcard_bindgen_core/
path.rs

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
use core::fmt::Display;
use std::borrow::Cow;

use genco::{lang::Lang, tokens::FormatInto};

/// A part of a path which can either be [str] or [String].
pub type Part<'a> = Cow<'a, str>;
/// A full path joined which can either be [str] or [String].
pub type FullPath<'a> = Cow<'a, str>;

/// A path buffer that can be used to build paths.
///
/// The difference between a `PathBuf` and a `Path` is that a `PathBuf` is mutable and can be
/// modified, while a `Path` is immutable and is joined into one but knows how to split it into
/// parts.
///
/// # Example
///
/// ```rust
/// use postcard_bindgen_core::path::PathBuf;
///
/// let mut path = PathBuf::new();
///
/// assert!(path.is_empty());
///
/// path.push("foo");
/// path.push("bar");
/// path.push("baz");
///
/// assert!(!path.is_empty());
/// assert_eq!(path.parts().map(|p| p.as_ref()).collect::<Vec<&str>>(), vec!["foo", "bar", "baz"]);
/// ```
#[derive(Debug, Hash, Eq, PartialEq, Clone, PartialOrd, Ord)]
pub struct PathBuf<'a> {
    parts: Vec<Part<'a>>,
}

impl Default for PathBuf<'_> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'a> PathBuf<'a> {
    /// Create a new empty path buffer.
    pub fn new() -> Self {
        PathBuf { parts: Vec::new() }
    }

    /// Join a part into the path buffer by consuming the [PathBuf].
    ///
    /// This allows to chain calls to join parts into the path buffer.
    ///
    /// # Example
    ///
    /// ```rust
    /// use postcard_bindgen_core::path::PathBuf;
    ///
    /// let path = PathBuf::new().join("foo").join("bar").join("baz");
    ///
    /// assert_eq!(path.parts().map(|p| p.as_ref()).collect::<Vec<&str>>(), vec!["foo", "bar", "baz"]);
    /// ```
    pub fn join(mut self, joiner: impl Into<Part<'a>>) -> Self {
        self.parts.push(joiner.into());
        self
    }

    /// Push a part to the end of the path buffer.
    pub fn push(&mut self, part: impl Into<Part<'a>>) {
        self.parts.push(part.into());
    }

    /// Push a part to the front of the path buffer.
    pub fn push_front(&mut self, part: impl Into<Part<'a>>) {
        self.parts.insert(0, part.into());
    }

    /// Pop a part from the end of the path buffer.
    pub fn pop_front(&mut self) {
        if !self.parts.is_empty() {
            let _ = self.parts.remove(0);
        }
    }

    /// Gives an iterator over the parts of the path buffer.
    pub fn parts(&self) -> impl Iterator<Item = &Part<'a>> {
        self.parts.iter()
    }

    /// Check if the path buffer is empty.
    pub fn is_empty(&self) -> bool {
        self.parts.is_empty()
    }

    /// Convert the path buffer into a [Path] by consuming the path buffer.
    pub fn into_path<'b>(self, joiner: impl Into<Part<'b>>) -> Path<'a, 'b> {
        let joiner = joiner.into();
        Path {
            path: Some(self.parts.join(joiner.as_ref()).into()),
            joiner,
        }
    }

    /// Flatten the path to the root by simply removing all parts.
    pub fn flatten(&mut self) {
        self.parts.clear();
    }

    /// Convert the path buffer into an owned path buffer by consuming the path buffer.
    pub fn into_owned(self) -> PathBuf<'static> {
        PathBuf {
            parts: self
                .parts
                .into_iter()
                .map(|p| p.into_owned().into())
                .collect(),
        }
    }
}

impl<'a> FromIterator<Part<'a>> for PathBuf<'a> {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = Part<'a>>,
    {
        PathBuf {
            parts: iter.into_iter().collect(),
        }
    }
}

impl<'a> From<&'a str> for PathBuf<'a> {
    fn from(value: &'a str) -> Self {
        PathBuf {
            parts: vec![Cow::Borrowed(value)],
        }
    }
}

/// A [Path] can be used to represent a path.
///
/// A path is a sequence of parts that are joined together by a joiner. The joiner is a string that
/// is used to split the path into parts and into a [PathBuf].
///
/// # Example
///
/// ```rust
/// use postcard_bindgen_core::path::Path;
///
/// let path = Path::new("foo/bar/baz", "/");
///
/// assert_eq!(path.parts().collect::<Vec<&str>>(), vec!["foo", "bar", "baz"]);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Path<'a, 'b> {
    path: Option<FullPath<'a>>,
    joiner: Cow<'b, str>,
}

impl<'a, 'b> Path<'a, 'b> {
    /// Create a new path from something which can be converted into a [FullPath] and a joiner
    /// which is either [str] or [String].
    pub fn new(path: impl Into<FullPath<'a>>, joiner: impl Into<Cow<'b, str>>) -> Self {
        Path {
            path: Some(path.into()),
            joiner: joiner.into(),
        }
    }

    /// Gives an iterator over the parts of the path.
    pub fn parts(&self) -> impl Iterator<Item = &str> {
        self.path
            .as_ref()
            .map(|p| p.split(self.joiner.as_ref()))
            .into_iter()
            .flatten()
    }

    /// Flatten the path to the root by simply removing all parts.
    pub fn flatten(&mut self) {
        self.path = None;
    }

    /// Convert the path into a [PathBuf] by consuming the path and splitting it into parts.
    pub fn into_buf(self) -> PathBuf<'a> {
        PathBuf {
            parts: self
                .path
                .map(|p| {
                    p.split(self.joiner.as_ref())
                        .map(|p| p.to_owned().into())
                        .collect::<Vec<Part<'a>>>()
                })
                .unwrap_or_default(),
        }
    }

    /// Check if the path is empty.
    pub fn is_empty(&self) -> bool {
        self.path.as_ref().map(|p| p.is_empty()).unwrap_or(true)
    }

    /// Convert the path into an owned path by consuming the path.
    pub fn into_owned(self) -> Path<'static, 'static> {
        Path {
            joiner: self.joiner.into_owned().into(),
            path: self.path.map(|p| p.into_owned().into()),
        }
    }
}

impl<'a, 'b> From<Path<'a, 'b>> for String {
    fn from(value: Path<'a, 'b>) -> Self {
        value.path.map(|c| c.into_owned()).unwrap_or_default()
    }
}

impl Display for Path<'_, '_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if let Some(path) = &self.path {
            write!(f, "{}", path)
        } else {
            write!(f, "")
        }
    }
}

impl<L: Lang> FormatInto<L> for Path<'_, '_> {
    fn format_into(self, t: &mut genco::tokens::Tokens<L>) {
        if let Some(path) = &self.path {
            path.format_into(t);
        }
    }
}