0.3.0 • Published 5 years ago

ts-rust-bridge-bincode v0.3.0

Weekly downloads
4
License
MIT
Repository
github
Last release
5 years ago

WIP

WARNING: The tool is far from being ready: no tests, no documentation, missing features. That said, you are welcome to take a look and give feedback.

Goal

A collection of helper functions to serialize data structures in typescript to rust bincode format

Example

Define AST(ish) structure in typescript. Note that it is a small subset of serde types from rust ecosystem.

import { EntryType, T, Variant as V } from '../src/schema';

const Message = EntryType.Union('Message', [
  V.Unit('Unit'),
  V.NewType('One', T.Scalar.F32),
  V.Tuple('Two', [T.Option(T.Scalar.Bool), T.Scalar.U32]),
  V.Struct('VStruct', { id: T.Scalar.Str, data: T.Scalar.Str })
]);

rust

#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "tag", content = "value")]
pub enum Message {
    Unit,
    One(f32),
    Two(Option<bool>, u32),
    VStruct { id: String, data: String },
}

typescript

export type Message =
  | { tag: 'Unit' }
  | { tag: 'One'; value: number }
  | { tag: 'Two'; value: [(boolean) | undefined, number] }
  | { tag: 'VStruct'; value: MessageVStruct };

export interface MessageVStruct {
  id: string;
  data: string;
}

export module Message {
  export const Unit: Message = { tag: 'Unit' };

  export const One = (value: number): Message => ({ tag: 'One', value });

  export const Two = (p0: (boolean) | undefined, p1: number): Message => ({
    tag: 'Two',
    value: [p0, p1]
  });

  export const VStruct = (value: MessageVStruct): Message => ({
    tag: 'VStruct',
    value
  });
}

Now let's try to serialize it to bincode format

import { Sink, SerFunc } from 'ts-rust-bridge-bincode';

// generated serialization file
import { writeMessage } from './generated/basic.ser.generated';

// generated types file
import { Message } from './basic.generated';

let sink: Sink = {
  arr: new Uint8Array(1), // it automatically grows, so let's start with 1
  pos: 0
};

// serialize a data structure to the sink and make a new slice of it
const writeAThing = <T>(thing: T, ser: SerFunc<T>): Uint8Array => {
  sink.pos = 0;
  sink = ser(sink, thing);
  return sink.arr.slice(0, sink.pos);
};

writeAThing(Message.Two(true, 7), writeMessage);
// [ 3, 0, 0, 0, 0, 0, 0, 0, 84, 119, 111, 1, 1, 7, 0, 0, 0 ]

// [ 3, 0, 0, 0, 0, 0, 0, 0 ] -> u64 === 3 (len of "Two")
// [ 84, 119, 111 ] -> "Two"
// 1 -> Some. Yes we have a value
// 1 -> true. And the value is "true"
// [ 7, 0, 0, 0 ] -> u32 === 7

Note that we serialize variant tag as a string "Two" because of #[serde(tag = "tag", content = "value")] in rust definition. Without it "Two" can be serialized as u32 instead.

Look at examples under ts-rust-bridge-codegen dir for more details.