Rust Base64标签化编解码库tagged-base64的使用,支持类型安全的高效数据转换与序列化

Rust Base64标签化编解码库tagged-base64的使用,支持类型安全的高效数据转换与序列化

安装

安装二进制工具

cargo install tagged-base64

作为库安装

在项目目录中运行以下Cargo命令:

cargo add tagged-base64

或在Cargo.toml中添加:

tagged-base64 = "0.4.0"

使用示例

下面是一个完整的示例,展示如何使用tagged-base64进行类型安全的Base64编解码:

use serde::{Serialize, Deserialize};
use tagged_base64::{TaggedB64, Tag};

// 定义自定义标签类型
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct MyTag;

// 实现Tag trait
impl Tag for MyTag {
    fn tag() -> &'static str {
        "mytag"  // 这个标签会包含在Base64编码的输出中
    }
}

// 定义使用标签的结构体
#[derive(Debug, Serialize, Deserialize)]
struct MyData {
    #[serde(with = "TaggedB64::<MyTag>")]
    data: Vec<u8>,
}

fn main() {
    // 原始数据
    let original_data = vec![1, 2, 3, 4, 5];
    
    // 创建数据结构
    let my_data = MyData {
        data: original_data.clone(),
    };
    
    // 序列化为JSON
    let json = serde_json::to_string(&my_data).unwrap();
    println!("Serialized JSON: {}", json);
    
    // 从JSON反序列化
    let deserialized: MyData = serde_json::from_str(&json).unwrap();
    
    // 验证数据
    assert_eq!(deserialized.data, original_data);
    println!("Deserialized data matches original!");
}

特性

  1. 类型安全:通过自定义标签确保只有正确标记的数据才能被解码
  2. 高效:利用Rust的性能优势提供快速的编解码操作
  3. 与Serde集成:无缝支持序列化和反序列化
  4. 可扩展:可以轻松定义自己的标签类型

完整示例代码

use serde::{Serialize, Deserialize};
use tagged_base64::{TaggedB64, Tag};

// 1. 定义两个不同的标签类型
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct UserDataTag;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct SessionDataTag;

// 2. 为每个标签实现Tag trait
impl Tag for UserDataTag {
    fn tag() -> &'static str {
        "user"  // 用户数据标签
    }
}

impl Tag for SessionDataTag {
    fn tag() -> &'static str {
        "session"  // 会话数据标签
    }
}

// 3. 定义两个使用不同标签的结构体
#[derive(Debug, Serialize, Deserialize)]
struct UserProfile {
    #[serde(with = "TaggedB64::<UserDataTag>")]
    avatar: Vec<u8>,  // 用户头像数据
    
    #[serde(with = "TaggedB64::<UserDataTag>")]
    settings: Vec<u8>,  // 用户设置数据
}

#[derive(Debug, Serialize, Deserialize)]
struct SessionInfo {
    #[serde(with = "TaggedB64::<SessionDataTag>")]
    token: Vec<u8>,  // 会话令牌
    
    #[serde(with = "TaggedB64::<SessionDataTag>")]
    metadata: Vec<u8>,  // 会话元数据
}

fn main() {
    // 4. 创建示例数据
    let user_profile = UserProfile {
        avatar: vec![10, 20, 30, 40, 50],
        settings: vec![1, 2, 3, 4, 5, 6, 7, 8],
    };
    
    let session_info = SessionInfo {
        token: vec![255, 254, 253],
        metadata: vec![100, 101, 102, 103],
    };
    
    // 5. 序列化为JSON
    let user_json = serde_json::to_string(&user_profile).unwrap();
    let session_json = serde_json::to_string(&session_info).unwrap();
    
    println!("User Profile JSON: {}", user_json);
    println!("Session Info JSON: {}", session_json);
    
    // 6. 尝试反序列化 - 确保类型安全
    // 正确的标签匹配
    let user: UserProfile = serde_json::from_str(&user_json).unwrap();
    let session: SessionInfo = serde_json::from_str(&session_json).unwrap();
    
    // 错误的标签匹配会失败
    let result: Result<UserProfile, _> = serde_json::from_str(&session_json);
    assert!(result.is_err(), "Should fail due to tag mismatch");
    
    println!("All operations completed successfully!");
}

文档

更多详细用法请参考官方文档。


1 回复

以下是关于tagged-base64库的完整使用指南,包含所有示例代码:

完整示例代码

1. 预定义标签使用示例

use tagged_base64::prelude::*;

