6 个版本 (稳定)
2.0.1 | 2023 年 12 月 26 日 |
---|---|
2.0.0 | 2023 年 10 月 7 日 |
1.0.1 | 2022 年 12 月 22 日 |
1.0.0 | 2021 年 12 月 21 日 |
0.1.0 | 2021 年 9 月 14 日 |
#82 在 算法 中
2,242 每月下载量
用于 5 个crate(2 个直接使用)
46KB
781 行
fractional_index
此crate实现了分数索引,这是Figma在其博客文章《有序序列的实时编辑》中提出的术语。
具体来说,此crate提供了一种名为 FractionalIndex
的类型。一个 FractionalIndex
作为一个“黑盒”,仅用于与另一个 FractionalIndex
进行比较。一个 FractionalIndex
只能通过默认构造函数或引用现有 FractionalIndex
来构造。
当我们在一个集合中能够任意插入或重新排序元素,但又不关心键值时,它作为 BTreeMap
中的键非常有用。它还用于解决多个用户同时修改列表时出现的冲突。
用法
FractionalIndex
的API非常简单
FractionalIndex::default()
创建一个新的分数索引。FractionalIndex::new_before(a)
在另一个之前创建一个分数索引。FractionalIndex::new_after(a)
在另一个之后创建一个分数索引。FractionalIndex::new_between(a, b)
在两个之间创建一个分数索引。
use fractional_index::FractionalIndex;
fn main() {
// Construct a fractional index.
let index = FractionalIndex::default();
// Construct another fractional index that comes before it.
let before_index = FractionalIndex::new_before(&index);
assert!(before_index < index);
// Construct a third fractional index between the other two.
let between_index = FractionalIndex::new_between(
&before_index,
&index
).unwrap();
assert!(before_index < between_index);
assert!(between_index < index);
}
字符串化
FractionalIndex
存储为字节字符串,但可以转换为字符串并从字符串转换。
use fractional_index::FractionalIndex;
fn main() {
let a = FractionalIndex::default();
let b = FractionalIndex::new_after(&a);
let c = FractionalIndex::new_between(&a, &b).unwrap();
let c_str = c.to_string();
assert_eq!("817f80", c_str);
let c = FractionalIndex::new_between(&a, &b).unwrap();
}
两个字符串化 FractionalIndex
值的字典序与未字符串化的版本顺序相同。
use fractional_index::FractionalIndex;
fn main() {
let a = FractionalIndex::default();
let b = FractionalIndex::new_after(&a);
let c = FractionalIndex::new_between(&a, &b).unwrap();
assert!(a.to_string() < c.to_string());
assert!(c.to_string() < b.to_string());
}
这在需要能够在具有原生字符串比较但没有字节字符串比较的语言(如JavaScript)中比较索引时非常有用。
::new()
构造函数
::new()
构造函数泛型化 ::default()
、::new_before()
、::new_after()
和 ::new_between()
。
use fractional_index::FractionalIndex;
fn main() {
let a = FractionalIndex::default();
let a2 = FractionalIndex::new(None, None).unwrap();
assert_eq!(a, a2);
let b = FractionalIndex::new_after(&a);
let b2 = FractionalIndex::new(Some(&a), None).unwrap();
assert_eq!(b, b2);
let c = FractionalIndex::new_between(&a, &b).unwrap();
let c2 = FractionalIndex::new(Some(&a), Some(&b)).unwrap();
assert_eq!(c, c2);
}
序列化
启用默认的 serde
功能后,FractionalIndexes
可以进行序列化。
use fractional_index::FractionalIndex;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct MyStruct {
a: FractionalIndex,
b: FractionalIndex,
c: FractionalIndex,
}
fn main() {
let a = FractionalIndex::default();
let b = FractionalIndex::new_after(&a);
let c = FractionalIndex::new_between(&a, &b).unwrap();
let my_struct = MyStruct {
a: a.clone(),
b: b.clone(),
c: c.clone(),
};
let json_string = serde_json::to_string(&my_struct).unwrap();
let my_struct_de = serde_json::from_str(&json_string).unwrap();
assert_eq!(my_struct, my_struct_de);
}
默认情况下,FractionalIndexes
以字节数组的形式进行序列化,可以在 bincode 等格式中高效地进行序列化。
当使用 JSON 等格式将数据发送到非 Rust 编程语言时,这些字节数组就不是很实用了。
对于这些用例,我们提供了一个字符串化序列化器,可以通过对字段进行注解来启用,注解方式为 #[serde(with="fractional_index::stringify")]
。
use fractional_index::FractionalIndex;
use serde::{Serialize, Deserialize};
use serde_json::json;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct MyStruct {
#[serde(with="fractional_index::stringify")]
a: FractionalIndex,
#[serde(with="fractional_index::stringify")]
b: FractionalIndex,
#[serde(with="fractional_index::stringify")]
c: FractionalIndex,
}
fn main() {
let a = FractionalIndex::default();
let b = FractionalIndex::new_after(&a);
let c = FractionalIndex::new_between(&a, &b).unwrap();
let my_struct = MyStruct {
a: a.clone(),
b: b.clone(),
c: c.clone(),
};
let json_value = serde_json::to_value(&my_struct).unwrap();
let expected = json!({
"a": "80",
"b": "8180",
"c": "817f80",
});
assert_eq!(expected, json_value);
}
稳定性
FractionalIndex
的字节数表示法可以保证与未来版本的此软件包完全向前和向后兼容,这意味着由任何版本的此软件包生成的两个 FractionalIndex
的序列化表示在任何其他版本反序列化时将按相同的方式进行比较。
new_before
、new_after
和 new_between
创建的 FractionalIndex
的实际字节数表示法可能在版本之间有所不同,但结果将始终与用于构建的参考 FractionalIndex
(es) 适当地进行比较,而不管版本如何。
FractionalIndex
的字节数表示法不旨在与 ZenoIndex
的字节数表示法兼容,它们的序列化对应物也不兼容。
2.x.x 版本说明
在此软件包的 1.x.x 版本中,分数索引是通过一个名为 ZenoIndex
的结构体实现的。与 FractionalIndex
的实现相似,它们都将以字节字符串表示底层数据,但 ZenoIndex
需要一个自定义的比较函数来与该字节字符串一起使用。而 FractionalIndex
更改了字节表示法,以便比较两个 FractionalIndex
需要的仅仅是底层字节数据的字典序比较。
ZenoIndex
结构体在 2.x.x 版本的此软件包中仍然可用,但它已被弃用。新代码应使用 FractionalIndex
代替,它实现了相同的功能。
依赖关系
~0.4–1MB
~23K SLoC