Skip to content

Commit

Permalink
strip out proc-macro-hack
Browse files Browse the repository at this point in the history
  • Loading branch information
abonander committed Jan 15, 2020
1 parent 684068a commit 4ea2326
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 114 deletions.
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ all-features = true

[features]
default = [ "macros" ]
macros = [ "sqlx-macros", "proc-macro-hack" ]
macros = [ "sqlx-macros" ]
tls = ["sqlx-core/tls"]

# database
Expand All @@ -43,7 +43,6 @@ uuid = [ "sqlx-core/uuid", "sqlx-macros/uuid" ]
[dependencies]
sqlx-core = { version = "=0.1.4", path = "sqlx-core" }
sqlx-macros = { version = "0.1.1", path = "sqlx-macros", optional = true }
proc-macro-hack = { version = "0.5.11", optional = true }
hex = "0.4.0"

[dev-dependencies]
Expand Down
1 change: 0 additions & 1 deletion sqlx-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ uuid = [ "sqlx/uuid" ]
async-std = { version = "1.4.0", default-features = false }
dotenv = { version = "0.15.0", default-features = false }
futures = { version = "0.3.1", default-features = false }
proc-macro-hack = { version = "0.5.11", default-features = false }
proc-macro2 = { version = "1.0.6", default-features = false }
sqlx = { version = "0.1.1", default-features = false, path = "../sqlx-core", package = "sqlx-core" }
syn = { version = "1.0.11", default-features = false, features = [ "full" ] }
Expand Down
45 changes: 26 additions & 19 deletions sqlx-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ extern crate proc_macro;

use proc_macro::TokenStream;

use proc_macro_hack::proc_macro_hack;

use quote::quote;

use syn::parse_macro_input;
Expand All @@ -26,8 +24,21 @@ mod query_macros;

use query_macros::*;

