Skip to content

Conversation

@ziara1
Copy link

@ziara1 ziara1 commented Dec 11, 2025

Motivation

Users often employ the newtype pattern (i.e., define single-field structs) to wrap the driver's types that implement {De,S}erialize{Value,Row}. In such cases, they are currently forced to manually implement (trivially) the respective de/ser traits for those new types, which results in unnecessary boilerplate code.

Solution

Add support for a new item-level attribute, #[scylla(transparent)].
It is supported on:

  • single-field structs (the original use case),
  • single-variant enums (technically identical to single-field structs).

The semantics are simple: delegate the trait method's implementation (serialization, deserialization, and type checking) to the only field/variant of the struct/enum.

What's done

Implemented transparent logic in DeserializeValue derive

Refactored deserialize_value_derive to delegate to a new derive_transparent function when the attribute is present.
The implementation ensures that:

  • type_check delegates to the inner type.
  • deserialize delegates to the inner type and wraps the result in the newtype constructor.
  • Generic where clauses are handled correctly by merging generated predicates with existing user predicates using make_where_clause().

Implemented transparent logic in SerializeValue derive

Modified serialize_value_derive to handle the transparent attribute.

  • For structs: Serializes the single field directly.
  • For enums: Matches the single variant and serializes its inner field.
  • Added validation to ensure the attribute is only used on items with exactly one field.

Updated Attribute Parsing

Updated StructAttrs and Attributes definitions in both deserialize and serialize modules to parse the #[scylla(transparent)] boolean flag via darling.

What has been tested

Tests

I added a comprehensive suite of tests covering:

  • Tuple Structs: struct Wrapper(i32)
  • Named Structs: struct Wrapper { val: i32 }
  • Enums: Single variant tuple and named enums.
  • Nested Composition: Outer(Inner(i32)) to verify deep delegation.
  • Type Safety: Verified that type_check correctly propagates errors (e.g., trying to read an int column as text through a wrapper fails).
  • Error Propagation: Verified that deserialization errors (e.g., not enough bytes) are correctly propagated from the inner type through the wrapper.

Fixes: #1293

Pre-review checklist

  • I have split my patch into logically separate commits.
  • All commit messages clearly explain what they change and why.
  • I added relevant tests for new features and bug fixes.
  • All commits compile, pass static checks and pass test.
  • PR description sums up the changes and reasons why they should be introduced.
  • I have provided docstrings for the public items that I want to introduce.
  • I have adjusted the documentation in ./docs/source/.
  • I added appropriate Fixes: annotations to PR description.

@github-actions
Copy link

github-actions bot commented Dec 11, 2025

cargo semver-checks found no API-breaking changes in this PR.
Checked commit: 24dd668

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds support for the #[scylla(transparent)] attribute to the SerializeValue and DeserializeValue derive macros. This attribute enables wrapper types (newtypes) to transparently serialize and deserialize as their inner type, similar to serde's transparent attribute. The implementation handles structs with single fields (both named and unnamed/tuple structs) and enums with a single variant containing one field.

Key Changes:

  • Added transparent attribute support to SerializeValue derive macro with validation for single-field structs and single-variant enums
  • Added transparent attribute support to DeserializeValue derive macro with corresponding validation and proper lifetime handling
  • Both implementations delegate serialization/deserialization to the inner field's type implementation

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
scylla-macros/src/serialize/value.rs Adds transparent attribute field and implements transparent serialization logic for single-field structs and single-variant enums by delegating to the inner field's SerializeValue implementation
scylla-macros/src/deserialize/value.rs Adds transparent attribute field and implements transparent deserialization logic through a new derive_transparent function that properly handles lifetimes and delegates to the inner field's DeserializeValue implementation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ziara1 ziara1 force-pushed the feature/scylla_transparent branch from 9139086 to 4dc482e Compare December 13, 2025 18:07
@ziara1 ziara1 changed the title Support #[scylla(transparent)] attribute by derive macros macros: Add support for #[scylla(transparent)] attribute Dec 13, 2025
@ziara1 ziara1 marked this pull request as ready for review December 13, 2025 20:25
@wprzytula wprzytula requested a review from Copilot December 13, 2025 20:26
@wprzytula wprzytula added the area/proc-macros Related to procedural macros label Dec 13, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@wprzytula wprzytula requested a review from Lorak-mmk December 13, 2025 20:51
Comment on lines +88 to +93
let input: syn::DeriveInput = syn::parse(tokens_input)?;

let attrs = StructAttrs::from_attributes(&input.attrs)?;
if attrs.transparent {
return derive_transparent(&input, &attrs);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the non-transparent case this will cause the struct attrs to be parsed twice: first time here, and then in StructDesc::new below.
One way to fix that that comes to my mind is to move this if below line let s = StructDesc::new... and use s.attrs instead of attrs. I did not test that, so it may not work. Is there a reason you chose the current approach? Do you see any downsides of my proposed approach?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried moving the check after StructDesc::new, but StructDesc strictly requires named fields during initialization. Since transparent structs are often tuple structs, StructDesc::new fails for them.

typ: &#crate_path::ColumnType,
) -> ::std::result::Result<(), #crate_path::TypeCheckError> {
<#inner_type as #crate_path::DeserializeValue<#frame_lifetime, #metadata_lifetime>>::type_check(typ)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mapped the type name in error in deserialize below, but not here. Why?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scylla-cql does not export a helper function to replace the Rust name in TypeCheckError (like value_deser_error_replace_rust_name for DeserializationError).

Comment on lines 123 to 134
return Ok(parse_quote! {
#[automatically_derived]
impl #impl_generics #implemented_trait for #struct_name #ty_generics #where_clause {
fn serialize<'b>(
&self,
typ: &#crate_path::ColumnType,
writer: #crate_path::CellWriter<'b>,
) -> ::std::result::Result<#crate_path::WrittenCellProof<'b>, #crate_path::SerializationError> {
#crate_path::SerializeValue::serialize(&self.#field_accessor, typ, writer)
}
}
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should error be mapped to correct name here too?

Comment on lines +168 to +222
match self {
#pattern_match => #crate_path::SerializeValue::serialize(inner, typ, writer)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto about name mapping

@ziara1 ziara1 force-pushed the feature/scylla_transparent branch 2 times, most recently from 3d47496 to d21a98a Compare January 3, 2026 10:04
@ziara1 ziara1 requested review from Lorak-mmk and wprzytula January 3, 2026 13:15
@ziara1
Copy link
Author

ziara1 commented Jan 8, 2026

@wprzytula

@wprzytula
Copy link
Collaborator

@ziara1 Please squash fixes into corresponding commits.

@ziara1 ziara1 force-pushed the feature/scylla_transparent branch from d21a98a to 24dd668 Compare January 8, 2026 20:30
@ziara1
Copy link
Author

ziara1 commented Jan 8, 2026

@wprzytula done

@wprzytula wprzytula added this to the 1.5.0 milestone Jan 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/proc-macros Related to procedural macros

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support #[scylla(transparent)] attribute by derive macros

3 participants