sim_table_core/path.rs
1//! Table path segments and the shared legal-segment predicate.
2
3/// Whether `name` is a legal single table path segment.
4///
5/// This is the exact predicate `sim-table-db` enforces in its `child_path`
6/// check: a segment is illegal when it is empty, the relative `.`/`..` markers,
7/// or contains a path separator (`/` or `\`). Everything else is legal.
8pub fn is_legal_table_segment(name: &str) -> bool {
9 !(name.is_empty() || name == "." || name == ".." || name.contains('/') || name.contains('\\'))
10}
11
12/// A validated, slash-joinable sequence of table path segments.
13#[derive(Clone, Debug, Default, PartialEq, Eq)]
14pub struct TablePath {
15 segments: Vec<String>,
16}
17
18impl TablePath {
19 /// Create an empty path.
20 pub fn new() -> Self {
21 Self::default()
22 }
23
24 /// The accumulated segments, in order.
25 pub fn segments(&self) -> &[String] {
26 &self.segments
27 }
28
29 /// Append `segment`, validating it with [`is_legal_table_segment`].
30 pub fn push(&mut self, segment: &str) -> Result<(), TablePathError> {
31 if !is_legal_table_segment(segment) {
32 return Err(TablePathError::IllegalSegment(segment.to_owned()));
33 }
34 self.segments.push(segment.to_owned());
35 Ok(())
36 }
37
38 /// Join the segments with `/`.
39 pub fn join(&self) -> String {
40 self.segments.join("/")
41 }
42}
43
44/// Why a [`TablePath`] operation failed.
45#[derive(Clone, Debug, PartialEq, Eq)]
46pub enum TablePathError {
47 /// The given segment did not satisfy [`is_legal_table_segment`].
48 IllegalSegment(String),
49}