创建一个基于数据生成traits的rust宏

dldeef67  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(163)

我正在尝试编写一个通用类的API客户端。返回的数据可以进行一般性处理,但这样做有相当多的工作要做。所以我试着写一个宏来做这样的事情:
在哪里转换:

gen_code! {
   People,
   updated_trades = Vec<Trades>,
   new_quote = Quote,
}
trait APITrait {
  fn updated_trades(&self) -> Vec<Trades>;
  fn new_quote(&self) -> Vec<Trades>;
}

impl APITrait for Client {
  fn updated_trades(&self) -> Vec<Trades> {
     self.client.get("updated_trades").into()
  }

  fn new_quote(&self) -> Vec<Trades> {
     self.client.get("new_quote").into()
  }
}
mzaanser

mzaanser1#

// Try to choose descriptive name as with anything
macro_rules! impl_api_definitions {
    // The outer repetition allows you to define the traits in bulk
    ($(
        // lets make the macro bit more fluent and easier to read, also notice that
        // I format the macro pattern as the input should be formatted
        $vis:vis impl $name:ident for $target:ty {$(
            // lest choose syntax close to rust
            fn $method:ident -> $return_type:ty;
        )*}
        
        // notice that `$` signifies macro specific syntax:
        // - `$()` is a capture group that should be followed by
        //   - `*` zero or more repetitions of the group
        //   - `+` one or more repetitions of the group
        //   - `?` zero or one repetitions of the group
        // - `$name:type` binds a syntax of `type` to a `$name` variable;
        // each use of the variable will expand to captured code
    )*) => {$(
        // just to showcase, you can also make visibility of the trait configurable
        $vis trait $name {$(
            fn $method(&self) -> $return_type;
        )*}

        impl $name for $target {$(
            fn $method(&self) -> $return_type {
                // i removed into, it does not really make sense, rather make the get deserialize
                // into return value, note though that that can fail and so you might need to
                // handle error
                self.client.get(stringify!($method))
            }
        )*}
    )*};
}

// little mock-up of your setup
struct Client;
pub struct Trade;
pub struct Quote;
impl Client {
    fn get<T>(&self, _: &str) -> T {
        todo!()
    }
}
struct ClientWrapper {
    client: Client,
}

// example use
impl_api_definitions! {
    pub impl Api for ClientWrapper {
        fn updated_trades -> Vec<Trade>;
        fn new_quotes -> Quote;
    }

    impl PrivateApi for ClientWrapper {
        fn updated_trades -> Vec<Trade>;
        fn new_quotes -> Quote;
    }
}

相关问题