fn main() {
    // 编码示例
    let data = b"hello world";
    let encoded = data.to_base64(Standard);  // 使用标准Base64编码
    println!("Encoded: {}", encoded);
    
    // 解码示例
    let decoded = Vec::<u8>::from_base64(&encoded, Standard).unwrap();
    assert_eq!(decoded, data);
}

2. 自定义标签实现示例

use tagged_base64::{TaggedBase64, Tag};

// 自定义标签定义
struct MyCustomTag;
impl Tag for MyCustomTag {
    const CONFIG: base64::Config = base64::Config::new(
        base64::CharacterSet::Standard,  // 使用标准字符集
        true                             // 使用填充
    );
}

fn main() {
    let secret_data = b"sensitive information";
    
    // 使用自定义标签编码
    let encoded = secret_data.to_base64(MyCustomTag);
    println!("Securely encoded: {}", encoded);
    
    // 必须使用相同标签解码
    let decoded = Vec::<u8>::from_base64(&encoded, MyCustomTag).unwrap();
    assert_eq!(decoded, secret_data);
}

3. 序列化/反序列化完整示例

use serde::{Serialize, Deserialize};
use tagged_base64::{TaggedBase64, Standard};

#[derive(Serialize, Deserialize, Debug)]
struct User {
    #[serde(with = "tagged_base64::serde")]  // 使用tagged-base64的serde支持
    avatar: Vec<u8>,
    name: String,
}

fn main() {
    // 创建用户对象
    let user = User {
        avatar: b"binary image data".to_vec(),
        name: "Alice".to_string(),
    };
    
    // 序列化为JSON
    let json = serde_json::to_string(&user).unwrap();
    println!("Serialized JSON: {}", json);
    
    // 从JSON反序列化
    let deserialized: User = serde_json::from_str(&json).unwrap();
    println!("Deserialized user: {:?}", deserialized);
    assert_eq!(deserialized.avatar, b"binary image data");
}

4. 高级用法完整示例

use tagged_base64::{TaggedBase64, UrlSafe, Standard, Mime, DecodeError};

fn main() {
    // 多种编码配置示例
    let data = b"complex data @#$%^&";
    println!("Standard编码: {}", data.to_base64(Standard));
    println!("URL安全编码: {}", data.to_base64(UrlSafe));
    println!("MIME编码: {}", data.to_base64(Mime));

    // 错误处理示例
    match Vec::<u8>::from_base64("invalid!data", Standard) {
        Ok(data) => println!("解码成功: {:?}", data),
        Err(DecodeError::InvalidByte(_, _)) => println!("错误: 包含无效字符"),
        Err(e) => println!("其他错误: {}", e),
    }
}

5. 性能优化完整示例

use std::borrow::Cow;
use tagged_base64::{TaggedBase64, Standard};

fn main() {
    // 预分配缓冲区示例
    let large_data = vec![0u8; 1024 * 1024];  // 1MB数据
    let encoded = encode_large_data(&large_data);
    println!("编码数据长度: {}", encoded.len());

    // Cow使用示例
    let input1 = "base64:SGVsbG8gV29ybGQ=";  // Base64编码数据
    let input2 = "plain text";               // 普通文本
    
    println!("解码结果1: {:?}", maybe_decode(input1));
    println!("解码结果2: {:?}", maybe_decode(input2));
}

// 预分配缓冲区的编码函数
fn encode_large_data(data: &[u8]) -> String {
    let mut buf = String::with_capacity(data.len() * 4 / 3 + 4);
    data.write_base64(Standard, &mut buf).unwrap();
    buf
}

// 使用Cow避免不必要拷贝的函数
fn maybe_decode<'a>(input: &'a str) -> Cow<'a, [u8]> {
    if input.starts_with("base64:") {
        let encoded = &input[7..];
        Cow::Owned(Vec::<u8>::from_base64(encoded, Standard).unwrap())
    } else {
        Cow::Borrowed(input.as_bytes())
    }
}

使用建议

  1. 对于安全性要求高的场景,建议为每种数据类型创建独立的标签
  2. 处理大型数据时,务必使用预分配缓冲区的方式
  3. 在Web应用中,URL路径或参数编码使用UrlSafe标签
  4. 考虑使用新类型模式(New Type Pattern)包装不同标签的Base64数据

这个库通过类型系统在编译期捕获了许多潜在错误,同时保持了良好的运行时性能,是传统Base64编码的强类型替代方案。

回到顶部