diff --git a/redis-derive/Cargo.toml b/redis-derive/Cargo.toml new file mode 100644 index 00000000..d360959d --- /dev/null +++ b/redis-derive/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "raiko-redis-derive" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0" +quote = "1.0" +syn = "1.0" diff --git a/redis-derive/src/lib.rs b/redis-derive/src/lib.rs new file mode 100644 index 00000000..408d2cb1 --- /dev/null +++ b/redis-derive/src/lib.rs @@ -0,0 +1,37 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(RedisValue)] +pub fn redis_value_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + let expanded = quote! { + impl redis::ToRedisArgs for #name { + fn write_redis_args(&self, out: &mut W) + where + W: ?Sized + redis::RedisWrite, + { + let serialized = serde_json::to_string(self) + .expect(&format!("Failed to serialize {}", stringify!(#name))); + out.write_arg(serialized.as_bytes()); + } + } + + impl redis::FromRedisValue for #name { + fn from_redis_value(v: &redis::Value) -> redis::RedisResult { + let serialized = String::from_redis_value(v)?; + serde_json::from_str(&serialized).map_err(|e| { + redis::RedisError::from(( + redis::ErrorKind::TypeError, + "Deserialization failed", + e.to_string(), + )) + }) + } + } + }; + + TokenStream::from(expanded) +}