Skip to content

Instantly share code, notes, and snippets.

@charmoniumQ
Created January 4, 2026 00:56
Show Gist options
  • Select an option

  • Save charmoniumQ/a4980e06fca3ee3a8ad9ae92a48c3c98 to your computer and use it in GitHub Desktop.

Select an option

Save charmoniumQ/a4980e06fca3ee3a8ad9ae92a48c3c98 to your computer and use it in GitHub Desktop.
Test serde deserialize with explicit discriminants
/*!
* This module tests whether it would be possible to use serde to deserialize an enum with explicit discriminants, e.g., `enum Test { A = 20 }`.
* I currently don't see a way to access the fact that 20 maps to `Test::A` from within Serde's datamodel.
*
* To test, start a new Rust project, `cargo add serde --features derive`, copy this file, and run `cargo test`.
*
* Also see <https://github.com/serde-rs/serde/issues/2763>
* */
use serde::{Deserialize, de::IntoDeserializer};
/**
* Test whether we can deserialize bytes into Test::A.
* It works if you delete the explicit dscriminant assignment (` = 20`) and fails otherwise with stdout:
*
* Error: Error("invalid value: integer `20`, expected variant index 0 <= i < 1")
* */
#[test]
fn test_int_enum() -> Result<(), Box<dyn std::error::Error>> {
#[derive(PartialEq, Eq, Debug, Clone, serde::Deserialize)]
enum Test {
A = 20,
}
let mut deserializer = MyDeserializer {
bytes: vec![Test::A as u64],
cursor: 0,
};
let parsed_value = Test::deserialize(&mut deserializer)?;
assert_eq!(parsed_value, Test::A);
Ok(())
}
/**
* An example that deserializes structured data from a buffer of integers.
* */
struct MyDeserializer {
bytes: Vec<u64>,
cursor: usize,
}
impl<'de> serde::Deserializer<'de> for &'de mut MyDeserializer {
type Error = serde::de::value::Error;
/**
* For the sake of minimality, none of the methods other than deserialize_enum are actually implemented.
* */
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
unimplemented!("any");
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_enum(self)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct identifier ignored_any
}
}
/**
* Proper style may dictate using a new struct that implements EnumAccess.
* But we can just reuse thes same MyDeserializer struct.
* */
impl<'de> serde::de::EnumAccess<'de> for &'de mut MyDeserializer {
type Error = serde::de::value::Error;
type Variant = &'de mut MyDeserializer;
fn variant_seed<V>(
self,
seed: V,
) -> Result<(<V as serde::de::DeserializeSeed<'de>>::Value, Self::Variant), Self::Error>
where
V: serde::de::DeserializeSeed<'de>,
{
let tag = self.bytes[self.cursor];
self.cursor += 1;
Ok((
seed.deserialize(tag.into_deserializer())?,
self,
))
}
}
impl<'de> serde::de::VariantAccess<'de> for &'de mut MyDeserializer {
type Error = serde::de::value::Error;
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T>(
self,
_seed: T,
) -> Result<<T as serde::de::DeserializeSeed<'de>>::Value, Self::Error>
where
T: serde::de::DeserializeSeed<'de>,
{
unimplemented!("newtype_variant_seed");
}
fn tuple_variant<V>(
self,
_len: usize,
_visitor: V,
) -> Result<<V as serde::de::Visitor<'de>>::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
unimplemented!("tuple_variant");
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<<V as serde::de::Visitor<'de>>::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
unimplemented!("struct_variant");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment