{"args":{"content":"# How does serde::Deserializer::deserialize_enum handle different enum representations during deserialization?\n\n**deserialize_enum is a specialized method on the Deserializer trait that handles enum deserialization by accepting a visitor that can process variant names and their associated data through the EnumAccess and VariantAccess traits.** This method enables serializers to represent enums in format-appropriate ways while allowing deserializers to interpret those representations uniformly.\n\n## The Enum Deserialization Interface\n\nrust\nuse serde::de::{Deserializer, EnumAccess, VariantAccess, Visitor};\n\n// The Deserializer trait method:\ntrait Deserializer<'de> {\n type Error;\n \n fn deserialize_enum<V>(\n self,\n name: &'static str,\n variants: &'static [&'static str],\n visitor: V,\n ) -> Result<V::Value, Self::Error>\n where\n V: Visitor<'de>;\n}\n\n// The EnumAccess trait provides variant access:\ntrait EnumAccess<'de> {\n type Error;\n type Variant: VariantAccess<'de>;\n \n fn variant_seed<S>(self, seed: S) -> Result<(S::Value, Self::Variant), Self::Error>\n where\n S: DeserializeSeed<'de>;\n}\n\n// The VariantAccess trait provides variant data access:\ntrait VariantAccess<'de> {\n type Error;\n \n fn unit_variant(self) -> Result<(), Self::Error>;\n \n fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>\n where\n T: DeserializeSeed<'de>;\n \n fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>\n where\n V: Visitor<'de>;\n \n fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error>\n where\n V: Visitor<'de>;\n}\n\n\nThe three-layer design separates format handling from data interpretation.\n\n## Basic Enum Deserialization\n\nrust\nuse serde::de::{Deserialize, Deserializer, EnumAccess, VariantAccess, Visitor};\nuse std::fmt;\n\n// A simple enum with different variant types\n#[derive(Debug)]\nenum Status {\n Active, // Unit variant\n Pending(String), // Newtype variant\n Failed { code: u32, message: String }, // Struct variant\n}\n\nimpl<'de> Deserialize<'de> for Status {\n fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n where D: Deserializer<'de>\n {\n // Name and variant names help deserializers with format-specific encoding\n deserializer.deserialize_enum(\n \"Status\", // Type name\n &[\n \"Active\",\n \"Pending\",\n \"Failed\",\n ],\n StatusVisitor,\n )\n }\n}\n\nstruct StatusVisitor;\n\nimpl<'de> Visitor<'de> for StatusVisitor {\n type Value = Status;\n \n fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"enum Status\")\n }\n \n fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>\n where A: EnumAccess<'de>\n {\n // Get the variant name and access to its data\n let (variant, variant_access) = data.variant()?;\n \n match variant {\n StatusVariant::Active => {\n // Unit variant - no data\n variant_access.unit_variant()?;\n Ok(Status::Active)\n }\n StatusVariant::Pending => {\n // Newtype variant - single field\n let value = variant_access.newtype_variant()?;\n Ok(Status::Pending(value))\n }\n StatusVariant::Failed => {\n // Struct variant - named fields\n let (code, message) = variant_access.struct_variant(\n &[\"code\", \"message\"],\n FailedFieldsVisitor,\n )?;\n Ok(Status::Failed { code, message })\n }\n }\n }\n}\n\n\nThe visitor receives variant access through the EnumAccess trait.\n\n## Variant Identification\n\nrust\nuse serde::de::{Deserialize, VariantAccess};\nuse std::fmt;\n\n// Variants can be identified by index or name\n#[derive(Debug, Clone, Copy)]\nenum StatusVariant {\n Active,\n Pending,\n Failed,\n}\n\nimpl<'de> Deserialize<'de> for StatusVariant {\n fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n where D: Deserializer<'de>\n {\n // Deserialize as variant identifier\n struct VariantVisitor;\n \n impl<'de> Visitor<'de> for VariantVisitor {\n type Value = StatusVariant;\n \n fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"variant identifier\")\n }\n \n fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>\n where E: serde::de::Error\n {\n match v {\n 0 => Ok(StatusVariant::Active),\n 1 => Ok(StatusVariant::Pending),\n 2 => Ok(StatusVariant::Failed),\n _ => Err(E::custom(format!(\"unknown variant index {}\", v))),\n }\n }\n \n fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n where E: serde::de::Error\n {\n match v {\n \"Active\" => Ok(StatusVariant::Active),\n \"Pending\" => Ok(StatusVariant::Pending),\n \"Failed\" => Ok(StatusVariant::Failed),\n _ => Err(E::custom(format!(\"unknown variant {}\", v))),\n }\n }\n }\n \n deserializer.deserialize_identifier(VariantVisitor)\n }\n}\n\n\nFormats can use either variant names or indices to identify variants.\n\n## Unit Variant Handling\n\nrust\nuse serde::de::{EnumAccess, VariantAccess, Visitor};\n\n// Unit variants have no associated data\nimpl<'de> Visitor<'de> for UnitEnumVisitor {\n type Value = Color;\n \n fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>\n where A: EnumAccess<'de>\n {\n let (variant, access) = data.variant()?;\n \n match variant {\n ColorVariant::Red => {\n // Call unit_variant to consume the variant data (nothing)\n access.unit_variant()?;\n Ok(Color::Red)\n }\n ColorVariant::Green => {\n access.unit_variant()?;\n Ok(Color::Green)\n }\n ColorVariant::Blue => {\n access.unit_variant()?;\n Ok(Color::Blue)\n }\n }\n }\n}\n\n#[derive(Debug)]\nenum Color {\n Red,\n Green,\n Blue,\n}\n\n\nunit_variant must be called even for variants with no data.\n\n## Newtype Variant Handling\n\nrust\nuse serde::de::{EnumAccess, VariantAccess, Visitor};\n\n// Newtype variants wrap a single value\nimpl<'de> Visitor<'de> for NewtypeEnumVisitor {\n type Value = Result<i32, String>;\n \n fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>\n where A: EnumAccess<'de>\n {\n let (variant, access) = data.variant()?;\n \n match variant {\n ResultVariant::Ok => {\n // newtype_variant deserializes the inner value\n let value = access.newtype_variant()?;\n Ok(Result::Ok(value))\n }\n ResultVariant::Err => {\n let error = access.newtype_variant()?;\n Ok(Result::Err(error))\n }\n }\n }\n}\n\n// Same enum, different representation:\n#[derive(Debug)]\nenum Result<T, E> {\n Ok(T), // Newtype variant\n Err(E), // Newtype variant\n}\n\n\nnewtype_variant deserializes the wrapped value directly.\n\n## Tuple Variant Handling\n\nrust\nuse serde::de::{EnumAccess, VariantAccess, Visitor};\nuse std::fmt;\n\n// Tuple variants have multiple unnamed fields\n#[derive(Debug)]\nenum Point3D {\n Origin,\n Coordinate(f64, f64, f64), // Tuple variant\n}\n\nimpl<'de> Visitor<'de> for Point3DVisitor {\n type Value = Point3D;\n \n fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>\n where A: EnumAccess<'de>\n {\n let (variant, access) = data.variant()?;\n \n match variant {\n Point3DVariant::Origin => {\n access.unit_variant()?;\n Ok(Point3D::Origin)\n }\n Point3DVariant::Coordinate => {\n // tuple_variant expects a visitor to receive the fields\n let (x, y, z) = access.tuple_variant(3, CoordinateVisitor)?;\n Ok(Point3D::Coordinate(x, y, z))\n }\n }\n }\n}\n\nstruct CoordinateVisitor;\n\nimpl<'de> Visitor<'de> for CoordinateVisitor {\n type Value = (f64, f64, f64);\n \n fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"3 f64 values\")\n }\n \n fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>\n where A: serde::de::SeqAccess<'de>\n {\n let x = seq.next_element()?.ok_or_else(|| serde::de::Error::missing_field(\"x\"))?;\n let y = seq.next_element()?.ok_or_else(|| serde::de::Error::missing_field(\"y\"))?;\n let z = seq.next_element()?.ok_or_else(|| serde::de::Error::missing_field(\"z\"))?;\n Ok((x, y, z))\n }\n}\n\n\nTuple variants use a visitor to receive sequential field access.\n\n## Struct Variant Handling\n\nrust\nuse serde::de::{EnumAccess, VariantAccess, Visitor};\nuse std::fmt;\n\n// Struct variants have named fields\n#[derive(Debug)]\nenum Message {\n Quit,\n Move { x: i32, y: i32 },\n Write(String),\n ChangeColor { r: u8, g: u8, b: u8 },\n}\n\nimpl<'de> Visitor<'de> for MessageVisitor {\n type Value = Message;\n \n fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>\n where A: EnumAccess<'de>\n {\n let (variant, access) = data.variant()?;\n \n match variant {\n MessageVariant::Quit => {\n access.unit_variant()?;\n Ok(Message::Quit)\n }\n MessageVariant::Move => {\n // struct_variant provides field-by-field access\n let (x, y) = access.struct_variant(\n &[\"x\", \"y\"],\n MoveFieldsVisitor,\n )?;\n Ok(Message::Move { x, y })\n }\n MessageVariant::Write => {\n let text = access.newtype_variant()?;\n Ok(Message::Write(text))\n }\n MessageVariant::ChangeColor => {\n let (r, g, b) = access.struct_variant(\n &[\"r\", \"g\", \"b\"],\n ColorFieldsVisitor,\n )?;\n Ok(Message::ChangeColor { r, g, b })\n }\n }\n }\n}\n\nstruct MoveFieldsVisitor;\n\nimpl<'de> Visitor<'de> for MoveFieldsVisitor {\n type Value = (i32, i32);\n \n fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"struct Move with fields x and y\")\n }\n \n fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>\n where A: serde::de::MapAccess<'de>\n {\n let mut x = None;\n let mut y = None;\n \n while let Some(key) = map.next_key()? {\n match key {\n \"x\" => x = Some(map.next_value()?),\n \"y\" => y = Some(map.next_value()?),\n _ => { let _ = map.next_value::<serde::de::IgnoredAny>()?; }\n }\n }\n \n let x = x.ok_or_else(|| serde::de::Error::missing_field(\"x\"))?;\n let y = y.ok_or_else(|| serde::de::Error::missing_field(\"y\"))?;\n Ok((x, y))\n }\n}\n\n\nStruct variants use map-like access for named fields.\n\n## JSON Enum Representations\n\nrust\nuse serde_json;\nuse serde::{Deserialize, Serialize};\n\n// Externally tagged (serde default):\n// {\"Move\": {\"x\": 10, \"y\": 20}}\n// {\"Quit\": null}\n#[derive(Serialize, Deserialize)]\nenum External {\n Quit,\n Move { x: i32, y: i32 },\n Write(String),\n}\n\n// Internally tagged:\n// {\"type\": \"Move\", \"x\": 10, \"y\": 20}\n#[derive(Serialize, Deserialize)]\n#[serde(tag = \"type\")]\nenum Internal {\n Quit,\n Move { x: i32, y: i32 },\n Write(String),\n}\n\n// Adjacently tagged:\n// {\"t\": \"Move\", \"c\": {\"x\": 10, \"y\": 20}}\n#[derive(Serialize, Deserialize)]\n#[serde(tag = \"t\", content = \"c\")]\nenum Adjacent {\n Quit,\n Move { x: i32, y: i32 },\n Write(String),\n}\n\n// Untagged:\n// Just the content directly - no variant tag\n// {\"x\": 10, \"y\": 20} // Move\n// \"hello\" // Write\n#[derive(Serialize, Deserialize)]\n#[serde(untagged)]\nenum Untagged {\n Quit,\n Move { x: i32, y: i32 },\n Write(String),\n}\n\n\nSerene supports multiple enum representations via attributes.\n\n## Binary Format Enum Handling\n\nrust\nuse serde::de::{Deserializer, EnumAccess, VariantAccess, Visitor};\nuse std::fmt;\n\n// Binary formats often use indices instead of names\n// Variant index followed by variant data\n// [0] for Quit\n// [1, x_low, x_high, y_low, y_high] for Move\n// [2, len, ...bytes] for Write\n\n// Binary deserializer implementation:\nimpl<'de> Deserializer<'de> for BinaryDeserializer<'de> {\n fn deserialize_enum<V>(\n self,\n name: &'static str,\n variants: &'static [&'static str],\n visitor: V,\n ) -> Result<V::Value, Self::Error>\n where V: Visitor<'de>\n {\n // Read variant index\n let index = self.read_u32()?;\n \n // Create variant access\n visitor.visit_enum(BinaryEnumAccess {\ index,\n variants,\n deserializer: self,\n })\n }\n}\n\nstruct BinaryEnumAccess<'de, 'a> {\n index: u32,\n variants: &'static [&'static str],\n deserializer: &'a mut BinaryDeserializer<'de>,\n}\n\nimpl<'de> EnumAccess<'de> for BinaryEnumAccess<'_, '_> {\n type Error = BinaryError;\n type Variant = Self;\n \n fn variant_seed<S>(self, seed: S) -> Result<(S::Value, Self::Variant), Self::Error>\n where S: serde::de::DeserializeSeed<'de>\n {\n // Deserialize variant index as identifier\n let variant_name = self.variants.get(self.index as usize)\n .ok_or_else(|| BinaryError::InvalidVariant(self.index))?;\n \n let variant = seed.deserialize(VariantIdDeserializer(self.index, *variant_name))?;\n Ok((variant, self))\n }\n}\n\nimpl<'de> VariantAccess<'de> for BinaryEnumAccess<'_, '_> {\n type Error = BinaryError;\n \n fn unit_variant(self) -> Result<(), Self::Error> {\n // No data for unit variants\n Ok(())\n }\n \n fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>\n where T: serde::de::DeserializeSeed<'de>\n {\n // Read the single value\n seed.deserialize(&mut *self.deserializer)\n }\n \n fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>\n where V: Visitor<'de>\n {\n // Read len elements\n visitor.visit_seq(BinarySeqAccess {\n len,\n deserializer: self.deserializer,\n })\n }\n \n fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error>\n where V: Visitor<'de>\n {\n // Binary format may encode struct as sequence\n visitor.visit_seq(BinarySeqAccess {\n len: _fields.len(),\n deserializer: self.deserializer,\n })\n }\n}\n\n\nBinary formats use indices for efficiency, name information optional.\n\n## The variant_seed Method\n\nrust\nuse serde::de::{DeserializeSeed, EnumAccess, VariantAccess};\n\n// variant_seed allows custom variant deserialization\nimpl<'de> EnumAccess<'de> for MyEnumAccess<'de> {\n type Error = MyError;\n type Variant = MyVariantAccess<'de>;\n \n fn variant_seed<S>(self, seed: S) -> Result<(S::Value, Self::Variant), Self::Error>\n where S: DeserializeSeed<'de>\n {\n // seed can provide context for variant interpretation\n let variant_id = self.read_variant_identifier()?;\n let variant = seed.deserialize(VariantIdDeserializer(variant_id))?;\n Ok((variant, MyVariantAccess { /* ... */ }))\n }\n}\n\n// Convenience method that uses Deserialize:\nfn variant<V>(self) -> Result<(V, Self::Variant), Self::Error>\nwhere V: Deserialize<'de>\n{\n self.variant_seed(serde::de::IntoDeserializer::into_deserializer)\n}\n\n// The variant method is implemented using variant_seed with identity seed\n\n\nvariant_seed enables context-aware variant identification.\n\n## EnumAccess and VariantAccess Interaction\n\nrust\nuse serde::de::{EnumAccess, VariantAccess};\n\n// The two-stage access pattern:\n// 1. EnumAccess.variant() returns (Variant, VariantAccess)\n// 2. VariantAccess methods consume variant data\n\n// Flow for externally tagged enum:\n// JSON: {\"Move\": {\"x\": 10, \"y\": 20}}\n// 1. EnumAccess sees object with one key \"Move\"\n// 2. variant() returns (Move, VariantAccess)\n// 3. VariantAccess.struct_variant provides {\"x\": 10, \"y\": 20}\n\n// Flow for internally tagged enum:\n// JSON: {\"type\": \"Move\", \"x\": 10, \"y\": 20}\n// 1. EnumAccess sees object with \"type\" field\n// 2. variant() returns (Move, VariantAccess pointing to remaining fields)\n// 3. VariantAccess.struct_variant provides {\"x\": 10, \"y\": 20}\n\n// Flow for adjacently tagged enum:\n// JSON: {\"t\": \"Move\", \"c\": {\"x\": 10, \"y\": 20}}\n// 1. EnumAccess reads \"t\" field\n// 2. variant() returns (Move, VariantAccess pointing to \"c\" value)\n// 3. VariantAccess.struct_variant provides {\"x\": 10, \"y\": 20}\n\n\nThe separation allows different enum representations with same visitor code.\n\n## Implementing a Custom Enum Visitor\n\nrust\nuse serde::de::{Deserialize, Deserializer, EnumAccess, VariantAccess, Visitor};\nuse std::fmt;\n\n// Custom visitor with error handling\n#[derive(Debug)]\nenum Command {\n Create { name: String },\n Delete { id: u64 },\n List,\n}\n\nimpl<'de> Deserialize<'de> for Command {\n fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n where D: Deserializer<'de>\n {\n deserializer.deserialize_enum(\n \"Command\",\n &[\"Create\", \"Delete\", \"List\"],\n CommandVisitor,\n )\n }\n}\n\nstruct CommandVisitor;\n\nimpl<'de> Visitor<'de> for CommandVisitor {\n type Value = Command;\n \n fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"enum Command\")\n }\n \n fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>\n where A: EnumAccess<'de>\n {\n let (variant, access) = data.variant()?;\n \n match variant {\n CommandVariant::Create => {\n let name = access.struct_variant(\n &[\"name\"],\n CreateFieldsVisitor,\n )?;\n Ok(Command::Create { name })\n }\n CommandVariant::Delete => {\n let id = access.struct_variant(\n &[\"id\"],\n DeleteFieldsVisitor,\n )?;\n Ok(Command::Delete { id })\n }\n CommandVariant::List => {\n access.unit_variant()?;\n Ok(Command::List)\n }\n CommandVariant::__Unknown => {\n Err(serde::de::Error::unknown_variant(\"unknown variant\", &[\"Create\", \"Delete\", \"List\"]))\n }\n }\n }\n}\n\nstruct CreateFieldsVisitor;\n\nimpl<'de> Visitor<'de> for CreateFieldsVisitor {\n type Value = String;\n \n fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"struct Create with field name\")\n }\n \n fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>\n where A: serde::de::MapAccess<'de>\n {\n let mut name = None;\n \n while let Some(key) = map.next_key()? {\n match key {\n \"name\" => name = Some(map.next_value()?),\n _ => { let _ = map.next_value::<serde::de::IgnoredAny>()?; }\n }\n }\n \n name.ok_or_else(|| serde::de::Error::missing_field(\"name\"))\n }\n}\n\n\nComplete visitor implementation handles all variant types with proper error handling.\n\n## Summary Comparison\n\nrust\nfn comparison_table() {\n // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n // β Variant Type β VariantAccess Method β Parameters β\n // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€\n // β Unit β unit_variant() β None β\n // β Newtype β newtype_variant() β None (returns inner value) β\n // β Tuple β tuple_variant() β len, visitor β\n // β Struct β struct_variant() β field names, visitor β\n // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n \n // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n // β Representation β JSON Example β Attribute β\n // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€\n // β External β {\"Variant\": data} β (default) β\n // β Internal β {\"type\": \"Variant\", ...data} β #[serde(tag)]β\n // β Adjacent β {\"t\": \"Variant\", \"c\": data} β tag + contentβ\n // β Untagged β data β untagged β\n // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n}\n\n\n## Key Points\n\nrust\nfn key_points() {\n // 1. deserialize_enum accepts type name and variant names for format hints\n // 2. EnumAccess provides variant identification via variant() method\n // 3. VariantAccess provides data access based on variant type\n // 4. unit_variant for variants with no data\n // 5. newtype_variant for single-field variants\n // 6. tuple_variant for multi-field unnamed variants\n // 7. struct_variant for named-field variants\n // 8. variant_seed enables context-aware variant identification\n // 9. Different formats use names or indices for variant identification\n // 10. JSON supports external, internal, adjacent, and untagged representations\n // 11. Binary formats typically use variant indices for efficiency\n // 12. Visitor's visit_enum receives EnumAccess and orchestrates variant handling\n // 13. The separation of EnumAccess and VariantAccess enables representation flexibility\n}\n\n\nKey insight: deserialize_enum orchestrates enum deserialization through a three-layer interface: the Deserializer calls deserialize_enum with type information, the visitor's visit_enum method receives EnumAccess to identify the variant, then uses VariantAccess methods to consume variant-specific data. This separation allows different serialization formats to represent enums differentlyβJSON uses string names, binary formats use indices, internally tagged formats embed the variant in a fieldβwhile the same visitor code handles all representations. The EnumAccess::variant() method bridges format-specific representation to semantic variant identification, and VariantAccess methods (unit_variant, newtype_variant, tuple_variant, struct_variant) handle the variant's data appropriately for each variant type.","path":"/articles/1865_how_does_serde_Deserializer_deserialize_enum_handle_different_enum_representations_during_deserialization.md"},"tool_call":"file.create"}
