mirror of
https://github.com/chatmail/core.git
synced 2026-05-06 06:46:35 +03:00
Implement procedural macro to derive {To,From}Sql traits
With this macro it is possible to #[derive(ToSql, FromSql)] for enums, that do not contain data (C-style).
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -467,6 +467,7 @@ dependencies = [
|
|||||||
"cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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 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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "deltachat_ffi"
|
name = "deltachat_ffi"
|
||||||
version = "1.0.0-alpha.3"
|
version = "1.0.0-alpha.3"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ cc = "1.0.35"
|
|||||||
pkg-config = "0.3"
|
pkg-config = "0.3"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
deltachat_derive = { path = "./deltachat_derive" }
|
||||||
libc = "0.2.51"
|
libc = "0.2.51"
|
||||||
pgp = { version = "0.2", default-features = false }
|
pgp = { version = "0.2", default-features = false }
|
||||||
hex = "0.3.2"
|
hex = "0.3.2"
|
||||||
@@ -53,7 +54,8 @@ pretty_env_logger = "0.3.0"
|
|||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"deltachat-ffi"
|
"deltachat-ffi",
|
||||||
|
"deltachat_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
|
|||||||
12
deltachat_derive/Cargo.toml
Normal file
12
deltachat_derive/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "deltachat_derive"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Dmitry Bogatov <KAction@debian.org>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = "0.14.4"
|
||||||
|
quote = "0.6.3"
|
||||||
45
deltachat_derive/src/lib.rs
Normal file
45
deltachat_derive/src/lib.rs
Normal file
@@ -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<rusqlite::types::ToSqlOutput> {
|
||||||
|
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<Self> {
|
||||||
|
let inner = rusqlite::types::FromSql::column_result(col)?;
|
||||||
|
num_traits::FromPrimitive::from_i64(inner).ok_or(rusqlite::types::FromSqlError::InvalidType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gen.into()
|
||||||
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
//! Constants
|
//! Constants
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use deltachat_derive::*;
|
||||||
use rusqlite as sql;
|
|
||||||
use rusqlite::types::*;
|
|
||||||
|
|
||||||
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
|
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
|
||||||
|
|
||||||
#[repr(u8)]
|
#[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 {
|
pub enum MoveState {
|
||||||
Undefined = 0,
|
Undefined = 0,
|
||||||
Pending = 1,
|
Pending = 1,
|
||||||
@@ -15,21 +13,6 @@ pub enum MoveState {
|
|||||||
Moving = 3,
|
Moving = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for MoveState {
|
|
||||||
fn to_sql(&self) -> sql::Result<ToSqlOutput> {
|
|
||||||
let num = *self as i64;
|
|
||||||
|
|
||||||
Ok(ToSqlOutput::Owned(Value::Integer(num)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromSql for MoveState {
|
|
||||||
fn column_result(col: ValueRef) -> FromSqlResult<Self> {
|
|
||||||
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_ARCHIVED_ONLY: usize = 0x01;
|
||||||
pub const DC_GCL_NO_SPECIALS: usize = 0x02;
|
pub const DC_GCL_NO_SPECIALS: usize = 0x02;
|
||||||
pub const DC_GCL_ADD_ALLDONE_HINT: usize = 0x04;
|
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 =
|
pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
|
||||||
(DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN);
|
(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)]
|
#[repr(i32)]
|
||||||
pub enum Viewtype {
|
pub enum Viewtype {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
@@ -221,23 +204,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Viewtype {
|
|
||||||
fn to_sql(&self) -> sql::Result<ToSqlOutput> {
|
|
||||||
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<Self> {
|
|
||||||
let inner = FromSql::column_result(col)?;
|
|
||||||
FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These constants are used as events
|
// These constants are used as events
|
||||||
// reported to the callback given to dc_context_new().
|
// 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,
|
// If you do not want to handle an event, it is always safe to return 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user