Rust错误处理库ic-error-types的使用:高效管理IC(Internet Computer)生态系统的自定义错误类型
Rust错误处理库ic-error-types的使用:高效管理IC(Internet Computer)生态系统的自定义错误类型
ic-error-types 是一个 Rust 库,包含了 Internet Computer (IC) 生态系统中定义的 RejectCode
错误代码,这些代码在 IC 接口规范中有详细说明,同时也包含了一些未在规范中定义的实现特定的错误代码。
安装
在你的项目目录中运行以下 Cargo 命令:
cargo add ic-error-types
或者在你的 Cargo.toml 文件中添加以下行:
ic-error-types = "0.2.0"
使用示例
下面是一个完整的使用示例,展示如何在你的 IC 项目中处理自定义错误类型:
use ic_error_types::{RejectCode, UserError};
use std::convert::TryFrom;
fn main() {
// 创建一个系统错误
let system_error = RejectCode::SysFatal;
// 将RejectCode转换为u64
let error_code: u64 = system_error as u64;
println!("System error code: {}", error_code);
// 从u64尝试转换回RejectCode
match RejectCode::try_from(5) {
Ok(code) => println!("Converted back to RejectCode: {:?}", code),
Err(_) => println!("Invalid error code"),
}
// 创建用户错误
let user_error = UserError::new(
RejectCode::CanisterError,
"Custom error message".to_string(),
);
// 处理用户错误
match user_error.reject_code() {
RejectCode::CanisterError => {
println!("Handling canister error: {}", user_error.message());
}
_ => println!("Other type of error"),
}
// 使用IC规范中定义的错误代码
let canister_reject = RejectCode::CanisterReject;
println!("Canister reject code: {}", canister_reject as u64);
}
完整示例demo
下面是一个更完整的示例,展示了如何在IC canister开发中使用ic-error-types进行错误处理:
use ic_error_types::{RejectCode, UserError};
use std::convert::TryFrom;
// 模拟一个canister函数
fn process_request(input: u32) -> Result<u32, UserError> {
if input == 0 {
// 返回一个系统错误
Err(UserError::new(
RejectCode::SysTransient,
"Input cannot be zero".to_string(),
))
} else if input > 100 {
// 返回一个canister错误
Err(UserError::new(
RejectCode::CanisterError,
"Input exceeds maximum value".to_string(),
))
} else {
// 处理成功
Ok(input * 2)
}
}
fn main() {
// 测试不同的输入情况
let test_cases = vec![0, 150, 50];
for input in test_cases {
match process_request(input) {
Ok(result) => println!("Success: {}", result),
Err(err) => {
// 根据错误类型进行不同处理
match err.reject_code() {
RejectCode::SysTransient => {
println!("System transient error: {}", err.message());
// 可以在这里添加重试逻辑
}
RejectCode::CanisterError => {
println!("Canister error: {}", err.message());
// 可以在这里记录错误或通知管理员
}
_ => println!("Unexpected error: {:?}", err),
}
// 打印错误代码
println!("Error code: {}", err.reject_code() as u64);
}
}
}
// 演示错误代码转换
println!("\nError code conversion examples:");
for code in 0..=6 {
match RejectCode::try_from(code) {
Ok(reject_code) => println!("Code {}: {:?}", code, reject_code),
Err(_) => println!("Code {}: Invalid", code),
}
}
// 使用IC规范中定义的错误代码
let important_error = RejectCode::CanisterReject;
println!("\nImportant error code: {}", important_error as u64);
}
示例代码说明
- 定义了一个
process_request
函数模拟canister中的请求处理 - 根据不同的输入返回不同的错误类型:
- 输入为0时返回系统临时错误
- 输入超过100时返回canister错误
- 正常情况下返回处理结果
- 在主函数中测试了不同的输入情况
- 展示了如何根据不同的错误类型采取不同的处理措施
- 演示了错误代码与枚举值之间的转换
- 使用了IC规范中定义的特定错误代码
主要功能
ic-error-types 提供以下主要功能:
- 标准化的 IC 错误代码枚举 (
RejectCode
) - 用户错误类型 (
UserError
) 用于创建自定义错误 - 错误代码与数字之间的转换
- 支持 IC 规范中定义的所有标准错误代码
- 一些实现特定的额外错误代码
这个库由 dfinity/execution 团队维护,是 Internet Computer 生态系统的重要组成部分,特别适合在 IC 上的 canister 开发中使用。
1 回复
Rust错误处理库 ic-error-types
的使用:高效管理IC生态系统的自定义错误类型
ic-error-types
是一个专门为 Internet Computer (IC) 生态系统设计的 Rust 错误处理库,它简化了在 IC 上开发时自定义错误类型的创建和管理。
主要特性
- 专为 IC 生态优化的错误处理
- 简化自定义错误类型的定义
- 提供与 IC 系统良好集成的错误转换
- 支持清晰的错误分类和层次结构
安装
在 Cargo.toml
中添加依赖:
[dependencies]
ic-error-types = "0.1"
完整示例代码
// 引入必要的库
use ic_error_types::{ErrorType, ErrorCode, ResultExt, ToCanisterError};
use ic_cdk::api;
// 定义数据库错误类型
#[derive(Debug, ErrorType)]
pub enum DatabaseError {
#[error("Connection failed")]
ConnectionFailed,
#[error("Query failed: {0}")]
QueryFailed(String),
}
// 实现错误代码
impl ErrorCode for DatabaseError {
fn code(&self) -> u32 {
match self {
DatabaseError::ConnectionFailed => 5001,
DatabaseError::QueryFailed(_) => 5002,
}
}
}
// 定义业务逻辑错误类型
#[derive(Debug, ErrorType)]
pub enum BusinessError {
#[error("User not found")]
UserNotFound,
#[error("Invalid permission")]
InvalidPermission,
#[error("Database error: {0}")]
DatabaseError(#[from] DatabaseError),
}
// 实现错误代码
impl ErrorCode for BusinessError {
fn code(&self) -> u32 {
match self {
BusinessError::UserNotFound => 4001,
BusinessError::InvalidPermission => 4003,
BusinessError::DatabaseError(e) => e.code(),
}
}
}
// 模拟数据库操作函数
fn db_query(user_id: u64) -> Result<String, DatabaseError> {
if user_id == 0 {
Err(DatabaseError::QueryFailed("Invalid user ID".to_string()))
} else {
Ok(format!("User data for {}", user_id))
}
}
// 业务逻辑函数
fn get_user_data(user_id: u64, is_admin: bool) -> Result<String, BusinessError> {
if !is_admin {
return Err(BusinessError::InvalidPermission);
}
let data = db_query(user_id)?; // 使用?自动转换错误
if data.contains("no data") {
Err(BusinessError::UserNotFound)
} else {
Ok(data)
}
}
// IC Canister 入口函数
#[ic_cdk::update]
fn canister_get_user_data(user_id: u64, is_admin: bool) -> Result<String, String> {
get_user_data(user_id, is_admin)
.to_canister_error() // 转换为IC canister兼容的错误格式
}
// 测试用例
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_permission_error() {
let result = get_user_data(1, false);
assert!(matches!(result, Err(BusinessError::InvalidPermission)));
}
#[test]
fn test_database_error_propagation() {
let result = get_user_data(0, true);
assert!(matches!(
result,
Err(BusinessError::DatabaseError(DatabaseError::QueryFailed(_)))
));
}
}
代码说明
-
错误类型定义:
- 定义了
DatabaseError
和BusinessError
两种错误类型 - 使用
#[derive(ErrorType)]
自动实现常见trait - 实现了
ErrorCode
trait为每种错误指定唯一代码
- 定义了
-
错误嵌套:
BusinessError
包含了DatabaseError
作为嵌套错误- 使用
#[from]
属性自动实现From
trait
-
IC集成:
to_canister_error()
方法将自定义错误转换为IC兼容格式- Canister入口函数返回
Result<String, String>
类型
-
测试用例:
- 验证权限错误处理
- 验证数据库错误传播
这个完整示例展示了如何在IC生态系统中使用ic-error-types
进行全面的错误处理,包括错误定义、嵌套、转换以及与IC系统的集成。