mirror of https://github.com/icedland/iced.git
Optimize bincode serialized data so it matches real instr struct size
This commit is contained in:
parent
3b495e2a5a
commit
bf77872c8b
|
@ -189,8 +189,9 @@ build_test_current_version() {
|
|||
cargo test --color always --release --features serde
|
||||
|
||||
# Make sure the two read-mem methods behave the same
|
||||
echo "==== TEST DEBUG: std decoder __internal_mem_vsib ===="
|
||||
cargo test --color always --no-default-features --features "std decoder __internal_mem_vsib" --tests
|
||||
# Also test serde code. It needs encoder to also test 'db x,y,z', see serde tests
|
||||
echo "==== TEST DEBUG: std decoder encoder serde __internal_flip ===="
|
||||
cargo test --color always --tests --no-default-features --features "std decoder encoder serde __internal_flip"
|
||||
|
||||
echo "==== TEST DEBUG ===="
|
||||
cargo test --color always --tests --features serde
|
||||
|
|
|
@ -37,7 +37,7 @@ no_xop = []
|
|||
no_d3now = []
|
||||
serde = ["serde_crate"]
|
||||
# Don't use
|
||||
__internal_mem_vsib = []
|
||||
__internal_flip = []
|
||||
|
||||
[dependencies]
|
||||
# if: always
|
||||
|
|
|
@ -28,7 +28,7 @@ use core::{cmp, fmt, mem, ptr, u32};
|
|||
use static_assertions::{const_assert, const_assert_eq};
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
static READ_OP_MEM_VSIB_FNS: [fn(&mut Decoder<'_>, &mut Instruction, Register, TupleType, bool) -> bool; 0x18] = [
|
||||
decoder_read_op_mem_vsib_0,
|
||||
decoder_read_op_mem_vsib_0,
|
||||
|
@ -541,9 +541,9 @@ where
|
|||
#[cfg(feature = "no_xop")]
|
||||
handlers_xop: [(); 3],
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
read_op_mem_fns: [fn(&mut Decoder<'a>, &mut Instruction) -> bool; 0x18],
|
||||
#[cfg(feature = "__internal_mem_vsib")]
|
||||
#[cfg(feature = "__internal_flip")]
|
||||
read_op_mem_fns: (),
|
||||
|
||||
state: State,
|
||||
|
@ -940,7 +940,7 @@ impl<'a> Decoder<'a> {
|
|||
mk_handlers_local!(handlers_xop_map10, "no_xop");
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
let read_op_mem_fns = [
|
||||
Decoder::read_op_mem_0,
|
||||
Decoder::read_op_mem_0,
|
||||
|
@ -969,7 +969,7 @@ impl<'a> Decoder<'a> {
|
|||
Decoder::read_op_mem_2,
|
||||
Decoder::read_op_mem_2,
|
||||
];
|
||||
#[cfg(feature = "__internal_mem_vsib")]
|
||||
#[cfg(feature = "__internal_flip")]
|
||||
let read_op_mem_fns = ();
|
||||
|
||||
Ok(Decoder {
|
||||
|
@ -1978,7 +1978,7 @@ impl<'a> Decoder<'a> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
#[cfg(feature = "__internal_mem_vsib")]
|
||||
#[cfg(feature = "__internal_flip")]
|
||||
fn read_op_mem_32_or_64(&mut self, instruction: &mut Instruction) -> bool {
|
||||
let base_reg = if self.state.address_size == OpSize::Size64 { Register::RAX } else { Register::EAX };
|
||||
decoder_read_op_mem_32_or_64_vsib(self, instruction, base_reg, TupleType::N1, false)
|
||||
|
@ -1987,7 +1987,7 @@ impl<'a> Decoder<'a> {
|
|||
// Returns `true` if the SIB byte was read
|
||||
// This is a specialized version of read_op_mem_32_or_64_vsib() which takes less arguments. Keep them in sync.
|
||||
#[must_use]
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
#[inline(always)]
|
||||
fn read_op_mem_32_or_64(&mut self, instruction: &mut Instruction) -> bool {
|
||||
debug_assert!(self.state.address_size == OpSize::Size32 || self.state.address_size == OpSize::Size64);
|
||||
|
@ -1998,7 +1998,7 @@ impl<'a> Decoder<'a> {
|
|||
unsafe { (self.read_op_mem_fns.get_unchecked(index))(self, instruction) }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
fn read_op_mem_1(&mut self, instruction: &mut Instruction) -> bool {
|
||||
instruction_internal::internal_set_memory_displ_size(instruction, 1);
|
||||
self.displ_index = self.data_ptr as u8;
|
||||
|
@ -2014,7 +2014,7 @@ impl<'a> Decoder<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
fn read_op_mem_1_4(&mut self, instruction: &mut Instruction) -> bool {
|
||||
instruction_internal::internal_set_memory_displ_size(instruction, 1);
|
||||
|
||||
|
@ -2044,7 +2044,7 @@ impl<'a> Decoder<'a> {
|
|||
true
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
fn read_op_mem_0(&mut self, instruction: &mut Instruction) -> bool {
|
||||
let base_reg = if self.state.address_size == OpSize::Size64 { Register::RAX } else { Register::EAX };
|
||||
write_base_reg!(instruction, self.state.extra_base_register_base + self.state.rm + base_reg as u32);
|
||||
|
@ -2052,7 +2052,7 @@ impl<'a> Decoder<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
fn read_op_mem_0_5(&mut self, instruction: &mut Instruction) -> bool {
|
||||
self.displ_index = self.data_ptr as u8;
|
||||
let d = self.read_u32();
|
||||
|
@ -2075,7 +2075,7 @@ impl<'a> Decoder<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
fn read_op_mem_2_4(&mut self, instruction: &mut Instruction) -> bool {
|
||||
let sib = self.read_u8() as u32;
|
||||
self.displ_index = self.data_ptr as u8;
|
||||
|
@ -2105,7 +2105,7 @@ impl<'a> Decoder<'a> {
|
|||
true
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
fn read_op_mem_2(&mut self, instruction: &mut Instruction) -> bool {
|
||||
self.displ_index = self.data_ptr as u8;
|
||||
let d = self.read_u32();
|
||||
|
@ -2122,7 +2122,7 @@ impl<'a> Decoder<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "__internal_mem_vsib"))]
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
fn read_op_mem_0_4(&mut self, instruction: &mut Instruction) -> bool {
|
||||
let sib = self.read_u8() as u32;
|
||||
const_assert_eq!(InstrScale::Scale1 as u32, 0);
|
||||
|
@ -2316,7 +2316,7 @@ impl<'a> Decoder<'a> {
|
|||
// Returns `true` if the SIB byte was read
|
||||
// Same as read_op_mem_32_or_64() except it works with vsib memory operands. Keep them in sync.
|
||||
#[must_use]
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[inline(always)]
|
||||
fn decoder_read_op_mem_32_or_64_vsib(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, index_reg: Register, tuple_type: TupleType, is_vsib: bool,
|
||||
|
@ -2329,7 +2329,7 @@ fn decoder_read_op_mem_32_or_64_vsib(
|
|||
unsafe { (READ_OP_MEM_VSIB_FNS.get_unchecked(index))(this, instruction, index_reg, tuple_type, is_vsib) }
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
fn decoder_read_op_mem_vsib_1(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, _index_reg: Register, tuple_type: TupleType, _is_vsib: bool,
|
||||
) -> bool {
|
||||
|
@ -2347,7 +2347,7 @@ fn decoder_read_op_mem_vsib_1(
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
fn decoder_read_op_mem_vsib_1_4(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, index_reg: Register, tuple_type: TupleType, is_vsib: bool,
|
||||
) -> bool {
|
||||
|
@ -2384,7 +2384,7 @@ fn decoder_read_op_mem_vsib_1_4(
|
|||
true
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
fn decoder_read_op_mem_vsib_0(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, _index_reg: Register, _tuple_type: TupleType, _is_vsib: bool,
|
||||
) -> bool {
|
||||
|
@ -2394,7 +2394,7 @@ fn decoder_read_op_mem_vsib_0(
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
fn decoder_read_op_mem_vsib_0_5(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, _index_reg: Register, _tuple_type: TupleType, _is_vsib: bool,
|
||||
) -> bool {
|
||||
|
@ -2419,7 +2419,7 @@ fn decoder_read_op_mem_vsib_0_5(
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
fn decoder_read_op_mem_vsib_2_4(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, index_reg: Register, _tuple_type: TupleType, is_vsib: bool,
|
||||
) -> bool {
|
||||
|
@ -2456,7 +2456,7 @@ fn decoder_read_op_mem_vsib_2_4(
|
|||
true
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
fn decoder_read_op_mem_vsib_2(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, _index_reg: Register, _tuple_type: TupleType, _is_vsib: bool,
|
||||
) -> bool {
|
||||
|
@ -2475,7 +2475,7 @@ fn decoder_read_op_mem_vsib_2(
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "__internal_mem_vsib", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
#[cfg(any(feature = "__internal_flip", not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
|
||||
fn decoder_read_op_mem_vsib_0_4(
|
||||
this: &mut Decoder<'_>, instruction: &mut Instruction, index_reg: Register, _tuple_type: TupleType, is_vsib: bool,
|
||||
) -> bool {
|
||||
|
|
|
@ -42,6 +42,8 @@ fn test_serde_json() {
|
|||
fn test_bincode() {
|
||||
test_serde(|instruction| {
|
||||
let ser_bytes = bincode::serialize(instruction).unwrap();
|
||||
#[cfg(not(feature = "__internal_flip"))]
|
||||
assert_eq!(ser_bytes.len(), INSTRUCTION_TOTAL_SIZE);
|
||||
bincode::deserialize(&ser_bytes).unwrap()
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10542,6 +10542,10 @@ impl FusedIterator for OpKindIterator {}
|
|||
|
||||
// All the enums have generated ser/de implementations without using the proc-macro. This is the only one left
|
||||
// that is needed to completely remove serde proc-macro.
|
||||
//
|
||||
// We've documented that we only support serializing and deserializing data created by the same version of iced.
|
||||
// That means we can optimize bincode serialized instructions. It's wasting 35 bytes per serialized instruction
|
||||
// because it stores each enum variant in a u32. That's almost a full instruction instance wasted with padding.
|
||||
#[cfg(feature = "serde")]
|
||||
const _: () = {
|
||||
#[cfg(not(feature = "std"))]
|
||||
|
@ -10556,101 +10560,100 @@ const _: () = {
|
|||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
#[cfg(feature = "std")]
|
||||
use std::collections::HashMap;
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum StructField {
|
||||
next_rip,
|
||||
flags1,
|
||||
immediate,
|
||||
mem_displ,
|
||||
mem_displ_hi,
|
||||
code,
|
||||
mem_base_reg,
|
||||
mem_index_reg,
|
||||
regs,
|
||||
op_kinds,
|
||||
scale,
|
||||
displ_size,
|
||||
len,
|
||||
db,
|
||||
}
|
||||
const NUM_STRUCT_FIELDS: usize = StructField::db as usize + 1;
|
||||
const FIELDS: [&str; NUM_STRUCT_FIELDS] = [
|
||||
"next_rip",
|
||||
"flags1",
|
||||
"immediate",
|
||||
"mem_displ",
|
||||
"mem_displ_hi",
|
||||
"code",
|
||||
"mem_base_reg",
|
||||
"mem_index_reg",
|
||||
"regs",
|
||||
"op_kinds",
|
||||
"scale",
|
||||
"displ_size",
|
||||
"len",
|
||||
"db",
|
||||
];
|
||||
impl StructField {
|
||||
#[inline]
|
||||
fn values() -> impl Iterator<Item = StructField> + DoubleEndedIterator + ExactSizeIterator + FusedIterator {
|
||||
// SAFETY: all values 0-max are valid enum values
|
||||
(0..NUM_STRUCT_FIELDS).map(|x| unsafe { mem::transmute::<u8, StructField>(x as u8) })
|
||||
}
|
||||
}
|
||||
lazy_static! {
|
||||
static ref NAME_TO_FIELD: HashMap<&'static [u8], StructField> = FIELDS.iter().map(|&s| s.as_bytes()).zip(StructField::values()).collect();
|
||||
}
|
||||
impl TryFrom<usize> for StructField {
|
||||
type Error = &'static str;
|
||||
#[inline]
|
||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||
if value < NUM_STRUCT_FIELDS {
|
||||
// SAFETY: all values 0-max are valid enum values
|
||||
Ok(unsafe { mem::transmute(value as u8) })
|
||||
} else {
|
||||
Err("Invalid struct field")
|
||||
}
|
||||
|
||||
// eg. json
|
||||
const NUM_FIELDS_READABLE: usize = 14;
|
||||
// eg. bincode
|
||||
const NUM_FIELDS_BINARY: usize = 20;
|
||||
|
||||
#[inline]
|
||||
fn is_human_readable(value: bool) -> bool {
|
||||
// This feature is used to test the other code paths
|
||||
if cfg!(feature = "__internal_flip") {
|
||||
value ^ true
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Instruction {
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut serde_state = serializer.serialize_struct("Instruction", NUM_STRUCT_FIELDS)?;
|
||||
let mut fields = 0;
|
||||
macro_rules! serialize {
|
||||
($field:ident) => {
|
||||
serde_state.serialize_field(stringify!($field), &self.$field)?;
|
||||
fields += 1;
|
||||
};
|
||||
if is_human_readable(serializer.is_human_readable()) {
|
||||
let mut serde_state = serializer.serialize_struct("Instruction", NUM_FIELDS_READABLE)?;
|
||||
let mut fields = 0;
|
||||
macro_rules! serialize {
|
||||
($field:ident) => {
|
||||
serde_state.serialize_field(stringify!($field), &self.$field)?;
|
||||
fields += 1;
|
||||
};
|
||||
}
|
||||
serialize!(next_rip);
|
||||
serialize!(flags1);
|
||||
serialize!(immediate);
|
||||
serialize!(mem_displ);
|
||||
serialize!(mem_displ_hi);
|
||||
serialize!(code);
|
||||
serialize!(mem_base_reg);
|
||||
serialize!(mem_index_reg);
|
||||
serialize!(regs);
|
||||
serialize!(op_kinds);
|
||||
serialize!(scale);
|
||||
serialize!(displ_size);
|
||||
serialize!(len);
|
||||
serialize!(db);
|
||||
debug_assert_eq!(fields, NUM_FIELDS_READABLE);
|
||||
serde_state.end()
|
||||
} else {
|
||||
let mut serde_state = serializer.serialize_struct("Instruction", NUM_FIELDS_BINARY)?;
|
||||
let mut fields = 0;
|
||||
macro_rules! serialize {
|
||||
($field:ident) => {
|
||||
serde_state.serialize_field(stringify!($field), &self.$field)?;
|
||||
fields += 1;
|
||||
};
|
||||
($field:ident, $underlying_ty:ty) => {
|
||||
serde_state.serialize_field(stringify!($field), &(self.$field as $underlying_ty))?;
|
||||
fields += 1;
|
||||
};
|
||||
($field:ident, $index:literal, $underlying_ty:ty) => {
|
||||
serde_state.serialize_field(concat!(stringify!($field), stringify!($index)), &(self.$field[$index] as $underlying_ty))?;
|
||||
fields += 1;
|
||||
};
|
||||
}
|
||||
serialize!(next_rip);
|
||||
serialize!(flags1);
|
||||
serialize!(immediate);
|
||||
serialize!(mem_displ);
|
||||
serialize!(mem_displ_hi);
|
||||
serialize!(code, CodeUnderlyingType);
|
||||
serialize!(mem_base_reg, RegisterUnderlyingType);
|
||||
serialize!(mem_index_reg, RegisterUnderlyingType);
|
||||
debug_assert_eq!(self.regs.len(), 4);
|
||||
serialize!(regs, 0, RegisterUnderlyingType);
|
||||
serialize!(regs, 1, RegisterUnderlyingType);
|
||||
serialize!(regs, 2, RegisterUnderlyingType);
|
||||
serialize!(regs, 3, RegisterUnderlyingType);
|
||||
debug_assert_eq!(self.op_kinds.len(), 4);
|
||||
serialize!(op_kinds, 0, OpKindUnderlyingType);
|
||||
serialize!(op_kinds, 1, OpKindUnderlyingType);
|
||||
serialize!(op_kinds, 2, OpKindUnderlyingType);
|
||||
serialize!(op_kinds, 3, OpKindUnderlyingType);
|
||||
serialize!(scale, InstrScaleUnderlyingType);
|
||||
serialize!(displ_size);
|
||||
serialize!(len);
|
||||
serialize!(db);
|
||||
debug_assert_eq!(fields, NUM_FIELDS_BINARY);
|
||||
serde_state.end()
|
||||
}
|
||||
serialize!(next_rip);
|
||||
serialize!(flags1);
|
||||
serialize!(immediate);
|
||||
serialize!(mem_displ);
|
||||
serialize!(mem_displ_hi);
|
||||
serialize!(code);
|
||||
serialize!(mem_base_reg);
|
||||
serialize!(mem_index_reg);
|
||||
serialize!(regs);
|
||||
serialize!(op_kinds);
|
||||
serialize!(scale);
|
||||
serialize!(displ_size);
|
||||
serialize!(len);
|
||||
serialize!(db);
|
||||
debug_assert_eq!(fields, NUM_STRUCT_FIELDS);
|
||||
serde_state.end()
|
||||
}
|
||||
}
|
||||
impl<'de> Deserialize<'de> for Instruction {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
|
||||
macro_rules! mk_struct_field_visitor {
|
||||
() => {
|
||||
struct StructFieldVisitor;
|
||||
impl<'de> de::Visitor<'de> for StructFieldVisitor {
|
||||
type Value = StructField;
|
||||
|
@ -10707,128 +10710,447 @@ const _: () = {
|
|||
deserializer.deserialize_identifier(StructFieldVisitor)
|
||||
}
|
||||
}
|
||||
struct Visitor<'de> {
|
||||
marker: PhantomData<Instruction>,
|
||||
lifetime: PhantomData<&'de ()>,
|
||||
}
|
||||
impl<'de> de::Visitor<'de> for Visitor<'de> {
|
||||
type Value = Instruction;
|
||||
#[inline]
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("struct Instruction")
|
||||
};
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Instruction {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if is_human_readable(deserializer.is_human_readable()) {
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum StructField {
|
||||
next_rip,
|
||||
flags1,
|
||||
immediate,
|
||||
mem_displ,
|
||||
mem_displ_hi,
|
||||
code,
|
||||
mem_base_reg,
|
||||
mem_index_reg,
|
||||
regs,
|
||||
op_kinds,
|
||||
scale,
|
||||
displ_size,
|
||||
len,
|
||||
db,
|
||||
}
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
#[allow(clippy::eval_order_dependence)]
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
let mut fields = 0;
|
||||
macro_rules! next_element {
|
||||
($field_name:ident : $field_ty:ty) => {{
|
||||
fields += 1;
|
||||
match seq.next_element::<$field_ty>()? {
|
||||
Some(value) => value,
|
||||
None => return Err(de::Error::invalid_length(fields, &"struct Instruction with all its fields")),
|
||||
}
|
||||
}};
|
||||
const_assert_eq!(StructField::db as usize + 1, NUM_FIELDS_READABLE);
|
||||
const FIELDS: [&str; NUM_FIELDS_READABLE] = [
|
||||
"next_rip",
|
||||
"flags1",
|
||||
"immediate",
|
||||
"mem_displ",
|
||||
"mem_displ_hi",
|
||||
"code",
|
||||
"mem_base_reg",
|
||||
"mem_index_reg",
|
||||
"regs",
|
||||
"op_kinds",
|
||||
"scale",
|
||||
"displ_size",
|
||||
"len",
|
||||
"db",
|
||||
];
|
||||
impl StructField {
|
||||
#[inline]
|
||||
fn values() -> impl Iterator<Item = StructField> + DoubleEndedIterator + ExactSizeIterator + FusedIterator {
|
||||
// SAFETY: all values 0-max are valid enum values
|
||||
(0..NUM_FIELDS_READABLE).map(|x| unsafe { mem::transmute::<u8, StructField>(x as u8) })
|
||||
}
|
||||
let instruction = Instruction {
|
||||
next_rip: next_element!(next_rip: u64),
|
||||
flags1: next_element!(flags1: u32),
|
||||
immediate: next_element!(immediate: u32),
|
||||
mem_displ: next_element!(mem_displ: u32),
|
||||
mem_displ_hi: next_element!(mem_displ_hi: u32),
|
||||
code: next_element!(code: Code),
|
||||
mem_base_reg: next_element!(mem_base_reg: Register),
|
||||
mem_index_reg: next_element!(mem_index_reg: Register),
|
||||
regs: next_element!(regs: [Register; 4]),
|
||||
op_kinds: next_element!(op_kinds: [OpKind; 4]),
|
||||
scale: next_element!(scale: InstrScale),
|
||||
displ_size: next_element!(displ_size: u8),
|
||||
len: next_element!(len: u8),
|
||||
db: next_element!(db: u8),
|
||||
};
|
||||
debug_assert_eq!(fields, NUM_STRUCT_FIELDS);
|
||||
Ok(instruction)
|
||||
}
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
#[allow(clippy::eval_order_dependence)]
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut next_rip: Option<u64> = None;
|
||||
let mut flags1: Option<u32> = None;
|
||||
let mut immediate: Option<u32> = None;
|
||||
let mut mem_displ: Option<u32> = None;
|
||||
let mut mem_displ_hi: Option<u32> = None;
|
||||
let mut code: Option<Code> = None;
|
||||
let mut mem_base_reg: Option<Register> = None;
|
||||
let mut mem_index_reg: Option<Register> = None;
|
||||
let mut regs: Option<[Register; 4]> = None;
|
||||
let mut op_kinds: Option<[OpKind; 4]> = None;
|
||||
let mut scale: Option<InstrScale> = None;
|
||||
let mut displ_size: Option<u8> = None;
|
||||
let mut len: Option<u8> = None;
|
||||
let mut db: Option<u8> = None;
|
||||
while let Some(field) = map.next_key::<StructField>()? {
|
||||
macro_rules! unpack {
|
||||
($field:ident : $field_ty:ty) => {{
|
||||
if $field.is_some() {
|
||||
return Err(<A::Error as de::Error>::duplicate_field(stringify!($field)));
|
||||
lazy_static! {
|
||||
static ref NAME_TO_FIELD: HashMap<&'static [u8], StructField> =
|
||||
FIELDS.iter().map(|&s| s.as_bytes()).zip(StructField::values()).collect();
|
||||
}
|
||||
impl TryFrom<usize> for StructField {
|
||||
type Error = &'static str;
|
||||
#[inline]
|
||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||
if value < NUM_FIELDS_READABLE {
|
||||
// SAFETY: all values 0-max are valid enum values
|
||||
Ok(unsafe { mem::transmute(value as u8) })
|
||||
} else {
|
||||
Err("Invalid struct field")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mk_struct_field_visitor!();
|
||||
|
||||
struct Visitor<'de> {
|
||||
marker: PhantomData<Instruction>,
|
||||
lifetime: PhantomData<&'de ()>,
|
||||
}
|
||||
impl<'de> de::Visitor<'de> for Visitor<'de> {
|
||||
type Value = Instruction;
|
||||
#[inline]
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("struct Instruction")
|
||||
}
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
#[allow(clippy::eval_order_dependence)]
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
let mut fields = 0;
|
||||
macro_rules! next_element {
|
||||
($field_name:ident : $field_ty:ty) => {{
|
||||
fields += 1;
|
||||
match seq.next_element::<$field_ty>()? {
|
||||
Some(value) => value,
|
||||
None => return Err(de::Error::invalid_length(fields, &"struct Instruction with all its fields")),
|
||||
}
|
||||
$field = Some(map.next_value::<$field_ty>()?);
|
||||
}};
|
||||
}
|
||||
match field {
|
||||
StructField::next_rip => unpack!(next_rip: u64),
|
||||
StructField::flags1 => unpack!(flags1: u32),
|
||||
StructField::immediate => unpack!(immediate: u32),
|
||||
StructField::mem_displ => unpack!(mem_displ: u32),
|
||||
StructField::mem_displ_hi => unpack!(mem_displ_hi: u32),
|
||||
StructField::code => unpack!(code: Code),
|
||||
StructField::mem_base_reg => unpack!(mem_base_reg: Register),
|
||||
StructField::mem_index_reg => unpack!(mem_index_reg: Register),
|
||||
StructField::regs => unpack!(regs: [Register; 4]),
|
||||
StructField::op_kinds => unpack!(op_kinds: [OpKind; 4]),
|
||||
StructField::scale => unpack!(scale: InstrScale),
|
||||
StructField::displ_size => unpack!(displ_size: u8),
|
||||
StructField::len => unpack!(len: u8),
|
||||
StructField::db => unpack!(db: u8),
|
||||
let instruction = Instruction {
|
||||
next_rip: next_element!(next_rip: u64),
|
||||
flags1: next_element!(flags1: u32),
|
||||
immediate: next_element!(immediate: u32),
|
||||
mem_displ: next_element!(mem_displ: u32),
|
||||
mem_displ_hi: next_element!(mem_displ_hi: u32),
|
||||
code: next_element!(code: Code),
|
||||
mem_base_reg: next_element!(mem_base_reg: Register),
|
||||
mem_index_reg: next_element!(mem_index_reg: Register),
|
||||
regs: next_element!(regs: [Register; 4]),
|
||||
op_kinds: next_element!(op_kinds: [OpKind; 4]),
|
||||
scale: next_element!(scale: InstrScale),
|
||||
displ_size: next_element!(displ_size: u8),
|
||||
len: next_element!(len: u8),
|
||||
db: next_element!(db: u8),
|
||||
};
|
||||
debug_assert_eq!(fields, NUM_FIELDS_READABLE);
|
||||
Ok(instruction)
|
||||
}
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
#[allow(clippy::eval_order_dependence)]
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut next_rip: Option<u64> = None;
|
||||
let mut flags1: Option<u32> = None;
|
||||
let mut immediate: Option<u32> = None;
|
||||
let mut mem_displ: Option<u32> = None;
|
||||
let mut mem_displ_hi: Option<u32> = None;
|
||||
let mut code: Option<Code> = None;
|
||||
let mut mem_base_reg: Option<Register> = None;
|
||||
let mut mem_index_reg: Option<Register> = None;
|
||||
let mut regs: Option<[Register; 4]> = None;
|
||||
let mut op_kinds: Option<[OpKind; 4]> = None;
|
||||
let mut scale: Option<InstrScale> = None;
|
||||
let mut displ_size: Option<u8> = None;
|
||||
let mut len: Option<u8> = None;
|
||||
let mut db: Option<u8> = None;
|
||||
while let Some(field) = map.next_key::<StructField>()? {
|
||||
macro_rules! unpack {
|
||||
($field:ident : $field_ty:ty) => {{
|
||||
if $field.is_some() {
|
||||
return Err(<A::Error as de::Error>::duplicate_field(stringify!($field)));
|
||||
}
|
||||
$field = Some(map.next_value::<$field_ty>()?);
|
||||
}};
|
||||
}
|
||||
match field {
|
||||
StructField::next_rip => unpack!(next_rip: u64),
|
||||
StructField::flags1 => unpack!(flags1: u32),
|
||||
StructField::immediate => unpack!(immediate: u32),
|
||||
StructField::mem_displ => unpack!(mem_displ: u32),
|
||||
StructField::mem_displ_hi => unpack!(mem_displ_hi: u32),
|
||||
StructField::code => unpack!(code: Code),
|
||||
StructField::mem_base_reg => unpack!(mem_base_reg: Register),
|
||||
StructField::mem_index_reg => unpack!(mem_index_reg: Register),
|
||||
StructField::regs => unpack!(regs: [Register; 4]),
|
||||
StructField::op_kinds => unpack!(op_kinds: [OpKind; 4]),
|
||||
StructField::scale => unpack!(scale: InstrScale),
|
||||
StructField::displ_size => unpack!(displ_size: u8),
|
||||
StructField::len => unpack!(len: u8),
|
||||
StructField::db => unpack!(db: u8),
|
||||
}
|
||||
}
|
||||
let mut fields = 0;
|
||||
macro_rules! unpack_field {
|
||||
($field:ident) => {{
|
||||
fields += 1;
|
||||
match $field {
|
||||
Some(value) => value,
|
||||
None => return Err(<A::Error as de::Error>::missing_field(stringify!($field))),
|
||||
}
|
||||
}};
|
||||
}
|
||||
let instruction = Instruction {
|
||||
next_rip: unpack_field!(next_rip),
|
||||
flags1: unpack_field!(flags1),
|
||||
immediate: unpack_field!(immediate),
|
||||
mem_displ: unpack_field!(mem_displ),
|
||||
mem_displ_hi: unpack_field!(mem_displ_hi),
|
||||
code: unpack_field!(code),
|
||||
mem_base_reg: unpack_field!(mem_base_reg),
|
||||
mem_index_reg: unpack_field!(mem_index_reg),
|
||||
regs: unpack_field!(regs),
|
||||
op_kinds: unpack_field!(op_kinds),
|
||||
scale: unpack_field!(scale),
|
||||
displ_size: unpack_field!(displ_size),
|
||||
len: unpack_field!(len),
|
||||
db: unpack_field!(db),
|
||||
};
|
||||
debug_assert_eq!(fields, NUM_FIELDS_READABLE);
|
||||
Ok(instruction)
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_struct("Instruction", &FIELDS[..], Visitor { marker: PhantomData::<Instruction>, lifetime: PhantomData })
|
||||
} else {
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum StructField {
|
||||
next_rip,
|
||||
flags1,
|
||||
immediate,
|
||||
mem_displ,
|
||||
mem_displ_hi,
|
||||
code,
|
||||
mem_base_reg,
|
||||
mem_index_reg,
|
||||
regs0,
|
||||
regs1,
|
||||
regs2,
|
||||
regs3,
|
||||
op_kinds0,
|
||||
op_kinds1,
|
||||
op_kinds2,
|
||||
op_kinds3,
|
||||
scale,
|
||||
displ_size,
|
||||
len,
|
||||
db,
|
||||
}
|
||||
const_assert_eq!(StructField::db as usize + 1, NUM_FIELDS_BINARY);
|
||||
const FIELDS: [&str; NUM_FIELDS_BINARY] = [
|
||||
"next_rip",
|
||||
"flags1",
|
||||
"immediate",
|
||||
"mem_displ",
|
||||
"mem_displ_hi",
|
||||
"code",
|
||||
"mem_base_reg",
|
||||
"mem_index_reg",
|
||||
"regs0",
|
||||
"regs1",
|
||||
"regs2",
|
||||
"regs3",
|
||||
"op_kinds0",
|
||||
"op_kinds1",
|
||||
"op_kinds2",
|
||||
"op_kinds3",
|
||||
"scale",
|
||||
"displ_size",
|
||||
"len",
|
||||
"db",
|
||||
];
|
||||
impl StructField {
|
||||
#[inline]
|
||||
fn values() -> impl Iterator<Item = StructField> + DoubleEndedIterator + ExactSizeIterator + FusedIterator {
|
||||
// SAFETY: all values 0-max are valid enum values
|
||||
(0..NUM_FIELDS_BINARY).map(|x| unsafe { mem::transmute::<u8, StructField>(x as u8) })
|
||||
}
|
||||
}
|
||||
lazy_static! {
|
||||
static ref NAME_TO_FIELD: HashMap<&'static [u8], StructField> =
|
||||
FIELDS.iter().map(|&s| s.as_bytes()).zip(StructField::values()).collect();
|
||||
}
|
||||
impl TryFrom<usize> for StructField {
|
||||
type Error = &'static str;
|
||||
#[inline]
|
||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||
if value < NUM_FIELDS_BINARY {
|
||||
// SAFETY: all values 0-max are valid enum values
|
||||
Ok(unsafe { mem::transmute(value as u8) })
|
||||
} else {
|
||||
Err("Invalid struct field")
|
||||
}
|
||||
}
|
||||
let mut fields = 0;
|
||||
macro_rules! unpack_field {
|
||||
($field:ident) => {{
|
||||
fields += 1;
|
||||
match $field {
|
||||
Some(value) => value,
|
||||
None => return Err(<A::Error as de::Error>::missing_field(stringify!($field))),
|
||||
}
|
||||
}};
|
||||
}
|
||||
let instruction = Instruction {
|
||||
next_rip: unpack_field!(next_rip),
|
||||
flags1: unpack_field!(flags1),
|
||||
immediate: unpack_field!(immediate),
|
||||
mem_displ: unpack_field!(mem_displ),
|
||||
mem_displ_hi: unpack_field!(mem_displ_hi),
|
||||
code: unpack_field!(code),
|
||||
mem_base_reg: unpack_field!(mem_base_reg),
|
||||
mem_index_reg: unpack_field!(mem_index_reg),
|
||||
regs: unpack_field!(regs),
|
||||
op_kinds: unpack_field!(op_kinds),
|
||||
scale: unpack_field!(scale),
|
||||
displ_size: unpack_field!(displ_size),
|
||||
len: unpack_field!(len),
|
||||
db: unpack_field!(db),
|
||||
};
|
||||
debug_assert_eq!(fields, NUM_STRUCT_FIELDS);
|
||||
Ok(instruction)
|
||||
}
|
||||
|
||||
mk_struct_field_visitor!();
|
||||
|
||||
struct Visitor<'de> {
|
||||
marker: PhantomData<Instruction>,
|
||||
lifetime: PhantomData<&'de ()>,
|
||||
}
|
||||
impl<'de> de::Visitor<'de> for Visitor<'de> {
|
||||
type Value = Instruction;
|
||||
#[inline]
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("struct Instruction")
|
||||
}
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
#[allow(clippy::eval_order_dependence)]
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
let mut fields = 0;
|
||||
macro_rules! next_element {
|
||||
($field_name:ident : $field_ty:ty) => {{
|
||||
fields += 1;
|
||||
match seq.next_element::<$field_ty>()? {
|
||||
Some(value) => value,
|
||||
None => return Err(de::Error::invalid_length(fields, &"struct Instruction with all its fields")),
|
||||
}
|
||||
}};
|
||||
($field_name:ident : $field_ty:ty : $underlying_ty:ty) => {{
|
||||
fields += 1;
|
||||
let value = match seq.next_element::<$underlying_ty>()? {
|
||||
Some(value) => value,
|
||||
None => return Err(de::Error::invalid_length(fields, &"struct Instruction with all its fields")),
|
||||
};
|
||||
if let Ok(enum_value) = <$field_ty as TryFrom<usize>>::try_from(value as usize) {
|
||||
enum_value
|
||||
} else {
|
||||
return Err(<A::Error as de::Error>::invalid_value(
|
||||
de::Unexpected::Unsigned(value.into()),
|
||||
&"an enum variant in range",
|
||||
));
|
||||
}
|
||||
}};
|
||||
}
|
||||
let instruction = Instruction {
|
||||
next_rip: next_element!(next_rip: u64),
|
||||
flags1: next_element!(flags1: u32),
|
||||
immediate: next_element!(immediate: u32),
|
||||
mem_displ: next_element!(mem_displ: u32),
|
||||
mem_displ_hi: next_element!(mem_displ_hi: u32),
|
||||
code: next_element!(code: Code: CodeUnderlyingType),
|
||||
mem_base_reg: next_element!(mem_base_reg: Register: RegisterUnderlyingType),
|
||||
mem_index_reg: next_element!(mem_index_reg: Register: RegisterUnderlyingType),
|
||||
regs: [
|
||||
next_element!(regs0: Register: RegisterUnderlyingType),
|
||||
next_element!(regs1: Register: RegisterUnderlyingType),
|
||||
next_element!(regs2: Register: RegisterUnderlyingType),
|
||||
next_element!(regs3: Register: RegisterUnderlyingType),
|
||||
],
|
||||
op_kinds: [
|
||||
next_element!(op_kinds0: OpKind: OpKindUnderlyingType),
|
||||
next_element!(op_kinds1: OpKind: OpKindUnderlyingType),
|
||||
next_element!(op_kinds2: OpKind: OpKindUnderlyingType),
|
||||
next_element!(op_kinds3: OpKind: OpKindUnderlyingType),
|
||||
],
|
||||
scale: next_element!(scale: InstrScale: InstrScaleUnderlyingType),
|
||||
displ_size: next_element!(displ_size: u8),
|
||||
len: next_element!(len: u8),
|
||||
db: next_element!(db: u8),
|
||||
};
|
||||
debug_assert_eq!(fields, NUM_FIELDS_BINARY);
|
||||
Ok(instruction)
|
||||
}
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
#[allow(clippy::eval_order_dependence)]
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut next_rip: Option<u64> = None;
|
||||
let mut flags1: Option<u32> = None;
|
||||
let mut immediate: Option<u32> = None;
|
||||
let mut mem_displ: Option<u32> = None;
|
||||
let mut mem_displ_hi: Option<u32> = None;
|
||||
let mut code: Option<Code> = None;
|
||||
let mut mem_base_reg: Option<Register> = None;
|
||||
let mut mem_index_reg: Option<Register> = None;
|
||||
let mut regs0: Option<Register> = None;
|
||||
let mut regs1: Option<Register> = None;
|
||||
let mut regs2: Option<Register> = None;
|
||||
let mut regs3: Option<Register> = None;
|
||||
let mut op_kinds0: Option<OpKind> = None;
|
||||
let mut op_kinds1: Option<OpKind> = None;
|
||||
let mut op_kinds2: Option<OpKind> = None;
|
||||
let mut op_kinds3: Option<OpKind> = None;
|
||||
let mut scale: Option<InstrScale> = None;
|
||||
let mut displ_size: Option<u8> = None;
|
||||
let mut len: Option<u8> = None;
|
||||
let mut db: Option<u8> = None;
|
||||
while let Some(field) = map.next_key::<StructField>()? {
|
||||
macro_rules! unpack {
|
||||
($field:ident : $field_ty:ty) => {{
|
||||
if $field.is_some() {
|
||||
return Err(<A::Error as de::Error>::duplicate_field(stringify!($field)));
|
||||
}
|
||||
$field = Some(map.next_value::<$field_ty>()?);
|
||||
}};
|
||||
($field:ident : $field_ty:ty : $underlying_ty:ty) => {{
|
||||
if $field.is_some() {
|
||||
return Err(<A::Error as de::Error>::duplicate_field(stringify!($field)));
|
||||
}
|
||||
let value = map.next_value::<$underlying_ty>()?;
|
||||
if let Ok(enum_value) = <$field_ty as TryFrom<usize>>::try_from(value as usize) {
|
||||
$field = Some(enum_value);
|
||||
} else {
|
||||
return Err(<A::Error as de::Error>::invalid_value(
|
||||
de::Unexpected::Unsigned(value.into()),
|
||||
&"an enum variant in range",
|
||||
));
|
||||
}
|
||||
}};
|
||||
}
|
||||
match field {
|
||||
StructField::next_rip => unpack!(next_rip: u64),
|
||||
StructField::flags1 => unpack!(flags1: u32),
|
||||
StructField::immediate => unpack!(immediate: u32),
|
||||
StructField::mem_displ => unpack!(mem_displ: u32),
|
||||
StructField::mem_displ_hi => unpack!(mem_displ_hi: u32),
|
||||
StructField::code => unpack!(code: Code: CodeUnderlyingType),
|
||||
StructField::mem_base_reg => unpack!(mem_base_reg: Register: RegisterUnderlyingType),
|
||||
StructField::mem_index_reg => unpack!(mem_index_reg: Register: RegisterUnderlyingType),
|
||||
StructField::regs0 => unpack!(regs0: Register: RegisterUnderlyingType),
|
||||
StructField::regs1 => unpack!(regs1: Register: RegisterUnderlyingType),
|
||||
StructField::regs2 => unpack!(regs2: Register: RegisterUnderlyingType),
|
||||
StructField::regs3 => unpack!(regs3: Register: RegisterUnderlyingType),
|
||||
StructField::op_kinds0 => unpack!(op_kinds0: OpKind: OpKindUnderlyingType),
|
||||
StructField::op_kinds1 => unpack!(op_kinds1: OpKind: OpKindUnderlyingType),
|
||||
StructField::op_kinds2 => unpack!(op_kinds2: OpKind: OpKindUnderlyingType),
|
||||
StructField::op_kinds3 => unpack!(op_kinds3: OpKind: OpKindUnderlyingType),
|
||||
StructField::scale => unpack!(scale: InstrScale: InstrScaleUnderlyingType),
|
||||
StructField::displ_size => unpack!(displ_size: u8),
|
||||
StructField::len => unpack!(len: u8),
|
||||
StructField::db => unpack!(db: u8),
|
||||
}
|
||||
}
|
||||
let mut fields = 0;
|
||||
macro_rules! unpack_field {
|
||||
($field:ident) => {{
|
||||
fields += 1;
|
||||
match $field {
|
||||
Some(value) => value,
|
||||
None => return Err(<A::Error as de::Error>::missing_field(stringify!($field))),
|
||||
}
|
||||
}};
|
||||
}
|
||||
let instruction = Instruction {
|
||||
next_rip: unpack_field!(next_rip),
|
||||
flags1: unpack_field!(flags1),
|
||||
immediate: unpack_field!(immediate),
|
||||
mem_displ: unpack_field!(mem_displ),
|
||||
mem_displ_hi: unpack_field!(mem_displ_hi),
|
||||
code: unpack_field!(code),
|
||||
mem_base_reg: unpack_field!(mem_base_reg),
|
||||
mem_index_reg: unpack_field!(mem_index_reg),
|
||||
regs: [unpack_field!(regs0), unpack_field!(regs1), unpack_field!(regs2), unpack_field!(regs3)],
|
||||
op_kinds: [unpack_field!(op_kinds0), unpack_field!(op_kinds1), unpack_field!(op_kinds2), unpack_field!(op_kinds3)],
|
||||
scale: unpack_field!(scale),
|
||||
displ_size: unpack_field!(displ_size),
|
||||
len: unpack_field!(len),
|
||||
db: unpack_field!(db),
|
||||
};
|
||||
debug_assert_eq!(fields, NUM_FIELDS_BINARY);
|
||||
Ok(instruction)
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_struct("Instruction", &FIELDS[..], Visitor { marker: PhantomData::<Instruction>, lifetime: PhantomData })
|
||||
}
|
||||
deserializer.deserialize_struct("Instruction", &FIELDS[..], Visitor { marker: PhantomData::<Instruction>, lifetime: PhantomData })
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue