A Rust implementation of generic prefix tree (trie) map with wildcard capture support

Overview

prefix_tree_map

A Rust implementation of generic prefix tree (trie) map with wildcard capture support.

Version Documentation License

Design

Trie is a good data structure for storing key-value pairs with wildcard support ability.

This prefix tree map implementation supports any type of key and value, as long as key parts are implemented the Ord and Clone trait. Internally, nodes are stored in a sorted Vec. So technically it can achieve O(log n) time complexity on finding every node by using binary search on the sorted Vec.

Using as a route-table-like structure could be the best scenario for this crate.

Pros and Cons

Pros

  • Fast and efficient
  • Wildcard Capture Support - Capture wildcard characters in a map while matching.
  • Generalization - Supports any type of key and value, as long as key parts are implemented the Ord and Clone trait.
  • Capture Map Customization - Customize the way key parts captured by wildcard stored.
  • No recursion in find operations - Rather than store the whole context of every node searching, this prefix tree map only store those tiny wildcard node pointers for backtracking on heap.

Cons

  • The map itself is immutable, because the map builder is using Binary Heap to sort the nodes when they are inserted. We can't get a item from a Binary Heap without iterating the whole Binary Heap. Once the build() is called, Binary Heaps are converted into sorted Vecs. We can't push any item to the Vec without a whole sort operation.
  • Currently, a single wildcard cannot be matched more than one time. It means word can be matched by w**d, not w*d.

Usage

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"));

Customizing Capture map:

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());
}

For more infomation, check out examples/router.rs

no_std

Opt out the std feature by disabling default-features in Cargo.toml to remove the Rust standard library dependency.

Examples

Check examples.

License

GNU General Public License v3.0

You might also like...
A radix tree implementation for router, and provides CRUD operations.

radixtree A radix tree implementation for router, and provides CRUD operations. Radixtree is part of treemux, on top of which updates and removes are

An Adaptive Radix Tree implementation.

Ryan's Adaptive Radix Tree This is yet another implementation of an Adaptive Radix Tree (ART) in Rust. ARTs are an ordered associative (key-value) str

Parallel pipelined map over iterators.

plmap Parallel pipelined map over iterators for rust. Documentation docs.rs/plmap Example Parallel pipelined mapping: // Import the iterator extension

A fast and flexible LRU map.

A fast and flexible LRU map This repository contains a fast and flexible LRU map. Blazingly fast. Up to twice as fast as the lru crate, and with less

A parser for the .map file included in the aimware leak
A parser for the .map file included in the aimware leak

a utility I wrote to parse the map file included with the recent aimware self-leak. there is also an IDAPython script to import the symbol information into IDA.

A typed map which can make sure item exist.

Certain Map A typed map which can make sure item exist. What Problem Does It Solve In Rust, we often use Service abstraction for modular structure des

Simple, automatic, and customizable tree pretty-printing in Rust.
Simple, automatic, and customizable tree pretty-printing in Rust.

display_tree Simple, automatic, and customizable tree pretty-printing in Rust. This crate provides tools to easily pretty-print data as a tree, includ

Use rust programming language to create a b+ tree.
Use rust programming language to create a b+ tree.

Use rust programming language to create a b+ tree.

Serialize & deserialize device tree binary using serde

serde_device_tree Use serde framework to deserialize Device Tree Blob binary files; no_std compatible. Use this library Run example: cargo run --examp

Releases(0.2.1)
Owner
EAimTY
Coding like an ape
EAimTY
Simple string matching with questionmark- and star-wildcard operator

wildmatch Match strings against a simple wildcard pattern. Tests a wildcard pattern p against an input string s. Returns true only when p matches the

Armin Becher 38 Dec 18, 2022
🦀 Rust crate that allows creating weighted prefix trees that can be used in autocomplete

weighted_trie ?? Rust crate that allows creating weighted prefix trees that can be used in autocomplete Released API Docs Quickstart To use weigthed-t

Alexander Osipenko 8 Mar 1, 2023
Rust based magic-string with source map chains support

enhanced-magic-string Rust implementation of https://www.npmjs.com/package/magic-string with original sourcemap chain support. license. This project i

Farm 3 Nov 5, 2023
a playground for exploring media capture, processing and publishing with rust

vidrs: a playground for exploring media capture, processing and publishing with rust How to use On a MacOS system with an attached camera you can call

Gilbert Röhrbein 6 Jan 2, 2023
Support SIMD low-memory overhead and high-performance adaptive radix tree.

Artful Artful is an adaptive radix tree library for Rust. At a high-level, it's like a BTreeMap. It is based on the implementation of paper, see The A

future 3 Sep 7, 2022
Generic inventory system built in pure rust.

game_inventory A framework for generalizing inventory logic and abstracting it away from item data in your specific game. See more examples and specif

null 7 Jul 30, 2022
Generic abstractions for combining and nesting reduction patterns for iterables.

reductor Generic abstractions for combining and nesting reduction patterns for iterables. Docs: https//docs.rs/reductor Before & After: Before fn proc

Yotam Ofek 2 Jul 9, 2022
Rust crates with map and set with interval keys (ranges x..y).

This crates implements map and set with interval keys (ranges x..y). IntervalMap is implemented using red-black binary tree, where each node contains

Timofey Prodanov 8 Aug 23, 2022
📈 The fastest map possible in Rust, where keys are integers and the capacity is fixed (faster than Vec!)

It is an alternative on-heap implementation of a map with keys of type usize and a fixed capacity. It works much faster than a standard HashMap becaus

Yegor Bugayenko 6 Apr 26, 2023
A Rust crate that implements a range map data structure backed by a Vec.

range_map_vec This crate implements a range map data structure backed by a Vec using binary search. Docs and usage can be found in the corresponding r

Microsoft 9 Sep 8, 2023