🕌

Rust の 手続き型マクロ を使って json から enum 型を生成する

2022/10/24に公開約2,100字

今回は、Rust の Function-like 手続き型マクロを使って json からenum型を生成します。(宣言型マクロでは多分無理です。)

まず、jsonファイルを用意します。今回は以下のような json ファイルを使用します。(bq の関数のカテゴリ。)

output/category.json
[
  "Aggregate functions",
  "Statistical aggregate functions",
  "Approximate aggregate functions",
  "HyperLogLog++ functions",
  "Numbering functions",
  "Bit functions",
  "Conversion functions",
  "Format clause for CAST",
  "Mathematical functions",
  "Navigation functions",
  "Hash functions",
  "String functions",
  "JSON functions",
  "Array functions",
  "Date functions",
  "Datetime functions",
  "Time functions",
  "Timestamp functions",
  "Interval functions",
  "Geography functions",
  "Security functions",
  "Utility functions",
  "Net functions",
  "Debugging functions",
  "AEAD encryption functions"
]

次に、ワークスペースをを作ります。

そして、手続き型マクロ用の crate を含めます。( 手続き型マクロは専用の crate を作る必要あり。)

そして、その手続き型マクロ用のcrate内 で json を parse し、TokenStream 型を生成する 関数を定義し、proc_macro 要素を加えます。

例えば、 lib.rs を以下のようになります。

crate1/src/lib.rs
use proc_macro::TokenStream;
use std::fs::File;
use std::io::prelude::*;

// generate enum Category from categories.json
#[proc_macro]
pub fn enum_category(_item: TokenStream) -> TokenStream {
    let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
    let mut f = File::open(path.join("output/categories.json")).unwrap();
    let mut contents = String::new();
    f.read_to_string(&mut contents).unwrap();
    let categories: Vec<String> = serde_json::from_str(&contents).unwrap();

    let mut enum_category = String::from("pub enum Category {\n");
    for category in categories.clone() {
        enum_category.push_str(&format!(
            "    {},\n",
            category.split(' ').collect::<Vec<&str>>()[0].replace('+', "")
        ));
    }
    enum_category.push_str("}");
		enum_category.parse().unwrap()
}

あとは このマクロを 他の crate (workspace内でも可) から呼び出すとコードが展開されます。

crate2/src/lib.rs
enum_category!();

以上です。

↑で記述したソースコードは以下に置いてあります。

https://github.com/kiibo382/bigquery-functions/tree/main/types-macros

データ記述言語から型を生成できると色々便利そうですね。他のデータ記述言語等も試してみたいです。

Discussion

ログインするとコメントできます