Qqw*_*qwy 5 b-tree tuples range multi-index rust
我正在尝试使用 aBTreeSet<(String, String, String)>作为创建一个简单的内存中“三重存储”的方法。
准确地说:
type Entity = String;
type Attribute = String;
type Value = String;
type EAV = (Entity, Attribute, Value);
type EAVSet = BTreeSet<EAV>;
pub fn example_db() -> EAVSet {
let mut example: EAVSet = BTreeSet::new();
insert_strtup(&mut example, ("1", "type", "user"));
insert_strtup(&mut example, ("1", "user/name", "Arthur Dent"));
insert_strtup(&mut example, ("1", "user/age", "33"));
insert_strtup(&mut example, ("2", "type", "user"));
insert_strtup(&mut example, ("2", "user/name", "Ford Prefect"));
insert_strtup(&mut example, ("2", "user/age", "42"));
return example;
}
fn insert_strtup(db: &mut EAVSet, val: (&str, &str, &str)) -> () {
db.insert((val.0.to_string(), val.1.to_string(), val.2.to_string()));
}
pub fn example() {
let db = example_db();
// How to customize this?
let range: (Bound<EAV>, Bound<EAV>) = (Bound::Unbounded, Bound::Unbounded);
for elem in eavt.range(range) {
println!("{:?}", elem);
}
}
Run Code Online (Sandbox Code Playgroud)
我面临的问题是,我希望人们能够迭代集合中的值的子范围。然而,简单的使用std::ops::Bound是不可能的,因为我们存储具有多个字段的元组。
我希望能够为以下所有内容构建范围查询:
x..y;1;1实体字段的当前值"user/age")。到目前为止,想到的唯一想法是使用字符串键,我们知道该字符串键的事实比较较低。高于我们在“占位符”字段中寻找的值。但这感觉非常黑客/容易出错,就像重新发明轮子一样。
有没有办法把a变成(Bound<String>, Bound<String>, Bound<String>)也许Bound<(String, String, String)>?或者这里可以采取另一种方法吗?
编辑:在 Rust 中过滤/查询多键 btree 索引显示了一种通过将所有值包装在有序 Enum ( Min, Exact(String), Max) 中的解决方案,但此解决方案需要更改 BTreeSet 中存储的值类型。这也感觉像是增加了内存开销,因为我们实际上从不存储除Exact(some_string)内部之外的任何内容。是否有另一种方法不需要更改存储在 中的值的类型BTreeSet?
由于Borrow总是返回一个引用(grrrrrrrr),并且Borrowed不一定Copy,您也许可以依赖哨兵内存地址?
请注意,由于static不允许关联项目,因此您可能需要为要使用的每种类型提供此代码的副本。
use std::borrow::Borrow;
use std::cmp::Ordering;
#[repr(transparent)]
pub struct StringWithMinMaxSentinel(String);
// must be static, not const, to ensure a constant memory address
pub static STRING_MIN_SENTINEL: StringWithMinMaxSentinel = StringWithMinMaxSentinel(String::new());
pub static STRING_MAX_SENTINEL: StringWithMinMaxSentinel = StringWithMinMaxSentinel(String::new());
impl Borrow<StringWithMinMaxSentinel> for String {
fn borrow(self: &String) -> &StringWithMinMaxSentinel {
unsafe { &*(self as *const String as *const StringWithMinMaxSentinel) }
}
}
impl PartialEq for StringWithMinMaxSentinel {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self, other) || (!std::ptr::eq(self, &STRING_MIN_SENTINEL) && !std::ptr::eq(other, &STRING_MAX_SENTINEL) && !std::ptr::eq(other, &STRING_MIN_SENTINEL) && !std::ptr::eq(self, &STRING_MAX_SENTINEL) && self.0.eq(&other.0))
}
}
impl Eq for StringWithMinMaxSentinel {}
impl PartialOrd for StringWithMinMaxSentinel {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for StringWithMinMaxSentinel {
fn cmp(&self, other: &Self) -> Ordering {
if std::ptr::eq(self, other) {
Ordering::Equal
} else if std::ptr::eq(self, &STRING_MIN_SENTINEL) || std::ptr::eq(other, &STRING_MAX_SENTINEL) {
Ordering::Less
} else if std::ptr::eq(self, &STRING_MAX_SENTINEL) || std::ptr::eq(other, &STRING_MIN_SENTINEL) {
Ordering::Greater
} else {
self.0.cmp(&other.0)
}
}
}
Run Code Online (Sandbox Code Playgroud)