Skip to content

Commit 1b49fed

Browse files
committed
scylla-macros: support renaming the scylla crate
Currently, the macros will only work, if the code using them has a dependency on the scylla driver, or on the scylla_cql if it's renamed to scylla. This is caused by the fact that the paths referring to the scylla code are hardcoded to use a `scylla` crate. As a result, if a someone uses the `scylla_cql` crate without renaming, or renames `scylla_cql` or `scylla` to a name differen name than `scylla`, the macros will not work. Similarily, when another crate re-exports the macros, or uses them in their own macros, it can only work if the crate is used under the name `scylla` and it additionally re-exports parts of the `scylla_cql` code that are used in the macro under the same paths. This patch adds a `crate` helper attribute that allows users to set the crate name that will export the code that is used in the macros. All the symbols that are used there are also additionally exported in a `_macro_internal` module to make re-exporting important code segments more convenient.
1 parent 222fa4d commit 1b49fed

File tree

9 files changed

+89
-34
lines changed

9 files changed

+89
-34
lines changed

scylla-cql/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,15 @@ pub use crate::frame::response::cql_to_rust;
77
pub use crate::frame::response::cql_to_rust::FromRow;
88

99
pub use crate::frame::types::Consistency;
10+
11+
#[doc(hidden)]
12+
pub mod _macro_internal {
13+
pub use crate::frame::response::cql_to_rust::{
14+
FromCqlVal, FromCqlValError, FromRow, FromRowError,
15+
};
16+
pub use crate::frame::response::result::{CqlValue, Row};
17+
pub use crate::frame::value::{
18+
SerializedResult, SerializedValues, Value, ValueList, ValueTooBig,
19+
};
20+
pub use crate::macros::*;
21+
}

scylla-macros/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ proc-macro = true
1414
[dependencies]
1515
syn = "1.0"
1616
quote = "1.0"
17+
proc-macro2 = "1.0"

