Skip to content

Commit

Permalink
chore(rpc): move SerializeForVersion into the dto module
Browse files Browse the repository at this point in the history
  • Loading branch information
t00ts committed Jan 7, 2025
1 parent cab975c commit 926fbb5
Show file tree
Hide file tree
Showing 63 changed files with 823 additions and 838 deletions.
238 changes: 235 additions & 3 deletions crates/rpc/src/dto.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(unused)]

use serde::de::{Error, IntoDeserializer};
use serde::de::{Error as SerdeError, IntoDeserializer};

mod block;
mod class;
Expand All @@ -12,8 +12,6 @@ mod simulation;
mod state_update;
mod transaction;

pub mod serialize;

pub use block::*;
pub use class::*;
pub use event::*;
Expand All @@ -26,6 +24,135 @@ pub use transaction::*;

use crate::RpcVersion;

#[derive(Copy, Clone)]
#[cfg_attr(test, derive(Default))]
pub struct Serializer {
pub version: RpcVersion,
}

pub struct SerializeStruct {
pub version: RpcVersion,
fields: serde_json::Map<String, Ok>,
}

type BaseSerializer = serde_json::value::Serializer;
pub(crate) type Ok = <BaseSerializer as serde::Serializer>::Ok;
pub(crate) type Error = <BaseSerializer as serde::Serializer>::Error;

pub trait SerializeForVersion {
fn serialize(&self, serializer: Serializer) -> Result<Ok, Error>;
}

// This blanket implementation should be removed once all existing DTOs have
// been migrated.
impl<T> SerializeForVersion for T
where
T: serde::Serialize,
{
fn serialize(&self, _serializer: Serializer) -> Result<Ok, Error> {
self.serialize(BaseSerializer {})
}
}

impl Serializer {
pub fn new(version: RpcVersion) -> Self {
Self { version }
}

pub fn serialize(self, value: &dyn SerializeForVersion) -> Result<Ok, Error> {
value.serialize(self)
}

pub fn serialize_str(self, value: &str) -> Result<Ok, Error> {
use serde::Serializer;
BaseSerializer {}.serialize_str(value)
}

pub fn serialize_u64(self, value: u64) -> Result<Ok, Error> {
use serde::Serializer;
BaseSerializer {}.serialize_u64(value)
}

pub fn serialize_bool(self, value: bool) -> Result<Ok, Error> {
use serde::Serializer;
BaseSerializer {}.serialize_bool(value)
}

pub fn serialize_struct(self) -> Result<SerializeStruct, Error> {
Ok(SerializeStruct {
version: self.version,
fields: Default::default(),
})
}

pub fn serialize_iter(
self,
len: usize,
values: &mut dyn Iterator<Item = impl SerializeForVersion>,
) -> Result<Ok, Error> {
use serde::ser::SerializeSeq;
use serde::Serializer;

let mut serializer = BaseSerializer {}.serialize_seq(Some(len))?;
for value in values {
let value = self.serialize(&value)?;
serializer.serialize_element(&value)?;
}
serializer.end()
}
}

impl SerializeStruct {
pub fn serialize_field(
&mut self,
key: &'static str,
value: &dyn SerializeForVersion,
) -> Result<(), Error> {
let value = value.serialize(Serializer::new(self.version))?;
self.fields.insert(key.to_owned(), value);
Ok(())
}

pub fn serialize_iter(
&mut self,
key: &'static str,
len: usize,
values: &mut dyn Iterator<Item = impl SerializeForVersion>,
) -> Result<(), Error> {
let seq = Serializer::new(self.version).serialize_iter(len, values)?;
self.serialize_field(key, &seq)
}

/// Skips serialization if its [`None`].
pub fn serialize_optional(
&mut self,
key: &'static str,
value: Option<impl SerializeForVersion>,
) -> Result<(), Error> {
if let Some(value) = value {
self.serialize_field(key, &value)?;
}

Ok(())
}

pub fn flatten(&mut self, value: &dyn SerializeForVersion) -> Result<(), Error> {
let value = value.serialize(Serializer::new(self.version))?;

if let serde_json::Value::Object(value) = value {
for (k, v) in value {
self.fields.insert(k, v);
}
}

Ok(())
}

pub fn end(self) -> Result<Ok, Error> {
Ok(serde_json::Value::Object(self.fields))
}
}

pub trait DeserializeForVersion: Sized {
fn deserialize(value: Value) -> Result<Self, serde_json::Error>;
}
Expand Down Expand Up @@ -448,3 +575,108 @@ impl Map {
}
}
}

