Skip to content
This repository was archived by the owner on Oct 10, 2019. It is now read-only.

Commit 01b642b

Browse files
committed
WIP
1 parent 27b0212 commit 01b642b

File tree

6 files changed

+161
-23
lines changed

6 files changed

+161
-23
lines changed

postgres-derive-internals/src/enums.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ pub struct Variant {
88
}
99

1010
impl Variant {
11-
pub fn parse(raw: &mut syn::Variant) -> Result<Variant, String> {
11+
pub fn parse(raw: &syn::Variant) -> Result<Variant, String> {
1212
match raw.data {
1313
VariantData::Unit => {}
1414
_ => return Err("non-C-like enums are not supported".to_owned()),
1515
}
1616

17-
let overrides = try!(Overrides::extract(&mut raw.attrs));
17+
let overrides = try!(Overrides::extract(&raw.attrs));
1818
Ok(Variant {
1919
ident: raw.ident.clone(),
2020
name: overrides.name.unwrap_or_else(|| raw.ident.to_string()),
Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,82 @@
1+
use std::fmt::Write;
2+
use syn::{self, Body, VariantData, Ident};
3+
use quote::{Tokens, ToTokens};
14

2-
pub fn expand_derive_fromsql(_: &str) -> Result<String, String> {
3-
unimplemented!();
5+
use accepts;
6+
use enums::Variant;
7+
use overrides::Overrides;
8+
9+
pub fn expand_derive_fromsql(source: &str) -> Result<String, String> {
10+
let mut input = try!(syn::parse_macro_input(source));
11+
let overrides = try!(Overrides::extract(&mut input.attrs));
12+
13+
let name = overrides.name.unwrap_or_else(|| input.ident.to_string());
14+
15+
let (accepts_body, to_sql_body) = match input.body {
16+
Body::Enum(ref mut variants) => {
17+
let variants: Vec<Variant> = try!(variants.iter_mut().map(Variant::parse).collect());
18+
(accepts::enum_body(&variants), enum_body(&input.ident, &variants))
19+
}
20+
_ => {
21+
return Err("#[derive(ToSql)] may only be applied to structs, single field tuple \
22+
structs, and enums".to_owned())
23+
}
24+
};
25+
26+
let mut tokens = Tokens::new();
27+
input.to_tokens(&mut tokens);
28+
29+
let out = format!("
30+
{}
31+
32+
impl ::postgres::types::ToSql for {} {{
33+
fn to_sql(&self,
34+
_: &::postgres::types::Type,
35+
buf: &mut ::std::vec::Vec<u8>,
36+
_: &::postgres::types::SessionInfo)
37+
-> ::postgres::Result<::postgres::types::IsNull> {{{}
38+
}}
39+
40+
fn accepts(type_: &::postgres::types::Type) -> bool {{
41+
if type_.name() != \"{}\" {{
42+
return false;
43+
}}
44+
{}
45+
}}
46+
47+
to_sql_checked!();
48+
}}", tokens, input.ident, to_sql_body, name, accepts_body);
49+
50+
Ok(out)
51+
}
52+
53+
fn enum_body(ident: &Ident, variants: &[Variant]) -> String {
54+
let mut out = "
55+
let s = match *self {".to_owned();
56+
57+
for variant in variants {
58+
write!(out, "
59+
{}::{} => \"{}\",", ident, variant.ident, variant.name).unwrap();
60+
}
61+
62+
out.push_str("
63+
};
64+
65+
buf.extend_from_slice(s.as_bytes());
66+
Ok(::postgres::types::IsNull::No)");
67+
68+
out
69+
}
70+
71+
#[test]
72+
fn foo() {
73+
let code = "
74+
#[postgres(name = \"foo\")]
75+
enum Foo {
76+
#[postgres(name = \"bar\")]
77+
Bar,
78+
Baz
79+
}
80+
";
81+
panic!(expand_derive_tosql(code).unwrap());
482
}

postgres-derive-internals/src/lib.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
extern crate syn;
22
extern crate quote;
33

4+
use syn::{MacroInput, MetaItem};
5+
46
pub use fromsql::expand_derive_fromsql;
57
pub use tosql::expand_derive_tosql;
68

@@ -9,3 +11,64 @@ mod enums;
911
mod fromsql;
1012
mod overrides;
1113
mod tosql;
14+
15+
pub fn expand_derive(source: &str) -> Result<String, String> {
16+
let mut input = try!(syn::parse_macro_input(source));
17+
let (tosql, fromsql) = strip_derives(&mut input);
18+
19+
let tosql = if tosql {
20+
try!(expand_derive_tosql(&input))
21+
} else {
22+
"".to_owned()
23+
};
24+
let fromsql = if fromsql {
25+
try!(expand_derive_fromsql(&input))
26+
} else {
27+
"".to_owned()
28+
};
29+
}
30+
31+
fn strip_derives(input: &mut MacroInput) -> (bool, bool) {
32+
let mut tosql = false;
33+
let mut fromsql = false;
34+
35+
let mut other_attrs = vec![];
36+
for mut attr in input.attrs.drain(..) {
37+
{
38+
let mut items = match attr.value {
39+
MetaItem::List(ref name, ref mut items) if name == "derive" => items,
40+
_ => {
41+
other_attrs.push(attr);
42+
continue;
43+
}
44+
};
45+
46+
items.retain(|i| {
47+
match *i {
48+
MetaItem::Word(ref name) if name == "ToSql" => {
49+
tosql = true;
50+
false
51+
}
52+
MetaItem::Word(ref name) if name == "FromSql" => {
53+
fromsql = true;
54+
false
55+
}
56+
_ => true,
57+
}
58+
});
59+
60+
if items.is_empty() {
61+
continue;
62+
}
63+
}
64+
65+
other_attrs.push(attr);
66+
}
67+
68+
input.attrs = other_attrs;
69+
(tosql, fromsql)
70+
}
71+
72+
fn strip_overrides(input: &mut MacroInput) {
73+
74+
}

postgres-derive-internals/src/overrides.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@ pub struct Overrides {
55
}
66

77
impl Overrides {
8-
pub fn extract(attrs: &mut Vec<Attribute>) -> Result<Overrides, String> {
8+
pub fn extract(attrs: &[Attribute]) -> Result<Overrides, String> {
99
let mut overrides = Overrides {
1010
name: None,
1111
};
12-
let mut other_attrs = vec![];
1312

1413
for attr in attrs.drain(..) {
1514
if attr.value.name() != "postgres" {
16-
other_attrs.push(attr);
1715
continue;
1816
}
1917

@@ -41,8 +39,10 @@ impl Overrides {
4139
}
4240
}
4341

44-
*attrs = other_attrs;
4542
Ok(overrides)
4643
}
47-
}
4844

45+
pub fn strip(attrs: &mut Vec<Attribute>) {
46+
attrs.retain(|a| a.name() != "postgres");
47+
}
48+
}

postgres-derive-internals/src/tosql.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,3 @@ fn enum_body(ident: &Ident, variants: &[Variant]) -> String {
6767

6868
out
6969
}
70-
71-
#[test]
72-
fn foo() {
73-
let code = "
74-
#[postgres(name = \"foo\")]
75-
enum Foo {
76-
#[postgres(name = \"bar\")]
77-
Bar,
78-
Baz
79-
}
80-
";
81-
panic!(expand_derive_tosql(code).unwrap());
82-
}

postgres-derive/src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,17 @@ use rustc_macro::TokenStream;
77

88
#[rustc_macro_derive(ToSql)]
99
pub fn derive_tosql(input: TokenStream) -> TokenStream {
10-
match postgres_derive_internals::expand_derive_tosql(&input.to_string()) {
10+
derive("ToSql", input)
11+
}
12+
13+
#[rustc_macro_derive(FromSql)]
14+
pub fn derive_fromsql(input: TokenStream) -> TokenStream {
15+
derive("FromSql", input)
16+
}
17+
18+
fn derive(trait_: &str, input: TokenStream) -> TokenStream {
19+
let input = format!("#[derive({})] {}", trait_, input);
20+
match postgres_derive_internals::expand_derive(&input) {
1121
Ok(expanded) => expanded.parse().unwrap(),
1222
Err(err) => panic!(err),
1323
}

0 commit comments

Comments
 (0)