Skip to content

Commit

Permalink
Merge branch 'main' into donovan/eigen-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Tjemmmic committed Nov 13, 2024
2 parents 013b6f7 + 47edd9a commit f736638
Show file tree
Hide file tree
Showing 58 changed files with 944 additions and 889 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions blueprint-serde/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub enum Error {
UnsupportedType(UnsupportedType),
/// Attempting to deserialize a [`char`] from a [`Field::String`](crate::Field::String)
BadCharLength(usize),
HeterogeneousTuple,
FromUtf8Error(alloc::string::FromUtf8Error),
Other(String),
}
Expand Down Expand Up @@ -79,6 +80,12 @@ impl Display for Error {
Error::BadCharLength(len) => {
write!(f, "String contains {len} characters, expected 1")
}
Error::HeterogeneousTuple => {
write!(
f,
"Attempted to serialize heterogeneous tuple, not currently supported"
)
}
Error::FromUtf8Error(e) => write!(f, "{e}"),
Error::Other(msg) => write!(f, "{}", msg),
}
Expand Down
2 changes: 1 addition & 1 deletion blueprint-serde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! use gadget_blueprint_serde::{new_bounded_string, BoundedVec, Field};
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Serialize, Deserialize)]
//! #[derive(PartialEq, Debug, Serialize, Deserialize)]
//! struct Person {
//! name: String,
//! age: u8,
Expand Down
52 changes: 51 additions & 1 deletion blueprint-serde/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,52 @@ pub struct SerializeSeq<'a> {
vec: Vec<Field<AccountId32>>,
}

impl SerializeSeq<'_> {
fn is_homogeneous(&self) -> bool {
if self.vec.is_empty() {
return true;
}

macro_rules! homogeneous_check {
($($field:pat),+ $(,)?) => {
paste::paste! {
match &self.vec[0] {
$($field => { self.vec.iter().all(|f| matches!(f, $field)) },)+
Field::Struct(name, fields) => {
self.vec.iter().all(|f| {
match f {
Field::Struct(n, f) => {
n == name && fields == f
},
_ => false,
}
})
}
}
}
}
}

homogeneous_check!(
Field::None,
Field::Bool(_),
Field::Uint8(_),
Field::Int8(_),
Field::Uint16(_),
Field::Int16(_),
Field::Uint32(_),
Field::Int32(_),
Field::Uint64(_),
Field::Int64(_),
Field::String(_),
Field::Bytes(_),
Field::Array(_),
Field::List(_),
Field::AccountId(_),
)
}
}

impl ser::SerializeSeq for SerializeSeq<'_> {
type Ok = Field<AccountId32>;
type Error = crate::error::Error;
Expand Down Expand Up @@ -232,7 +278,11 @@ impl ser::SerializeTuple for SerializeSeq<'_> {

#[inline]
fn end(self) -> Result<Self::Ok> {
<SerializeSeq<'_> as ser::SerializeSeq>::end(self)
if self.is_homogeneous() {
return Ok(Field::Array(BoundedVec(self.vec)));
}

Err(crate::error::Error::HeterogeneousTuple)
}
}

Expand Down
190 changes: 190 additions & 0 deletions blueprint-serde/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,193 @@ mod primitives {
i64 => 0, Token::I64, Field::Int64;
);
}

