11 个版本 (4 个破坏性更新)
0.4.2 | 2024年6月24日 |
---|---|
0.4.1 | 2024年6月24日 |
0.3.2 | 2024年4月13日 |
0.2.1 | 2024年4月9日 |
0.0.1 | 2023年12月28日 |
#209 in 文本处理
每月111次下载
41KB
698 行
容器镜像参考
用于使用和处理类型对象 ID 的库。
关于
对象 ID (OID) 是一个基于32进制hex(这是带有扩展十六进制字母表的32进制;有关详细信息,请参阅RFC4648)编码的 UUID。UUID 是 v4(随机)或 v7(基于 UNIX纪元;有关详细信息,请参阅[draft RFC4122v17])- 此库进一步通过一个 "类型" 对 OID 进行了限定,这是一个由一个 -
与 OID 分隔的简短字母数字前缀。此库将类型为 OID 的 TOID 称为 TOID,这些 TOID 与缺少 "类型" 前缀的 OID 对应物不同。
例如 EXA-4GKFGPRVND4QT3PDR90PDKF66O
,按照惯例,前缀是三个 ASCII 字符,但这并不是 TOID 的一般性约束。
介绍
TOID 允许使用前缀形式的一个 "人类可读的主题行",其中实际数据是 UUIDv7。这意味着在调试或审查系统时,通过查看前缀即可轻松确定特定位置是否传入了错误的 TOID。这是无法通过裸 UUID 或 GUID 实现的,因为它们缺少任何类型标识符。
换句话说,如果不使用 TOID,则将一个简单的 GUID 的 UserID
与一个 OrderID
混淆的可能性很大。而 TOID 则会使错误更容易识别,甚至程序上不可能发生。
将 UUID 编码为 base32hex 还可以将数据压缩成更小、更易于人类理解的形式,类似于提交哈希。使用 "扩展十六进制编码" 添加了这样一个额外属性,即当按位比较时,编码不会失去它们的排序顺序。
最后,当用作数据库条目时,使用 UUIDv7 可启用索引局部性。
反介绍
TOID 的缺点是在处理 ID 和值时存在一层间接层,TOID 是前缀 UUIDv7 并不是一目了然的。此外,前缀本身必须以某种方式控制,包括在更改时迁移,这为应用层增加了复杂性。
与裸UUID相比,还需要额外的处理开销,以便进行编码/解码以及处理添加和删除前缀。
然而,我们认为这些缺点与从格式中获得的好处相比微不足道。
示例
use typed_oid::{error::*, Oid, OidStr, OidPrefix};
use uuid::Uuid;
use anyhow::Result;
fn main() -> Result<()> {
// TOIDs come in two flavors, Oid<T> and `OidStr`.
// A Oid<T> is a TOID using a Rust types as the type, e.g. a true Typed OID
// These are less ergonomic, but more type-safe.
run_oid()?;
// A `OidStr` is a TOID using a bare string as the type, e.g. "Stringly Typed OID"
// These easier to use, but less type-safe.
run_oidstr()?;
Ok(())
}
fn run_oidstr() -> Result<()> {
// OIDs can be created with a given prefix alone
#[cfg(feature = "uuid_v4")]
{
let oid = OidStr::new_v4("EXA")?;
println!("OidStr from UUIDv4: {oid}");
}
#[cfg(feature = "uuid_v7")]
{
let oid = OidStr::new_v7_now("EXA")?;
println!("OidStr from UUIDv7: {oid}");
}
// OIDs can also be created from the raw parts
let oid = OidStr::try_with_uuid("EXA", "b3cfdafa-3fec-41e2-82bf-ff881131abf1")?;
println!("OidStr from UUID: {oid}");
// OIDs can be parsed from strings, however the "value" must be a valid
// base32hex (no pad) encoded UUID
let oid: OidStr = "EXA-4GKFGPRVND4QT3PDR90PDKF66O".parse()?;
println!("OidStr from string: {oid}");
// One can retrieve the various parts of the OID if needed
println!("Components of {oid}:");
println!("\tPrefix: {}", oid.prefix());
println!("\tValue: {}", oid.value());
println!("\tUUID: {}", oid.uuid());
Ok(())
}
fn run_oid() -> Result<()> {
// In order for a struct to be used as a type it must implement typed_oid::OidPrefix
#[derive(Debug)]
struct EXA;
impl OidPrefix for EXA {}
// We can create a new OID by generating a random UUID
#[cfg(feature = "uuid_v4")]
{
let oid: Oid<EXA> = Oid::new_v4();
println!("Oid<EXA> with new UUIDv4: {oid}");
}
#[cfg(feature = "uuid_v7")]
{
let oid: Oid<EXA> = Oid::new_v7_now();
println!("Oid<EXA> with new UUIDv7: {oid}");
}
// Or by giving a UUID
let oid: Oid<EXA> = Oid::try_with_uuid("b3cfdafa-3fec-41e2-82bf-ff881131abf1")?;
println!("Oid<EXA> with new UUID: {oid}");
// We can go the other direction and parse a string to a Oid<EXA>
let oid: Oid<EXA> = "EXA-4GKFGPRVND4QT3PDR90PDKF66O".parse()?;
println!("Oid<EXA> with from string: {oid}");
// One can retrieve the various parts of the OID if needed
println!("Components of {oid}:");
println!("\tPrefix: {}", oid.prefix());
println!("\tValue: {}", oid.value());
println!("\tUUID: {}", oid.uuid());
// However, if we change the prefix to something that doesn't match our EXA type
// we get an error even if the UUID is valid
let res = "FAIL-4GKFGPRVND4QT3PDR90PDKF66O".parse::<Oid<EXA>>();
assert!(res.is_err());
assert_eq!(res.unwrap_err(), Error::InvalidPrefix { valid_until: 0 });
Ok(())
}
最低支持的 Rust 版本 (MSRV)
MSRV取决于启用了哪些crate功能
功能 | MSRV |
---|---|
uuid_4 |
1.60.0 |
uuid_7 |
1.60.0 |
serde |
1.60.0 |
surrealdb |
1.75.0 |
许可证
该项目根据您的选择,可在Apache License Version 2.0或MIT许可证下双授权:LICENSE-APACHE或LICENSE-MIT。
typed-oid
最初是从seaplane-oid
v0.4.0分叉而来,该版本许可协议为Apache License Version 2.0。
依赖项
~2–36MB
~577K SLoC