extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::Ident;
use quote::quote;
use syn::{parse_macro_input, Data, DataEnum, DataStruct, DeriveInput};
pub fn derive_sqlite_to_value_inner(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let expanded = match input.data {
Data::Enum(data) => process_enum(name, data),
syn::Data::Struct(data) => process_struct(name, data),
_ => panic!("ToSqliteValue can only be used with enums or simple tuple struct for now"),
};
TokenStream::from(expanded)
}
fn process_struct(name: Ident, _data: DataStruct) -> proc_macro2::TokenStream {
#[rustfmt::skip]
let expanded = quote! {
impl From<#name> for rusqlite::types::Value {
fn from(rust_value: #name) -> rusqlite::types::Value {
rust_value.0.into()
}
}
impl rusqlite::types::ToSql for #name {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
Ok(rusqlite::types::ToSqlOutput::Owned(self.0.into()))
}
}
};
expanded
}
fn process_enum(name: Ident, data: DataEnum) -> proc_macro2::TokenStream {
let arms = data
.variants
.iter()
.map(|variant| {
let variant_ident = &variant.ident;
let variant_name_str = variant_ident.to_string();
quote! {
#name::#variant_ident => #variant_name_str,
}
})
.collect::<Vec<_>>();
#[rustfmt::skip]
let expanded = quote! {
impl From<#name> for rusqlite::types::Value {
fn from(rust_value: #name) -> rusqlite::types::Value {
let val = match rust_value {
#(#arms)*
}.to_string();
val.into()
}
}
impl rusqlite::types::ToSql for #name {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
let val = match self {
#(#arms)*
}.to_string();
Ok(rusqlite::types::ToSqlOutput::Owned(val.into()))
}
}
};
expanded
}