-
Notifications
You must be signed in to change notification settings - Fork 808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Merged by Bors] - add quoted serialization util for FixedVector
and VariableList
#1794
Changes from 4 commits
717a0d7
57bdc63
f8fc03b
1d0a2d6
a3fed2a
16c94c4
02a60c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,7 @@ | |
#[macro_use] | ||
mod bitfield; | ||
mod fixed_vector; | ||
pub mod serde_utils; | ||
mod tree_hash; | ||
mod variable_list; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod quoted_u64_fixed_vec; | ||
pub mod quoted_u64_var_list; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
//! Formats `FixedVector<u64,N>` using quotes. | ||
//! | ||
//! E.g., `FixedVector::from(vec![0, 1, 2])` serializes as `["0", "1", "2"]`. | ||
//! | ||
//! Quotes can be optional during decoding. If `N` does not equal the length of the `Vec`, the `Vec` is truncated. | ||
|
||
use crate::FixedVector; | ||
use serde::ser::SerializeSeq; | ||
use serde::{Deserializer, Serializer}; | ||
use serde_utils::quoted_u64_vec::QuotedIntWrapper; | ||
use std::marker::PhantomData; | ||
use typenum::Unsigned; | ||
|
||
pub struct QuotedIntFixedVecVisitor<N> { | ||
_phantom: PhantomData<N>, | ||
} | ||
|
||
impl<'a, N> serde::de::Visitor<'a> for QuotedIntFixedVecVisitor<N> | ||
where | ||
N: Unsigned, | ||
{ | ||
type Value = FixedVector<u64, N>; | ||
|
||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
write!(formatter, "a list of quoted or unquoted integers") | ||
} | ||
|
||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> | ||
where | ||
A: serde::de::SeqAccess<'a>, | ||
{ | ||
let mut vec = vec![]; | ||
|
||
while let Some(val) = seq.next_element()? { | ||
let val: QuotedIntWrapper = val; | ||
vec.push(val.int); | ||
} | ||
let fix: FixedVector<u64, N> = FixedVector::new(vec) | ||
.map_err(|e| serde::de::Error::custom(format!("FixedVector: {:?}", e)))?; | ||
Ok(fix) | ||
} | ||
} | ||
|
||
pub fn serialize<S>(value: &[u64], serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: Serializer, | ||
{ | ||
let mut seq = serializer.serialize_seq(Some(value.len()))?; | ||
for &int in value { | ||
seq.serialize_element(&QuotedIntWrapper { int })?; | ||
} | ||
seq.end() | ||
} | ||
|
||
pub fn deserialize<'de, D, N>(deserializer: D) -> Result<FixedVector<u64, N>, D::Error> | ||
where | ||
D: Deserializer<'de>, | ||
N: Unsigned, | ||
{ | ||
deserializer.deserialize_any(QuotedIntFixedVecVisitor { | ||
_phantom: PhantomData, | ||
}) | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
use serde_derive::{Deserialize, Serialize}; | ||
use typenum::U4; | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
struct Obj { | ||
#[serde(with = "crate::serde_utils::quoted_u64_fixed_vec")] | ||
values: FixedVector<u64, U4>, | ||
} | ||
|
||
#[test] | ||
fn quoted_list_success() { | ||
let obj: Obj = serde_json::from_str(r#"{ "values": ["1", "2", "3", "4"] }"#).unwrap(); | ||
let expected: FixedVector<u64, U4> = FixedVector::from(vec![1, 2, 3, 4]); | ||
assert_eq!(obj.values, expected); | ||
} | ||
|
||
#[test] | ||
fn unquoted_list_success() { | ||
let obj: Obj = serde_json::from_str(r#"{ "values": [1, 2, 3, 4] }"#).unwrap(); | ||
let expected: FixedVector<u64, U4> = FixedVector::from(vec![1, 2, 3, 4]); | ||
assert_eq!(obj.values, expected); | ||
} | ||
|
||
#[test] | ||
fn mixed_list_success() { | ||
let obj: Obj = serde_json::from_str(r#"{ "values": ["1", 2, "3", "4"] }"#).unwrap(); | ||
let expected: FixedVector<u64, U4> = FixedVector::from(vec![1, 2, 3, 4]); | ||
assert_eq!(obj.values, expected); | ||
} | ||
|
||
#[test] | ||
fn empty_list_err() { | ||
serde_json::from_str::<Obj>(r#"{ "values": [] }"#).unwrap_err(); | ||
} | ||
|
||
#[test] | ||
fn short_list_err() { | ||
serde_json::from_str::<Obj>(r#"{ "values": [1, 2] }"#).unwrap_err(); | ||
} | ||
|
||
#[test] | ||
fn long_list_err() { | ||
serde_json::from_str::<Obj>(r#"{ "values": [1, 2, 3, 4, 5] }"#).unwrap_err(); | ||
} | ||
|
||
#[test] | ||
fn whole_list_quoted_err() { | ||
serde_json::from_str::<Obj>(r#"{ "values": "[1, 2, 3, 4]" }"#).unwrap_err(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,120 @@ | ||||||
//! Formats `VariableList<u64,N>` using quotes. | ||||||
//! | ||||||
//! E.g., `VariableList::from(vec![0, 1, 2])` serializes as `["0", "1", "2"]`. | ||||||
//! | ||||||
//! Quotes can be optional during decoding. If `N` is greater than the length of the `Vec`, the `Vec` is truncated. | ||||||
|
||||||
use crate::VariableList; | ||||||
use serde::ser::SerializeSeq; | ||||||
use serde::{Deserializer, Serializer}; | ||||||
use serde_utils::quoted_u64_vec::QuotedIntWrapper; | ||||||
use std::marker::PhantomData; | ||||||
use typenum::Unsigned; | ||||||
|
||||||
pub struct QuotedIntVarListVisitor<N> { | ||||||
_phantom: PhantomData<N>, | ||||||
} | ||||||
|
||||||
impl<'a, N> serde::de::Visitor<'a> for QuotedIntVarListVisitor<N> | ||||||
where | ||||||
N: Unsigned, | ||||||
{ | ||||||
type Value = VariableList<u64, N>; | ||||||
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
write!(formatter, "a list of quoted or unquoted integers") | ||||||
} | ||||||
|
||||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> | ||||||
where | ||||||
A: serde::de::SeqAccess<'a>, | ||||||
{ | ||||||
let mut vec = vec![]; | ||||||
|
||||||
while let Some(val) = seq.next_element()? { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That |
||||||
let val: QuotedIntWrapper = val; | ||||||
vec.push(val.int); | ||||||
} | ||||||
let fix: VariableList<u64, N> = VariableList::new(vec) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
.map_err(|e| serde::de::Error::custom(format!("VariableList: {:?}", e)))?; | ||||||
Ok(fix) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
} | ||||||
|
||||||
pub fn serialize<S>(value: &[u64], serializer: S) -> Result<S::Ok, S::Error> | ||||||
where | ||||||
S: Serializer, | ||||||
{ | ||||||
let mut seq = serializer.serialize_seq(Some(value.len()))?; | ||||||
for &int in value { | ||||||
seq.serialize_element(&QuotedIntWrapper { int })?; | ||||||
} | ||||||
seq.end() | ||||||
} | ||||||
|
||||||
pub fn deserialize<'de, D, N>(deserializer: D) -> Result<VariableList<u64, N>, D::Error> | ||||||
where | ||||||
D: Deserializer<'de>, | ||||||
N: Unsigned, | ||||||
{ | ||||||
deserializer.deserialize_any(QuotedIntVarListVisitor { | ||||||
_phantom: PhantomData, | ||||||
}) | ||||||
} | ||||||
|
||||||
#[cfg(test)] | ||||||
mod test { | ||||||
use super::*; | ||||||
use serde_derive::{Deserialize, Serialize}; | ||||||
use typenum::U4; | ||||||
|
||||||
#[derive(Debug, Serialize, Deserialize)] | ||||||
struct Obj { | ||||||
#[serde(with = "crate::serde_utils::quoted_u64_var_list")] | ||||||
values: VariableList<u64, U4>, | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn quoted_list_success() { | ||||||
let obj: Obj = serde_json::from_str(r#"{ "values": ["1", "2", "3", "4"] }"#).unwrap(); | ||||||
let expected: VariableList<u64, U4> = VariableList::from(vec![1, 2, 3, 4]); | ||||||
assert_eq!(obj.values, expected); | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn unquoted_list_success() { | ||||||
let obj: Obj = serde_json::from_str(r#"{ "values": [1, 2, 3, 4] }"#).unwrap(); | ||||||
let expected: VariableList<u64, U4> = VariableList::from(vec![1, 2, 3, 4]); | ||||||
assert_eq!(obj.values, expected); | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn mixed_list_success() { | ||||||
let obj: Obj = serde_json::from_str(r#"{ "values": ["1", 2, "3", "4"] }"#).unwrap(); | ||||||
let expected: VariableList<u64, U4> = VariableList::from(vec![1, 2, 3, 4]); | ||||||
assert_eq!(obj.values, expected); | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn empty_list_success() { | ||||||
let obj: Obj = serde_json::from_str(r#"{ "values": [] }"#).unwrap(); | ||||||
assert!(obj.values.is_empty()); | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn short_list_success() { | ||||||
let obj: Obj = serde_json::from_str(r#"{ "values": [1, 2] }"#).unwrap(); | ||||||
let expected: VariableList<u64, U4> = VariableList::from(vec![1, 2]); | ||||||
assert_eq!(obj.values, expected); | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn long_list_err() { | ||||||
serde_json::from_str::<Obj>(r#"{ "values": [1, 2, 3, 4, 5] }"#).unwrap_err(); | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn whole_list_quoted_err() { | ||||||
serde_json::from_str::<Obj>(r#"{ "values": "[1, 2, 3, 4]" }"#).unwrap_err(); | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -320,7 +320,8 @@ mod test { | |
|
||
let vec = vec![]; | ||
let fixed: VariableList<u64, U4> = VariableList::from(vec); | ||
assert_eq!(&fixed[..], &vec![][..]); | ||
let expected: Vec<u64> = vec![]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is weird that the modules caused the change tho. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated 👍 |
||
assert_eq!(&fixed[..], &expected[..]); | ||
} | ||
|
||
#[test] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't clear on this before, but I think we should add a safe-guard against growing
vec
greater thanN::to_usize()
. I was tempted to just leave it as is, but some of the vulnerabilities observed inssz
have made me weary of over-allocating.E.g., (I'm not sure if this compiles)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, makes sense. Updated 👍