|
@ -5,8 +5,12 @@ |
|
|
//! few compared to the full range of `u64`) integers we are matching against
|
|
|
//! few compared to the full range of `u64`) integers we are matching against
|
|
|
//! here and then reference them by `IntegerId`.
|
|
|
//! here and then reference them by `IntegerId`.
|
|
|
|
|
|
|
|
|
|
|
|
use serde::de::{Deserializer, SeqAccess, Visitor}; |
|
|
|
|
|
use serde::ser::{SerializeSeq, Serializer}; |
|
|
use serde::{Deserialize, Serialize}; |
|
|
use serde::{Deserialize, Serialize}; |
|
|
use std::collections::BTreeMap; |
|
|
use std::collections::BTreeMap; |
|
|
|
|
|
use std::fmt; |
|
|
|
|
|
use std::marker::PhantomData; |
|
|
use std::num::{NonZeroU16, NonZeroU32}; |
|
|
use std::num::{NonZeroU16, NonZeroU32}; |
|
|
|
|
|
|
|
|
/// An identifier for an interned integer.
|
|
|
/// An identifier for an interned integer.
|
|
@ -14,7 +18,7 @@ use std::num::{NonZeroU16, NonZeroU32}; |
|
|
pub struct IntegerId(#[doc(hidden)] pub NonZeroU16); |
|
|
pub struct IntegerId(#[doc(hidden)] pub NonZeroU16); |
|
|
|
|
|
|
|
|
/// An interner for integer values.
|
|
|
/// An interner for integer values.
|
|
|
#[derive(Debug, Default, Serialize, Deserialize)] |
|
|
#[derive(Debug, Default)] |
|
|
pub struct IntegerInterner { |
|
|
pub struct IntegerInterner { |
|
|
// Note: we use `BTreeMap`s for deterministic serialization.
|
|
|
// Note: we use `BTreeMap`s for deterministic serialization.
|
|
|
map: BTreeMap<u64, IntegerId>, |
|
|
map: BTreeMap<u64, IntegerId>, |
|
@ -71,3 +75,118 @@ impl From<IntegerId> for NonZeroU32 { |
|
|
id.0.into() |
|
|
id.0.into() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Serialize for IntegerInterner { |
|
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
|
|
|
|
|
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<D>(deserializer: D) -> Result<Self, D::Error> |
|
|
|
|
|
where |
|
|
|
|
|
D: Deserializer<'de>, |
|
|
|
|
|
{ |
|
|
|
|
|
deserializer.deserialize_seq(IntegerInternerVisitor { |
|
|
|
|
|
marker: PhantomData, |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct IntegerInternerVisitor { |
|
|
|
|
|
marker: PhantomData<fn() -> 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<M>(self, mut access: M) -> Result<Self::Value, M::Error> |
|
|
|
|
|
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::<u64>()? { |
|
|
|
|
|
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, |
|
|
|
|
|
], |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|