Skip to content
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

[TASK] Support custom types as job parameters #424

Open
Serial-ATA opened this issue Oct 31, 2024 · 2 comments
Open

[TASK] Support custom types as job parameters #424

Serial-ATA opened this issue Oct 31, 2024 · 2 comments
Assignees
Labels
feature ➕ Tasks that are functional additions or enhancements task ✔️

Comments

@Serial-ATA
Copy link
Contributor

Serial-ATA commented Oct 31, 2024

Overview

It'd be nice to have support for custom structured arguments, since Field::Struct exists.

Original idea

This will be split into two derive macros:

  • TryFromField to support new types as parameters
  • TryIntoField to support new types as return types

Will also require changes to the job macro.

Examples

As a parameter:

use gadget_blueprint_proc_macro::TryFromField;

// Implements TryFrom<Field<AccountId32>> for `MulArgs`
#[derive(TryFromField)]
struct MulArgs {
    a: u32,
    b: u32,
}

#[job(id = 0, params(args), /* ... */)]
pub fn mul(args: MulArgs, context: MyContext) -> Result<u32, gadget_sdk::Error> {
    Ok(args.a.saturating_mul(args.b))
}

As a return type:

use gadget_blueprint_proc_macro::TryIntoField;

// Implements TryFrom<BundledArgs> for `Field<AccountId32>`
#[derive(TryIntoField)]
struct BundledArgs {
    a: u32,
    b: u32,
    c: u32,
}

#[job(id = 0, params(a, b, c), /* ... */)]
pub fn bundle(a: u32, b: u32, c: u32, context: MyContext) -> Result<BundledArgs, gadget_sdk::Error> {
    Ok(BundledArgs {
        a,
        b,
        c,
    })
}

We can have a blueprint-serde crate that converts to and from the Field type.

Examples

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    let person = Person {
        name: String::from("John"),
        age: 40,
    };

    let field = gadget_blueprint_serde::to_field(&person).unwrap();
    assert_eq!(
        field,
        Field::Struct(
            BoundedString("Person"),
            Box(BoundedVec(
                (
                    BoundedString("name"),
                    Field::String(BoundedString(&self.name)),
                ),
                (BoundedString("age"), Field::Uint8(self.age)),
            )),
        )
    );

    let person: Person = gadget_blueprint_serde::from_field(&field).unwrap();
    assert_eq!(
        person,
        Person {
            name: String::from("John"),
            age: 40
        }
    );
}
@Serial-ATA Serial-ATA added feature ➕ Tasks that are functional additions or enhancements task ✔️ labels Oct 31, 2024
@Serial-ATA Serial-ATA self-assigned this Oct 31, 2024
@shekohex
Copy link
Contributor

Will this design work with Nested structs? what about remote types? is it possible to leverage serde instead of our custom macros? i.e create serde_blueprint::to_fileds and serde_blueprint::from_fields such that we can use it with anything that implements serde traits?

@Serial-ATA
Copy link
Contributor Author

@shekohex

Will this design work with Nested structs?

Yes, this works ATM:

use gadget_blueprint_proc_macro::TryIntoField;

#[derive(TryIntoField)]
struct MyType {
    a: u8,
}

#[derive(TryIntoField)]
struct Foo {
    bar: u8,
    baz: MyType,
}

is it possible to leverage serde instead of our custom macros

I'll look into it. That'd be ideal if not too complicated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature ➕ Tasks that are functional additions or enhancements task ✔️
Projects
Status: Building 🏗️
Development

No branches or pull requests

2 participants