specta_serde/serde_attrs.rs
1//! Comprehensive serde attribute parsing and transformation system.
2//!
3//! This module provides functionality to parse serde attributes like `#[serde(rename = "...")]`,
4//! `#[serde(rename_all = "...")]`, and repr-related attributes, and apply them to DataType
5//! instances with separate handling for serialization and deserialization phases.
6
7use std::{borrow::Cow, fmt};
8
9use specta::{
10 datatype::{
11 DataType, Enum, Fields, RuntimeAttribute, RuntimeLiteral, RuntimeMeta, RuntimeNestedMeta,
12 RuntimeValue, Struct, Tuple,
13 },
14 internal,
15};
16
17use crate::{Error, inflection::RenameRule, repr::EnumRepr};
18
19/// Specifies whether to apply serde transformations for serialization or deserialization
20#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
21pub enum SerdeMode {
22 /// Apply transformations for serialization (Rust -> JSON/etc)
23 Serialize,
24 /// Apply transformations for deserialization (JSON/etc -> Rust)
25 Deserialize,
26 /// Apply transformations for both serialization and deserialization
27 ///
28 /// This mode uses common transformations (like `rename`, `rename_all`, `skip`)
29 /// but skips mode-specific attributes (like `rename_serialize`, `skip_serializing`).
30 /// A field/type is only skipped if it's skipped in both modes.
31 #[default]
32 Both,
33}
34
35impl fmt::Display for SerdeMode {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "{self:?}")
38 }
39}
40
41/// Contains parsed serde attributes for a type
42#[derive(Debug, Clone, Default)]
43pub struct SerdeAttributes {
44 /// Direct rename specified by #[serde(rename = "name")]
45 pub rename: Option<String>,
46 /// Separate names for serialization and deserialization
47 pub rename_serialize: Option<String>,
48 pub rename_deserialize: Option<String>,
49 /// Rename all fields/variants according to #[serde(rename_all = "case")]
50 pub rename_all: Option<RenameRule>,
51 /// Separate rename_all for serialization and deserialization
52 pub rename_all_serialize: Option<RenameRule>,
53 pub rename_all_deserialize: Option<RenameRule>,
54 /// Rename all fields in enum variants according to #[serde(rename_all_fields = "case")]
55 pub rename_all_fields: Option<RenameRule>,
56 /// Separate rename_all_fields for serialization and deserialization
57 pub rename_all_fields_serialize: Option<RenameRule>,
58 pub rename_all_fields_deserialize: Option<RenameRule>,
59 /// Skip serialization with #[serde(skip_serializing)]
60 pub skip_serializing: bool,
61 /// Skip deserialization with #[serde(skip_deserializing)]
62 pub skip_deserializing: bool,
63 /// Skip both serialization and deserialization with #[serde(skip)]
64 pub skip: bool,
65 /// Flatten this field/variant with #[serde(flatten)]
66 pub flatten: bool,
67 /// Default value with #[serde(default)]
68 pub default: bool,
69 /// Default value with custom function #[serde(default = "path")]
70 pub default_with: Option<String>,
71 /// Transparent container with #[serde(transparent)]
72 pub transparent: bool,
73 /// Deny unknown fields #[serde(deny_unknown_fields)]
74 pub deny_unknown_fields: bool,
75 /// Enum representation
76 pub repr: Option<EnumRepr>,
77 /// Tag for internally tagged enums
78 pub tag: Option<String>,
79 /// Content field for adjacently tagged enums
80 pub content: Option<String>,
81 /// Untagged enum
82 pub untagged: bool,
83 /// Remote type definition #[serde(remote = "...")]
84 pub remote: Option<String>,
85 /// Convert from another type #[serde(from = "...")]
86 pub from: Option<String>,
87 /// Try convert from another type #[serde(try_from = "...")]
88 pub try_from: Option<String>,
89 /// Convert into another type #[serde(into = "...")]
90 pub into: Option<String>,
91 /// Deserialize unknown variants to this variant #[serde(other)]
92 pub other: bool,
93 /// Aliases for deserialization #[serde(alias = "name")]
94 pub alias: Vec<String>,
95 /// Serialize with custom function #[serde(serialize_with = "path")]
96 pub serialize_with: Option<String>,
97 /// Deserialize with custom function #[serde(deserialize_with = "path")]
98 pub deserialize_with: Option<String>,
99 /// Combined serialize/deserialize with module #[serde(with = "module")]
100 pub with: Option<String>,
101}
102
103/// Contains parsed serde attributes for a field
104#[derive(Debug, Clone, Default)]
105pub struct SerdeFieldAttributes {
106 /// Field-specific attributes
107 pub base: SerdeAttributes,
108 /// Field alias for deserialization #[serde(alias = "name")]
109 #[allow(dead_code)]
110 pub alias: Vec<String>,
111 /// Serialize with custom function #[serde(serialize_with = "path")]
112 pub serialize_with: Option<String>,
113 /// Deserialize with custom function #[serde(deserialize_with = "path")]
114 pub deserialize_with: Option<String>,
115 /// Combined serialize/deserialize with module #[serde(with = "module")]
116 pub with: Option<String>,
117 /// Skip serializing if condition is true #[serde(skip_serializing_if = "path")]
118 pub skip_serializing_if: Option<String>,
119}
120
121/// Apply serde transformations to a DataType for the specified mode
122pub fn apply_serde_transformations(
123 datatype: &DataType,
124 mode: SerdeMode,
125) -> Result<DataType, Error> {
126 let mut transformer = SerdeTransformer::new(mode, None);
127 transformer.transform_datatype(datatype)
128}
129
130/// Apply serde transformations to a DataType with a type name (for struct tagging)
131pub fn apply_serde_transformations_with_name(
132 datatype: &DataType,
133 type_name: &str,
134 mode: SerdeMode,
135) -> Result<DataType, Error> {
136 let mut transformer = SerdeTransformer::new(mode, Some(type_name.to_string()));
137 transformer.transform_datatype(datatype)
138}
139
140/// Internal transformer that applies serde attributes to DataType instances
141struct SerdeTransformer {
142 mode: SerdeMode,
143 type_name: Option<String>,
144}
145
146impl SerdeTransformer {
147 fn new(mode: SerdeMode, type_name: Option<String>) -> Self {
148 Self { mode, type_name }
149 }
150
151 /// Transform a DataType with serde attributes applied
152 fn transform_datatype(&mut self, datatype: &DataType) -> Result<DataType, Error> {
153 match datatype {
154 DataType::Primitive(p) => Ok(DataType::Primitive(p.clone())),
155 DataType::List(list) => {
156 let transformed_inner = self.transform_datatype(list.ty())?;
157 let mut transformed_list = list.clone();
158 transformed_list.set_ty(transformed_inner);
159 Ok(DataType::List(transformed_list))
160 }
161 DataType::Map(map) => {
162 let transformed_key = self.transform_datatype(map.key_ty())?;
163 let transformed_value = self.transform_datatype(map.value_ty())?;
164 Ok(DataType::Map(specta::datatype::Map::new(
165 transformed_key,
166 transformed_value,
167 )))
168 }
169 DataType::Nullable(inner) => {
170 let transformed_inner = self.transform_datatype(inner)?;
171 Ok(DataType::Nullable(Box::new(transformed_inner)))
172 }
173 DataType::Struct(s) => self.transform_struct(s),
174 DataType::Enum(e) => self.transform_enum(e),
175 DataType::Tuple(t) => self.transform_tuple(t),
176 DataType::Reference(r) => Ok(DataType::Reference(r.clone())),
177 DataType::Generic(g) => Ok(DataType::Generic(g.clone())),
178 }
179 }
180
181 /// Transform a Struct with serde attributes
182 fn transform_struct(&mut self, struct_type: &Struct) -> Result<DataType, Error> {
183 let attrs = parse_serde_attributes(struct_type.attributes())?;
184
185 // Handle transparent structs
186 if attrs.transparent {
187 return self.handle_transparent_struct(struct_type);
188 }
189
190 // Handle skip based on mode
191 if self.should_skip_type(&attrs) {
192 // Return a unit type or some representation of skipped field
193 return Ok(DataType::Tuple(Tuple::new(vec![])));
194 }
195
196 let mut transformed_fields = self.transform_fields(struct_type.fields(), &attrs)?;
197
198 // If the struct has a tag attribute (for struct tagging), add the tag field
199 if let Some(tag_name) = &attrs.tag {
200 transformed_fields =
201 self.add_struct_tag_field(tag_name, struct_type, transformed_fields)?;
202 }
203
204 let mut new_struct = Struct::unit();
205 new_struct.set_fields(transformed_fields);
206 new_struct.set_attributes(struct_type.attributes().clone());
207
208 Ok(DataType::Struct(new_struct))
209 }
210
211 /// Transform an Enum with serde attributes
212 fn transform_enum(&mut self, enum_type: &Enum) -> Result<DataType, Error> {
213 let attrs = parse_serde_attributes(enum_type.attributes())?;
214
215 // Handle skip based on mode
216 if self.should_skip_type(&attrs) {
217 return Ok(DataType::Tuple(Tuple::new(vec![])));
218 }
219
220 // Determine enum representation
221 let repr = attrs.repr.clone().unwrap_or(EnumRepr::External);
222
223 // Handle string enums specially, but only if they're not internally/adjacently tagged
224 // Internally/adjacently tagged enums need to go through the normal tagging transformation
225 // to add tag fields to unit variants
226 if enum_type.is_string_enum()
227 && attrs.rename_all.is_some()
228 && !matches!(repr, EnumRepr::Internal { .. } | EnumRepr::Adjacent { .. })
229 {
230 return self.transform_string_enum(enum_type, &attrs);
231 }
232
233 let mut transformed_variants = Vec::new();
234
235 for (variant_name, variant) in enum_type.variants() {
236 let variant_attrs = parse_serde_attributes(variant.attributes())?;
237
238 if variant.skip() || self.should_skip_type(&variant_attrs) {
239 continue;
240 }
241
242 let transformed_name = self.apply_rename_rule(
243 variant_name,
244 attrs.rename_all,
245 &variant_attrs.rename,
246 &variant_attrs,
247 true, // is_variant
248 )?;
249
250 // For enum variant fields, use rename_all_fields instead of rename_all
251 let mut variant_field_attrs = attrs.clone();
252 // Apply rename_all_fields to variant fields based on mode
253 match self.mode {
254 SerdeMode::Serialize => {
255 if let Some(rule) = attrs
256 .rename_all_fields_serialize
257 .or(attrs.rename_all_fields)
258 {
259 variant_field_attrs.rename_all = Some(rule);
260 variant_field_attrs.rename_all_serialize = Some(rule);
261 }
262 }
263 SerdeMode::Deserialize => {
264 if let Some(rule) = attrs
265 .rename_all_fields_deserialize
266 .or(attrs.rename_all_fields)
267 {
268 variant_field_attrs.rename_all = Some(rule);
269 variant_field_attrs.rename_all_deserialize = Some(rule);
270 }
271 }
272 SerdeMode::Both => {
273 // For Both mode, use rename_all_fields if available
274 if let Some(rule) = attrs.rename_all_fields {
275 variant_field_attrs.rename_all = Some(rule);
276 }
277 }
278 }
279
280 let transformed_fields =
281 self.transform_fields(variant.fields(), &variant_field_attrs)?;
282
283 // Apply enum tagging transformation based on representation
284 let final_fields =
285 self.apply_enum_tagging(&repr, &transformed_name, transformed_fields)?;
286
287 let mut new_variant = variant.clone();
288 new_variant.set_fields(final_fields);
289
290 transformed_variants.push((transformed_name, new_variant));
291 }
292
293 if !enum_type.variants().is_empty() && transformed_variants.is_empty() {
294 return Err(Error::InvalidUsageOfSkip);
295 }
296
297 let mut new_enum = Enum::new();
298 *new_enum.variants_mut() = transformed_variants;
299 *new_enum.attributes_mut() = enum_type.attributes().clone();
300
301 Ok(DataType::Enum(new_enum))
302 }
303
304 /// Transform a string enum (unit-only enum) with rename_all support
305 fn transform_string_enum(
306 &mut self,
307 enum_type: &Enum,
308 attrs: &SerdeAttributes,
309 ) -> Result<DataType, Error> {
310 let mut transformed_variants = Vec::new();
311
312 for (variant_name, variant) in enum_type.variants() {
313 if !matches!(variant.fields(), Fields::Unit) {
314 return Err(Error::InvalidUsageOfSkip); // Not a string enum
315 }
316
317 let variant_attrs = parse_serde_attributes(variant.attributes())?;
318 if self.should_skip_type(&variant_attrs) {
319 continue;
320 }
321
322 let transformed_name = self.apply_rename_rule(
323 variant_name,
324 attrs.rename_all,
325 &variant_attrs.rename,
326 &variant_attrs,
327 true,
328 )?;
329
330 transformed_variants.push((transformed_name, variant.clone()));
331 }
332
333 // Create enum with String representation
334 let mut new_enum = Enum::new();
335 *new_enum.variants_mut() = transformed_variants;
336 *new_enum.attributes_mut() = enum_type.attributes().clone();
337
338 Ok(DataType::Enum(new_enum))
339 }
340
341 /// Transform a Tuple with serde attributes
342 fn transform_tuple(&mut self, tuple: &Tuple) -> Result<DataType, Error> {
343 let mut transformed_elements = Vec::new();
344
345 for element in tuple.elements() {
346 let transformed = self.transform_datatype(element)?;
347 transformed_elements.push(transformed);
348 }
349
350 Ok(DataType::Tuple(Tuple::new(transformed_elements)))
351 }
352
353 /// Transform Fields with serde attributes applied
354 fn transform_fields(
355 &mut self,
356 fields: &Fields,
357 parent_attrs: &SerdeAttributes,
358 ) -> Result<Fields, Error> {
359 match fields {
360 Fields::Unit => Ok(Fields::Unit),
361 Fields::Unnamed(unnamed) => {
362 let mut transformed_fields = Vec::new();
363
364 for (idx, field) in unnamed.fields().iter().enumerate() {
365 let field_attrs = parse_field_serde_attributes(field.attributes())?;
366
367 if self.should_skip_field(&field_attrs) {
368 let new_field = internal::construct::field(
369 field.optional(),
370 field.deprecated().cloned(),
371 field.docs().clone(),
372 field.inline(),
373 field.attributes().clone(),
374 None,
375 );
376 transformed_fields.push((idx, new_field));
377 continue;
378 }
379
380 let new_field = match field.ty().cloned() {
381 Some(field_ty) => {
382 let transformed_ty = self.transform_datatype(&field_ty)?;
383 let mut new_field = field.clone();
384 new_field.set_ty(transformed_ty);
385 new_field
386 }
387 // Keep previous behavior for `#[specta(skip)]` fields that were
388 // lowered to `ty = None` by the macro.
389 None => continue,
390 };
391
392 transformed_fields.push((idx, new_field));
393 }
394
395 Ok(internal::construct::fields_unnamed(
396 transformed_fields.into_iter().map(|(_, f)| f).collect(),
397 vec![],
398 ))
399 }
400 Fields::Named(named) => {
401 let mut transformed_fields = Vec::new();
402
403 for (field_name, field) in named.fields() {
404 // Parse field-specific serde attributes from stored runtime attributes
405 let field_attrs = parse_field_serde_attributes(field.attributes())?;
406
407 if self.should_skip_field(&field_attrs) {
408 continue;
409 }
410
411 let transformed_name = self.apply_rename_rule(
412 field_name,
413 parent_attrs.rename_all,
414 &field_attrs.base.rename,
415 &field_attrs.base,
416 false, // is_variant
417 )?;
418
419 if let Some(field_ty) = field.ty() {
420 let transformed_ty = self.transform_datatype(field_ty)?;
421 let mut new_field = field.clone();
422 new_field.set_ty(transformed_ty);
423
424 // Set optional flag based on serde attributes
425 // This matches the behavior that was previously in the macro
426 if field_attrs.skip_serializing_if.is_some() || field_attrs.base.default {
427 new_field.set_optional(true);
428 }
429
430 transformed_fields.push((transformed_name, new_field));
431 }
432 }
433
434 Ok(internal::construct::fields_named(
435 transformed_fields,
436 vec![],
437 ))
438 }
439 }
440 }
441
442 /// Handle transparent structs
443 fn handle_transparent_struct(&mut self, struct_type: &Struct) -> Result<DataType, Error> {
444 use specta::datatype::{skip_fields, skip_fields_named};
445
446 match struct_type.fields() {
447 Fields::Unnamed(unnamed) => {
448 // Collect non-skipped fields
449 let non_skipped: Vec<_> = skip_fields(unnamed.fields()).collect();
450
451 if non_skipped.len() == 1 {
452 self.transform_datatype(non_skipped[0].1)
453 } else {
454 Err(Error::InvalidUsageOfSkip)
455 }
456 }
457 Fields::Named(named) => {
458 // Collect non-skipped fields
459 let non_skipped: Vec<_> = skip_fields_named(named.fields()).collect();
460
461 if non_skipped.len() == 1 {
462 self.transform_datatype(non_skipped[0].1.1)
463 } else {
464 Err(Error::InvalidUsageOfSkip)
465 }
466 }
467 _ => Err(Error::InvalidUsageOfSkip), // Invalid transparent usage
468 }
469 }
470
471 /// Check if a type should be skipped based on the current mode
472 fn should_skip_type(&self, attrs: &SerdeAttributes) -> bool {
473 if attrs.skip {
474 return true;
475 }
476
477 match self.mode {
478 SerdeMode::Serialize => attrs.skip_serializing,
479 SerdeMode::Deserialize => attrs.skip_deserializing,
480 // For Both mode, only skip if skipped in both directions
481 SerdeMode::Both => attrs.skip_serializing && attrs.skip_deserializing,
482 }
483 }
484
485 /// Check if a field should be skipped based on the current mode
486 fn should_skip_field(&self, attrs: &SerdeFieldAttributes) -> bool {
487 self.should_skip_type(&attrs.base)
488 }
489
490 /// Apply rename rules to a field or variant name
491 fn apply_rename_rule(
492 &self,
493 original_name: &str,
494 rename_all_rule: Option<RenameRule>,
495 direct_rename: &Option<String>,
496 attrs: &SerdeAttributes,
497 is_variant: bool,
498 ) -> Result<Cow<'static, str>, Error> {
499 // Direct rename takes precedence
500 if let Some(renamed) = direct_rename {
501 return Ok(Cow::Owned(renamed.clone()));
502 }
503
504 // Check for mode-specific renames
505 match self.mode {
506 SerdeMode::Serialize => {
507 if let Some(renamed) = &attrs.rename_serialize {
508 return Ok(Cow::Owned(renamed.clone()));
509 }
510 }
511 SerdeMode::Deserialize => {
512 if let Some(renamed) = &attrs.rename_deserialize {
513 return Ok(Cow::Owned(renamed.clone()));
514 }
515 }
516 SerdeMode::Both => {
517 // For Both mode, don't use mode-specific renames
518 // Only use if serialize and deserialize renames match
519 if let (Some(ser), Some(de)) = (&attrs.rename_serialize, &attrs.rename_deserialize)
520 && ser == de
521 {
522 return Ok(Cow::Owned(ser.clone()));
523 }
524 }
525 }
526
527 // Apply mode-specific rename_all rule
528 let rule = match self.mode {
529 SerdeMode::Serialize => attrs
530 .rename_all_serialize
531 .or(attrs.rename_all_fields_serialize)
532 .or(rename_all_rule),
533 SerdeMode::Deserialize => attrs
534 .rename_all_deserialize
535 .or(attrs.rename_all_fields_deserialize)
536 .or(rename_all_rule),
537 SerdeMode::Both => {
538 // For Both mode, use common rename_all or only if both modes match
539 if let (Some(ser), Some(de)) =
540 (attrs.rename_all_serialize, attrs.rename_all_deserialize)
541 {
542 if ser == de {
543 Some(ser)
544 } else {
545 rename_all_rule // Fall back to common rule
546 }
547 } else {
548 rename_all_rule
549 }
550 }
551 };
552
553 // Apply rename_all rule
554 if let Some(rule) = rule {
555 let transformed = if is_variant {
556 rule.apply_to_variant(original_name)
557 } else {
558 rule.apply_to_field(original_name)
559 };
560 return Ok(Cow::Owned(transformed));
561 }
562
563 // No transformation needed
564 Ok(Cow::Owned(original_name.to_string()))
565 }
566
567 /// Apply enum tagging transformation to variant fields based on representation
568 /// This transforms the DataType to include tag/content fields for Internal/Adjacent representations
569 fn apply_enum_tagging(
570 &self,
571 repr: &EnumRepr,
572 variant_name: &str,
573 fields: Fields,
574 ) -> Result<Fields, Error> {
575 match repr {
576 EnumRepr::External | EnumRepr::Untagged | EnumRepr::String { .. } => {
577 // No transformation needed for external/untagged enums
578 Ok(fields)
579 }
580 EnumRepr::Internal { tag } => {
581 // Add tag field to the variant
582 self.add_tag_field(tag, variant_name, fields)
583 }
584 EnumRepr::Adjacent { tag, content } => {
585 // Wrap fields in content and add tag field
586 self.add_adjacent_tag_fields(tag, content, variant_name, fields)
587 }
588 }
589 }
590
591 /// Create a literal string type using an enum with a single unit variant
592 fn create_literal_string_type(value: &str) -> DataType {
593 use specta::datatype::EnumVariant;
594
595 let mut literal_enum = Enum::new();
596 let unit_variant = EnumVariant::unit();
597 *literal_enum.variants_mut() = vec![(Cow::Owned(value.to_string()), unit_variant)];
598 DataType::Enum(literal_enum)
599 }
600
601 fn is_valid_internal_tag_payload(ty: &DataType) -> bool {
602 match ty {
603 DataType::Primitive(_) | DataType::List(_) => false,
604 DataType::Tuple(tuple) => tuple.elements().is_empty(),
605 DataType::Nullable(inner) => Self::is_valid_internal_tag_payload(inner),
606 _ => true,
607 }
608 }
609
610 /// Add a tag field to a struct (for `#[serde(tag = "...")]` on structs)
611 fn add_struct_tag_field(
612 &self,
613 tag_name: &str,
614 _struct_type: &Struct,
615 fields: Fields,
616 ) -> Result<Fields, Error> {
617 use specta::datatype::Field;
618
619 // Get the struct name from the transformer
620 let struct_name = self.type_name.as_deref().unwrap_or("Unknown");
621 let tag_type = Self::create_literal_string_type(struct_name);
622
623 match fields {
624 Fields::Named(named) => {
625 let mut new_fields = vec![];
626
627 // Add tag field first
628 let tag_field = Field::new(tag_type);
629 new_fields.push((Cow::Owned(tag_name.to_string()), tag_field));
630
631 // Add existing fields
632 for (field_name, field) in named.fields() {
633 new_fields.push((field_name.clone(), field.clone()));
634 }
635
636 Ok(internal::construct::fields_named(new_fields, vec![]))
637 }
638 _ => {
639 // Struct tagging only works with named fields
640 Ok(fields)
641 }
642 }
643 }
644
645 /// Add a tag field to variant fields for internally tagged enums
646 fn add_tag_field(
647 &self,
648 tag_name: &str,
649 variant_name: &str,
650 fields: Fields,
651 ) -> Result<Fields, Error> {
652 use specta::datatype::Field;
653
654 let tag_type = Self::create_literal_string_type(variant_name);
655
656 match fields {
657 Fields::Unit => {
658 // Unit variant becomes { tag: "VariantName" }
659 let tag_field = Field::new(tag_type);
660 Ok(internal::construct::fields_named(
661 vec![(Cow::Owned(tag_name.to_string()), tag_field)],
662 vec![],
663 ))
664 }
665 Fields::Named(named) => {
666 // Named variant: add tag field to existing fields
667 let mut new_fields = vec![];
668
669 // Add tag field first
670 let tag_field = Field::new(tag_type);
671 new_fields.push((Cow::Owned(tag_name.to_string()), tag_field));
672
673 // Add existing fields
674 for (field_name, field) in named.fields() {
675 new_fields.push((field_name.clone(), field.clone()));
676 }
677
678 Ok(internal::construct::fields_named(new_fields, vec![]))
679 }
680 Fields::Unnamed(unnamed) => {
681 use specta::datatype::skip_fields;
682
683 let invalid_payload = {
684 let mut non_skipped_fields = skip_fields(unnamed.fields());
685 if let Some((_, field_ty)) = non_skipped_fields.next() {
686 non_skipped_fields.next().is_some()
687 || !Self::is_valid_internal_tag_payload(field_ty)
688 } else {
689 false
690 }
691 };
692
693 if invalid_payload {
694 return Err(Error::InvalidInternallyTaggedEnum);
695 }
696
697 // Keep tuple payloads unchanged so exporters can render `{ tag } & payload`
698 // for valid internally tagged tuple variants.
699 Ok(Fields::Unnamed(unnamed))
700 }
701 }
702 }
703
704 /// Add tag and content fields for adjacently tagged enums
705 fn add_adjacent_tag_fields(
706 &self,
707 tag_name: &str,
708 content_name: &str,
709 variant_name: &str,
710 fields: Fields,
711 ) -> Result<Fields, Error> {
712 use specta::datatype::Field;
713
714 let tag_type = Self::create_literal_string_type(variant_name);
715
716 match fields {
717 Fields::Unit => {
718 // Unit variant becomes { tag: "VariantName" } (no content field)
719 let tag_field = Field::new(tag_type);
720 Ok(internal::construct::fields_named(
721 vec![(Cow::Owned(tag_name.to_string()), tag_field)],
722 vec![],
723 ))
724 }
725 Fields::Named(named) => {
726 // Named variant: { tag: "VariantName", content: { ...fields } }
727 let mut new_fields = vec![];
728
729 // Add tag field
730 let tag_field = Field::new(tag_type);
731 new_fields.push((Cow::Owned(tag_name.to_string()), tag_field));
732
733 // Wrap existing fields in a struct for content
734 let mut content_struct = Struct::unit();
735 content_struct.set_fields(Fields::Named(named.clone()));
736
737 let content_field = Field::new(DataType::Struct(content_struct));
738 new_fields.push((Cow::Owned(content_name.to_string()), content_field));
739
740 Ok(internal::construct::fields_named(new_fields, vec![]))
741 }
742 Fields::Unnamed(unnamed) => {
743 use specta::datatype::skip_fields;
744
745 // Tuple variant: { tag: "VariantName", content: tuple }
746 let mut new_fields = vec![];
747
748 // Add tag field
749 let tag_field = Field::new(tag_type);
750 new_fields.push((Cow::Owned(tag_name.to_string()), tag_field));
751
752 // Wrap tuple fields as content
753 let tuple_types: Vec<DataType> = skip_fields(unnamed.fields())
754 .map(|(_, ty)| ty.clone())
755 .collect();
756
757 // If all tuple fields are skipped, omit content.
758 // This keeps adjacently tagged output aligned with serde behavior.
759 if tuple_types.is_empty() && !unnamed.fields().is_empty() {
760 return Ok(internal::construct::fields_named(new_fields, vec![]));
761 }
762
763 let content_type = if let [single] = tuple_types.as_slice() {
764 single.clone()
765 } else {
766 DataType::Tuple(Tuple::new(tuple_types))
767 };
768
769 let content_field = Field::new(content_type);
770 new_fields.push((Cow::Owned(content_name.to_string()), content_field));
771
772 Ok(internal::construct::fields_named(new_fields, vec![]))
773 }
774 }
775 }
776}
777
778/// Parse serde attributes from a vector of RuntimeAttribute
779fn parse_serde_attributes(attributes: &[RuntimeAttribute]) -> Result<SerdeAttributes, Error> {
780 let mut attrs = SerdeAttributes::default();
781
782 for attr in attributes {
783 if attr.path == "serde" {
784 parse_serde_attribute_content(&attr.kind, &mut attrs)?;
785 }
786 }
787
788 Ok(attrs)
789}
790
791/// Parse the content of a serde attribute
792fn parse_serde_attribute_content(
793 meta: &RuntimeMeta,
794 attrs: &mut SerdeAttributes,
795) -> Result<(), Error> {
796 match meta {
797 RuntimeMeta::Path(path) => {
798 // Handle path-only attributes (e.g., #[serde(untagged)], #[serde(skip)])
799 parse_serde_path_attribute(attrs, path);
800 }
801 RuntimeMeta::NameValue { key, value } => {
802 match key.as_str() {
803 "rename" => {
804 if let RuntimeValue::Literal(RuntimeLiteral::Str(name)) = value {
805 attrs.rename = Some(name.clone());
806 }
807 }
808 "rename_all" => {
809 if let RuntimeValue::Literal(RuntimeLiteral::Str(rule_str)) = value {
810 attrs.rename_all = Some(
811 RenameRule::from_str(rule_str)
812 .map_err(|_| Error::InvalidUsageOfSkip)?,
813 ); // TODO: Better error
814 }
815 }
816 "rename_all_fields" => {
817 if let RuntimeValue::Literal(RuntimeLiteral::Str(rule_str)) = value {
818 attrs.rename_all_fields = Some(
819 RenameRule::from_str(rule_str)
820 .map_err(|_| Error::InvalidUsageOfSkip)?,
821 );
822 }
823 }
824 "tag" => {
825 if let RuntimeValue::Literal(RuntimeLiteral::Str(tag_name)) = value {
826 attrs.tag = Some(tag_name.clone());
827 // If we have a tag, this is an internally tagged enum
828 if attrs.repr.is_none() {
829 attrs.repr = Some(EnumRepr::Internal {
830 tag: Cow::Owned(tag_name.clone()),
831 });
832 }
833 }
834 }
835 "content" => {
836 if let RuntimeValue::Literal(RuntimeLiteral::Str(content_name)) = value {
837 attrs.content = Some(content_name.clone());
838 }
839 }
840 "default" => match value {
841 RuntimeValue::Literal(RuntimeLiteral::Bool(true)) => attrs.default = true,
842 RuntimeValue::Literal(RuntimeLiteral::Str(func_path)) => {
843 attrs.default_with = Some(func_path.clone());
844 }
845 RuntimeValue::Expr(func_path) => attrs.default_with = Some(func_path.clone()),
846 _ => {}
847 },
848 "remote" => {
849 if let RuntimeValue::Literal(RuntimeLiteral::Str(remote_type)) = value {
850 attrs.remote = Some(remote_type.clone());
851 }
852 }
853 "from" => {
854 if let RuntimeValue::Literal(RuntimeLiteral::Str(from_type)) = value {
855 attrs.from = Some(from_type.clone());
856 }
857 }
858 "try_from" => {
859 if let RuntimeValue::Literal(RuntimeLiteral::Str(try_from_type)) = value {
860 attrs.try_from = Some(try_from_type.clone());
861 }
862 }
863 "into" => {
864 if let RuntimeValue::Literal(RuntimeLiteral::Str(into_type)) = value {
865 attrs.into = Some(into_type.clone());
866 }
867 }
868 "alias" => {
869 if let RuntimeValue::Literal(RuntimeLiteral::Str(alias_name)) = value {
870 attrs.alias.push(alias_name.clone());
871 }
872 }
873 "serialize_with" => {
874 if let RuntimeValue::Literal(RuntimeLiteral::Str(serialize_fn)) = value {
875 attrs.serialize_with = Some(serialize_fn.clone());
876 }
877 }
878 "deserialize_with" => {
879 if let RuntimeValue::Literal(RuntimeLiteral::Str(deserialize_fn)) = value {
880 attrs.deserialize_with = Some(deserialize_fn.clone());
881 }
882 }
883 "with" => match value {
884 RuntimeValue::Literal(RuntimeLiteral::Str(with_module))
885 | RuntimeValue::Expr(with_module) => {
886 attrs.with = Some(with_module.clone());
887 }
888 _ => {}
889 },
890 _ => {}
891 }
892 }
893 RuntimeMeta::List(list) => {
894 // Check if this is a complex attribute with serialize/deserialize modifiers
895 let mut has_serialize_deserialize = false;
896 for nested in list {
897 if let RuntimeNestedMeta::Meta(RuntimeMeta::NameValue { key, .. }) = nested
898 && (key == "serialize" || key == "deserialize")
899 {
900 has_serialize_deserialize = true;
901 break;
902 }
903 }
904
905 if has_serialize_deserialize {
906 // This is a complex attribute like rename(serialize="...", deserialize="...")
907 for nested in list {
908 if let RuntimeNestedMeta::Meta(nested_meta) = nested {
909 parse_complex_serde_attribute(nested_meta, attrs, "rename")?;
910 }
911 }
912 } else {
913 // Regular list processing
914 for nested in list {
915 match nested {
916 RuntimeNestedMeta::Meta(nested_meta) => {
917 parse_serde_attribute_content(nested_meta, attrs)?;
918 }
919 RuntimeNestedMeta::Literal(RuntimeLiteral::Str(s)) => {
920 // Handle string literals that might be path attributes
921 parse_serde_path_attribute(attrs, s);
922 }
923 RuntimeNestedMeta::Expr(_) => {}
924 RuntimeNestedMeta::Literal(_) => {
925 // Handle other literal values in lists if needed
926 }
927 }
928 }
929 }
930 }
931 }
932
933 // Handle special cases for enum representation
934 if let (Some(tag), Some(content)) = (&attrs.tag, &attrs.content) {
935 attrs.repr = Some(EnumRepr::Adjacent {
936 tag: Cow::Owned(tag.clone()),
937 content: Cow::Owned(content.clone()),
938 });
939 }
940
941 if attrs.untagged {
942 attrs.repr = Some(EnumRepr::Untagged);
943 }
944
945 Ok(())
946}
947
948fn parse_complex_serde_attribute(
949 meta: &RuntimeMeta,
950 attrs: &mut SerdeAttributes,
951 parent_key: &str,
952) -> Result<(), Error> {
953 match meta {
954 RuntimeMeta::NameValue { key, value } => match key.as_str() {
955 "serialize" => {
956 if let RuntimeValue::Literal(RuntimeLiteral::Str(name)) = value {
957 match parent_key {
958 "rename" => attrs.rename_serialize = Some(name.clone()),
959 "rename_all" => {
960 if let Ok(rule) = RenameRule::from_str(name) {
961 attrs.rename_all_serialize = Some(rule);
962 }
963 }
964 "rename_all_fields" => {
965 if let Ok(rule) = RenameRule::from_str(name) {
966 attrs.rename_all_fields_serialize = Some(rule);
967 }
968 }
969 _ => {}
970 }
971 }
972 }
973 "deserialize" => {
974 if let RuntimeValue::Literal(RuntimeLiteral::Str(name)) = value {
975 match parent_key {
976 "rename" => attrs.rename_deserialize = Some(name.clone()),
977 "rename_all" => {
978 if let Ok(rule) = RenameRule::from_str(name) {
979 attrs.rename_all_deserialize = Some(rule);
980 }
981 }
982 "rename_all_fields" => {
983 if let Ok(rule) = RenameRule::from_str(name) {
984 attrs.rename_all_fields_deserialize = Some(rule);
985 }
986 }
987 _ => {}
988 }
989 }
990 }
991 _ => {}
992 },
993 RuntimeMeta::List(list) => {
994 // Handle nested complex attributes
995 for nested in list {
996 if let RuntimeNestedMeta::Meta(nested_meta) = nested {
997 parse_complex_serde_attribute(nested_meta, attrs, parent_key)?;
998 }
999 }
1000 }
1001 _ => {}
1002 }
1003 Ok(())
1004}
1005
1006/// Parse string attributes that are commonly used with serde
1007/// This is a helper for parsing path-only attributes like #[serde(skip)]
1008fn parse_serde_path_attribute(attrs: &mut SerdeAttributes, attribute_name: &str) {
1009 match attribute_name {
1010 "skip" => attrs.skip = true,
1011 "skip_serializing" => attrs.skip_serializing = true,
1012 "skip_deserializing" => attrs.skip_deserializing = true,
1013 "flatten" => attrs.flatten = true,
1014 "default" => attrs.default = true,
1015 "transparent" => attrs.transparent = true,
1016 "untagged" => attrs.untagged = true,
1017 "deny_unknown_fields" => attrs.deny_unknown_fields = true,
1018 "other" => attrs.other = true,
1019 _ => {}
1020 }
1021}
1022
1023/// Parse serde field attributes from a vector of RuntimeAttribute
1024#[allow(dead_code)]
1025fn parse_serde_field_attributes(attrs: &[RuntimeAttribute]) -> Result<SerdeFieldAttributes, Error> {
1026 let mut result = SerdeFieldAttributes {
1027 base: parse_serde_attributes(attrs)?,
1028 ..Default::default()
1029 };
1030
1031 for attr in attrs {
1032 if attr.path == "serde" {
1033 parse_serde_field_attribute_content(&attr.kind, &mut result)?;
1034 }
1035 }
1036
1037 Ok(result)
1038}
1039
1040/// Parse the content of a serde field attribute
1041#[allow(dead_code)]
1042fn parse_serde_field_attribute_content(
1043 meta: &RuntimeMeta,
1044 attrs: &mut SerdeFieldAttributes,
1045) -> Result<(), Error> {
1046 // First parse as base attributes
1047 parse_serde_attribute_content(meta, &mut attrs.base)?;
1048
1049 // Then parse field-specific attributes
1050 match meta {
1051 RuntimeMeta::Path(_path) => {
1052 // Path-only attributes are already handled by parse_serde_attribute_content above
1053 }
1054 RuntimeMeta::NameValue { key, value } => match key.as_str() {
1055 "alias" => {
1056 if let RuntimeValue::Literal(RuntimeLiteral::Str(alias_name)) = value {
1057 attrs.alias.push(alias_name.clone());
1058 }
1059 }
1060 "serialize_with" => {
1061 if let RuntimeValue::Literal(RuntimeLiteral::Str(func_name)) = value {
1062 attrs.serialize_with = Some(func_name.clone());
1063 }
1064 }
1065 "deserialize_with" => {
1066 if let RuntimeValue::Literal(RuntimeLiteral::Str(func_name)) = value {
1067 attrs.deserialize_with = Some(func_name.clone());
1068 }
1069 }
1070 "with" => match value {
1071 RuntimeValue::Literal(RuntimeLiteral::Str(module_path))
1072 | RuntimeValue::Expr(module_path) => {
1073 attrs.with = Some(module_path.clone());
1074 }
1075 _ => {}
1076 },
1077 "skip_serializing_if" => {
1078 if let RuntimeValue::Literal(RuntimeLiteral::Str(func_name)) = value {
1079 attrs.skip_serializing_if = Some(func_name.clone());
1080 }
1081 }
1082 _ => {}
1083 },
1084 RuntimeMeta::List(list) => {
1085 for nested in list {
1086 if let RuntimeNestedMeta::Meta(nested_meta) = nested {
1087 parse_serde_field_attribute_content(nested_meta, attrs)?;
1088 }
1089 }
1090 }
1091 }
1092
1093 Ok(())
1094}
1095
1096fn parse_field_serde_attributes(
1097 attributes: &[specta::datatype::RuntimeAttribute],
1098) -> Result<SerdeFieldAttributes, Error> {
1099 parse_serde_field_attributes(attributes)
1100}
1101
1102// #[cfg(test)]
1103// mod tests {
1104// use super::*;
1105// use specta::datatype::Primitive;
1106
1107// #[test]
1108// fn test_rename_rule_parsing() {
1109// let mut attrs = SerdeAttributes::default();
1110// let meta = RuntimeMeta::NameValue {
1111// key: "rename_all".to_string(),
1112// value: RuntimeLiteral::Str("camelCase".to_string()),
1113// };
1114
1115// parse_serde_attribute_content(&meta, &mut attrs).expect("Failed to parse serde attribute");
1116// assert_eq!(attrs.rename_all, Some(RenameRule::CamelCase));
1117// }
1118
1119// #[test]
1120// fn test_direct_rename() {
1121// let mut attrs = SerdeAttributes::default();
1122// let meta = RuntimeMeta::NameValue {
1123// key: "rename".to_string(),
1124// value: RuntimeLiteral::Str("customName".to_string()),
1125// };
1126
1127// parse_serde_attribute_content(&meta, &mut attrs).expect("Failed to parse serde attribute");
1128// assert_eq!(attrs.rename, Some("customName".to_string()));
1129// }
1130
1131// #[test]
1132// fn test_skip_attributes() {
1133// let mut attrs = SerdeAttributes::default();
1134
1135// // Test various skip scenarios
1136// let transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1137// attrs.skip = true;
1138// assert!(transformer.should_skip_type(&attrs));
1139
1140// attrs.skip = false;
1141// attrs.skip_serializing = true;
1142// assert!(transformer.should_skip_type(&attrs));
1143
1144// let deserialize_transformer = SerdeTransformer::new(SerdeMode::Deserialize, None);
1145// assert!(!deserialize_transformer.should_skip_type(&attrs));
1146// }
1147
1148// #[test]
1149// fn test_all_rename_rules() {
1150// let test_cases = vec![
1151// ("lowercase", RenameRule::LowerCase),
1152// ("UPPERCASE", RenameRule::UpperCase),
1153// ("PascalCase", RenameRule::PascalCase),
1154// ("camelCase", RenameRule::CamelCase),
1155// ("snake_case", RenameRule::SnakeCase),
1156// ("SCREAMING_SNAKE_CASE", RenameRule::ScreamingSnakeCase),
1157// ("kebab-case", RenameRule::KebabCase),
1158// ("SCREAMING-KEBAB-CASE", RenameRule::ScreamingKebabCase),
1159// ];
1160
1161// for (rule_str, expected_rule) in test_cases {
1162// let mut attrs = SerdeAttributes::default();
1163// let meta = RuntimeMeta::NameValue {
1164// key: "rename_all".to_string(),
1165// value: RuntimeLiteral::Str(rule_str.to_string()),
1166// };
1167
1168// parse_serde_attribute_content(&meta, &mut attrs)
1169// .expect("Failed to parse serde attribute");
1170// assert_eq!(
1171// attrs.rename_all,
1172// Some(expected_rule),
1173// "Failed for rule: {}",
1174// rule_str
1175// );
1176// }
1177// }
1178
1179// #[test]
1180// fn test_rename_rule_application() {
1181// let transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1182
1183// // Test field renaming
1184// let result = transformer
1185// .apply_rename_rule(
1186// "test_field",
1187// Some(RenameRule::CamelCase),
1188// &None,
1189// &SerdeAttributes::default(),
1190// false,
1191// )
1192// .unwrap();
1193// assert_eq!(result, "testField");
1194
1195// // Test variant renaming
1196// let result = transformer
1197// .apply_rename_rule(
1198// "TestVariant",
1199// Some(RenameRule::SnakeCase),
1200// &None,
1201// &SerdeAttributes::default(),
1202// true,
1203// )
1204// .unwrap();
1205// assert_eq!(result, "test_variant");
1206
1207// // Test direct rename takes precedence
1208// let result = transformer
1209// .apply_rename_rule(
1210// "test_field",
1211// Some(RenameRule::CamelCase),
1212// &Some("customName".to_string()),
1213// &SerdeAttributes::default(),
1214// false,
1215// )
1216// .unwrap();
1217// assert_eq!(result, "customName");
1218// }
1219
1220// #[test]
1221// fn test_tag_parsing() {
1222// let mut attrs = SerdeAttributes::default();
1223// let meta = RuntimeMeta::NameValue {
1224// key: "tag".to_string(),
1225// value: RuntimeLiteral::Str("type".to_string()),
1226// };
1227
1228// parse_serde_attribute_content(&meta, &mut attrs).expect("Failed to parse serde attribute");
1229// assert_eq!(attrs.tag, Some("type".to_string()));
1230// // Should automatically set internal representation
1231// match attrs.repr {
1232// Some(EnumRepr::Internal { tag }) => assert_eq!(tag, "type"),
1233// _ => panic!("Expected internal enum representation"),
1234// }
1235// }
1236
1237// #[test]
1238// fn test_adjacent_tag_parsing() {
1239// let mut attrs = SerdeAttributes::default();
1240
1241// // Set tag first
1242// let tag_meta = RuntimeMeta::NameValue {
1243// key: "tag".to_string(),
1244// value: RuntimeLiteral::Str("type".to_string()),
1245// };
1246// parse_serde_attribute_content(&tag_meta, &mut attrs).expect("Failed to parse tag");
1247
1248// // Set content second
1249// let content_meta = RuntimeMeta::NameValue {
1250// key: "content".to_string(),
1251// value: RuntimeLiteral::Str("data".to_string()),
1252// };
1253// parse_serde_attribute_content(&content_meta, &mut attrs).expect("Failed to parse content");
1254
1255// // Should create adjacent representation
1256// match attrs.repr {
1257// Some(EnumRepr::Adjacent { tag, content }) => {
1258// assert_eq!(tag, "type");
1259// assert_eq!(content, "data");
1260// }
1261// _ => panic!("Expected adjacent enum representation"),
1262// }
1263// }
1264
1265// #[test]
1266// fn test_default_attribute() {
1267// let mut attrs = SerdeAttributes::default();
1268// let meta = RuntimeMeta::NameValue {
1269// key: "default".to_string(),
1270// value: RuntimeLiteral::Bool(true),
1271// };
1272
1273// parse_serde_attribute_content(&meta, &mut attrs).expect("Failed to parse serde attribute");
1274// assert!(attrs.default);
1275// }
1276
1277// #[test]
1278// fn test_primitive_type_passthrough() {
1279// let mut transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1280// let primitive = DataType::Primitive(Primitive::String);
1281
1282// let result = transformer.transform_datatype(&primitive).unwrap();
1283// assert_eq!(result, primitive);
1284// }
1285
1286// #[test]
1287// fn test_nullable_type_transformation() {
1288// let mut transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1289// let nullable = DataType::Nullable(Box::new(DataType::Primitive(Primitive::String)));
1290
1291// let result = transformer.transform_datatype(&nullable).unwrap();
1292// match result {
1293// DataType::Nullable(inner) => {
1294// assert_eq!(*inner.as_ref(), DataType::Primitive(Primitive::String));
1295// }
1296// _ => panic!("Expected nullable type"),
1297// }
1298// }
1299
1300// #[test]
1301// fn test_list_type_transformation() {
1302// let mut transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1303// let list = DataType::List(specta::datatype::List::new(DataType::Primitive(
1304// Primitive::String,
1305// )));
1306
1307// let result = transformer.transform_datatype(&list).unwrap();
1308// match result {
1309// DataType::List(list_result) => {
1310// assert_eq!(*list_result.ty(), DataType::Primitive(Primitive::String));
1311// }
1312// _ => panic!("Expected list type"),
1313// }
1314// }
1315
1316// #[test]
1317// fn test_mode_specific_skip_behavior() {
1318// let mut attrs = SerdeAttributes::default();
1319
1320// // Test skip_serializing only affects serialize mode
1321// attrs.skip_serializing = true;
1322// let ser_transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1323// let de_transformer = SerdeTransformer::new(SerdeMode::Deserialize, None);
1324
1325// assert!(ser_transformer.should_skip_type(&attrs));
1326// assert!(!de_transformer.should_skip_type(&attrs));
1327
1328// // Reset and test skip_deserializing
1329// attrs.skip_serializing = false;
1330// attrs.skip_deserializing = true;
1331
1332// assert!(!ser_transformer.should_skip_type(&attrs));
1333// assert!(de_transformer.should_skip_type(&attrs));
1334
1335// // Test universal skip
1336// attrs.skip_deserializing = false;
1337// attrs.skip = true;
1338
1339// assert!(ser_transformer.should_skip_type(&attrs));
1340// assert!(de_transformer.should_skip_type(&attrs));
1341// }
1342
1343// #[test]
1344// fn test_transparent_struct_handling() {
1345// let mut transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1346
1347// // Create a transparent struct with single field using List format
1348// let transparent_attr = RuntimeAttribute {
1349// path: "serde".to_string(),
1350// kind: RuntimeMeta::List(vec![RuntimeNestedMeta::Literal(RuntimeLiteral::Str(
1351// "transparent".to_string(),
1352// ))]),
1353// };
1354
1355// let field = specta::datatype::Field::new(DataType::Primitive(Primitive::String));
1356// let mut struct_dt = match Struct::unnamed().field(field).build() {
1357// DataType::Struct(s) => s,
1358// _ => unreachable!(),
1359// };
1360// struct_dt.set_attributes(vec![transparent_attr]);
1361
1362// let datatype = DataType::Struct(struct_dt);
1363// let result = transformer.transform_datatype(&datatype).unwrap();
1364
1365// // Should resolve to the inner type
1366// assert_eq!(result, DataType::Primitive(Primitive::String));
1367// }
1368
1369// #[test]
1370// fn test_field_attributes_parsing() {
1371// let serialize_with_attr = RuntimeAttribute {
1372// path: "serde".to_string(),
1373// kind: RuntimeMeta::NameValue {
1374// key: "serialize_with".to_string(),
1375// value: RuntimeLiteral::Str("custom_serialize".to_string()),
1376// },
1377// };
1378
1379// let attrs = parse_serde_field_attributes(&[serialize_with_attr]).unwrap();
1380// assert_eq!(attrs.serialize_with, Some("custom_serialize".to_string()));
1381// }
1382
1383// #[test]
1384// fn test_other_attribute() {
1385// let mut attrs = SerdeAttributes::default();
1386// parse_serde_path_attribute(&mut attrs, "other");
1387// assert!(attrs.other);
1388// }
1389
1390// #[test]
1391// fn test_alias_attribute() {
1392// let mut attrs = SerdeAttributes::default();
1393// let meta = RuntimeMeta::NameValue {
1394// key: "alias".to_string(),
1395// value: RuntimeLiteral::Str("alternative_name".to_string()),
1396// };
1397
1398// parse_serde_attribute_content(&meta, &mut attrs).expect("Failed to parse serde attribute");
1399// assert_eq!(attrs.alias, vec!["alternative_name".to_string()]);
1400// }
1401
1402// #[test]
1403// fn test_serialize_with_attribute() {
1404// let mut attrs = SerdeAttributes::default();
1405// let meta = RuntimeMeta::NameValue {
1406// key: "serialize_with".to_string(),
1407// value: RuntimeLiteral::Str("custom_serialize".to_string()),
1408// };
1409
1410// parse_serde_attribute_content(&meta, &mut attrs).expect("Failed to parse serde attribute");
1411// assert_eq!(attrs.serialize_with, Some("custom_serialize".to_string()));
1412// }
1413
1414// #[test]
1415// fn test_with_attribute() {
1416// let mut attrs = SerdeAttributes::default();
1417// let meta = RuntimeMeta::NameValue {
1418// key: "with".to_string(),
1419// value: RuntimeLiteral::Str("custom_module".to_string()),
1420// };
1421
1422// parse_serde_attribute_content(&meta, &mut attrs).expect("Failed to parse serde attribute");
1423// assert_eq!(attrs.with, Some("custom_module".to_string()));
1424// }
1425
1426// #[test]
1427// fn test_complex_rename_attribute() {
1428// let mut attrs = SerdeAttributes::default();
1429
1430// // Simulate parsing rename(serialize = "ser_name", deserialize = "de_name")
1431// let serialize_meta = RuntimeMeta::NameValue {
1432// key: "serialize".to_string(),
1433// value: RuntimeLiteral::Str("ser_name".to_string()),
1434// };
1435// let deserialize_meta = RuntimeMeta::NameValue {
1436// key: "deserialize".to_string(),
1437// value: RuntimeLiteral::Str("de_name".to_string()),
1438// };
1439
1440// parse_complex_serde_attribute(&serialize_meta, &mut attrs, "rename")
1441// .expect("Failed to parse serialize");
1442// parse_complex_serde_attribute(&deserialize_meta, &mut attrs, "rename")
1443// .expect("Failed to parse deserialize");
1444
1445// assert_eq!(attrs.rename_serialize, Some("ser_name".to_string()));
1446// assert_eq!(attrs.rename_deserialize, Some("de_name".to_string()));
1447// }
1448
1449// #[test]
1450// fn test_complex_rename_all_attribute() {
1451// let mut attrs = SerdeAttributes::default();
1452
1453// // Simulate parsing rename_all(serialize = "camelCase", deserialize = "snake_case")
1454// let serialize_meta = RuntimeMeta::NameValue {
1455// key: "serialize".to_string(),
1456// value: RuntimeLiteral::Str("camelCase".to_string()),
1457// };
1458// let deserialize_meta = RuntimeMeta::NameValue {
1459// key: "deserialize".to_string(),
1460// value: RuntimeLiteral::Str("snake_case".to_string()),
1461// };
1462
1463// parse_complex_serde_attribute(&serialize_meta, &mut attrs, "rename_all")
1464// .expect("Failed to parse serialize");
1465// parse_complex_serde_attribute(&deserialize_meta, &mut attrs, "rename_all")
1466// .expect("Failed to parse deserialize");
1467
1468// assert_eq!(attrs.rename_all_serialize, Some(RenameRule::CamelCase));
1469// assert_eq!(attrs.rename_all_deserialize, Some(RenameRule::SnakeCase));
1470// }
1471
1472// #[test]
1473// fn test_mode_specific_rename_behavior() {
1474// let mut attrs = SerdeAttributes::default();
1475// attrs.rename_serialize = Some("ser_name".to_string());
1476// attrs.rename_deserialize = Some("de_name".to_string());
1477
1478// let ser_transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1479// let de_transformer = SerdeTransformer::new(SerdeMode::Deserialize, None);
1480
1481// let ser_result = ser_transformer
1482// .apply_rename_rule("original", None, &None, &attrs, false)
1483// .unwrap();
1484// assert_eq!(ser_result, "ser_name");
1485
1486// let de_result = de_transformer
1487// .apply_rename_rule("original", None, &None, &attrs, false)
1488// .unwrap();
1489// assert_eq!(de_result, "de_name");
1490// }
1491
1492// #[test]
1493// fn test_mode_specific_rename_all_behavior() {
1494// let mut attrs = SerdeAttributes::default();
1495// attrs.rename_all_serialize = Some(RenameRule::CamelCase);
1496// attrs.rename_all_deserialize = Some(RenameRule::SnakeCase);
1497
1498// let ser_transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1499// let de_transformer = SerdeTransformer::new(SerdeMode::Deserialize, None);
1500
1501// // Test field renaming (fields start as snake_case in Rust)
1502// let ser_result = ser_transformer
1503// .apply_rename_rule("test_field", None, &None, &attrs, false)
1504// .unwrap();
1505// assert_eq!(ser_result, "testField");
1506
1507// let de_result = de_transformer
1508// .apply_rename_rule("test_field", None, &None, &attrs, false)
1509// .unwrap();
1510// assert_eq!(de_result, "test_field"); // snake_case rule returns input unchanged for fields
1511
1512// // Test variant renaming (variants start as PascalCase in Rust)
1513// let ser_result = ser_transformer
1514// .apply_rename_rule("TestVariant", None, &None, &attrs, true)
1515// .unwrap();
1516// assert_eq!(ser_result, "testVariant"); // camelCase
1517
1518// let de_result = de_transformer
1519// .apply_rename_rule("TestVariant", None, &None, &attrs, true)
1520// .unwrap();
1521// assert_eq!(de_result, "test_variant"); // snake_case
1522// }
1523
1524// #[test]
1525// fn test_both_mode_skip_behavior() {
1526// let mut attrs = SerdeAttributes::default();
1527// let both_transformer = SerdeTransformer::new(SerdeMode::Both, None);
1528
1529// // Test that Both mode only skips if both modes skip
1530// attrs.skip_serializing = true;
1531// attrs.skip_deserializing = false;
1532// assert!(!both_transformer.should_skip_type(&attrs));
1533
1534// attrs.skip_serializing = false;
1535// attrs.skip_deserializing = true;
1536// assert!(!both_transformer.should_skip_type(&attrs));
1537
1538// // Should skip only when both are true
1539// attrs.skip_serializing = true;
1540// attrs.skip_deserializing = true;
1541// assert!(both_transformer.should_skip_type(&attrs));
1542
1543// // Universal skip should still work
1544// attrs.skip_serializing = false;
1545// attrs.skip_deserializing = false;
1546// attrs.skip = true;
1547// assert!(both_transformer.should_skip_type(&attrs));
1548// }
1549
1550// #[test]
1551// fn test_both_mode_rename_behavior() {
1552// let both_transformer = SerdeTransformer::new(SerdeMode::Both, None);
1553// let mut attrs = SerdeAttributes::default();
1554
1555// // Test that Both mode uses common rename
1556// attrs.rename = Some("commonName".to_string());
1557// let result = both_transformer
1558// .apply_rename_rule("original", None, &attrs.rename, &attrs, false)
1559// .unwrap();
1560// assert_eq!(result, "commonName");
1561
1562// // Test that Both mode uses matching mode-specific renames
1563// attrs.rename = None;
1564// attrs.rename_serialize = Some("sameName".to_string());
1565// attrs.rename_deserialize = Some("sameName".to_string());
1566// let result = both_transformer
1567// .apply_rename_rule("original", None, &None, &attrs, false)
1568// .unwrap();
1569// assert_eq!(result, "sameName");
1570
1571// // Test that Both mode ignores non-matching mode-specific renames
1572// attrs.rename_serialize = Some("serName".to_string());
1573// attrs.rename_deserialize = Some("deName".to_string());
1574// let result = both_transformer
1575// .apply_rename_rule("original", None, &None, &attrs, false)
1576// .unwrap();
1577// assert_eq!(result, "original"); // Falls back to original name
1578// }
1579
1580// #[test]
1581// fn test_both_mode_rename_all_behavior() {
1582// let both_transformer = SerdeTransformer::new(SerdeMode::Both, None);
1583// let mut attrs = SerdeAttributes::default();
1584
1585// // Test that Both mode uses common rename_all
1586// let result = both_transformer
1587// .apply_rename_rule(
1588// "test_field",
1589// Some(RenameRule::CamelCase),
1590// &None,
1591// &attrs,
1592// false,
1593// )
1594// .unwrap();
1595// assert_eq!(result, "testField");
1596
1597// // Test that Both mode uses matching mode-specific rename_all
1598// attrs.rename_all_serialize = Some(RenameRule::PascalCase);
1599// attrs.rename_all_deserialize = Some(RenameRule::PascalCase);
1600// let result = both_transformer
1601// .apply_rename_rule("test_field", None, &None, &attrs, false)
1602// .unwrap();
1603// assert_eq!(result, "TestField");
1604
1605// // Test that Both mode falls back to common rule when modes differ
1606// attrs.rename_all_serialize = Some(RenameRule::CamelCase);
1607// attrs.rename_all_deserialize = Some(RenameRule::SnakeCase);
1608// let result = both_transformer
1609// .apply_rename_rule(
1610// "test_field",
1611// Some(RenameRule::PascalCase),
1612// &None,
1613// &attrs,
1614// false,
1615// )
1616// .unwrap();
1617// assert_eq!(result, "TestField"); // Uses common rule
1618// }
1619
1620// #[test]
1621// fn test_variant_attribute_parsing() {
1622// // Test that variant attributes are parsed when transforming enums
1623// let variant_attr = RuntimeAttribute {
1624// path: "serde".to_string(),
1625// kind: RuntimeMeta::NameValue {
1626// key: "rename".to_string(),
1627// value: RuntimeLiteral::Str("custom_variant".to_string()),
1628// },
1629// };
1630
1631// let attrs = parse_serde_attributes(&[variant_attr]).unwrap();
1632// assert_eq!(attrs.rename, Some("custom_variant".to_string()));
1633// }
1634
1635// #[test]
1636// fn test_internally_tagged_unit_variants_with_rename() {
1637// use specta::datatype::{Enum, EnumVariant};
1638// use std::borrow::Cow;
1639
1640// // Create an enum with only unit variants
1641// let mut test_enum = Enum::new();
1642// *test_enum.variants_mut() = vec![
1643// (Cow::Borrowed("A"), EnumVariant::unit()),
1644// (Cow::Borrowed("B"), EnumVariant::unit()),
1645// (Cow::Borrowed("C"), EnumVariant::unit()),
1646// ];
1647
1648// // Add serde attributes for internal tagging + rename_all
1649// *test_enum.attributes_mut() = vec![
1650// RuntimeAttribute {
1651// path: "serde".to_string(),
1652// kind: RuntimeMeta::NameValue {
1653// key: "tag".to_string(),
1654// value: RuntimeLiteral::Str("phase".to_string()),
1655// },
1656// },
1657// RuntimeAttribute {
1658// path: "serde".to_string(),
1659// kind: RuntimeMeta::NameValue {
1660// key: "rename_all".to_string(),
1661// value: RuntimeLiteral::Str("snake_case".to_string()),
1662// },
1663// },
1664// ];
1665
1666// let mut transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1667// let result = transformer.transform_enum(&test_enum).unwrap();
1668
1669// // Should produce an enum where each unit variant is transformed into a named field
1670// // with a tag field containing a literal string type
1671// match result {
1672// DataType::Enum(transformed_enum) => {
1673// assert_eq!(transformed_enum.variants().len(), 3);
1674
1675// // Check first variant
1676// let (name, variant) = &transformed_enum.variants()[0];
1677// assert_eq!(name.as_ref(), "a"); // snake_case transformation
1678
1679// // Variant should have named fields with a "phase" tag
1680// match variant.fields() {
1681// Fields::Named(named) => {
1682// assert_eq!(named.fields().len(), 1);
1683// let (field_name, _field) = &named.fields()[0];
1684// assert_eq!(field_name.as_ref(), "phase");
1685// }
1686// _ => panic!("Expected named fields for internally tagged unit variant"),
1687// }
1688// }
1689// _ => panic!("Expected enum type"),
1690// }
1691// }
1692
1693// #[test]
1694// fn test_adjacently_tagged_unit_variants_with_rename() {
1695// use specta::datatype::{Enum, EnumVariant};
1696// use std::borrow::Cow;
1697
1698// // Create an enum with only unit variants
1699// let mut test_enum = Enum::new();
1700// *test_enum.variants_mut() = vec![
1701// (Cow::Borrowed("VariantA"), EnumVariant::unit()),
1702// (Cow::Borrowed("VariantB"), EnumVariant::unit()),
1703// ];
1704
1705// // Add serde attributes for adjacent tagging + rename_all
1706// *test_enum.attributes_mut() = vec![
1707// RuntimeAttribute {
1708// path: "serde".to_string(),
1709// kind: RuntimeMeta::NameValue {
1710// key: "tag".to_string(),
1711// value: RuntimeLiteral::Str("t".to_string()),
1712// },
1713// },
1714// RuntimeAttribute {
1715// path: "serde".to_string(),
1716// kind: RuntimeMeta::NameValue {
1717// key: "content".to_string(),
1718// value: RuntimeLiteral::Str("c".to_string()),
1719// },
1720// },
1721// RuntimeAttribute {
1722// path: "serde".to_string(),
1723// kind: RuntimeMeta::NameValue {
1724// key: "rename_all".to_string(),
1725// value: RuntimeLiteral::Str("snake_case".to_string()),
1726// },
1727// },
1728// ];
1729
1730// let mut transformer = SerdeTransformer::new(SerdeMode::Serialize, None);
1731// let result = transformer.transform_enum(&test_enum).unwrap();
1732
1733// // Should produce an enum where each unit variant has a tag field
1734// // For unit variants, adjacently tagged enums only add the tag (no content)
1735// match result {
1736// DataType::Enum(transformed_enum) => {
1737// assert_eq!(transformed_enum.variants().len(), 2);
1738
1739// // Check first variant
1740// let (name, variant) = &transformed_enum.variants()[0];
1741// assert_eq!(name.as_ref(), "variant_a"); // snake_case transformation
1742
1743// // Unit variants in adjacently tagged enums only have the tag field
1744// match variant.fields() {
1745// Fields::Named(named) => {
1746// assert_eq!(named.fields().len(), 1);
1747// let (field_name, _field) = &named.fields()[0];
1748// assert_eq!(field_name.as_ref(), "t");
1749// }
1750// _ => panic!("Expected named fields for adjacently tagged unit variant"),
1751// }
1752// }
1753// _ => panic!("Expected enum type"),
1754// }
1755// }
1756// }