diff --git a/Cargo.lock b/Cargo.lock index d35fb2f938..31c4c940d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1338,6 +1338,7 @@ dependencies = [ "peepmatic-automata", "peepmatic-macro", "serde", + "serde_test", "thiserror", "wast 15.0.0", ] @@ -1881,6 +1882,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_test" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58190d074af17bd48118303db08afadbd506bc2ba511b4582cebd8f882a9b8d" +dependencies = [ + "serde", +] + [[package]] name = "sha2" version = "0.8.2" diff --git a/cranelift/codegen/src/preopt.serialized b/cranelift/codegen/src/preopt.serialized index f016c6d32d..bae915dab0 100644 Binary files a/cranelift/codegen/src/preopt.serialized and b/cranelift/codegen/src/preopt.serialized differ diff --git a/cranelift/peepmatic/crates/runtime/Cargo.toml b/cranelift/peepmatic/crates/runtime/Cargo.toml index 75b73388dd..fe21c3defd 100644 --- a/cranelift/peepmatic/crates/runtime/Cargo.toml +++ b/cranelift/peepmatic/crates/runtime/Cargo.toml @@ -18,6 +18,8 @@ serde = { version = "1.0.105", features = ["derive"] } thiserror = "1.0.15" wast = { version = "15.0.0", optional = true } +[dev-dependencies] +serde_test = "1.0.114" [features] # Enable support for a few extra methods that are required by the `peepmatic` diff --git a/cranelift/peepmatic/crates/runtime/src/integer_interner.rs b/cranelift/peepmatic/crates/runtime/src/integer_interner.rs index 996100a66d..035027c2a2 100644 --- a/cranelift/peepmatic/crates/runtime/src/integer_interner.rs +++ b/cranelift/peepmatic/crates/runtime/src/integer_interner.rs @@ -5,8 +5,12 @@ //! few compared to the full range of `u64`) integers we are matching against //! here and then reference them by `IntegerId`. +use serde::de::{Deserializer, SeqAccess, Visitor}; +use serde::ser::{SerializeSeq, Serializer}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; +use std::fmt; +use std::marker::PhantomData; use std::num::{NonZeroU16, NonZeroU32}; /// An identifier for an interned integer. @@ -14,7 +18,7 @@ use std::num::{NonZeroU16, NonZeroU32}; pub struct IntegerId(#[doc(hidden)] pub NonZeroU16); /// An interner for integer values. -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Default)] pub struct IntegerInterner { // Note: we use `BTreeMap`s for deterministic serialization. map: BTreeMap, @@ -71,3 +75,118 @@ impl From for NonZeroU32 { id.0.into() } } + +impl Serialize for IntegerInterner { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.values.len()))?; + for p in &self.values { + seq.serialize_element(&p)?; + } + seq.end() + } +} + +impl<'de> Deserialize<'de> for IntegerInterner { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(IntegerInternerVisitor { + marker: PhantomData, + }) + } +} + +struct IntegerInternerVisitor { + marker: PhantomData IntegerInterner>, +} + +impl<'de> Visitor<'de> for IntegerInternerVisitor { + type Value = IntegerInterner; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "a `peepmatic_runtime::integer_interner::IntegerInterner`" + ) + } + + fn visit_seq(self, mut access: M) -> Result + where + M: SeqAccess<'de>, + { + const DEFAULT_CAPACITY: usize = 16; + let capacity = access.size_hint().unwrap_or(DEFAULT_CAPACITY); + + let mut interner = IntegerInterner { + map: BTreeMap::new(), + values: Vec::with_capacity(capacity), + }; + + while let Some(path) = access.next_element::()? { + interner.intern(path); + } + + Ok(interner) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_test::{assert_tokens, Token}; + use std::iter::successors; + + #[derive(Debug, Serialize, Deserialize)] + #[serde(transparent)] + pub struct OrderedIntegerInterner(IntegerInterner); + + impl PartialEq for OrderedIntegerInterner { + fn eq(&self, other: &OrderedIntegerInterner) -> bool { + self.0.values.iter().eq(other.0.values.iter()) + } + } + + fn intern_fib(interner: &mut IntegerInterner, skip: usize, take: usize) { + successors(Some((0, 1)), |(a, b): &(u64, u64)| { + a.checked_add(*b).map(|c| (*b, c)) + }) + .skip(skip) + .take(take) + .for_each(|(i, _)| { + interner.intern(i); + }) + } + + #[test] + fn test_ser_de_empty_interner() { + let interner = IntegerInterner::new(); + + assert_tokens( + &OrderedIntegerInterner(interner), + &[Token::Seq { len: Some(0) }, Token::SeqEnd], + ); + } + + #[test] + fn test_ser_de_fibonacci_interner() { + let mut interner = IntegerInterner::new(); + intern_fib(&mut interner, 10, 5); + + assert_tokens( + &OrderedIntegerInterner(interner), + &[ + Token::Seq { len: Some(5) }, + Token::U64(55), + Token::U64(89), + Token::U64(144), + Token::U64(233), + Token::U64(377), + Token::SeqEnd, + ], + ); + } +}