#prefix-tree #map #prefix #trie #tree #collection #key-value

无 std prefixtreemap

A Rust 实现的通用前缀树(trie)映射,支持通配符捕获

2 个版本

0.2.1 2022 年 2 月 28 日
0.2.0 2021 年 12 月 6 日
0.1.0 2021 年 12 月 5 日

#1534 in 数据结构


用于 hyper-tree-router

GPL-3.0-or-later

23KB
472

prefix_tree_map

A Rust 实现的通用前缀树(trie)映射,支持通配符捕获。

Version Documentation License

优缺点

优点

  • 快速高效
  • 通配符捕获支持 - 在匹配时捕获映射中的通配符字符。
  • 泛化 - 支持任何类型的键和值,只要键部分实现了 OrdClone 特性。
  • 捕获映射定制 - 自定义通配符捕获的键部分存储方式。
  • 查找操作中无递归 - 由于键可能是一个巨大的数据结构,为了避免栈溢出,这个前缀树映射只存储那些用于回溯的小型通配符节点指针,而不是存储每个节点搜索的整个上下文。

缺点

  • 映射本身是不可变的,因为映射构建器在插入节点时使用二叉堆进行排序。我们无法在二叉堆上获取任何项而不进行整个迭代。一旦调用 build(),二叉堆将转换为排序后的 Vec。我们不能在不排序的情况下向 Vec 中推送任何项。
  • 单个通配符不能匹配多次。这意味着 word 只能由 w**d 匹配,不能由 w*d 匹配。

用法

use prefix_tree_map::PrefixTreeMapBuilder;

let mut map_builder = PrefixTreeMapBuilder::new();

// To insert an exact key path, call `insert_exact()`
map_builder.insert_exact(["path", "to", "value"], "value0");

// Insert into a existed key path could overwrite the value in it
map_builder.insert_exact(["path", "to", "value"], "value1");

// To insert an key path with wildcards, mark key parts using `prefix_tree_map::KeyPart` and call `insert()`
use prefix_tree_map::KeyPart;

map_builder.insert(
    [
        KeyPart::Exact("path"),
        KeyPart::Wildcard("to"),
        KeyPart::Exact("value"),
    ],
    "value2",
);

// Anything implemented trait `FromIterator` can be inserted as a key path:
let path = "path/to/anothor/value";
map_builder.insert_exact(path.split('/'), "value3");

let anothor_path = "path/to/:some/value";
map_builder.insert(
    anothor_path.split('/').map(|part| {
        if part.starts_with(':') {
            KeyPart::Wildcard(part)
        } else {
            KeyPart::Exact(part)
        }
    }),
    "value4",
);

// Then build the map
let map = map_builder.build();

// Find a value without matching any wildcard part
assert_eq!(
    Some(&"value3"),
    map.find_exact(&["path", "to", "anothor", "value"])
);

// Find a value with matching wildcard part
assert_eq!(Some(&"value4"), map.find(&["path", "to", "a", "value"]));

// `KeyPart::Exact` has a higher match priority than `KeyPart::Wildcard`
assert_eq!(Some(&"value3"), map.find(&["path", "to", "anothor", "value"]));

// Find a value with matching wildcard part, and store captured matched wildcard parts in a map
use std::collections::HashMap;

let mut captures = HashMap::new();
assert_eq!(
    Some(&"value4"),
    map.find_and_capture(&["path", "to", "a", "value"], &mut captures)
);

assert_eq!(Some(&"a"), captures.get(&":some"));

定制捕获映射

struct Map {
    pub data: [Option<String>; 2],
}

impl Map {
    fn new() -> Self {
        Self { data: [None, None] }
    }
}

use prefix_tree_map::Captures;

impl Captures<&str, &str> for Map {
    fn insert(&mut self, key: &str, value: &str) {
        match key {
            ":user_id" => self.data[0] = Some(value.to_string()),
            ":product_id" => self.data[1] = Some(value.to_string()),
            _ => (),
        }
    }
}

fn capture() {
    use prefix_tree_map::{KeyPart, PrefixTreeMapBuilder};

    let mut builder = PrefixTreeMapBuilder::new();

    builder.insert(
        [
            KeyPart::Exact("user"),
            KeyPart::Wildcard(":user_id"),
            KeyPart::Exact("home"),
        ],
        "user",
    );

    builder.insert(
        [
            KeyPart::Exact("product"),
            KeyPart::Wildcard(":product_id"),
            KeyPart::Exact("info"),
        ],
        "product",
    );

    let map = builder.build();
    let mut captures = Map::new();

    map.find_and_capture(
        &"/user/00000/home".split('/').collect::<Vec<_>>(),
        &mut captures,
    );

    assert_eq!("00000", captures.data[0].as_ref().unwrap());
}

有关更多信息,请参阅 examples/router.rs

no_std

通过在 Cargo.toml 中禁用 default-features 来取消 std 功能,以删除 Rust 标准库依赖。

示例

查看 示例

许可证

GNU 通用公共许可证 v3.0

无运行时依赖

功能