macro_rules! decode_primitive {
($bytes:expr, $type:ty) => {
rkyv::from_bytes::<$type, rkyv::rancor::Error>($bytes)
.ok()
.map(|v| format!("{}", v))
};
($bytes:expr, $type:ty, debug) => {
rkyv::from_bytes::<$type, rkyv::rancor::Error>($bytes)
.ok()
.map(|v| format!("{:?}", v))
};
($bytes:expr, $type:ty, quoted) => {
rkyv::from_bytes::<$type, rkyv::rancor::Error>($bytes)
.ok()
.map(|v| format!("\"{}\"", v))
};
}
pub fn try_decode_value(type_name: &str, bytes: &[u8]) -> Option<String> {
match type_name {
"i8" => decode_primitive!(bytes, i8),
"i16" => decode_primitive!(bytes, i16),
"i32" => decode_primitive!(bytes, i32),
"i64" => decode_primitive!(bytes, i64),
"u8" => decode_primitive!(bytes, u8),
"u16" => decode_primitive!(bytes, u16),
"u32" => decode_primitive!(bytes, u32),
"u64" => decode_primitive!(bytes, u64),
"f32" => decode_primitive!(bytes, f32),
"f64" => decode_primitive!(bytes, f64),
"bool" => decode_primitive!(bytes, bool),
"String" | "&str" => decode_primitive!(bytes, String, quoted),
"()" => Some("()".to_string()),
t if t.starts_with("Vec<") => decode_vec(t, bytes),
t if t.starts_with("Option<") => decode_option(t, bytes),
_ => None,
}
}
fn decode_vec(type_name: &str, bytes: &[u8]) -> Option<String> {
let inner = type_name.strip_prefix("Vec<")?.strip_suffix('>')?;
match inner {
"i32" => decode_primitive!(bytes, Vec<i32>, debug),
"i64" => decode_primitive!(bytes, Vec<i64>, debug),
"f32" => decode_primitive!(bytes, Vec<f32>, debug),
"f64" => decode_primitive!(bytes, Vec<f64>, debug),
"u8" => decode_primitive!(bytes, Vec<u8>, debug),
"u16" => decode_primitive!(bytes, Vec<u16>, debug),
"u32" => decode_primitive!(bytes, Vec<u32>, debug),
"u64" => decode_primitive!(bytes, Vec<u64>, debug),
"String" => decode_primitive!(bytes, Vec<String>, debug),
"bool" => decode_primitive!(bytes, Vec<bool>, debug),
_ => None,
}
}
fn decode_option(type_name: &str, bytes: &[u8]) -> Option<String> {
let inner = type_name.strip_prefix("Option<")?.strip_suffix('>')?;
match inner {
"i32" => decode_primitive!(bytes, Option<i32>, debug),
"i64" => decode_primitive!(bytes, Option<i64>, debug),
"f32" => decode_primitive!(bytes, Option<f32>, debug),
"f64" => decode_primitive!(bytes, Option<f64>, debug),
"String" => decode_primitive!(bytes, Option<String>, debug),
"bool" => decode_primitive!(bytes, Option<bool>, debug),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decode_i32() {
let value: i32 = 42;
let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&value).unwrap();
assert_eq!(try_decode_value("i32", &bytes), Some("42".to_string()));
}
#[test]
fn test_decode_string() {
let value = "hello".to_string();
let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&value).unwrap();
assert_eq!(
try_decode_value("String", &bytes),
Some("\"hello\"".to_string())
);
}
#[test]
fn test_decode_vec_i32() {
let value: Vec<i32> = vec![1, 2, 3];
let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&value).unwrap();
assert_eq!(
try_decode_value("Vec<i32>", &bytes),
Some("[1, 2, 3]".to_string())
);
}
#[test]
fn test_decode_unknown_type() {
assert_eq!(try_decode_value("CustomType", &[1, 2, 3]), None);
}
#[test]
fn test_decode_unit() {
assert_eq!(try_decode_value("()", &[]), Some("()".to_string()));
}
}