mod sequences {
use super::*;
use alloc::vec::Vec;

fn expected_vec_field() -> Field<AccountId32> {
Field::List(BoundedVec(vec![
Field::Uint32(1),
Field::Uint32(2),
Field::Uint32(3),
]))
}

#[test]
fn test_ser_vec() {
let vec: Vec<u32> = vec![1, 2, 3];

assert_ser_tokens(
&vec,
&[
Token::Seq { len: Some(3) },
Token::U32(1),
Token::U32(2),
Token::U32(3),
Token::SeqEnd,
],
);

let field = to_field(&vec).unwrap();
assert_eq!(field, expected_vec_field());
}

#[test]
fn test_de_vec() {
let vec: Vec<u32> = vec![1, 2, 3];

assert_de_tokens(
&vec,
&[
Token::Seq { len: Some(3) },
Token::U32(1),
Token::U32(2),
Token::U32(3),
Token::SeqEnd,
],
);

let vec_de: Vec<u32> = from_field(expected_vec_field()).unwrap();
assert_eq!(vec, vec_de);
}

fn expected_array_field() -> Field<AccountId32> {
Field::Array(BoundedVec(vec![
Field::Uint32(1),
Field::Uint32(2),
Field::Uint32(3),
]))
}

#[test]
fn test_ser_array() {
let array: [u32; 3] = [1, 2, 3];

assert_ser_tokens(
&array,
&[
Token::Tuple { len: 3 },
Token::U32(1),
Token::U32(2),
Token::U32(3),
Token::TupleEnd,
],
);

let field = to_field(array).unwrap();
assert_eq!(field, expected_array_field());
}

#[test]
fn test_de_array() {
let array: [u32; 3] = [1, 2, 3];

assert_de_tokens(
&array,
&[
Token::Tuple { len: 3 },
Token::U32(1),
Token::U32(2),
Token::U32(3),
Token::TupleEnd,
],
);

let array_de: [u32; 3] = from_field(expected_array_field()).unwrap();
assert_eq!(array, array_de);
}

fn expected_same_type_field() -> Field<AccountId32> {
Field::Array(BoundedVec(vec![
Field::Uint32(1u32),
Field::Uint32(2u32),
Field::Uint32(3u32),
]))
}

#[test]
fn test_ser_tuple_same_type() {
let tuple: (u32, u32, u32) = (1, 2, 3);

assert_ser_tokens(
&tuple,
&[
Token::Tuple { len: 3 },
Token::U32(1),
Token::U32(2),
Token::U32(3),
Token::TupleEnd,
],
);

let field = to_field(tuple).unwrap();
assert_eq!(field, expected_same_type_field());
}

#[test]
fn test_de_tuple_same_type() {
let tuple: (u32, u32, u32) = (1, 2, 3);

assert_de_tokens(
&tuple,
&[
Token::Tuple { len: 3 },
Token::U32(1),
Token::U32(2),
Token::U32(3),
Token::TupleEnd,
],
);

let tuple_de: (u32, u32, u32) = from_field(expected_same_type_field()).unwrap();
assert_eq!(tuple, tuple_de);
}

fn expected_different_type_field() -> Field<AccountId32> {
Field::Array(BoundedVec(vec![
Field::Uint32(1u32),
Field::Uint16(2u16),
Field::Uint8(3u8),
]))
}

#[test]
#[should_panic = "HeterogeneousTuple"] // TODO: Support heterogeneous tuples
fn test_ser_tuple_different_type() {
let tuple: (u32, u16, u8) = (1, 2, 3);

assert_ser_tokens(
&tuple,
&[
Token::Tuple { len: 3 },
Token::U32(1),
Token::U16(2),
Token::U8(3),
Token::TupleEnd,
],
);

let field = to_field(tuple).unwrap();
assert_eq!(field, expected_different_type_field());
}

#[test]
fn test_de_tuple_different_type() {
let tuple: (u32, u16, u8) = (1, 2, 3);

assert_de_tokens(
&tuple,
&[
Token::Tuple { len: 3 },
Token::U32(1),
Token::U16(2),
Token::U8(3),
Token::TupleEnd,
],
);

let tuple_de: (u32, u16, u8) = from_field(expected_different_type_field()).unwrap();
assert_eq!(tuple, tuple_de);
}
}
4 changes: 2 additions & 2 deletions blueprints/examples/src/periodic_web_poller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ pub async fn web_poller(value: bool, client: reqwest::Client) -> Result<u8, Infa
}

