17e2e9c0cSopenharmony_ciuse crate::internals::ast::{Container, Data, Field, Style}; 27e2e9c0cSopenharmony_ciuse crate::internals::attr::{Default, Identifier, TagType}; 37e2e9c0cSopenharmony_ciuse crate::internals::{ungroup, Ctxt, Derive}; 47e2e9c0cSopenharmony_ciuse syn::{Member, Type}; 57e2e9c0cSopenharmony_ci 67e2e9c0cSopenharmony_ci// Cross-cutting checks that require looking at more than a single attrs object. 77e2e9c0cSopenharmony_ci// Simpler checks should happen when parsing and building the attrs. 87e2e9c0cSopenharmony_cipub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { 97e2e9c0cSopenharmony_ci check_default_on_tuple(cx, cont); 107e2e9c0cSopenharmony_ci check_remote_generic(cx, cont); 117e2e9c0cSopenharmony_ci check_getter(cx, cont); 127e2e9c0cSopenharmony_ci check_flatten(cx, cont); 137e2e9c0cSopenharmony_ci check_identifier(cx, cont); 147e2e9c0cSopenharmony_ci check_variant_skip_attrs(cx, cont); 157e2e9c0cSopenharmony_ci check_internal_tag_field_name_conflict(cx, cont); 167e2e9c0cSopenharmony_ci check_adjacent_tag_conflict(cx, cont); 177e2e9c0cSopenharmony_ci check_transparent(cx, cont, derive); 187e2e9c0cSopenharmony_ci check_from_and_try_from(cx, cont); 197e2e9c0cSopenharmony_ci} 207e2e9c0cSopenharmony_ci 217e2e9c0cSopenharmony_ci// If some field of a tuple struct is marked #[serde(default)] then all fields 227e2e9c0cSopenharmony_ci// after it must also be marked with that attribute, or the struct must have a 237e2e9c0cSopenharmony_ci// container-level serde(default) attribute. A field's default value is only 247e2e9c0cSopenharmony_ci// used for tuple fields if the sequence is exhausted at that point; that means 257e2e9c0cSopenharmony_ci// all subsequent fields will fail to deserialize if they don't have their own 267e2e9c0cSopenharmony_ci// default. 277e2e9c0cSopenharmony_cifn check_default_on_tuple(cx: &Ctxt, cont: &Container) { 287e2e9c0cSopenharmony_ci if let Default::None = cont.attrs.default() { 297e2e9c0cSopenharmony_ci if let Data::Struct(Style::Tuple, fields) = &cont.data { 307e2e9c0cSopenharmony_ci let mut first_default_index = None; 317e2e9c0cSopenharmony_ci for (i, field) in fields.iter().enumerate() { 327e2e9c0cSopenharmony_ci // Skipped fields automatically get the #[serde(default)] 337e2e9c0cSopenharmony_ci // attribute. We are interested only on non-skipped fields here. 347e2e9c0cSopenharmony_ci if field.attrs.skip_deserializing() { 357e2e9c0cSopenharmony_ci continue; 367e2e9c0cSopenharmony_ci } 377e2e9c0cSopenharmony_ci if let Default::None = field.attrs.default() { 387e2e9c0cSopenharmony_ci if let Some(first) = first_default_index { 397e2e9c0cSopenharmony_ci cx.error_spanned_by( 407e2e9c0cSopenharmony_ci field.ty, 417e2e9c0cSopenharmony_ci format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first), 427e2e9c0cSopenharmony_ci ); 437e2e9c0cSopenharmony_ci } 447e2e9c0cSopenharmony_ci continue; 457e2e9c0cSopenharmony_ci } 467e2e9c0cSopenharmony_ci if first_default_index.is_none() { 477e2e9c0cSopenharmony_ci first_default_index = Some(i); 487e2e9c0cSopenharmony_ci } 497e2e9c0cSopenharmony_ci } 507e2e9c0cSopenharmony_ci } 517e2e9c0cSopenharmony_ci } 527e2e9c0cSopenharmony_ci} 537e2e9c0cSopenharmony_ci 547e2e9c0cSopenharmony_ci// Remote derive definition type must have either all of the generics of the 557e2e9c0cSopenharmony_ci// remote type: 567e2e9c0cSopenharmony_ci// 577e2e9c0cSopenharmony_ci// #[serde(remote = "Generic")] 587e2e9c0cSopenharmony_ci// struct Generic<T> {…} 597e2e9c0cSopenharmony_ci// 607e2e9c0cSopenharmony_ci// or none of them, i.e. defining impls for one concrete instantiation of the 617e2e9c0cSopenharmony_ci// remote type only: 627e2e9c0cSopenharmony_ci// 637e2e9c0cSopenharmony_ci// #[serde(remote = "Generic<T>")] 647e2e9c0cSopenharmony_ci// struct ConcreteDef {…} 657e2e9c0cSopenharmony_ci// 667e2e9c0cSopenharmony_cifn check_remote_generic(cx: &Ctxt, cont: &Container) { 677e2e9c0cSopenharmony_ci if let Some(remote) = cont.attrs.remote() { 687e2e9c0cSopenharmony_ci let local_has_generic = !cont.generics.params.is_empty(); 697e2e9c0cSopenharmony_ci let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none(); 707e2e9c0cSopenharmony_ci if local_has_generic && remote_has_generic { 717e2e9c0cSopenharmony_ci cx.error_spanned_by(remote, "remove generic parameters from this path"); 727e2e9c0cSopenharmony_ci } 737e2e9c0cSopenharmony_ci } 747e2e9c0cSopenharmony_ci} 757e2e9c0cSopenharmony_ci 767e2e9c0cSopenharmony_ci// Getters are only allowed inside structs (not enums) with the `remote` 777e2e9c0cSopenharmony_ci// attribute. 787e2e9c0cSopenharmony_cifn check_getter(cx: &Ctxt, cont: &Container) { 797e2e9c0cSopenharmony_ci match cont.data { 807e2e9c0cSopenharmony_ci Data::Enum(_) => { 817e2e9c0cSopenharmony_ci if cont.data.has_getter() { 827e2e9c0cSopenharmony_ci cx.error_spanned_by( 837e2e9c0cSopenharmony_ci cont.original, 847e2e9c0cSopenharmony_ci "#[serde(getter = \"...\")] is not allowed in an enum", 857e2e9c0cSopenharmony_ci ); 867e2e9c0cSopenharmony_ci } 877e2e9c0cSopenharmony_ci } 887e2e9c0cSopenharmony_ci Data::Struct(_, _) => { 897e2e9c0cSopenharmony_ci if cont.data.has_getter() && cont.attrs.remote().is_none() { 907e2e9c0cSopenharmony_ci cx.error_spanned_by( 917e2e9c0cSopenharmony_ci cont.original, 927e2e9c0cSopenharmony_ci "#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]", 937e2e9c0cSopenharmony_ci ); 947e2e9c0cSopenharmony_ci } 957e2e9c0cSopenharmony_ci } 967e2e9c0cSopenharmony_ci } 977e2e9c0cSopenharmony_ci} 987e2e9c0cSopenharmony_ci 997e2e9c0cSopenharmony_ci// Flattening has some restrictions we can test. 1007e2e9c0cSopenharmony_cifn check_flatten(cx: &Ctxt, cont: &Container) { 1017e2e9c0cSopenharmony_ci match &cont.data { 1027e2e9c0cSopenharmony_ci Data::Enum(variants) => { 1037e2e9c0cSopenharmony_ci for variant in variants { 1047e2e9c0cSopenharmony_ci for field in &variant.fields { 1057e2e9c0cSopenharmony_ci check_flatten_field(cx, variant.style, field); 1067e2e9c0cSopenharmony_ci } 1077e2e9c0cSopenharmony_ci } 1087e2e9c0cSopenharmony_ci } 1097e2e9c0cSopenharmony_ci Data::Struct(style, fields) => { 1107e2e9c0cSopenharmony_ci for field in fields { 1117e2e9c0cSopenharmony_ci check_flatten_field(cx, *style, field); 1127e2e9c0cSopenharmony_ci } 1137e2e9c0cSopenharmony_ci } 1147e2e9c0cSopenharmony_ci } 1157e2e9c0cSopenharmony_ci} 1167e2e9c0cSopenharmony_ci 1177e2e9c0cSopenharmony_cifn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { 1187e2e9c0cSopenharmony_ci if !field.attrs.flatten() { 1197e2e9c0cSopenharmony_ci return; 1207e2e9c0cSopenharmony_ci } 1217e2e9c0cSopenharmony_ci match style { 1227e2e9c0cSopenharmony_ci Style::Tuple => { 1237e2e9c0cSopenharmony_ci cx.error_spanned_by( 1247e2e9c0cSopenharmony_ci field.original, 1257e2e9c0cSopenharmony_ci "#[serde(flatten)] cannot be used on tuple structs", 1267e2e9c0cSopenharmony_ci ); 1277e2e9c0cSopenharmony_ci } 1287e2e9c0cSopenharmony_ci Style::Newtype => { 1297e2e9c0cSopenharmony_ci cx.error_spanned_by( 1307e2e9c0cSopenharmony_ci field.original, 1317e2e9c0cSopenharmony_ci "#[serde(flatten)] cannot be used on newtype structs", 1327e2e9c0cSopenharmony_ci ); 1337e2e9c0cSopenharmony_ci } 1347e2e9c0cSopenharmony_ci _ => {} 1357e2e9c0cSopenharmony_ci } 1367e2e9c0cSopenharmony_ci} 1377e2e9c0cSopenharmony_ci 1387e2e9c0cSopenharmony_ci// The `other` attribute must be used at most once and it must be the last 1397e2e9c0cSopenharmony_ci// variant of an enum. 1407e2e9c0cSopenharmony_ci// 1417e2e9c0cSopenharmony_ci// Inside a `variant_identifier` all variants must be unit variants. Inside a 1427e2e9c0cSopenharmony_ci// `field_identifier` all but possibly one variant must be unit variants. The 1437e2e9c0cSopenharmony_ci// last variant may be a newtype variant which is an implicit "other" case. 1447e2e9c0cSopenharmony_cifn check_identifier(cx: &Ctxt, cont: &Container) { 1457e2e9c0cSopenharmony_ci let variants = match &cont.data { 1467e2e9c0cSopenharmony_ci Data::Enum(variants) => variants, 1477e2e9c0cSopenharmony_ci Data::Struct(_, _) => return, 1487e2e9c0cSopenharmony_ci }; 1497e2e9c0cSopenharmony_ci 1507e2e9c0cSopenharmony_ci for (i, variant) in variants.iter().enumerate() { 1517e2e9c0cSopenharmony_ci match ( 1527e2e9c0cSopenharmony_ci variant.style, 1537e2e9c0cSopenharmony_ci cont.attrs.identifier(), 1547e2e9c0cSopenharmony_ci variant.attrs.other(), 1557e2e9c0cSopenharmony_ci cont.attrs.tag(), 1567e2e9c0cSopenharmony_ci ) { 1577e2e9c0cSopenharmony_ci // The `other` attribute may not be used in a variant_identifier. 1587e2e9c0cSopenharmony_ci (_, Identifier::Variant, true, _) => { 1597e2e9c0cSopenharmony_ci cx.error_spanned_by( 1607e2e9c0cSopenharmony_ci variant.original, 1617e2e9c0cSopenharmony_ci "#[serde(other)] may not be used on a variant identifier", 1627e2e9c0cSopenharmony_ci ); 1637e2e9c0cSopenharmony_ci } 1647e2e9c0cSopenharmony_ci 1657e2e9c0cSopenharmony_ci // Variant with `other` attribute cannot appear in untagged enum 1667e2e9c0cSopenharmony_ci (_, Identifier::No, true, &TagType::None) => { 1677e2e9c0cSopenharmony_ci cx.error_spanned_by( 1687e2e9c0cSopenharmony_ci variant.original, 1697e2e9c0cSopenharmony_ci "#[serde(other)] cannot appear on untagged enum", 1707e2e9c0cSopenharmony_ci ); 1717e2e9c0cSopenharmony_ci } 1727e2e9c0cSopenharmony_ci 1737e2e9c0cSopenharmony_ci // Variant with `other` attribute must be the last one. 1747e2e9c0cSopenharmony_ci (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => { 1757e2e9c0cSopenharmony_ci if i < variants.len() - 1 { 1767e2e9c0cSopenharmony_ci cx.error_spanned_by( 1777e2e9c0cSopenharmony_ci variant.original, 1787e2e9c0cSopenharmony_ci "#[serde(other)] must be on the last variant", 1797e2e9c0cSopenharmony_ci ); 1807e2e9c0cSopenharmony_ci } 1817e2e9c0cSopenharmony_ci } 1827e2e9c0cSopenharmony_ci 1837e2e9c0cSopenharmony_ci // Variant with `other` attribute must be a unit variant. 1847e2e9c0cSopenharmony_ci (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => { 1857e2e9c0cSopenharmony_ci cx.error_spanned_by( 1867e2e9c0cSopenharmony_ci variant.original, 1877e2e9c0cSopenharmony_ci "#[serde(other)] must be on a unit variant", 1887e2e9c0cSopenharmony_ci ); 1897e2e9c0cSopenharmony_ci } 1907e2e9c0cSopenharmony_ci 1917e2e9c0cSopenharmony_ci // Any sort of variant is allowed if this is not an identifier. 1927e2e9c0cSopenharmony_ci (_, Identifier::No, false, _) => {} 1937e2e9c0cSopenharmony_ci 1947e2e9c0cSopenharmony_ci // Unit variant without `other` attribute is always fine. 1957e2e9c0cSopenharmony_ci (Style::Unit, _, false, _) => {} 1967e2e9c0cSopenharmony_ci 1977e2e9c0cSopenharmony_ci // The last field is allowed to be a newtype catch-all. 1987e2e9c0cSopenharmony_ci (Style::Newtype, Identifier::Field, false, _) => { 1997e2e9c0cSopenharmony_ci if i < variants.len() - 1 { 2007e2e9c0cSopenharmony_ci cx.error_spanned_by( 2017e2e9c0cSopenharmony_ci variant.original, 2027e2e9c0cSopenharmony_ci format!("`{}` must be the last variant", variant.ident), 2037e2e9c0cSopenharmony_ci ); 2047e2e9c0cSopenharmony_ci } 2057e2e9c0cSopenharmony_ci } 2067e2e9c0cSopenharmony_ci 2077e2e9c0cSopenharmony_ci (_, Identifier::Field, false, _) => { 2087e2e9c0cSopenharmony_ci cx.error_spanned_by( 2097e2e9c0cSopenharmony_ci variant.original, 2107e2e9c0cSopenharmony_ci "#[serde(field_identifier)] may only contain unit variants", 2117e2e9c0cSopenharmony_ci ); 2127e2e9c0cSopenharmony_ci } 2137e2e9c0cSopenharmony_ci 2147e2e9c0cSopenharmony_ci (_, Identifier::Variant, false, _) => { 2157e2e9c0cSopenharmony_ci cx.error_spanned_by( 2167e2e9c0cSopenharmony_ci variant.original, 2177e2e9c0cSopenharmony_ci "#[serde(variant_identifier)] may only contain unit variants", 2187e2e9c0cSopenharmony_ci ); 2197e2e9c0cSopenharmony_ci } 2207e2e9c0cSopenharmony_ci } 2217e2e9c0cSopenharmony_ci } 2227e2e9c0cSopenharmony_ci} 2237e2e9c0cSopenharmony_ci 2247e2e9c0cSopenharmony_ci// Skip-(de)serializing attributes are not allowed on variants marked 2257e2e9c0cSopenharmony_ci// (de)serialize_with. 2267e2e9c0cSopenharmony_cifn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { 2277e2e9c0cSopenharmony_ci let variants = match &cont.data { 2287e2e9c0cSopenharmony_ci Data::Enum(variants) => variants, 2297e2e9c0cSopenharmony_ci Data::Struct(_, _) => return, 2307e2e9c0cSopenharmony_ci }; 2317e2e9c0cSopenharmony_ci 2327e2e9c0cSopenharmony_ci for variant in variants { 2337e2e9c0cSopenharmony_ci if variant.attrs.serialize_with().is_some() { 2347e2e9c0cSopenharmony_ci if variant.attrs.skip_serializing() { 2357e2e9c0cSopenharmony_ci cx.error_spanned_by( 2367e2e9c0cSopenharmony_ci variant.original, 2377e2e9c0cSopenharmony_ci format!( 2387e2e9c0cSopenharmony_ci "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]", 2397e2e9c0cSopenharmony_ci variant.ident 2407e2e9c0cSopenharmony_ci ), 2417e2e9c0cSopenharmony_ci ); 2427e2e9c0cSopenharmony_ci } 2437e2e9c0cSopenharmony_ci 2447e2e9c0cSopenharmony_ci for field in &variant.fields { 2457e2e9c0cSopenharmony_ci let member = member_message(&field.member); 2467e2e9c0cSopenharmony_ci 2477e2e9c0cSopenharmony_ci if field.attrs.skip_serializing() { 2487e2e9c0cSopenharmony_ci cx.error_spanned_by( 2497e2e9c0cSopenharmony_ci variant.original, 2507e2e9c0cSopenharmony_ci format!( 2517e2e9c0cSopenharmony_ci "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]", 2527e2e9c0cSopenharmony_ci variant.ident, member 2537e2e9c0cSopenharmony_ci ), 2547e2e9c0cSopenharmony_ci ); 2557e2e9c0cSopenharmony_ci } 2567e2e9c0cSopenharmony_ci 2577e2e9c0cSopenharmony_ci if field.attrs.skip_serializing_if().is_some() { 2587e2e9c0cSopenharmony_ci cx.error_spanned_by( 2597e2e9c0cSopenharmony_ci variant.original, 2607e2e9c0cSopenharmony_ci format!( 2617e2e9c0cSopenharmony_ci "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]", 2627e2e9c0cSopenharmony_ci variant.ident, member 2637e2e9c0cSopenharmony_ci ), 2647e2e9c0cSopenharmony_ci ); 2657e2e9c0cSopenharmony_ci } 2667e2e9c0cSopenharmony_ci } 2677e2e9c0cSopenharmony_ci } 2687e2e9c0cSopenharmony_ci 2697e2e9c0cSopenharmony_ci if variant.attrs.deserialize_with().is_some() { 2707e2e9c0cSopenharmony_ci if variant.attrs.skip_deserializing() { 2717e2e9c0cSopenharmony_ci cx.error_spanned_by( 2727e2e9c0cSopenharmony_ci variant.original, 2737e2e9c0cSopenharmony_ci format!( 2747e2e9c0cSopenharmony_ci "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]", 2757e2e9c0cSopenharmony_ci variant.ident 2767e2e9c0cSopenharmony_ci ), 2777e2e9c0cSopenharmony_ci ); 2787e2e9c0cSopenharmony_ci } 2797e2e9c0cSopenharmony_ci 2807e2e9c0cSopenharmony_ci for field in &variant.fields { 2817e2e9c0cSopenharmony_ci if field.attrs.skip_deserializing() { 2827e2e9c0cSopenharmony_ci let member = member_message(&field.member); 2837e2e9c0cSopenharmony_ci 2847e2e9c0cSopenharmony_ci cx.error_spanned_by( 2857e2e9c0cSopenharmony_ci variant.original, 2867e2e9c0cSopenharmony_ci format!( 2877e2e9c0cSopenharmony_ci "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]", 2887e2e9c0cSopenharmony_ci variant.ident, member 2897e2e9c0cSopenharmony_ci ), 2907e2e9c0cSopenharmony_ci ); 2917e2e9c0cSopenharmony_ci } 2927e2e9c0cSopenharmony_ci } 2937e2e9c0cSopenharmony_ci } 2947e2e9c0cSopenharmony_ci } 2957e2e9c0cSopenharmony_ci} 2967e2e9c0cSopenharmony_ci 2977e2e9c0cSopenharmony_ci// The tag of an internally-tagged struct variant must not be the same as either 2987e2e9c0cSopenharmony_ci// one of its fields, as this would result in duplicate keys in the serialized 2997e2e9c0cSopenharmony_ci// output and/or ambiguity in the to-be-deserialized input. 3007e2e9c0cSopenharmony_cifn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { 3017e2e9c0cSopenharmony_ci let variants = match &cont.data { 3027e2e9c0cSopenharmony_ci Data::Enum(variants) => variants, 3037e2e9c0cSopenharmony_ci Data::Struct(_, _) => return, 3047e2e9c0cSopenharmony_ci }; 3057e2e9c0cSopenharmony_ci 3067e2e9c0cSopenharmony_ci let tag = match cont.attrs.tag() { 3077e2e9c0cSopenharmony_ci TagType::Internal { tag } => tag.as_str(), 3087e2e9c0cSopenharmony_ci TagType::External | TagType::Adjacent { .. } | TagType::None => return, 3097e2e9c0cSopenharmony_ci }; 3107e2e9c0cSopenharmony_ci 3117e2e9c0cSopenharmony_ci let diagnose_conflict = || { 3127e2e9c0cSopenharmony_ci cx.error_spanned_by( 3137e2e9c0cSopenharmony_ci cont.original, 3147e2e9c0cSopenharmony_ci format!("variant field name `{}` conflicts with internal tag", tag), 3157e2e9c0cSopenharmony_ci ); 3167e2e9c0cSopenharmony_ci }; 3177e2e9c0cSopenharmony_ci 3187e2e9c0cSopenharmony_ci for variant in variants { 3197e2e9c0cSopenharmony_ci match variant.style { 3207e2e9c0cSopenharmony_ci Style::Struct => { 3217e2e9c0cSopenharmony_ci if variant.attrs.untagged() { 3227e2e9c0cSopenharmony_ci continue; 3237e2e9c0cSopenharmony_ci } 3247e2e9c0cSopenharmony_ci for field in &variant.fields { 3257e2e9c0cSopenharmony_ci let check_ser = 3267e2e9c0cSopenharmony_ci !(field.attrs.skip_serializing() || variant.attrs.skip_serializing()); 3277e2e9c0cSopenharmony_ci let check_de = 3287e2e9c0cSopenharmony_ci !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing()); 3297e2e9c0cSopenharmony_ci let name = field.attrs.name(); 3307e2e9c0cSopenharmony_ci let ser_name = name.serialize_name(); 3317e2e9c0cSopenharmony_ci 3327e2e9c0cSopenharmony_ci if check_ser && ser_name == tag { 3337e2e9c0cSopenharmony_ci diagnose_conflict(); 3347e2e9c0cSopenharmony_ci return; 3357e2e9c0cSopenharmony_ci } 3367e2e9c0cSopenharmony_ci 3377e2e9c0cSopenharmony_ci for de_name in field.attrs.aliases() { 3387e2e9c0cSopenharmony_ci if check_de && de_name == tag { 3397e2e9c0cSopenharmony_ci diagnose_conflict(); 3407e2e9c0cSopenharmony_ci return; 3417e2e9c0cSopenharmony_ci } 3427e2e9c0cSopenharmony_ci } 3437e2e9c0cSopenharmony_ci } 3447e2e9c0cSopenharmony_ci } 3457e2e9c0cSopenharmony_ci Style::Unit | Style::Newtype | Style::Tuple => {} 3467e2e9c0cSopenharmony_ci } 3477e2e9c0cSopenharmony_ci } 3487e2e9c0cSopenharmony_ci} 3497e2e9c0cSopenharmony_ci 3507e2e9c0cSopenharmony_ci// In the case of adjacently-tagged enums, the type and the contents tag must 3517e2e9c0cSopenharmony_ci// differ, for the same reason. 3527e2e9c0cSopenharmony_cifn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { 3537e2e9c0cSopenharmony_ci let (type_tag, content_tag) = match cont.attrs.tag() { 3547e2e9c0cSopenharmony_ci TagType::Adjacent { tag, content } => (tag, content), 3557e2e9c0cSopenharmony_ci TagType::Internal { .. } | TagType::External | TagType::None => return, 3567e2e9c0cSopenharmony_ci }; 3577e2e9c0cSopenharmony_ci 3587e2e9c0cSopenharmony_ci if type_tag == content_tag { 3597e2e9c0cSopenharmony_ci cx.error_spanned_by( 3607e2e9c0cSopenharmony_ci cont.original, 3617e2e9c0cSopenharmony_ci format!( 3627e2e9c0cSopenharmony_ci "enum tags `{}` for type and content conflict with each other", 3637e2e9c0cSopenharmony_ci type_tag 3647e2e9c0cSopenharmony_ci ), 3657e2e9c0cSopenharmony_ci ); 3667e2e9c0cSopenharmony_ci } 3677e2e9c0cSopenharmony_ci} 3687e2e9c0cSopenharmony_ci 3697e2e9c0cSopenharmony_ci// Enums and unit structs cannot be transparent. 3707e2e9c0cSopenharmony_cifn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { 3717e2e9c0cSopenharmony_ci if !cont.attrs.transparent() { 3727e2e9c0cSopenharmony_ci return; 3737e2e9c0cSopenharmony_ci } 3747e2e9c0cSopenharmony_ci 3757e2e9c0cSopenharmony_ci if cont.attrs.type_from().is_some() { 3767e2e9c0cSopenharmony_ci cx.error_spanned_by( 3777e2e9c0cSopenharmony_ci cont.original, 3787e2e9c0cSopenharmony_ci "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", 3797e2e9c0cSopenharmony_ci ); 3807e2e9c0cSopenharmony_ci } 3817e2e9c0cSopenharmony_ci 3827e2e9c0cSopenharmony_ci if cont.attrs.type_try_from().is_some() { 3837e2e9c0cSopenharmony_ci cx.error_spanned_by( 3847e2e9c0cSopenharmony_ci cont.original, 3857e2e9c0cSopenharmony_ci "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]", 3867e2e9c0cSopenharmony_ci ); 3877e2e9c0cSopenharmony_ci } 3887e2e9c0cSopenharmony_ci 3897e2e9c0cSopenharmony_ci if cont.attrs.type_into().is_some() { 3907e2e9c0cSopenharmony_ci cx.error_spanned_by( 3917e2e9c0cSopenharmony_ci cont.original, 3927e2e9c0cSopenharmony_ci "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", 3937e2e9c0cSopenharmony_ci ); 3947e2e9c0cSopenharmony_ci } 3957e2e9c0cSopenharmony_ci 3967e2e9c0cSopenharmony_ci let fields = match &mut cont.data { 3977e2e9c0cSopenharmony_ci Data::Enum(_) => { 3987e2e9c0cSopenharmony_ci cx.error_spanned_by( 3997e2e9c0cSopenharmony_ci cont.original, 4007e2e9c0cSopenharmony_ci "#[serde(transparent)] is not allowed on an enum", 4017e2e9c0cSopenharmony_ci ); 4027e2e9c0cSopenharmony_ci return; 4037e2e9c0cSopenharmony_ci } 4047e2e9c0cSopenharmony_ci Data::Struct(Style::Unit, _) => { 4057e2e9c0cSopenharmony_ci cx.error_spanned_by( 4067e2e9c0cSopenharmony_ci cont.original, 4077e2e9c0cSopenharmony_ci "#[serde(transparent)] is not allowed on a unit struct", 4087e2e9c0cSopenharmony_ci ); 4097e2e9c0cSopenharmony_ci return; 4107e2e9c0cSopenharmony_ci } 4117e2e9c0cSopenharmony_ci Data::Struct(_, fields) => fields, 4127e2e9c0cSopenharmony_ci }; 4137e2e9c0cSopenharmony_ci 4147e2e9c0cSopenharmony_ci let mut transparent_field = None; 4157e2e9c0cSopenharmony_ci 4167e2e9c0cSopenharmony_ci for field in fields { 4177e2e9c0cSopenharmony_ci if allow_transparent(field, derive) { 4187e2e9c0cSopenharmony_ci if transparent_field.is_some() { 4197e2e9c0cSopenharmony_ci cx.error_spanned_by( 4207e2e9c0cSopenharmony_ci cont.original, 4217e2e9c0cSopenharmony_ci "#[serde(transparent)] requires struct to have at most one transparent field", 4227e2e9c0cSopenharmony_ci ); 4237e2e9c0cSopenharmony_ci return; 4247e2e9c0cSopenharmony_ci } 4257e2e9c0cSopenharmony_ci transparent_field = Some(field); 4267e2e9c0cSopenharmony_ci } 4277e2e9c0cSopenharmony_ci } 4287e2e9c0cSopenharmony_ci 4297e2e9c0cSopenharmony_ci match transparent_field { 4307e2e9c0cSopenharmony_ci Some(transparent_field) => transparent_field.attrs.mark_transparent(), 4317e2e9c0cSopenharmony_ci None => match derive { 4327e2e9c0cSopenharmony_ci Derive::Serialize => { 4337e2e9c0cSopenharmony_ci cx.error_spanned_by( 4347e2e9c0cSopenharmony_ci cont.original, 4357e2e9c0cSopenharmony_ci "#[serde(transparent)] requires at least one field that is not skipped", 4367e2e9c0cSopenharmony_ci ); 4377e2e9c0cSopenharmony_ci } 4387e2e9c0cSopenharmony_ci Derive::Deserialize => { 4397e2e9c0cSopenharmony_ci cx.error_spanned_by( 4407e2e9c0cSopenharmony_ci cont.original, 4417e2e9c0cSopenharmony_ci "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", 4427e2e9c0cSopenharmony_ci ); 4437e2e9c0cSopenharmony_ci } 4447e2e9c0cSopenharmony_ci }, 4457e2e9c0cSopenharmony_ci } 4467e2e9c0cSopenharmony_ci} 4477e2e9c0cSopenharmony_ci 4487e2e9c0cSopenharmony_cifn member_message(member: &Member) -> String { 4497e2e9c0cSopenharmony_ci match member { 4507e2e9c0cSopenharmony_ci Member::Named(ident) => format!("`{}`", ident), 4517e2e9c0cSopenharmony_ci Member::Unnamed(i) => format!("#{}", i.index), 4527e2e9c0cSopenharmony_ci } 4537e2e9c0cSopenharmony_ci} 4547e2e9c0cSopenharmony_ci 4557e2e9c0cSopenharmony_cifn allow_transparent(field: &Field, derive: Derive) -> bool { 4567e2e9c0cSopenharmony_ci if let Type::Path(ty) = ungroup(field.ty) { 4577e2e9c0cSopenharmony_ci if let Some(seg) = ty.path.segments.last() { 4587e2e9c0cSopenharmony_ci if seg.ident == "PhantomData" { 4597e2e9c0cSopenharmony_ci return false; 4607e2e9c0cSopenharmony_ci } 4617e2e9c0cSopenharmony_ci } 4627e2e9c0cSopenharmony_ci } 4637e2e9c0cSopenharmony_ci 4647e2e9c0cSopenharmony_ci match derive { 4657e2e9c0cSopenharmony_ci Derive::Serialize => !field.attrs.skip_serializing(), 4667e2e9c0cSopenharmony_ci Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), 4677e2e9c0cSopenharmony_ci } 4687e2e9c0cSopenharmony_ci} 4697e2e9c0cSopenharmony_ci 4707e2e9c0cSopenharmony_cifn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) { 4717e2e9c0cSopenharmony_ci if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() { 4727e2e9c0cSopenharmony_ci cx.error_spanned_by( 4737e2e9c0cSopenharmony_ci cont.original, 4747e2e9c0cSopenharmony_ci "#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other", 4757e2e9c0cSopenharmony_ci ); 4767e2e9c0cSopenharmony_ci } 4777e2e9c0cSopenharmony_ci} 478