fn macro_result(tokens: proc_macro2::TokenStream) -> TokenStream {
quote! (
macro_rules! macro_result {
($($args:tt)*) => (#tokens)
}
).into()
}

macro_rules! async_macro (
($db:ident => $expr:expr) => {{
($db:ident, $input:ident: $ty:ty => $expr:expr) => {{
let $input = match syn::parse::<$ty>($input) {
Ok(input) => input,
Err(e) => return macro_result(e.to_compile_error()),
};

let res: Result<proc_macro2::TokenStream> = task::block_on(async {
use sqlx::Connection;

Expand Down Expand Up @@ -70,40 +81,36 @@ macro_rules! async_macro (
Ok(ts) => ts.into(),
Err(e) => {
if let Some(parse_err) = e.downcast_ref::<syn::Error>() {
return dbg!(parse_err).to_compile_error().into();
macro_result(parse_err.to_compile_error())
} else {
let msg = format!("{:?}", e);
macro_result(quote!(compile_error(#msg)))
}

let msg = format!("{:?}", e);
quote!(compile_error!(#msg);).into()
}
}
}}
);

#[proc_macro_hack]
#[proc_macro]
pub fn query(input: TokenStream) -> TokenStream {
#[allow(unused_variables)]
let input = parse_macro_input!(input as QueryMacroInput);
async_macro!(db => expand_query(input, db))
async_macro!(db, input: QueryMacroInput => expand_query(input, db))
}

#[proc_macro_hack]
#[proc_macro]
pub fn query_file(input: TokenStream) -> TokenStream {
#[allow(unused_variables)]
let input = parse_macro_input!(input as QueryMacroInput);
async_macro!(db => expand_query_file(input, db))
async_macro!(db, input: QueryMacroInput => expand_query_file(input, db))
}

#[proc_macro_hack]
#[proc_macro]
pub fn query_as(input: TokenStream) -> TokenStream {
#[allow(unused_variables)]
let input = parse_macro_input!(input as QueryAsMacroInput);
async_macro!(db => expand_query_as(input, db))
async_macro!(db, input: QueryAsMacroInput => expand_query_as(input, db))
}

#[proc_macro_hack]
#[proc_macro]
pub fn query_file_as(input: TokenStream) -> TokenStream {
#[allow(unused_variables)]
let input = parse_macro_input!(input as QueryAsMacroInput);
async_macro!(db => expand_query_file_as(input, db))
async_macro!(db, input: QueryAsMacroInput => expand_query_file_as(input, db))
}
10 changes: 5 additions & 5 deletions sqlx-macros/src/query_macros/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub fn quote_args<DB: DatabaseExt>(
input: &QueryMacroInput,
describe: &Describe<DB>,
) -> crate::Result<TokenStream> {
if input.args.is_empty() {
if input.arg_names.is_empty() {
return Ok(quote! {
let args = ();
});
Expand All @@ -22,7 +22,7 @@ pub fn quote_args<DB: DatabaseExt>(
let param_types = describe
.param_types
.iter()
.zip(&*input.args)
.zip(&*input.arg_exprs)
.map(|(type_, expr)| {
get_type_override(expr)
.or_else(|| {
Expand All @@ -36,7 +36,7 @@ pub fn quote_args<DB: DatabaseExt>(
})
.collect::<crate::Result<Vec<_>>>()?;

let args_ty_cons = input.args.iter().enumerate().map(|(i, expr)| {
let args_ty_cons = input.arg_names.iter().enumerate().map(|(i, expr)| {
// required or `quote!()` emits it as `Nusize`
let i = syn::Index::from(i);
quote_spanned!( expr.span() => {
Expand All @@ -56,10 +56,10 @@ pub fn quote_args<DB: DatabaseExt>(
TokenStream::new()
};

let args = input.args.iter();
let args = input.arg_names.iter();

Ok(quote! {
let args = (#(&#args),*,);
let args = (#(&$#args),*,);
#args_check
})
}
Expand Down
88 changes: 68 additions & 20 deletions sqlx-macros/src/query_macros/input.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use std::env;

use async_std::fs;
use proc_macro2::Span;
use proc_macro2::{Span, TokenStream, Ident};
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::Token;
use syn::spanned::Spanned;
use syn::token::Group;
use syn::{Expr, ExprLit, ExprPath, Lit};
use syn::{ExprGroup, Token};

use quote::{quote, format_ident, ToTokens};

use sqlx::describe::Describe;
use sqlx::Connection;
Expand All @@ -14,28 +18,55 @@ use sqlx::Connection;
pub struct QueryMacroInput {
pub(super) source: String,
pub(super) source_span: Span,
pub(super) args: Vec<Expr>,
// `arg0 .. argN` for N arguments
pub(super) arg_names: Vec<Ident>,
pub(super) arg_exprs: Vec<Expr>,
}

impl QueryMacroInput {
fn from_exprs(input: ParseStream, mut args: impl Iterator<Item = Expr>) -> syn::Result<Self> {
let sql = match args.next() {
fn lit_err<T>(span: Span, unexpected: Expr) -> syn::Result<T> {
Err(syn::Error::new(
span,
format!(
"expected string literal, got {}",
unexpected.to_token_stream()
),
))
}

let (source, source_span) = match args.next() {
Some(Expr::Lit(ExprLit {
lit: Lit::Str(sql), ..
})) => sql,
Some(other_expr) => {
return Err(syn::Error::new_spanned(
other_expr,
"expected string literal",
));
})) => (sql.value(), sql.span()),
Some(Expr::Group(ExprGroup {
expr,
group_token: Group { span },
..
})) => {
// this duplication with the above is necessary because `expr` is `Box<Expr>` here
// which we can't directly pattern-match without `box_patterns`
match *expr {
Expr::Lit(ExprLit {
lit: Lit::Str(sql), ..
}) => (sql.value(), span),
other_expr => return lit_err(span, other_expr),
}
}
Some(other_expr) => return lit_err(other_expr.span(), other_expr),
None => return Err(input.error("expected SQL string literal")),
};

let arg_exprs: Vec<_> = args.collect();
let arg_names = (0 .. arg_exprs.len())
.map(|i| format_ident!("arg{}", i))
.collect();

Ok(Self {
source: sql.value(),
source_span: sql.span(),
args: args.collect(),
source,
source_span,
arg_exprs,
arg_names,
})
}

Expand All @@ -56,13 +87,13 @@ impl QueryMacroInput {
.await
.map_err(|e| syn::Error::new(self.source_span, e))?;

if self.args.len() != describe.param_types.len() {
if self.arg_names.len() != describe.param_types.len() {
return Err(syn::Error::new(
Span::call_site(),
format!(
"expected {} parameters, got {}",
describe.param_types.len(),
self.args.len()
self.arg_names.len()
),
)
.into());
Expand Down Expand Up @@ -97,16 +128,33 @@ impl QueryAsMacroInput {

impl Parse for QueryAsMacroInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
fn path_err<T>(span: Span, unexpected: Expr) -> syn::Result<T> {
Err(syn::Error::new(
span,
format!(
"expected path to a type, got {}",
unexpected.to_token_stream()
),
))
}

let mut args = Punctuated::<Expr, Token![,]>::parse_terminated(input)?.into_iter();

let as_ty = match args.next() {
Some(Expr::Path(path)) => path,
Some(other_expr) => {
return Err(syn::Error::new_spanned(
other_expr,
"expected path to a type",
));
Some(Expr::Group(ExprGroup {
expr,
group_token: Group { span },
..
})) => {
// this duplication with the above is necessary because `expr` is `Box<Expr>` here
// which we can't directly pattern-match without `box_patterns`
match *expr {
Expr::Path(path) => path,
other_expr => return path_err(span, other_expr),
}
}
Some(other_expr) => return path_err(other_expr.span(), other_expr),
None => return Err(input.error("expected path to SQL file")),
};

Expand Down
13 changes: 9 additions & 4 deletions sqlx-macros/src/query_macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ where
}

let args_tokens = args::quote_args(&input.query_input, &describe)?;
let arg_names = &input.query_input.arg_names;

let columns = output::columns_to_rust(&describe)?;
let output = output::quote_query_as::<C::Database>(
Expand All @@ -54,10 +55,14 @@ where
&columns,
);

Ok(quote! {{
#args_tokens
#output.bind_all(args)
}})
Ok(quote! {
macro_rules! macro_result {
(#($#arg_names:expr),*) => {{
#args_tokens
#output.bind_all(args)
}}
}
})
}

pub async fn expand_query_file_as<C: Connection>(
Expand Down
21 changes: 13 additions & 8 deletions sqlx-macros/src/query_macros/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,20 @@ where
.collect::<TokenStream>();

let output = output::quote_query_as::<C::Database>(sql, &record_type, &columns);
let arg_names = &input.arg_names;

Ok(quote! {{
#[derive(Debug)]
struct #record_type {
#record_fields
}
Ok(quote! {
macro_rules! macro_result {
(#($#arg_names:expr),*) => {{
#[derive(Debug)]
struct #record_type {
#record_fields
}

#args
#args

#output.bind_all(args)
}})
#output.bind_all(args)
}
}}
})
}
26 changes: 3 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,13 @@ pub use sqlx_core::mysql::{self, MySql, MySqlConnection, MySqlPool};
#[cfg(feature = "postgres")]
pub use sqlx_core::postgres::{self, PgConnection, PgPool, Postgres};

#[allow(unused_attributes)]
#[macro_export]
mod macros;

#[cfg(feature = "macros")]
#[doc(hidden)]
#[proc_macro_hack::proc_macro_hack(fake_call_site)]
#[allow(dead_code)]
pub use sqlx_macros::query as query_;

#[cfg(feature = "macros")]
#[doc(hidden)]
#[proc_macro_hack::proc_macro_hack(fake_call_site)]
#[allow(dead_code)]
pub use sqlx_macros::query_as as query_as_;
pub extern crate sqlx_macros;

#[cfg(feature = "macros")]
#[doc(hidden)]
#[proc_macro_hack::proc_macro_hack(fake_call_site)]
#[allow(dead_code)]
pub use sqlx_macros::query_file as query_file_;

#[cfg(feature = "macros")]
#[doc(hidden)]
#[proc_macro_hack::proc_macro_hack(fake_call_site)]
#[allow(dead_code)]
pub use sqlx_macros::query_file_as as query_file_as_;
#[macro_export]
mod macros;

// macro support
#[cfg(feature = "macros")]
Expand Down
Loading

0 comments on commit 4ea2326

Please sign in to comment.