// Maps a JSON response to a boolean value
async fn pre_process(event: serde_json::Value) -> Result<bool, gadget_sdk::Error> {
pub async fn pre_process(event: serde_json::Value) -> Result<bool, gadget_sdk::Error> {
gadget_sdk::info!("Running web_poller pre-processor on value: {event}");
let completed = event["completed"].as_bool().unwrap_or(false);
Ok(completed)
}

// Received the u8 value output from the job and performs any last post-processing
async fn post_process(job_output: u8) -> Result<(), gadget_sdk::Error> {
pub async fn post_process(job_output: u8) -> Result<(), gadget_sdk::Error> {
gadget_sdk::info!("Running web_poller post-processor on value: {job_output}");
if job_output == 1 {
Ok(())
Expand Down
55 changes: 36 additions & 19 deletions macros/blueprint-proc-macro-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::borrow::Cow;

pub type BlueprintString<'a> = std::borrow::Cow<'a, str>;
/// A type that represents an EVM Address.
pub type Address = ethereum_types::H160;
Expand Down Expand Up @@ -45,31 +47,46 @@ pub enum FieldType {
List(Box<FieldType>),
/// A Struct of items of type [`FieldType`].
Struct(String, Vec<(String, Box<FieldType>)>),
/// Tuple
Tuple(Vec<FieldType>),
// NOTE: Special types starts from 100
/// A special type for AccountId
AccountId,
}

impl AsRef<str> for FieldType {
fn as_ref(&self) -> &str {
impl FieldType {
pub fn as_rust_type(&self) -> Cow<'_, str> {
match self {
FieldType::Uint8 => "u8",
FieldType::Uint16 => "u16",
FieldType::Uint32 => "u32",
FieldType::Uint64 => "u64",
FieldType::Int8 => "i8",
FieldType::Int16 => "i16",
FieldType::Int32 => "i32",
FieldType::Int64 => "i64",
FieldType::Uint128 => "u128",
FieldType::U256 => "U256",
FieldType::Int128 => "i128",
FieldType::Float64 => "f64",
FieldType::Bool => "bool",
FieldType::String => "String",
FieldType::Bytes => "Bytes",
FieldType::AccountId => "AccountId",
ty => unimplemented!("Unsupported FieldType {ty:?}"),
FieldType::Uint8 => Cow::Borrowed("u8"),
FieldType::Uint16 => Cow::Borrowed("u16"),
FieldType::Uint32 => Cow::Borrowed("u32"),
FieldType::Uint64 => Cow::Borrowed("u64"),
FieldType::Int8 => Cow::Borrowed("i8"),
FieldType::Int16 => Cow::Borrowed("i16"),
FieldType::Int32 => Cow::Borrowed("i32"),
FieldType::Int64 => Cow::Borrowed("i64"),
FieldType::Uint128 => Cow::Borrowed("u128"),
FieldType::U256 => Cow::Borrowed("U256"),
FieldType::Int128 => Cow::Borrowed("i128"),
FieldType::Float64 => Cow::Borrowed("f64"),
FieldType::Bool => Cow::Borrowed("bool"),
FieldType::String => Cow::Borrowed("String"),
FieldType::Bytes => Cow::Borrowed("Vec<u8>"),
FieldType::AccountId => Cow::Borrowed("AccountId"),

FieldType::Optional(ty) => Cow::Owned(format!("Option<{}>", ty.as_rust_type())),
FieldType::Array(size, ty) => Cow::Owned(format!("[{}; {size}]", ty.as_rust_type())),
FieldType::List(ty) => Cow::Owned(format!("Vec<{}>", ty.as_rust_type())),
FieldType::Struct(..) => unimplemented!("FieldType::Struct encoding"),
FieldType::Tuple(tys) => {
let mut s = String::from("(");
for ty in tys {
s.push_str(&format!("{},", ty.as_rust_type()));
}
s.push(')');
Cow::Owned(s)
}
FieldType::Void => panic!("Void is not a representable type"),
}
}
}
Expand Down
Loading

0 comments on commit f736638

Please sign in to comment.