scylla-macros/src/from_row.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use syn::{spanned::Spanned, DeriveInput};
55
/// #[derive(FromRow)] derives FromRow for struct
66
pub fn from_row_derive(tokens_input: TokenStream) -> TokenStream {
77
let item = syn::parse::<DeriveInput>(tokens_input).expect("No DeriveInput");
8+
let path = crate::parser::get_path(&item).expect("No path");
89
let struct_fields = crate::parser::parse_named_fields(&item, "FromRow");
910

1011
let struct_name = &item.ident;
@@ -22,8 +23,8 @@ pub fn from_row_derive(tokens_input: TokenStream) -> TokenStream {
2223
.unwrap(); // vals_iter size is checked before this code is reached, so
2324
// it is safe to unwrap
2425

25-
<#field_type as scylla::cql_to_rust::FromCqlVal<::std::option::Option<scylla::frame::response::result::CqlValue>>>::from_cql(col_value)
26-
.map_err(|e| scylla::cql_to_rust::FromRowError::BadCqlVal {
26+
<#field_type as #path::_macro_internal::FromCqlVal<::std::option::Option<#path::_macro_internal::CqlValue>>>::from_cql(col_value)
27+
.map_err(|e| #path::_macro_internal::FromRowError::BadCqlVal {
2728
err: e,
2829
column: col_ix,
2930
})?
@@ -33,14 +34,12 @@ pub fn from_row_derive(tokens_input: TokenStream) -> TokenStream {
3334

3435
let fields_count = struct_fields.named.len();
3536
let generated = quote! {
36-
impl #impl_generics scylla::cql_to_rust::FromRow for #struct_name #ty_generics #where_clause {
37-
fn from_row(row: scylla::frame::response::result::Row)
38-
-> ::std::result::Result<Self, scylla::cql_to_rust::FromRowError> {
39-
use scylla::frame::response::result::CqlValue;
40-
use scylla::cql_to_rust::{FromCqlVal, FromRow, FromRowError};
37+
impl #impl_generics #path::_macro_internal::FromRow for #struct_name #ty_generics #where_clause {
38+
fn from_row(row: #path::_macro_internal::Row)
39+
-> ::std::result::Result<Self, #path::_macro_internal::FromRowError> {
4140

4241
if #fields_count != row.columns.len() {
43-
return ::std::result::Result::Err(FromRowError::WrongRowSize {
42+
return ::std::result::Result::Err(#path::_macro_internal::FromRowError::WrongRowSize {
4443
expected: #fields_count,
4544
actual: row.columns.len(),
4645
});

scylla-macros/src/from_user_type.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use syn::{spanned::Spanned, DeriveInput};
55
/// #[derive(FromUserType)] allows to parse a struct as User Defined Type
66
pub fn from_user_type_derive(tokens_input: TokenStream) -> TokenStream {
77
let item = syn::parse::<DeriveInput>(tokens_input).expect("No DeriveInput");
8+
let path = crate::parser::get_path(&item).expect("Couldn't get path to the scylla crate");
89
let struct_fields = crate::parser::parse_named_fields(&item, "FromUserType");
910

1011
let struct_name = &item.ident;
@@ -16,7 +17,7 @@ pub fn from_user_type_derive(tokens_input: TokenStream) -> TokenStream {
1617
let field_type = &field.ty;
1718

1819
quote_spanned! {field.span() =>
19-
#field_name: <#field_type as scylla::cql_to_rust::FromCqlVal<::std::option::Option<scylla::frame::response::result::CqlValue>>>::from_cql(
20+
#field_name: <#field_type as #path::_macro_internal::FromCqlVal<::std::option::Option<#path::_macro_internal::CqlValue>>>::from_cql(
2021
{
2122
let received_field_name: ::std::option::Option<&::std::string::String> = fields_iter
2223
.peek()
@@ -43,17 +44,14 @@ pub fn from_user_type_derive(tokens_input: TokenStream) -> TokenStream {
4344
});
4445

4546
let generated = quote! {
46-
impl #impl_generics scylla::cql_to_rust::FromCqlVal<scylla::frame::response::result::CqlValue> for #struct_name #ty_generics #where_clause {
47-
fn from_cql(cql_val: scylla::frame::response::result::CqlValue)
48-
-> ::std::result::Result<Self, scylla::cql_to_rust::FromCqlValError> {
49-
use ::std::collections::BTreeMap;
50-
use scylla::cql_to_rust::{FromCqlVal, FromCqlValError};
51-
use scylla::frame::response::result::CqlValue;
47+
impl #impl_generics #path::_macro_internal::FromCqlVal<#path::_macro_internal::CqlValue> for #struct_name #ty_generics #where_clause {
48+
fn from_cql(cql_val: #path::_macro_internal::CqlValue)
49+
-> Result<Self, #path::_macro_internal::FromCqlValError> {
5250

5351
// Interpret CqlValue as CQlValue::UserDefinedType
5452
let mut fields_iter = match cql_val {
55-
CqlValue::UserDefinedType{fields, ..} => fields.into_iter().peekable(),
56-
_ => return std::result::Result::Err(FromCqlValError::BadCqlType),
53+
#path::_macro_internal::CqlValue::UserDefinedType{fields, ..} => fields.into_iter().peekable(),
54+
_ => return ::std::result::Result::Err(#path::_macro_internal::FromCqlValError::BadCqlType),
5755
};
5856

5957
// Parse struct using values from fields
@@ -63,10 +61,10 @@ pub fn from_user_type_derive(tokens_input: TokenStream) -> TokenStream {
6361

6462
// There should be no unused fields when reading user defined type
6563
if fields_iter.next().is_some() {
66-
return std::result::Result::Err(FromCqlValError::BadCqlType);
64+
return ::std::result::Result::Err(#path::_macro_internal::FromCqlValError::BadCqlType);
6765
}
6866

69-
return std::result::Result::Ok(result);
67+
return ::std::result::Result::Ok(result);
7068
}
7169
}
7270
};

scylla-macros/src/into_user_type.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use syn::{spanned::Spanned, DeriveInput};
55
/// #[derive(IntoUserType)] allows to parse a struct as User Defined Type
66
pub fn into_user_type_derive(tokens_input: TokenStream) -> TokenStream {
77
let item = syn::parse::<DeriveInput>(tokens_input).expect("No DeriveInput");
8+
let path = crate::parser::get_path(&item).expect("No path");
89
let struct_fields = crate::parser::parse_named_fields(&item, "IntoUserType");
910

1011
let struct_name = &item.ident;
@@ -14,17 +15,14 @@ pub fn into_user_type_derive(tokens_input: TokenStream) -> TokenStream {
1415
let field_name = &field.ident;
1516

1617
quote_spanned! {field.span() =>
17-
<_ as scylla::frame::value::Value>::serialize(&self.#field_name, buf) ?;
18+
<_ as #path::_macro_internal::Value>::serialize(&self.#field_name, buf) ?;
1819
}
1920
});
2021

2122
let generated = quote! {
22-
impl #impl_generics scylla::frame::value::Value for #struct_name #ty_generics #where_clause {
23-
fn serialize(&self, buf: &mut ::std::vec::Vec<::core::primitive::u8>) -> ::std::result::Result<(), scylla::frame::value::ValueTooBig> {
24-
use scylla::frame::value::{Value, ValueTooBig};
25-
use scylla::macros::BufMut;
26-
use ::std::convert::TryInto;
27-
23+
impl #impl_generics #path::_macro_internal::Value for #struct_name #ty_generics #where_clause {
24+
fn serialize(&self, buf: &mut ::std::vec::Vec<::core::primitive::u8>) -> ::std::result::Result<(), #path::_macro_internal::ValueTooBig> {
25+
use #path::_macro_internal::BufMut;
2826

2927
// Reserve space to put serialized size in
3028
let total_size_index: ::core::primitive::usize = buf.len();
@@ -37,7 +35,7 @@ pub fn into_user_type_derive(tokens_input: TokenStream) -> TokenStream {
3735

3836
// Put serialized size in its place
3937
let total_size : ::core::primitive::usize = buf.len() - len_before_serialize;
40-
let total_size_i32: ::core::primitive::i32 = total_size.try_into().map_err(|_| ValueTooBig) ?;
38+
let total_size_i32: ::core::primitive::i32 = total_size.try_into().map_err(|_| #path::_macro_internal::ValueTooBig) ?;
4139
buf[total_size_index..(total_size_index+4)].copy_from_slice(&total_size_i32.to_be_bytes()[..]);
4240

4341
::std::result::Result::Ok(())

scylla-macros/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,28 @@ mod value_list;
88

99
/// #[derive(FromRow)] derives FromRow for struct
1010
/// Works only on simple structs without generics etc
11-
#[proc_macro_derive(FromRow)]
11+
#[proc_macro_derive(FromRow, attributes(scylla_macros))]
1212
pub fn from_row_derive(tokens_input: TokenStream) -> TokenStream {
1313
from_row::from_row_derive(tokens_input)
1414
}
1515

1616
/// #[derive(FromUserType)] allows to parse a struct as User Defined Type
1717
/// Works only on simple structs without generics etc
18-
#[proc_macro_derive(FromUserType)]
18+
#[proc_macro_derive(FromUserType, attributes(scylla_macros))]
1919
pub fn from_user_type_derive(tokens_input: TokenStream) -> TokenStream {
2020
from_user_type::from_user_type_derive(tokens_input)
2121
}
2222

2323
/// #[derive(IntoUserType)] allows to parse a struct as User Defined Type
2424
/// Works only on simple structs without generics etc
25-
#[proc_macro_derive(IntoUserType)]
25+
#[proc_macro_derive(IntoUserType, attributes(scylla_macros))]
2626
pub fn into_user_type_derive(tokens_input: TokenStream) -> TokenStream {
2727
into_user_type::into_user_type_derive(tokens_input)
2828
}
2929

3030
/// #[derive(ValueList)] derives ValueList for struct
3131
/// Works only on simple structs without generics etc
32-
#[proc_macro_derive(ValueList)]
32+
#[proc_macro_derive(ValueList, attributes(scylla_macros))]
3333
pub fn value_list_derive(tokens_input: TokenStream) -> TokenStream {
3434
value_list::value_list_derive(tokens_input)
3535
}

scylla-macros/src/parser.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use syn::{Data, DeriveInput, Fields, FieldsNamed};
2+
use syn::{Lit, Meta};
23

34
/// Parses the tokens_input to a DeriveInput and returns the struct name from which it derives and
45
/// the named fields
@@ -17,3 +18,43 @@ pub(crate) fn parse_named_fields<'a>(
1718
_ => panic!("derive({}) works only on structs!", current_derive),
1819
}
1920
}
21+
22+
pub(crate) fn get_path(input: &DeriveInput) -> Result<proc_macro2::TokenStream, syn::Error> {
23+
let mut this_path = quote::quote!(scylla);
24+
for attr in input.attrs.iter() {
25+
if !attr.path.is_ident("scylla_macros") {
26+
continue;
27+
}
28+
match attr.parse_meta() {
29+
Ok(Meta::List(meta_list)) => {
30+
for nested_meta in meta_list.nested.iter() {
31+
if let syn::NestedMeta::Meta(Meta::NameValue(meta_name_value)) = nested_meta {
32+
if !meta_name_value.path.is_ident("crate") {
33+
continue;
34+
}
35+
if let Lit::Str(lit_str) = &meta_name_value.lit {
36+
let path_val =
37+
&lit_str.value().parse::<proc_macro2::TokenStream>().unwrap();
38+
this_path = quote::quote!(#path_val);
39+
} else {
40+
return Err(syn::Error::new_spanned(
41+
&meta_name_value.lit,
42+
"the `crate` attribute should be a string literal",
43+
));
44+
}
45+
}
46+
}
47+
}
48+
Ok(other) => {
49+
return Err(syn::Error::new_spanned(
50+
other,
51+
"unexpected scylla_macros helper attribute",
52+
));
53+
}
54+
Err(err) => {
55+
return Err(err);
56+
}
57+
}
58+
}
59+
Ok(this_path)
60+
}

scylla-macros/src/value_list.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use syn::DeriveInput;
66
/// which can be fed to the query directly.
77
pub fn value_list_derive(tokens_input: TokenStream) -> TokenStream {
88
let item = syn::parse::<DeriveInput>(tokens_input).expect("No DeriveInput");
9+
let path = crate::parser::get_path(&item).expect("No path");
910
let struct_fields = crate::parser::parse_named_fields(&item, "ValueList");
1011

1112
let struct_name = &item.ident;
@@ -14,9 +15,9 @@ pub fn value_list_derive(tokens_input: TokenStream) -> TokenStream {
1415
let values_len = struct_fields.named.len();
1516
let field_name = struct_fields.named.iter().map(|field| &field.ident);
1617
let generated = quote! {
17-
impl #impl_generics scylla::frame::value::ValueList for #struct_name #ty_generics #where_clause {
18-
fn serialized(&self) -> scylla::frame::value::SerializedResult {
19-
let mut result = scylla::frame::value::SerializedValues::with_capacity(#values_len);
18+
impl #impl_generics #path::_macro_internal::ValueList for #struct_name #ty_generics #where_clause {
19+
fn serialized(&self) -> #path::_macro_internal::SerializedResult {
20+
let mut result = #path::_macro_internal::SerializedValues::with_capacity(#values_len);
2021
#(
2122
result.add_value(&self.#field_name)?;
2223
)*

scylla/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@
9393
9494
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
9595

96+
#[doc(hidden)]
97+
pub mod _macro_internal {
98+
pub use scylla_cql::_macro_internal::*;
99+
}
100+
96101
pub use scylla_cql::frame;
97102
pub use scylla_cql::macros::{self, *};
98103

0 commit comments

Comments
 (0)