Derive macro icepick_module::Interface to automatically generate Operations and imply Deserialize #19

Open
opened 2024-11-29 16:58:24 +00:00 by ryan · 1 comment
Owner
use serde::{Serialize, Deserialize};
use icepick_module::Interface;

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub enum Cluster {
    Devnet,
    Testnet,
    Mainnet,
}

impl std::str::FromStr for Cluster {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "devnet" => Ok(Self::Devnet),
            "testnet" => Ok(Self::Testnet),
            "mainnet" => Ok(Self::Mainnet),
            _ => Err("Invalid value")
        }
    }
}

#[derive(Serialize, Deserialize, Interface, Clone, Debug)]
#[serde(tag = "operation", content = "values", rename_all = "kebab-case")]
pub enum Operations {
    GetBlockhash {
        // implies: Cluster::from_str() exists
        #[interface(optional, default = Cluster::Devnet)]
        cluster: Cluster,
    },
    GenerateWallet {
        #[interface(optional, default = 0)]
        account: u32,
    },
    // ....
}

This would impl Operations to make Operations::operations() -> Vec<Operation> that can be parsed by Icepick, as well as make a struct OperationsRequest that is #[serde(flatten)] so it can hold derived_keys and the blob from the previous invocation.

Maybe also have a #[interface(requests = Solana)] which makes a Solana struct that is flattened and is used to impl Module and handle_request(). As a side note, this would make handle_request() consume Self.

```rust use serde::{Serialize, Deserialize}; use icepick_module::Interface; #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(rename_all = "kebab-case")] pub enum Cluster { Devnet, Testnet, Mainnet, } impl std::str::FromStr for Cluster { type Err = &'static str; fn from_str(s: &str) -> Result<Self, Self::Err> { match s { "devnet" => Ok(Self::Devnet), "testnet" => Ok(Self::Testnet), "mainnet" => Ok(Self::Mainnet), _ => Err("Invalid value") } } } #[derive(Serialize, Deserialize, Interface, Clone, Debug)] #[serde(tag = "operation", content = "values", rename_all = "kebab-case")] pub enum Operations { GetBlockhash { // implies: Cluster::from_str() exists #[interface(optional, default = Cluster::Devnet)] cluster: Cluster, }, GenerateWallet { #[interface(optional, default = 0)] account: u32, }, // .... } ``` This would `impl Operations` to make `Operations::operations() -> Vec<Operation>` that can be parsed by Icepick, as well as make a struct `OperationsRequest` that is `#[serde(flatten)]` so it can hold `derived_keys` and the `blob` from the previous invocation. Maybe also have a `#[interface(requests = Solana)]` which makes a `Solana` struct that is flattened and is used to `impl Module` and `handle_request()`. As a side note, this would make `handle_request()` consume Self.
ryan added this to the Custody Framework project 2024-11-29 16:58:36 +00:00
Author
Owner

To limit the scope of this, I need to decide to do this either by having enum-of-struct-tuples-of-struct, or enum-of-structs. I don't want to complicate everything this early by supporting both. I think the easiest thing to do i.e. not complicate the codebase would be to support only enum-of-struct, i.e. what was listed in the issue. Then, making it support how it exists in-repo now can be implemented down the line. Every field in the struct would require a FromStr implementation to deserialize from the blob parsed by clap::Command and sent to the application, until perhaps down the line (far in the future) we can move to something like exporting a JSON Schema to Icepick, having a Clap parser for that, and pass that back to be parsed.

To limit the scope of this, I need to decide to do this either by having enum-of-struct-tuples-of-struct, or enum-of-structs. I don't want to complicate everything this early by supporting both. I think the easiest thing to do i.e. not complicate the codebase would be to support only enum-of-struct, i.e. what was listed in the issue. Then, making it support how it exists in-repo now can be implemented down the line. Every field in the struct would require a FromStr implementation to deserialize from the blob parsed by clap::Command and sent to the application, until perhaps down the line (far in the future) we can move to something like exporting a JSON Schema to Icepick, having a Clap parser for that, and pass that back to be parsed.
ryan self-assigned this 2024-12-05 20:52:34 +00:00
ryan added this to the Icepick v0.2.0 milestone 2024-12-12 20:28:59 +00:00
Sign in to join this conversation.
No Label
No Milestone
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: public/icepick#19
No description provided.