#![allow(unsafe_code)]
use rustc_hash::FxHashMap;
use std::sync::Arc;
pub(crate) const SEGMENT_SEPARATOR: char = '\n';
#[derive(Clone, Debug)]
pub(crate) enum SegmentEntry {
Field(Arc<[u8]>),
Node(SegmentsTree),
Both(Arc<[u8]>, SegmentsTree),
}
impl SegmentEntry {
#[inline]
pub(crate) const fn field(&self) -> Option<&Arc<[u8]>> {
match self {
Self::Field(f) | Self::Both(f, _) => Some(f),
Self::Node(_) => None,
}
}
#[inline]
pub(crate) const fn node(&self) -> Option<&SegmentsTree> {
match self {
Self::Node(n) | Self::Both(_, n) => Some(n),
Self::Field(_) => None,
}
}
fn ensure_node(&mut self) -> &mut SegmentsTree {
if matches!(self, Self::Field(_)) {
let old = std::mem::replace(self, Self::Node(SegmentsTree::new_node()));
let Self::Field(f) = old else { unreachable!() };
*self = Self::Both(f, SegmentsTree::new_node());
}
match self {
Self::Node(n) | Self::Both(_, n) => n,
Self::Field(_) => unreachable!(),
}
}
fn set_field(&mut self, path: Arc<[u8]>) {
match self {
Self::Field(f) | Self::Both(f, _) => *f = path,
Self::Node(_) => {
let old = std::mem::replace(self, Self::Field(path.clone()));
let Self::Node(n) = old else { unreachable!() };
*self = Self::Both(path, n);
}
}
}
}
#[derive(Clone, Debug)]
pub struct SegmentsTree {
is_root: bool,
entries: FxHashMap<String, SegmentEntry>,
field_count: usize,
node_count: usize,
}
impl Default for SegmentsTree {
fn default() -> Self {
Self::new()
}
}
impl SegmentsTree {
#[must_use]
pub fn new() -> Self {
Self {
is_root: true,
entries: FxHashMap::default(),
field_count: 0,
node_count: 0,
}
}
fn new_node() -> Self {
Self {
is_root: false,
entries: FxHashMap::default(),
field_count: 0,
node_count: 0,
}
}
pub fn add(&mut self, path: &str) {
let segments: Vec<&str> = path.split(SEGMENT_SEPARATOR).collect();
if segments.len() == 1 {
let path_arc = Arc::from(path.as_bytes());
self.insert_field(path.to_string(), path_arc);
return;
}
let mut node = self;
for (i, segment) in segments.iter().enumerate() {
if i == segments.len() - 1 {
let path_arc = Arc::from(path.as_bytes());
node.insert_field((*segment).to_string(), path_arc);
} else {
node = node.ensure_child_node((*segment).to_string());
}
}
}
fn insert_field(&mut self, key: String, path_arc: Arc<[u8]>) {
if let Some(entry) = self.entries.get_mut(&key) {
let had_field = entry.field().is_some();
entry.set_field(path_arc);
if !had_field {
self.field_count += 1;
}
} else {
self.entries.insert(key, SegmentEntry::Field(path_arc));
self.field_count += 1;
}
}
fn ensure_child_node(&mut self, key: String) -> &mut Self {
let had_entry = self.entries.contains_key(&key);
let entry = self
.entries
.entry(key)
.or_insert_with(|| SegmentEntry::Node(Self::new_node()));
let had_node = matches!(entry, SegmentEntry::Node(_) | SegmentEntry::Both(_, _));
let child = entry.ensure_node();
if !had_entry || !had_node {
self.node_count += 1;
}
child
}
#[inline]
#[must_use]
pub const fn is_root(&self) -> bool {
self.is_root
}
#[inline]
pub(crate) fn lookup(&self, segment: &[u8]) -> Option<&SegmentEntry> {
let s = unsafe { std::str::from_utf8_unchecked(segment) };
self.entries.get(s)
}
#[inline]
#[must_use]
pub fn is_segment_used(&self, segment: &[u8]) -> bool {
self.lookup(segment).is_some()
}
#[inline]
#[must_use]
pub fn get(&self, segment: &[u8]) -> Option<&Self> {
self.lookup(segment).and_then(|e| e.node())
}
#[inline]
#[must_use]
pub fn path_for_segment(&self, segment: &[u8]) -> Option<&[u8]> {
self.lookup(segment)
.and_then(|e| e.field())
.map(std::convert::AsRef::as_ref)
}
#[inline]
#[must_use]
pub fn path_arc_for_segment(&self, segment: &[u8]) -> Option<Arc<[u8]>> {
self.lookup(segment).and_then(|e| e.field()).cloned()
}
#[inline]
#[must_use]
pub const fn nodes_count(&self) -> usize {
self.node_count
}
#[inline]
#[must_use]
pub const fn fields_count(&self) -> usize {
self.field_count
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_single_field() {
let mut tree = SegmentsTree::new();
tree.add("status");
assert!(tree.is_segment_used(b"status"));
assert!(!tree.is_segment_used(b"other"));
assert_eq!(tree.fields_count(), 1);
assert_eq!(tree.nodes_count(), 0);
}
#[test]
fn test_nested_path() {
let mut tree = SegmentsTree::new();
tree.add("context\nuser\nid");
assert!(tree.is_segment_used(b"context"));
assert_eq!(tree.nodes_count(), 1);
assert_eq!(tree.fields_count(), 0);
let context = tree.get(b"context").unwrap();
assert!(context.is_segment_used(b"user"));
assert_eq!(context.nodes_count(), 1);
assert_eq!(context.fields_count(), 0);
let user = context.get(b"user").unwrap();
assert!(user.is_segment_used(b"id"));
assert_eq!(user.fields_count(), 1);
assert_eq!(user.nodes_count(), 0);
assert_eq!(
user.path_for_segment(b"id"),
Some(b"context\nuser\nid".as_slice())
);
}
#[test]
fn test_multiple_paths() {
let mut tree = SegmentsTree::new();
tree.add("a\nb");
tree.add("a\nc");
tree.add("d");
assert!(tree.is_segment_used(b"a"));
assert!(tree.is_segment_used(b"d"));
assert!(!tree.is_segment_used(b"x"));
let a = tree.get(b"a").unwrap();
assert!(a.is_segment_used(b"b"));
assert!(a.is_segment_used(b"c"));
assert_eq!(a.fields_count(), 2);
}
#[test]
fn test_is_root() {
let tree = SegmentsTree::new();
assert!(tree.is_root());
let mut tree = SegmentsTree::new();
tree.add("a\nb");
let child = tree.get(b"a").unwrap();
assert!(!child.is_root());
}
#[test]
fn test_both_field_and_node() {
let mut tree = SegmentsTree::new();
tree.add("a"); tree.add("a\nb");
assert!(tree.is_segment_used(b"a"));
assert_eq!(tree.fields_count(), 1);
assert_eq!(tree.nodes_count(), 1);
let entry = tree.lookup(b"a").unwrap();
assert!(entry.field().is_some());
assert!(entry.node().is_some());
assert_eq!(entry.field().unwrap().as_ref(), b"a");
let child = entry.node().unwrap();
assert!(child.is_segment_used(b"b"));
}
#[test]
fn test_node_then_field() {
let mut tree = SegmentsTree::new();
tree.add("a\nb"); tree.add("a");
assert_eq!(tree.fields_count(), 1);
assert_eq!(tree.nodes_count(), 1);
let entry = tree.lookup(b"a").unwrap();
assert!(entry.field().is_some());
assert!(entry.node().is_some());
}
#[test]
fn test_duplicate_add() {
let mut tree = SegmentsTree::new();
tree.add("a");
tree.add("a");
assert_eq!(tree.fields_count(), 1);
assert_eq!(tree.nodes_count(), 0);
}
#[test]
fn test_path_arc_for_segment() {
let mut tree = SegmentsTree::new();
tree.add("x\ny");
let x_node = tree.get(b"x").unwrap();
let arc = x_node.path_arc_for_segment(b"y");
assert_eq!(arc.as_deref(), Some(b"x\ny".as_slice()));
assert!(x_node.path_arc_for_segment(b"z").is_none());
}
}