#[cfg(test)]
mod tests {
use serde_json::json;

use super::*;

mod serialize {
use super::*;

#[test]
fn str() {
let encoded = Serializer::default().serialize_str("value").unwrap();
assert_eq!(encoded, json!("value"));
}

#[test]
fn u64() {
let encoded = Serializer::default().serialize_u64(123).unwrap();
assert_eq!(encoded, json!(123));
}

#[test]
fn bool() {
let encoded_true = Serializer::default().serialize_bool(true).unwrap();
assert_eq!(encoded_true, json!(true));

let encoded_false = Serializer::default().serialize_bool(false).unwrap();
assert_eq!(encoded_false, json!(false));
}
}

mod serialize_struct {
use super::*;

#[test]
fn version_carries_over() {
let uut = Serializer::new(RpcVersion::PathfinderV01)
.serialize_struct()
.unwrap();
assert_eq!(uut.version, RpcVersion::PathfinderV01);
}

#[test]
fn optional() {
let mut uut = Serializer::default().serialize_struct().unwrap();
uut.serialize_optional("missing", None::<u64>).unwrap();
uut.serialize_optional("present", Some(200u64)).unwrap();
let encoded = uut.end().unwrap();
let expected = json!({"present": 200u64});

assert_eq!(encoded, expected);
}

#[test]
fn iter() {
let empty = vec![0u64; 0];
let count = vec![0u64, 1, 2, 3];

let mut uut = Serializer::default().serialize_struct().unwrap();
uut.serialize_iter("empty", 0, &mut empty.iter()).unwrap();
uut.serialize_iter("count", 0, &mut count.iter()).unwrap();
let encoded = uut.end().unwrap();
let expected = json!({
"count": count,
"empty": empty,
});

assert_eq!(encoded, expected);
}

#[test]
fn flatten() {
struct TypeX(u64);
impl SerializeForVersion for TypeX {
fn serialize(&self, serializer: Serializer) -> Result<Ok, Error> {
let mut serializer = serializer.serialize_struct()?;
serializer.serialize_field("x", &self.0);
serializer.end()
}
}

let mut uut = Serializer::default().serialize_struct().unwrap();
uut.serialize_field("y", &200u64).unwrap();
uut.flatten(&TypeX(300)).unwrap();
let encoded = uut.end().unwrap();

let expected = json!({
"x": 300,
"y": 200,
});

assert_eq!(encoded, expected);
}

#[test]
fn field() {
let mut uut = Serializer::default().serialize_struct().unwrap();
uut.serialize_field("field", &"value").unwrap();
let encoded = uut.end().unwrap();
let expected = json!({"field": "value"});
assert_eq!(encoded, expected);
}
}
}
26 changes: 13 additions & 13 deletions crates/rpc/src/dto/block.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use pathfinder_common::{GasPrice, L1DataAvailabilityMode};
use serde::de::Error;

use super::serialize::SerializeStruct;
use crate::dto::SerializeStruct;
use crate::{Reorg, RpcVersion};

#[derive(Debug)]
Expand Down Expand Up @@ -38,11 +38,11 @@ impl crate::dto::DeserializeForVersion for pathfinder_common::BlockId {
}
}

impl crate::dto::serialize::SerializeForVersion for BlockHeader<'_> {
impl crate::dto::SerializeForVersion for BlockHeader<'_> {
fn serialize(
&self,
serializer: super::serialize::Serializer,
) -> Result<super::serialize::Ok, super::serialize::Error> {
serializer: crate::dto::Serializer,
) -> Result<crate::dto::Ok, crate::dto::Error> {
let mut serializer = serializer.serialize_struct()?;
serializer.serialize_field("block_hash", &crate::dto::Felt(&self.0.hash.0))?;
serializer.serialize_field("parent_hash", &crate::dto::Felt(&self.0.parent_hash.0))?;
Expand Down Expand Up @@ -88,11 +88,11 @@ impl crate::dto::serialize::SerializeForVersion for BlockHeader<'_> {
}
}

impl crate::dto::serialize::SerializeForVersion for PendingBlockHeader<'_> {
impl crate::dto::SerializeForVersion for PendingBlockHeader<'_> {
fn serialize(
&self,
serializer: super::serialize::Serializer,
) -> Result<super::serialize::Ok, super::serialize::Error> {
serializer: crate::dto::Serializer,
) -> Result<crate::dto::Ok, crate::dto::Error> {
let mut serializer = serializer.serialize_struct()?;
serializer.serialize_field("parent_hash", &crate::dto::Felt(&self.0.parent_hash.0))?;
serializer.serialize_field("timestamp", &self.0.timestamp.get())?;
Expand Down Expand Up @@ -141,23 +141,23 @@ struct ResourcePrice {
pub price_in_fri: GasPrice,
}

impl crate::dto::serialize::SerializeForVersion for ResourcePrice {
impl crate::dto::SerializeForVersion for ResourcePrice {
fn serialize(
&self,
serializer: super::serialize::Serializer,
) -> Result<super::serialize::Ok, super::serialize::Error> {
serializer: crate::dto::Serializer,
) -> Result<crate::dto::Ok, crate::dto::Error> {
let mut serializer = serializer.serialize_struct()?;
serializer.serialize_field("price_in_wei", &crate::dto::U128Hex(self.price_in_wei.0))?;
serializer.serialize_field("price_in_fri", &crate::dto::U128Hex(self.price_in_fri.0))?;
serializer.end()
}
}

impl crate::dto::serialize::SerializeForVersion for Reorg {
impl crate::dto::SerializeForVersion for Reorg {
fn serialize(
&self,
serializer: super::serialize::Serializer,
) -> Result<super::serialize::Ok, super::serialize::Error> {
serializer: crate::dto::Serializer,
) -> Result<crate::dto::Ok, crate::dto::Error> {
let mut serializer = serializer.serialize_struct()?;
serializer.serialize_field("first_block_number", &self.first_block_number.get())?;
serializer.serialize_field(
Expand Down
Loading

0 comments on commit 926fbb5

Please sign in to comment.