#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SegmentKind {
Object,
Nested,
}
#[derive(Debug, Clone, Copy)]
pub struct Segment {
pub name: &'static str,
pub kind: SegmentKind,
}
#[must_use]
pub fn nested_boundaries(path: &[Segment]) -> Vec<String> {
let mut running = String::new();
let mut boundaries = Vec::new();
for segment in path {
if !running.is_empty() {
running.push('.');
}
running.push_str(segment.name);
if segment.kind == SegmentKind::Nested {
boundaries.push(running.clone());
}
}
boundaries
}
#[cfg(test)]
mod tests {
use super::{Segment, SegmentKind, nested_boundaries};
const OBJECT: SegmentKind = SegmentKind::Object;
const NESTED: SegmentKind = SegmentKind::Nested;
#[test]
fn root_has_no_boundaries() {
assert!(nested_boundaries(&[]).is_empty());
}
#[test]
fn a_flattened_object_adds_no_boundary() {
let path = &[Segment {
name: "account",
kind: OBJECT,
}];
assert!(nested_boundaries(path).is_empty());
}
#[test]
fn one_nested_level_yields_its_path() {
let path = &[Segment {
name: "orders",
kind: NESTED,
}];
assert_eq!(nested_boundaries(path), ["orders"]);
}
#[test]
fn an_object_hop_extends_the_path_without_a_boundary() {
let path = &[
Segment {
name: "orders",
kind: NESTED,
},
Segment {
name: "shipping",
kind: OBJECT,
},
Segment {
name: "packages",
kind: NESTED,
},
];
assert_eq!(
nested_boundaries(path),
["orders", "orders.shipping.packages"]
);
}
}