mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-22 14:24:44 +00:00
Re-export context_deserialize_derive inside context_deserialize (#7852)
Re-export `context_deserialize_derive` inside of `context_deserialize` so they are both available from the same interface, which matches how popular crates (like `serde`) handle this. This also nests both crates inside a new `context_deserialize` directory which will make it easier to eventually spin out into a different repo (if/when) we decide to do that (plus I prefer it aesthetically).
This commit is contained in:
17
consensus/context_deserialize/context_deserialize/Cargo.toml
Normal file
17
consensus/context_deserialize/context_deserialize/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "context_deserialize"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["derive"]
|
||||
derive = ["dep:context_deserialize_derive"]
|
||||
milhouse = ["dep:milhouse"]
|
||||
ssz = ["dep:ssz_types"]
|
||||
all = ["derive", "milhouse", "ssz"]
|
||||
|
||||
[dependencies]
|
||||
context_deserialize_derive = { version = "0.1.0", path = "../context_deserialize_derive", optional = true }
|
||||
milhouse = { workspace = true, optional = true }
|
||||
serde = { workspace = true }
|
||||
ssz_types = { workspace = true, optional = true }
|
||||
@@ -0,0 +1,103 @@
|
||||
use crate::ContextDeserialize;
|
||||
use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl<'de, C, T> ContextDeserialize<'de, T> for Arc<C>
|
||||
where
|
||||
C: ContextDeserialize<'de, T>,
|
||||
{
|
||||
fn context_deserialize<D>(deserializer: D, context: T) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(Arc::new(C::context_deserialize(deserializer, context)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T, C> ContextDeserialize<'de, C> for Vec<T>
|
||||
where
|
||||
T: ContextDeserialize<'de, C>,
|
||||
C: Clone,
|
||||
{
|
||||
fn context_deserialize<D>(deserializer: D, context: C) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// Our Visitor, which owns one copy of the context T
|
||||
struct ContextVisitor<C, T> {
|
||||
context: T,
|
||||
_marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<'de, C, T> Visitor<'de> for ContextVisitor<C, T>
|
||||
where
|
||||
C: ContextDeserialize<'de, T>,
|
||||
T: Clone,
|
||||
{
|
||||
type Value = Vec<C>;
|
||||
|
||||
fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fmt.write_str("a sequence of context‐deserialized elements")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Vec<C>, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
let mut out = Vec::with_capacity(seq.size_hint().unwrap_or(0));
|
||||
// for each element, we clone the context and hand it to the seed
|
||||
while let Some(elem) = seq.next_element_seed(ContextSeed {
|
||||
context: self.context.clone(),
|
||||
_marker: PhantomData,
|
||||
})? {
|
||||
out.push(elem);
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
// A little seed that hands the deserializer + context into C::context_deserialize
|
||||
struct ContextSeed<T, C> {
|
||||
context: C,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'de, T, C> DeserializeSeed<'de> for ContextSeed<T, C>
|
||||
where
|
||||
T: ContextDeserialize<'de, C>,
|
||||
C: Clone,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::context_deserialize(deserializer, self.context)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_seq(ContextVisitor {
|
||||
context,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! trivial_deserialize {
|
||||
($($t:ty),* $(,)?) => {
|
||||
$(
|
||||
impl<'de, T> ContextDeserialize<'de, T> for $t {
|
||||
fn context_deserialize<D>(deserializer: D, _context: T) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
<$t>::deserialize(deserializer)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
trivial_deserialize!(bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
|
||||
@@ -0,0 +1,45 @@
|
||||
use crate::ContextDeserialize;
|
||||
use milhouse::{List, Value, Vector};
|
||||
use serde::de::Deserializer;
|
||||
use ssz_types::typenum::Unsigned;
|
||||
|
||||
impl<'de, C, T, N> ContextDeserialize<'de, C> for List<T, N>
|
||||
where
|
||||
T: ContextDeserialize<'de, C> + Value,
|
||||
N: Unsigned,
|
||||
C: Clone,
|
||||
{
|
||||
fn context_deserialize<D>(deserializer: D, context: C) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// First deserialize as a Vec.
|
||||
// This is not the most efficient implementation as it allocates a temporary Vec. In future
|
||||
// we could write a more performant implementation using `List::builder()`.
|
||||
let vec = Vec::<T>::context_deserialize(deserializer, context)?;
|
||||
|
||||
// Then convert to List, which will check the length.
|
||||
List::new(vec)
|
||||
.map_err(|e| serde::de::Error::custom(format!("Failed to create List: {:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, C, T, N> ContextDeserialize<'de, C> for Vector<T, N>
|
||||
where
|
||||
T: ContextDeserialize<'de, C> + Value,
|
||||
N: Unsigned,
|
||||
C: Clone,
|
||||
{
|
||||
fn context_deserialize<D>(deserializer: D, context: C) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// First deserialize as a List
|
||||
let list = List::<T, N>::context_deserialize(deserializer, context)?;
|
||||
|
||||
// Then convert to Vector, which will check the length
|
||||
Vector::try_from(list).map_err(|e| {
|
||||
serde::de::Error::custom(format!("Failed to convert List to Vector: {:?}", e))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
mod core;
|
||||
|
||||
#[cfg(feature = "milhouse")]
|
||||
mod milhouse;
|
||||
|
||||
#[cfg(feature = "ssz")]
|
||||
mod ssz;
|
||||
@@ -0,0 +1,51 @@
|
||||
use crate::ContextDeserialize;
|
||||
use serde::{
|
||||
de::{Deserializer, Error},
|
||||
Deserialize,
|
||||
};
|
||||
use ssz_types::{
|
||||
length::{Fixed, Variable},
|
||||
typenum::Unsigned,
|
||||
Bitfield, FixedVector,
|
||||
};
|
||||
|
||||
impl<'de, C, T, N> ContextDeserialize<'de, C> for FixedVector<T, N>
|
||||
where
|
||||
T: ContextDeserialize<'de, C>,
|
||||
N: Unsigned,
|
||||
C: Clone,
|
||||
{
|
||||
fn context_deserialize<D>(deserializer: D, context: C) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let vec = Vec::<T>::context_deserialize(deserializer, context)?;
|
||||
FixedVector::new(vec).map_err(|e| D::Error::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, C, N> ContextDeserialize<'de, C> for Bitfield<Variable<N>>
|
||||
where
|
||||
N: Unsigned + Clone,
|
||||
{
|
||||
fn context_deserialize<D>(deserializer: D, _context: C) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Bitfield::<Variable<N>>::deserialize(deserializer)
|
||||
.map_err(|e| D::Error::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, C, N> ContextDeserialize<'de, C> for Bitfield<Fixed<N>>
|
||||
where
|
||||
N: Unsigned + Clone,
|
||||
{
|
||||
fn context_deserialize<D>(deserializer: D, _context: C) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Bitfield::<Fixed<N>>::deserialize(deserializer)
|
||||
.map_err(|e| D::Error::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
13
consensus/context_deserialize/context_deserialize/src/lib.rs
Normal file
13
consensus/context_deserialize/context_deserialize/src/lib.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
mod impls;
|
||||
|
||||
#[cfg(feature = "derive")]
|
||||
pub use context_deserialize_derive::context_deserialize;
|
||||
|
||||
use serde::de::Deserializer;
|
||||
|
||||
/// General-purpose deserialization trait that accepts extra context `C`.
|
||||
pub trait ContextDeserialize<'de, C>: Sized {
|
||||
fn context_deserialize<D>(deserializer: D, context: C) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>;
|
||||
}
|
||||
Reference in New Issue
Block a user