Refactor usage of SecondaryMap impls (serde, PartialEq)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::address_map::{ModuleAddressMap, ValueLabelsRanges};
|
||||
use crate::compilation::{CodeAndJTOffsets, Compilation, Relocations};
|
||||
use crate::compilation::{Compilation, Relocations};
|
||||
use crate::module::Module;
|
||||
use crate::module_environ::FunctionBodyData;
|
||||
use core::hash::Hasher;
|
||||
@@ -8,10 +8,8 @@ use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::DefinedFuncIndex;
|
||||
use lazy_static::lazy_static;
|
||||
use log::{debug, warn};
|
||||
use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
|
||||
use serde::ser::{self, Serialize, SerializeSeq, SerializeStruct, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
@@ -181,7 +179,7 @@ pub struct ModuleCacheEntry {
|
||||
mod_cache_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
pub struct ModuleCacheData {
|
||||
compilation: Compilation,
|
||||
relocations: Relocations,
|
||||
@@ -239,7 +237,7 @@ impl ModuleCacheEntry {
|
||||
None
|
||||
};
|
||||
|
||||
ModuleCacheEntry { mod_cache_path }
|
||||
Self { mod_cache_path }
|
||||
}
|
||||
|
||||
pub fn get_data(&self) -> Option<ModuleCacheData> {
|
||||
@@ -370,175 +368,5 @@ impl Hasher for Sha256Hasher {
|
||||
}
|
||||
}
|
||||
|
||||
//-////////////////////////////////////////////////////////////////////
|
||||
// Serialization and deserialization of type containing SecondaryMap //
|
||||
//-////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum JtOffsetsWrapper<'a> {
|
||||
Ref(&'a ir::JumpTableOffsets), // for serialization
|
||||
Data(ir::JumpTableOffsets), // for deserialization
|
||||
}
|
||||
|
||||
impl Serialize for CodeAndJTOffsets {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut cajto = serializer.serialize_struct("CodeAndJTOffsets", 2)?;
|
||||
cajto.serialize_field("body", &self.body)?;
|
||||
cajto.serialize_field("jt_offsets", &JtOffsetsWrapper::Ref(&self.jt_offsets))?;
|
||||
cajto.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for CodeAndJTOffsets {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "lowercase")]
|
||||
enum Field {
|
||||
Body,
|
||||
JtOffsets,
|
||||
};
|
||||
|
||||
struct CodeAndJTOffsetsVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for CodeAndJTOffsetsVisitor {
|
||||
type Value = CodeAndJTOffsets;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("struct CodeAndJTOffsets")
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
|
||||
where
|
||||
V: SeqAccess<'de>,
|
||||
{
|
||||
let body = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||
let jt_offsets = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
||||
match jt_offsets {
|
||||
JtOffsetsWrapper::Data(jt_offsets) => Ok(CodeAndJTOffsets { body, jt_offsets }),
|
||||
JtOffsetsWrapper::Ref(_) => Err(de::Error::custom(
|
||||
"Received invalid variant of JtOffsetsWrapper",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
{
|
||||
let mut body = None;
|
||||
let mut jt_offsets = None;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
Field::Body => {
|
||||
if body.is_some() {
|
||||
return Err(de::Error::duplicate_field("body"));
|
||||
}
|
||||
body = Some(map.next_value()?);
|
||||
}
|
||||
Field::JtOffsets => {
|
||||
if jt_offsets.is_some() {
|
||||
return Err(de::Error::duplicate_field("jt_offsets"));
|
||||
}
|
||||
jt_offsets = Some(map.next_value()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let body = body.ok_or_else(|| de::Error::missing_field("body"))?;
|
||||
let jt_offsets =
|
||||
jt_offsets.ok_or_else(|| de::Error::missing_field("jt_offsets"))?;
|
||||
match jt_offsets {
|
||||
JtOffsetsWrapper::Data(jt_offsets) => Ok(CodeAndJTOffsets { body, jt_offsets }),
|
||||
JtOffsetsWrapper::Ref(_) => Err(de::Error::custom(
|
||||
"Received invalid variant of JtOffsetsWrapper",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FIELDS: &'static [&'static str] = &["body", "jt_offsets"];
|
||||
deserializer.deserialize_struct("CodeAndJTOffsets", FIELDS, CodeAndJTOffsetsVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for JtOffsetsWrapper<'_> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
JtOffsetsWrapper::Ref(data) => {
|
||||
// TODO: bincode encodes option as "byte for Some/None" and then optionally the content
|
||||
// TODO: we can actually optimize it by encoding manually bitmask, then elements
|
||||
let default_val = data.get_default();
|
||||
let mut seq = serializer.serialize_seq(Some(1 + data.len()))?;
|
||||
seq.serialize_element(&Some(default_val))?;
|
||||
for e in data.values() {
|
||||
let some_e = Some(e);
|
||||
seq.serialize_element(if e == default_val { &None } else { &some_e })?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
JtOffsetsWrapper::Data(_) => Err(ser::Error::custom(
|
||||
"Received invalid variant of JtOffsetsWrapper",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for JtOffsetsWrapper<'_> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct JtOffsetsWrapperVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for JtOffsetsWrapperVisitor {
|
||||
type Value = JtOffsetsWrapper<'static>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("struct JtOffsetsWrapper")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
match seq.next_element()? {
|
||||
Some(Some(default_val)) => {
|
||||
let mut m = cranelift_entity::SecondaryMap::with_default(default_val);
|
||||
let mut idx = 0;
|
||||
while let Some(val) = seq.next_element()? {
|
||||
let val: Option<_> = val; // compiler can't infer the type, and this line is needed
|
||||
match ir::JumpTable::with_number(idx) {
|
||||
Some(jt_idx) => m[jt_idx] = val.unwrap_or(default_val),
|
||||
None => {
|
||||
return Err(serde::de::Error::custom(
|
||||
"Invalid JumpTable reference",
|
||||
))
|
||||
}
|
||||
};
|
||||
idx += 1;
|
||||
}
|
||||
Ok(JtOffsetsWrapper::Data(m))
|
||||
}
|
||||
_ => Err(serde::de::Error::custom("Default value required")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_seq(JtOffsetsWrapperVisitor {})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
Reference in New Issue
Block a user