8个版本
1.0.7-beta.1 | 2024年7月15日 |
---|---|
1.0.6-beta.1 | 2024年7月14日 |
1.0.5-beta.1 | 2024年7月13日 |
1.0.2-beta.1 | 2024年7月12日 |
#381 在 解析器实现 中
136 每月下载量
56KB
400 行
魔法类型ID (MTI):用智能标识符赋予分布式系统力量
欢迎来到 mti
,这是一个将类型安全、前缀增强标识符的强大功能带入您分布式系统的Rust包。它基于 TypeID规范 构建,将UUID的唯一性、前缀标识符的可读性和类型安全结合起来,为跨应用程序的标识符管理提供了一种强大的解决方案。
致谢
此包实现了由 Jetify 创建和维护的 TypeID规范 版本0.3.0。我为他们在开发和维护此规范方面所做的工作表示感激。
功能
- 类型安全:直接在标识符中嵌入类型信息。
- 可读性:人类可读的前缀使标识符具有自描述性。
- 唯一性:使用UUID(包括UUIDv7)保证全局唯一性。
- 排序性:当使用UUIDv7时,标识符具有固有的时间排序性。
- 灵活性:支持各种UUID版本和自定义前缀。
- 易用性:直观的API,带有扩展方法,可轻松创建和操作。
- 性能:字符串操作的零成本抽象。
- 可靠性:基于经过彻底测试和验证的 TypeIdPrefix 和 TypeIdSuffix 包。
快速入门
将 mti
添加到您的 Cargo.toml
[dependencies]
mti = "1.0.5-beta.1"
然后,在您的Rust代码中
use mti::prelude::*;
// Create a MagicTypeId for a user
let user_id = "user".create_type_id::<V7>();
println!("New User ID: {}", user_id); // e.g., "user_01h455vb4pex5vsknk084sn02q"
// Parse an existing MagicTypeId
let order_id = MagicTypeId::from_str("order_01h455vb4pex5vsknk084sn02q").unwrap();
assert_eq!(order_id.prefix().as_str(), "order");
使用示例
创建MagicTypeIds
use mti::prelude::*;
// Create with UUIDv7 (sortable, recommended)
let product_id = "product".create_type_id::<V7>();
// Create with UUIDv4 (random)
let user_id = "user".create_type_id::<V4>();
// Create with custom suffix
let custom_suffix = TypeIdSuffix::new::<V7>();
let order_id = "order".create_type_id_with_suffix(custom_suffix);
灵活的前缀处理
use mti::prelude::*;
// Sanitized creation (always produces a valid prefix)
let sanitized_id = "Invalid Prefix!".create_type_id::<V7>();
assert!(sanitized_id.to_string().starts_with("invalidprefix_"));
// Strict creation (returns an error for invalid prefixes)
let result = "Invalid Prefix!".try_create_type_id::<V7>();
assert!(result.is_err());
字符串-like行为
use mti::prelude::*;
let id = "user".create_type_id::<V7>();
assert!(id.starts_with("user_"));
assert_eq!(id.len(), 31);
// Use in string comparisons
assert_eq!(id.as_str(), id.to_string());
解析和组件提取
use mti::prelude::*;
let id_str = "product_01h455vb4pex5vsknk084sn02q";
let magic_id = MagicTypeId::from_str(id_str).unwrap();
assert_eq!(magic_id.prefix().as_str(), "product");
assert_eq!(magic_id.suffix().to_string(), "01h455vb4pex5vsknk084sn02q");
// Extract UUID
let uuid = magic_id.suffix().to_uuid();
println!("Extracted UUID: {}", uuid);
排序
当使用MagicTypeId
与V7
UUID创建时,它提供了一种自然的排序顺序
- 主要排序:由
UUIDv7
后缀中的时间戳决定。这意味着生成的较晚的标识符将出现在较早生成的标识符之后。 - 次要排序:如果时间戳相等,则基于前缀的字典序进行排序。这确保了即使在标识符同时创建的情况下,也能保持一致的排序顺序。
use std::str::FromStr;
use std::thread::sleep;
use std::time::Duration;
use mti::prelude::*;
use typeid_prefix::prelude::*;
use typeid_suffix::prelude::*;
let prefix1 = TypeIdPrefix::from_str("user").unwrap();
let prefix2 = TypeIdPrefix::from_str("admin").unwrap();
let id1 = MagicTypeId::new(prefix1.clone(), TypeIdSuffix::new::<V7>());
sleep(Duration::from_millis(10)); // Ensure different timestamps
let id2 = MagicTypeId::new(prefix1.clone(), TypeIdSuffix::new::<V7>());
let id3 = MagicTypeId::new(prefix2.clone(), TypeIdSuffix::from_str(&id2.suffix().to_string()).unwrap());
assert!(id1 < id2, "Expected id1 to be less than id2 due to earlier timestamp");
assert_eq!(id2.suffix(), id3.suffix(), "Suffixes for id2 and id3 should be the same");
assert!(id3 < id2, "Expected id3 to be less than id2 due to lexicographically smaller prefix when timestamps are equal");
使用案例
MagicTypeId非常灵活,可应用于各种场景。
- 分布式系统:在微服务之间生成全局唯一、类型安全的标识符。
let order_id = "order".create_type_id::<V7>(); // Send to another service: "order_01h455vb4pex5vsknk084sn02q"
- 数据库记录:创建可读、可排序的主键。
let user_id = "user".create_type_id::<V7>();
// MagicTypeIds behave like strings
db.insert_user(user_id, user_data);
- API 开发:在 REST 或 GraphQL API 中用作资源标识符。
#[get("/users/{id}")]
async fn get_user(id: Path<MagicTypeId>) -> impl Responder {
// Retrieve user with id
}
- 非唯一、可重复的 ID:使用 UUIDv5 根据输入生成一致的 ID。
let namespace = Uuid::parse_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8").unwrap();
let name = "example.com";
let v5_uuid = Uuid::new_v5( & namespace, name.as_bytes());
let domain_id = MagicTypeId::new(
TypeIdPrefix::from_str("domain").unwrap(),
TypeIdSuffix::from(v5_uuid)
);
// Always produces the same ID for "example.com"
assert_eq!(domain_id.uuid_str().unwrap(), "cfbff0d1-9375-5685-968c-48ce8b15ae17");
- 日志和跟踪:在日志条目中嵌入类型信息,以便于调试。
log::info!("Processing order {}", "order".create_type_id::<V7>());
高级用法
自定义类型安全的 ID 类型
use mti::prelude::*;
struct UserId(MagicTypeId);
struct OrderId(MagicTypeId);
impl UserId {
fn new() -> Self {
Self("user".create_type_id::<V7>())
}
}
impl OrderId {
fn new() -> Self {
Self("order".create_type_id::<V7>())
}
}
// Compile-time type safety
fn process_user(id: UserId) { /* ... */ }
fn process_order(id: OrderId) { /* ... */ }
let user_id = UserId::new();
let order_id = OrderId::new();
process_user(user_id);
process_order(order_id);
// process_user(order_id); // This would cause a compile-time error!
数据库集成
use mti::prelude::*;
#[derive(Debug)]
struct User {
id: MagicTypeId,
name: String,
}
fn create_user(name: &str) -> User {
User {
id: "user".create_type_id::<V7>(),
name: name.to_string(),
}
}
// In your database operations
let user = create_user("Alice");
// MagicTypeId behaves like a string
db.insert(user.id, & user);
// Retrieving
let retrieved_id = MagicTypeId::from_str("user_01h455vb4pex5vsknk084sn02q").unwrap();
let retrieved_user = db.get::<User>(retrieved_id.to_string());
性能和安全
mti
的设计考虑了性能和安全
- 字符串操作的无成本抽象。
- 建立在经过充分测试和验证的
TypeIdPrefix
和TypeIdSuffix
包的基础上。 - 广泛使用 Rust 的类型系统来防止编译时错误。
- 全面的测试套件确保可靠性和正确性。
测试版状态
虽然这个包功能完善且经过充分测试,但它目前处于测试版,以收集更广泛的社区反馈。我鼓励您将其用于您的项目并提供反馈。如果您遇到任何问题或有一些建议,请在我的 GitHub 仓库 上提交。
贡献
我欢迎贡献!请查看我的 GitHub 仓库,以获取问题、功能请求和拉取请求。
许可
此项目受以下任一许可证的许可:
- Apache License,版本 2.0,(LICENSE-APACHE)
- MIT 许可证 (LICENSE-MIT)
任选其一。
关于作者
我是 @rrrodzilla,一名拥有 30 年行业经验的技术人员。我曾是一名 SOA 和云架构师,也是 AWS Rust 编程语言的资深技术产品经理。目前,我是 Govcraft 的所有者和运营者,致力于构建和咨询 Rust 和 AI 解决方案。
更多信息,请访问 https://www.govcraft.ai
依赖项
~535KB