diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1948f88..f74fd55 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -70,6 +70,11 @@ jobs: cargo build --example loadable_extension --features "loadable_extension functions trace" cargo run --example load_extension --features "load_extension bundled functions trace" + - name: macros + run: | + cargo test --package rusqlite-macros + cargo test --features 'bundled rusqlite-macros' + # TODO: move into own action for better caching - name: Static build # Do we expect this to work / should we test with gnu toolchain? diff --git a/rusqlite-macros/src/lib.rs b/rusqlite-macros/src/lib.rs index d98dee1..211af9d 100644 --- a/rusqlite-macros/src/lib.rs +++ b/rusqlite-macros/src/lib.rs @@ -1,7 +1,7 @@ //! Private implementation details of `rusqlite`. use litrs::StringLit; -use proc_macro::{Group, Span, TokenStream, TokenTree}; +use proc_macro::{Delimiter, Group, Literal, Span, TokenStream, TokenTree}; use fallible_iterator::FallibleIterator; use sqlite3_parser::ast::{ParameterInfo, ToTokens}; @@ -26,6 +26,10 @@ fn try_bind(input: TokenStream) -> Result { (stmt, literal) }; + let literal = match into_literal(&literal) { + Some(it) => it, + None => return Err("expected a plain string literal".to_string()), + }; let call_site = literal.span(); let string_lit = match StringLit::try_from(literal) { Ok(string_lit) => string_lit, @@ -68,6 +72,20 @@ fn try_bind(input: TokenStream) -> Result { Ok(res) } +fn into_literal(ts: &TokenTree) -> Option { + match ts { + TokenTree::Literal(l) => Some(l.clone()), + TokenTree::Group(g) => match g.delimiter() { + Delimiter::None => match g.stream().into_iter().collect::>().as_slice() { + [TokenTree::Literal(l)] => Some(l.clone()), + _ => None, + }, + Delimiter::Parenthesis | Delimiter::Brace | Delimiter::Bracket => None, + }, + _ => None, + } +} + fn respan(ts: TokenStream, span: Span) -> TokenStream { let mut res = TokenStream::new(); for tt in ts {