diff --git a/Cargo.lock b/Cargo.lock index 9a7559b4a..a9d4ac751 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -467,6 +467,7 @@ dependencies = [ "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "deltachat_derive 0.1.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -501,6 +502,14 @@ dependencies = [ "thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "deltachat_derive" +version = "0.1.0" +dependencies = [ + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "deltachat_ffi" version = "1.0.0-alpha.3" diff --git a/Cargo.toml b/Cargo.toml index 94ddf9337..e3672d45b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ cc = "1.0.35" pkg-config = "0.3" [dependencies] +deltachat_derive = { path = "./deltachat_derive" } libc = "0.2.51" pgp = { version = "0.2", default-features = false } hex = "0.3.2" @@ -53,7 +54,8 @@ pretty_env_logger = "0.3.0" [workspace] members = [ - "deltachat-ffi" + "deltachat-ffi", + "deltachat_derive", ] [[example]] diff --git a/deltachat_derive/Cargo.toml b/deltachat_derive/Cargo.toml new file mode 100644 index 000000000..c456e99ea --- /dev/null +++ b/deltachat_derive/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "deltachat_derive" +version = "0.1.0" +authors = ["Dmitry Bogatov "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +syn = "0.14.4" +quote = "0.6.3" diff --git a/deltachat_derive/src/lib.rs b/deltachat_derive/src/lib.rs new file mode 100644 index 000000000..276b2085c --- /dev/null +++ b/deltachat_derive/src/lib.rs @@ -0,0 +1,45 @@ +#![recursion_limit = "128"] +extern crate proc_macro; + +use crate::proc_macro::TokenStream; +use quote::quote; +use syn; + +// For now, assume (not check) that these macroses are applied to enum without +// data. If this assumption is violated, compiler error will point to +// generated code, which is not very user-friendly. + +#[proc_macro_derive(ToSql)] +pub fn to_sql_derive(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let name = &ast.ident; + + let gen = quote! { + impl rusqlite::types::ToSql for #name { + fn to_sql(&self) -> rusqlite::Result { + let num = *self as i64; + let value = rusqlite::types::Value::Integer(num); + let output = rusqlite::types::ToSqlOutput::Owned(value); + + std::result::Result::Ok(output) + } + } + }; + gen.into() +} + +#[proc_macro_derive(FromSql)] +pub fn from_sql_derive(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let name = &ast.ident; + + let gen = quote! { + impl rusqlite::types::FromSql for #name { + fn column_result(col: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult { + let inner = rusqlite::types::FromSql::column_result(col)?; + num_traits::FromPrimitive::from_i64(inner).ok_or(rusqlite::types::FromSqlError::InvalidType) + } + } + }; + gen.into() +} diff --git a/src/constants.rs b/src/constants.rs index 73386b6af..9e74fba86 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,13 +1,11 @@ //! Constants #![allow(non_camel_case_types)] -use num_traits::{FromPrimitive, ToPrimitive}; -use rusqlite as sql; -use rusqlite::types::*; +use deltachat_derive::*; pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00"; #[repr(u8)] -#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] +#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql)] pub enum MoveState { Undefined = 0, Pending = 1, @@ -15,21 +13,6 @@ pub enum MoveState { Moving = 3, } -impl ToSql for MoveState { - fn to_sql(&self) -> sql::Result { - let num = *self as i64; - - Ok(ToSqlOutput::Owned(Value::Integer(num))) - } -} - -impl FromSql for MoveState { - fn column_result(col: ValueRef) -> FromSqlResult { - let inner = FromSql::column_result(col)?; - FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType) - } -} - pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01; pub const DC_GCL_NO_SPECIALS: usize = 0x02; pub const DC_GCL_ADD_ALLDONE_HINT: usize = 0x04; @@ -166,7 +149,7 @@ pub const DC_LP_IMAP_SOCKET_FLAGS: usize = pub const DC_LP_SMTP_SOCKET_FLAGS: usize = (DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN); -#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] +#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)] #[repr(i32)] pub enum Viewtype { Unknown = 0, @@ -221,23 +204,6 @@ mod tests { } } -impl ToSql for Viewtype { - fn to_sql(&self) -> sql::Result { - let num: i64 = self - .to_i64() - .expect("impossible: Viewtype -> i64 conversion failed"); - - Ok(ToSqlOutput::Owned(Value::Integer(num))) - } -} - -impl FromSql for Viewtype { - fn column_result(col: ValueRef) -> FromSqlResult { - let inner = FromSql::column_result(col)?; - FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType) - } -} - // These constants are used as events // reported to the callback given to dc_context_new(). // If you do not want to handle an event, it is always safe to return 0,