Skip to content

Commit

Permalink
Add a serde feature to wasmparser for its collections (#1569)
Browse files Browse the repository at this point in the history
Required now that the types here are new types defined in this crate.
  • Loading branch information
alexcrichton authored May 20, 2024
1 parent fe250db commit f3128ea
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ jobs:
- run: cargo check --no-default-features -p wasmparser --target x86_64-unknown-none
- run: cargo check --no-default-features -p wasmparser --features std
- run: cargo check --no-default-features -p wasmparser --features validate
- run: cargo check --no-default-features -p wasmparser --features no-hash-maps
- run: cargo check --no-default-features -p wasmparser --features serde
- run: cargo check --no-default-features -p wasmparser --features serde,no-hash-maps
- run: cargo check --no-default-features -p wast
- run: cargo check --no-default-features -p wast --features wasm-module
- run: |
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion crates/wasmparser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ indexmap = { workspace = true, optional = true }
semver = { workspace = true, optional = true }
hashbrown = { workspace = true, optional = true }
ahash = { workspace = true, optional = true }
serde = { workspace = true, optional = true }

[dev-dependencies]
anyhow = { workspace = true }
Expand All @@ -39,7 +40,7 @@ name = "benchmark"
harness = false

[features]
default = ['std', 'validate']
default = ['std', 'validate', 'serde']

# A feature which enables implementations of `std::error::Error` as appropriate
# along with other convenience APIs. This additionally uses the standard
Expand All @@ -61,3 +62,7 @@ validate = [
'dep:hashbrown',
'dep:ahash',
]

# Enable Serialize/Deserialize implementations for types in
# `wasmparser::collections`
serde = ['dep:serde', 'indexmap/serde', 'hashbrown/serde']
30 changes: 30 additions & 0 deletions crates/wasmparser/src/collections/index_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,33 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
}

impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}

#[cfg(feature = "serde")]
impl<K, V> serde::Serialize for IndexMap<K, V>
where
K: serde::Serialize + Eq + Hash + Ord,
V: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serde::Serialize::serialize(&self.inner, serializer)
}
}

#[cfg(feature = "serde")]
impl<'a, K, V> serde::Deserialize<'a> for IndexMap<K, V>
where
K: serde::Deserialize<'a> + Eq + Hash + Ord + Clone,
V: serde::Deserialize<'a>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'a>,
{
Ok(IndexMap {
inner: serde::Deserialize::deserialize(deserializer)?,
})
}
}
70 changes: 70 additions & 0 deletions crates/wasmparser/src/collections/index_map/detail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,3 +1022,73 @@ where
.finish()
}
}

#[cfg(feature = "serde")]
mod serde_impls {
use super::IndexMap;
use core::fmt;
use core::marker::PhantomData;
use serde::de::{Deserialize, MapAccess, Visitor};
use serde::ser::{Serialize, SerializeMap, Serializer};

impl<K, V> Serialize for IndexMap<K, V>
where
K: Serialize + Ord,
V: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(self.len()))?;
for (k, v) in self.iter() {
map.serialize_entry(k, v)?;
}
map.end()
}
}

impl<'a, K, V> Deserialize<'a> for IndexMap<K, V>
where
K: Deserialize<'a> + Clone + Ord,
V: Deserialize<'a>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'a>,
{
deserializer.deserialize_map(IndexMapVisitor {
_marker: PhantomData,
})
}
}

struct IndexMapVisitor<K, V> {
_marker: PhantomData<fn() -> IndexMap<K, V>>,
}

impl<'de, K, V> Visitor<'de> for IndexMapVisitor<K, V>
where
K: Deserialize<'de> + Clone + Ord,
V: Deserialize<'de>,
{
type Value = IndexMap<K, V>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map")
}

fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = IndexMap::with_capacity(access.size_hint().unwrap_or(0));

while let Some((key, value)) = access.next_entry()? {
map.insert(key, value);
}

Ok(map)
}
}
}
28 changes: 28 additions & 0 deletions crates/wasmparser/src/collections/index_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,31 @@ impl<T> ExactSizeIterator for IntoIter<T> {
}

impl<T> FusedIterator for IntoIter<T> {}

#[cfg(feature = "serde")]
impl<T> serde::Serialize for IndexSet<T>
where
T: serde::Serialize + Eq + Hash + Ord,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serde::Serialize::serialize(&self.inner, serializer)
}
}

#[cfg(feature = "serde")]
impl<'a, T> serde::Deserialize<'a> for IndexSet<T>
where
T: serde::Deserialize<'a> + Eq + Hash + Ord + Clone,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'a>,
{
Ok(IndexSet {
inner: serde::Deserialize::deserialize(deserializer)?,
})
}
}
30 changes: 30 additions & 0 deletions crates/wasmparser/src/collections/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,3 +808,33 @@ impl<K, V> ExactSizeIterator for IntoValues<K, V> {
}

impl<K, V> FusedIterator for IntoValues<K, V> where detail::IntoValuesImpl<K, V>: FusedIterator {}

#[cfg(feature = "serde")]
impl<K, V> serde::Serialize for Map<K, V>
where
K: serde::Serialize + Eq + Hash + Ord,
V: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serde::Serialize::serialize(&self.inner, serializer)
}
}

#[cfg(feature = "serde")]
impl<'a, K, V> serde::Deserialize<'a> for Map<K, V>
where
K: serde::Deserialize<'a> + Eq + Hash + Ord,
V: serde::Deserialize<'a>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'a>,
{
Ok(Map {
inner: serde::Deserialize::deserialize(deserializer)?,
})
}
}
28 changes: 28 additions & 0 deletions crates/wasmparser/src/collections/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,3 +630,31 @@ where
detail::UnionImpl<'a, T>: FusedIterator,
{
}

#[cfg(feature = "serde")]
impl<T> serde::Serialize for Set<T>
where
T: serde::Serialize + Eq + Hash + Ord,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serde::Serialize::serialize(&self.inner, serializer)
}
}

#[cfg(feature = "serde")]
impl<'a, T> serde::Deserialize<'a> for Set<T>
where
T: serde::Deserialize<'a> + Eq + Hash + Ord,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'a>,
{
Ok(Set {
inner: serde::Deserialize::deserialize(deserializer)?,
})
}
}

0 comments on commit f3128ea

Please sign in to comment.