1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
#![feature(proc_macro_diagnostic, proc_macro_span)] #![feature(core_intrinsics, decl_macro)] #![recursion_limit = "256"] #[macro_use] extern crate quote; extern crate proc_macro; use crate::proc_macro::TokenStream; use quote::quote; fn impl_serde_enum_derive(ast: &syn::DeriveInput) -> quote::Tokens { let name = &ast.ident; quote! { impl postgres::types::FromSql for #name { fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> { let value = postgres_protocol::types::int8_from_sql(raw)?; Self::from_i64(value).ok_or(Box::from("Failed to deserialize enum")) } fn accepts(ty: &Type) -> bool { <i64 as ToSql>::accepts(ty) } } impl postgres::types::ToSql for #name { fn to_sql(&self, _: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<dyn Error + Sync + Send>> where Self: Sized, { let res = self.to_i64().ok_or::<Box<dyn Error + Sync + Send>>(Box::from("Failed to serialize enum"))?; postgres_protocol::types::int8_to_sql(res, out); Ok(IsNull::No) } fn accepts(ty: &Type) -> bool { <i64 as ToSql>::accepts(ty) } to_sql_checked!(); } } } fn impl_serde_enum_struct_derive(ast: &syn::DeriveInput) -> quote::Tokens { let name = &ast.ident; quote! { impl postgres::types::FromSql for #name { fn from_sql( _: &postgres::types::Type, raw: &[u8], ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> { serde_json::from_slice(&raw).map_err(|_| Box::from("FATAL: Failed to deserialize data")) } fn accepts(ty: &postgres::types::Type) -> bool { <serde_json::Value as postgres::types::FromSql>::accepts(ty) } } impl postgres::types::ToSql for #name { fn to_sql( &self, _: &postgres::types::Type, out: &mut Vec<u8>, ) -> Result<postgres::types::IsNull, Box<dyn std::error::Error + Sync + Send>> where Self: Sized, { *out = serde_json::to_vec(self)?; Ok(postgres::types::IsNull::No) } fn accepts(ty: &postgres::types::Type) -> bool { serde_json::Value::accepts(ty) } to_sql_checked!(); } } } #[proc_macro_derive(EnumSql)] pub fn serde_enum_derive(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_derive_input(&s).unwrap(); let gen = impl_serde_enum_derive(&ast); gen.parse().unwrap() } #[proc_macro_derive(JsonEnumSql)] pub fn serde_json_enum_derive(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_derive_input(&s).unwrap(); let gen = impl_serde_enum_struct_derive(&ast); gen.parse().unwrap() }