For structs, it works perfectly. But for C-like enums, I'm wondering how to get the enum value ? The serialize_unit_variant method is only passing the enum name, index and variant name. Not its value.
serialize_unit_variant is for serialising enum variants without values. If a variant has values then you want serialize_struct_variant or serialize_tuple_variant, depending on whether the values are named.
C-like enums don't normally store values though. If you mean you want to serialise the value the enum variant corresponds to rather than storing it by name, then you probably want to serialise an integer instead and do the conversion in the Serialize implementation. You could also vary it based on the result of is_human_readable if you want to support both text and integers.
Now, I think its time to come back to serde to do this.
You're right, I want the value of the enum variant. I have access to the name but not the value. The methods you're referring to seem dedicated to what their name hints toward, not unit variants.
I actually made it work for a single C-like enum with a trick but defining a trait which gives the C-like enum value.
pub trait Extract {
fn extract(&self) -> u64;
}
#[derive(Debug, Serialize, Clone, Copy)]
#[repr(u16)]
enum Color {
Red = 0xFF,
Green = 9 * 3,
Blue = 9 * 4,
}
impl Extract for Color {
fn extract(&self) -> u64 {
return *self as u64;
}
}
#[derive(Debug)]
pub struct MySerializer {
// length of data being serialized
length: usize,
// resulting buffer where data are copied
buffer: Vec<u8>,
size: usize,
extracted: u64,
}
pub fn to_network<T: Extract>(value: &T) -> Result<Vec<u8>>
where
T: Serialize,
{
//println!("value of T: {:?}", value);
let extracted = value.extract();
let mut serializer = MySerializer {
length: 0,
buffer: Vec::new(),
size: std::mem::size_of::<T>(),
extracted: extracted,
};
value.serialize(&mut serializer)?;
Ok(serializer.buffer)
}
...
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<usize> {
println!(
"serializing enum named: {}, variant named: {}, variant index: {}",
_name, variant, _variant_index
);
match self.size {
// enum was repr(u8)
1 => self.serialize_u8(self.extracted as u8),
// enum was repr(u16)
2 => self.serialize_u16(self.extracted as u16),
// enum was repr(u32)
4 => self.serialize_u32(self.extracted as u32),
// enum was repr(u64)
8 => self.serialize_u64(self.extracted),
_ => unimplemented!("value {} is not implemented", self.size ),
}
// self.serialize_str(variant)
}
...
This way it works. But whenever the enum is inside a struct, it doesn't.
Serde only gives serializers two options for[1] enum variants: name or index. That's hardcoded into the serde data model. If you want it to serialize as an integer, you need to change the enum's implementation of Serialize. You can use serde_repr for this.
#[derive(Debug, Serialize_repr, Clone, Copy)]
#[repr(u16)]
enum Color {
Red = 0xFF,
Green = 9 * 3,
Blue = 9 * 4,
}