feat(serialize): 添加Base36编解码模块
新增Base36编码和解码功能,支持字节数据与Base36字符串之间的相互转换, 并提供对i64整数的Base36编解码支持。同时更新了相关依赖版本以提升安全性 和性能。 - 新增 `base36` 模块,实现完整的Base36编解码逻辑 - 支持去除填充字符 `=` 后的容错处理 - 提供 `encode`, `decode`, `encode_int64`, `decode_to_int64` 等公共接口 - 更新 Cargo.toml 中多项依赖至最新稳定版本
This commit is contained in:
24
Cargo.toml
24
Cargo.toml
@@ -9,24 +9,24 @@ crate-type = ["dylib", "rlib"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
aes = "0.8.3"
|
||||
base64 = "0.21.2"
|
||||
aes = "0.8.4"
|
||||
base64 = "0.22.1"
|
||||
blake2b_simd = "1.0.3"
|
||||
blake3 = { version = "1.8.2", features = ["serde", "digest"] }
|
||||
blockhash = "0.5.0"
|
||||
blockhash = "1.0.0"
|
||||
cbc = { version = "0.1.2", features = ["std"] }
|
||||
chrono = "0.4.26"
|
||||
cipher = "0.4.4"
|
||||
des = "0.8.1"
|
||||
hex = "0.4.3"
|
||||
hmac-sha256 = "1.1.7"
|
||||
hmac-sha512 = "1.1.5"
|
||||
image = "0.24.6"
|
||||
md-5 = "0.10.5"
|
||||
once_cell = "1.18.0"
|
||||
hmac-sha256 = "1.1.12"
|
||||
hmac-sha512 = "1.1.7"
|
||||
image = "0.25.8"
|
||||
md-5 = "0.10.6"
|
||||
once_cell = "1.21.3"
|
||||
rand = "0.8.5"
|
||||
rsa = { version = "0.9.2", features = ["sha2"] }
|
||||
sha1 = "0.10.5"
|
||||
sha2 = "0.10.7"
|
||||
thiserror = "1.0.40"
|
||||
uuid = { version = "1.4.0", features = ["v4", "fast-rng"] }
|
||||
sha1 = "0.10.6"
|
||||
sha2 = "0.10.9"
|
||||
thiserror = "2.0.17"
|
||||
uuid = { version = "1.18.1", features = ["v4", "fast-rng"] }
|
||||
|
144
src/serialize/base36.rs
Normal file
144
src/serialize/base36.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
use thiserror::Error;
|
||||
|
||||
const BASE36_CHARS: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Base36Error {
|
||||
#[error("number too large for i64")]
|
||||
NumberTooLarge,
|
||||
#[error("invalid character '{0}'")]
|
||||
InvalidCharacter(char),
|
||||
}
|
||||
|
||||
/// 将字节数据编码为Base36字符串(大写),使用=作为padding字符
|
||||
pub fn encode(src: &[u8]) -> String {
|
||||
if src.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
// 将字节转换为大数表示,这里使用Vec<u8>模拟大整数运算
|
||||
let mut num = src.to_vec();
|
||||
|
||||
// 去除前导零但保留至少一个字节
|
||||
while num.len() > 1 && num[0] == 0 {
|
||||
num.remove(0);
|
||||
}
|
||||
|
||||
// 如果输入为全零字节,则直接返回"0"
|
||||
if num.iter().all(|&b| b == 0) {
|
||||
return "0".to_string();
|
||||
}
|
||||
|
||||
// 进行Base36编码
|
||||
let mut result = Vec::new();
|
||||
let base = 36u8;
|
||||
|
||||
// 重复除以36,获取余数作为字符
|
||||
while !num.is_empty() && !(num.len() == 1 && num[0] == 0) {
|
||||
let mut remainder: u16 = 0;
|
||||
let mut new_num = Vec::new();
|
||||
let mut first = true;
|
||||
|
||||
for &byte in &num {
|
||||
remainder = remainder * 256 + byte as u16;
|
||||
let quotient = remainder / base as u16;
|
||||
remainder %= base as u16;
|
||||
|
||||
if quotient > 0 || !first {
|
||||
new_num.push(quotient as u8);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果new_num为空,说明这是最后一次除法
|
||||
if !new_num.is_empty() || num.len() > 1 {
|
||||
num = new_num;
|
||||
} else {
|
||||
num.clear();
|
||||
}
|
||||
|
||||
result.push(BASE36_CHARS[remainder as usize]);
|
||||
}
|
||||
|
||||
// 反转字符串,因为我们是从低位开始计算的
|
||||
result.reverse();
|
||||
String::from_utf8(result).unwrap()
|
||||
}
|
||||
|
||||
/// 将Base36字符串(可为任意大小写)解码为字节数组
|
||||
pub fn decode(src: &str) -> Result<Vec<u8>, Base36Error> {
|
||||
if src.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
// 移除padding字符并转换为大写
|
||||
let cleaned: String = src.chars().filter(|&c| c != '=').collect();
|
||||
let cleaned = cleaned.to_uppercase();
|
||||
|
||||
// 使用Vec<u8>模拟大整数进行解码
|
||||
let mut num = Vec::new();
|
||||
let base = 36u16;
|
||||
|
||||
for c in cleaned.chars() {
|
||||
let digit = match c {
|
||||
'0'..='9' => c as u16 - '0' as u16,
|
||||
'A'..='Z' => c as u16 - 'A' as u16 + 10,
|
||||
_ => return Err(Base36Error::InvalidCharacter(c)),
|
||||
};
|
||||
|
||||
// num = num * 36 + digit
|
||||
let mut carry = digit as u32;
|
||||
for byte in num.iter_mut() {
|
||||
let product = *byte as u32 * base as u32 + carry;
|
||||
*byte = (product % 256) as u8;
|
||||
carry = product / 256;
|
||||
}
|
||||
|
||||
while carry > 0 {
|
||||
num.push((carry % 256) as u8);
|
||||
carry /= 256;
|
||||
}
|
||||
}
|
||||
|
||||
// 反转字节数组,因为我们的计算是从低位开始的
|
||||
num.reverse();
|
||||
|
||||
// 如果结果为空,返回单个零字节
|
||||
if num.is_empty() {
|
||||
num.push(0);
|
||||
}
|
||||
|
||||
Ok(num)
|
||||
}
|
||||
|
||||
/// Encode的别名,用于保持与标准库一致的命名
|
||||
pub fn encode_to_string(src: &[u8]) -> String {
|
||||
encode(src)
|
||||
}
|
||||
|
||||
/// Decode的别名,用于保持与标准库一致的命名
|
||||
pub fn decode_string(src: &str) -> Result<Vec<u8>, Base36Error> {
|
||||
decode(src)
|
||||
}
|
||||
|
||||
/// 将int64转换为Base36字符串
|
||||
pub fn encode_int64(num: i64) -> String {
|
||||
let bytes = num.to_be_bytes().to_vec();
|
||||
encode(&bytes)
|
||||
}
|
||||
|
||||
/// 将Base36字符串解码为int64
|
||||
pub fn decode_to_int64(src: &str) -> Result<i64, Base36Error> {
|
||||
let bytes = decode(src)?;
|
||||
if bytes.len() > 8 {
|
||||
return Err(Base36Error::NumberTooLarge);
|
||||
}
|
||||
|
||||
let mut array = [0u8; 8];
|
||||
let start = 8 - bytes.len();
|
||||
for (i, &byte) in bytes.iter().enumerate() {
|
||||
array[start + i] = byte;
|
||||
}
|
||||
|
||||
Ok(i64::from_be_bytes(array))
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
use base64::Engine;
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod base36;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum HexSerializeError {
|
||||
#[error("Invalid hex char: {0}")]
|
||||
|
Reference in New Issue
Block a user