Skip to main content

tds_driver_macros/
lib.rs

1//! A utility proc-macro crate that generates trivial trait implementations used
2//! in the Rust-to-SQL data exchange for tds-driver table-valued parameters.
3extern crate proc_macro;
4
5#[macro_use]
6extern crate quote;
7#[macro_use]
8extern crate syn;
9
10use proc_macro::TokenStream;
11
12macro_rules! sp_quote {
13    ($($t:tt)*) => (quote_spanned!(proc_macro2::Span::call_site() => $($t)*))
14}
15
16mod attr;
17mod table_value_param;
18
19/// Generates a trivial implementation of the `TableValueRow` trait.
20///
21/// # Applications
22/// Apply to structs that represent rows of a table-valued parameter.
23///
24/// # Example
25/// ```rust,ignore
26/// # use tds_driver::*;
27/// #[derive(TableValueRow)]
28/// pub struct SomeGeoList {
29///   #[colname = "SomeID"]
30///   pub id: i32,
31///   #[colname = "LastSyncIPGeoLat"]
32///   pub lat: Numeric,
33///   #[colname = "LastSyncIPGeoLong"]
34///   pub lon: Numeric,
35/// }
36/// ```
37///
38/// # Supported field types
39///
40/// Each field is bound with `SqlTableDataRow::add_field(self.<field>)`, so the
41/// field type must implement `IntoSql` *by value*. That covers the `Copy`
42/// scalar/marker types (`i32`, `i64`, `bool`, `f64`, `Numeric`, `Uuid`, …) and
43/// borrowed strings/bytes (`&str`, `&[u8]`). Owned, non-`Copy` columns such as
44/// `String` or `Vec<u8>` cannot be moved out of `&self`; model those columns as
45/// `&str` / `&[u8]` (with a struct lifetime) instead.
46#[proc_macro_derive(TableValueRow, attributes(colname))]
47pub fn table_value_param(input: TokenStream) -> TokenStream {
48    let ast: syn::DeriveInput = match syn::parse(input) {
49        Ok(ast) => ast,
50        Err(e) => return e.to_compile_error().into(),
51    };
52
53    let result = match ast.data {
54        syn::Data::Struct(ref s) => table_value_param::for_struct(&ast, &s.fields),
55        syn::Data::Enum(_) => Err(syn::Error::new_spanned(
56            &ast.ident,
57            "TableValueRow can only be derived for structs, not enums",
58        )),
59        syn::Data::Union(_) => Err(syn::Error::new_spanned(
60            &ast.ident,
61            "TableValueRow can only be derived for structs, not unions",
62        )),
63    };
64
65    match result {
66        Ok(tokens) => tokens.into(),
67        Err(e) => e.to_compile_error().into(),
68    }
69}