Denoシリーズ第2編、denoにrust拡張をします

9528 ワード

この文章は主に「denoをコンパイルし、deno構造解析」の第2編に続いて、denoの目標はブラウザのような安全な環境を提供することですが、バックエンドでdenoが実現しにくいものを実現する必要がある場合は、どうすればいいですか?なぜ私たちはdenoに拡張できないのでしょうか?フィボナッチ数列を計算する方法でdenoをrust拡張の例にします.
ステップ1:メッセージ・タイプの定義
前の文章のディレクトリの解析によると、denoは中間層を通じてv 8とrustが互いに呼び出されているが、v 8はc++で書かれており、rustは別の言語である.通信はどうすればいいのだろうか.denoは通常のRPCのような呼び出しを使用しているが,rを削除しただけである.thriftとgrpcを使用したことがある学生は、多言語通信を実現するには実際に相互定義タイプであることを知っています.denoも例外ではありませんが、flatbuffersを使用しているだけで、ここでは自分で勉強することに興味があります.
最初のステップでは、タイプを定義します.
  • はsrc/msg.fbsにGetFiboとGetFiboResの2種類を追加し、タイプ名は任意に取ることができ、コードは以下の
  • である.
    union Any {
      Start,
      ...
      GetFibo,
      GetFiboRes
    }
    
    table GetFibo {
      num: int32;
    }
    
    table GetFiboRes {
      result: int32;
    }
    

    どういう意味ですか.GetFiboは、私が入力したパラメータリストのタイプを定義し、GetFiboResは戻り値を定義したタイプだと考えることができます.フィボナッチ数列を計算する方法では、パラメータは1つの数字しかなく、結果も1つの数字しかないので、1つの数字タイプを定義すればいいです.
    書き終わったら、コンパイルしてもいいです.
    ./tools/build.py 
    #   target/debug/gen/msg_generated.ts,         
    

    第2歩:rustと通信する方法とtsの方法定義を確立する
  • 新規ファイルjs/get_fibo.ts、コードは以下の
  • import * as msg from "gen/msg_generated";
    import * as flatbuffers from "./flatbuffers";
    import { assert } from "./util";
    import * as dispatch from "./dispatch";
    
    function req(
        num: number,
      ): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
        const builder = flatbuffers.createBuilder();
        msg.GetFibo.startGetFibo(builder);
        msg.GetFibo.addNum(builder, num);
        const inner = msg.GetFibo.endGetFibo(builder);
        return [builder, msg.Any.GetFibo, inner];
      }
      
      function res(baseRes: null | msg.Base): number {
        assert(baseRes !== null);
        assert(msg.Any.GetFiboRes === baseRes!.innerType());
        const res = new msg.GetFiboRes();
        assert(baseRes!.inner(res) !== null);
        return res.result();
      }
    
    
    export function getFiboSync(num: number): number {
        return res(dispatch.sendSync(...req(num)));
    }
      
    
    export async function getFibo(num: number): Promise<number> {
        return res(await dispatch.sendAsync(...req(num)));
    }
    

    以下の説明を行います.
  • gen/msg_generatedは、以前に生成したデータ型定義
  • です.
  • flatbuffersプロトコルデータを生成するためのツール
  • assertデータに異常がないかを検出するツール
  • dispatch送信データ通信の方法
  • またjsを書くだけでrustを通信する必要がなければ、実際にはこれらのライブラリを参照する必要はありません.getFiboSyncとgetFiboで直接書く方法でいいです.このファイルtsの主な用途はrustとインタラクティブに使用することであり、同時に露出するtsメソッドを定義し、reqメソッドは送信するデータ構造をグループ化し、resは受信したメッセージを処理し、dispatchはデータを送信する. :getFiboSyncとgetFiboは、同期メソッドと非同期メソッドをそれぞれ表します.
    rustメソッドの追加
    src/ops.rs増加方法、ここでの方法も主に受信とデータの組み立てであり、コードは以下の通りである.
    ...
    let op_creator: OpCreator = match inner_type {
          msg::Any::Accept => op_accept,
          msg::Any::Chdir => op_chdir,
          ...
          msg::Any::GetFibo => op_get_fibo //       
          _ => panic!(format!(
            "Unhandled message {}",
            msg::enum_name_any(inner_type)
          )),
    ...
    fn op_get_fibo(
      _state: &Arc,
      base: &msg::Base<'_>,
      data: libdeno::deno_buf,
    ) -> Box {
      assert_eq!(data.len(), 0);
      let inner = base.inner_as_get_fibo().unwrap();
      let cmd_id = base.cmd_id();
      let num = inner.num();
    
      blocking(base.sync(), move || -> OpResult {
        //   fibonacci  
        let sqrt5 = 5_f64.sqrt();
        let c1 = (1.0_f64+sqrt5)/2.0_f64;
        let c2 = (1.0_f64-sqrt5)/2.0_f64;
        let result_f = (sqrt5/5.0_f64)*(c1.powi(num)-c2.powi(num));
        let result = result_f as i32;
    
        let builder = &mut FlatBufferBuilder::new();
        let inner = msg::GetFiboRes::create(
          builder,
          &msg::GetFiboResArgs {
            result, 
          },
        );
    
        Ok(serialize_response(
          cmd_id,
          builder,
          msg::BaseArgs {
            inner: Some(inner.as_union_value()),
            inner_type: msg::Any::GetFiboRes,
            ..Default::default()
          },
        ))
      })
    }
    ...
    

    ここでrustのmatchの意味を少し説明すると、強化版のswitchと理解できます.GetFiboのデータ型が来たら、op_を実行します.get_fiboメソッド、op_get_fiboは主にFlatBufferBuilderデータをカプセル化していますが、フィボナッチ数列を本当に効果的に計算するコードは少しです.もちろん、機能コードの量が大きい場合はrustファイルを新規作成することができます.以下のようにします.
        let sqrt5 = 5_f64.sqrt();
        let c1 = (1.0_f64+sqrt5)/2.0_f64;
        let c2 = (1.0_f64-sqrt5)/2.0_f64;
        let result_f = (sqrt5/5.0_f64)*(c1.powi(num)-c2.powi(num));
        let result = result_f as i32;
    

    最後の一歩
    実はここまでリンクが完全に通じていても、私たちは最後の一歩しか残っていません.私たちの方法を暴露します.
  • js/denoを修正する.tsファイル、get_fibo.tsの方法は暴露すれば
  • である.
    ...
    export { getFiboSync, getFibo } from "./get_fibo";
    ...
    

    コンパイルして終わりました
    ./tools/build.py 
    

    テストコードは次のとおりです.
    import * as deno from "deno";
    
    (async()=>{
        console.log(deno.getFiboSync(10));
        console.log(await deno.getFibo(11));
    })();
    

    実は前の記事でも、denoを学ぶことはライブラリを学ぶことであり、テストコードを見て原因がわかると信じています.
    締めくくり
    今回は本当にお正月前の最後の一編だったはずです.