• Stars
    star
    181
  • Rank 212,110 (Top 5 %)
  • Language
    Rust
  • License
    MIT License
  • Created about 8 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Easy protocol definitions in Rust

protocol

Build Status Crates.io MIT licensed

Documentation

Easy protocol definitions in Rust.

This crate adds a custom derive that can be added to types, allowing structured data to be sent and received from any IO stream.

Networking is built-in, with special support for TCP and UDP.

The protocol you define can be used outside of networking too - see the Parcel::from_raw_bytes and Parcel::raw_bytes methods.

This crate also provides:

  • TCP and UDP modules for easy sending and receiving of Parcels
  • A generic middleware library for automatic transformation of sent/received data
    • Middleware has already been written to support compression
    • Custom middleware can be implemented via a trait with two methods

Checkout the examples folder for usage.

Usage

Add this to your Cargo.toml:

[dependencies]
protocol = { version = "3.4", features = ["derive"] }

And then define a type with the #[derive(protocol::Protocol)] attribute:

#[derive(protocol::Protocol)]
struct Hello {
    pub a: String,
    pub b: u32,
}

Under the hood

The most interesting part here is the protocol::Parcel trait. Any type that implements this trait can then be serialized to and from a byte stream. All primitive types, standard collections, tuples, and arrays implement this trait.

This crate becomes particularly useful when you define your own Parcel types. You can use #[derive(protocol::Protocol)] to do this. Note that in order for a type to implement Parcel, it must also implement Clone, Debug, and PartialEq.

#[derive(Parcel, Clone, Debug, PartialEq)]
pub struct Health(f32);

#[derive(Parcel, Clone, Debug, PartialEq)]
pub struct SetPlayerPosition {
    pub position: (f32, f32),
    pub health: Health,
    pub values: Vec<String>,
}

Custom derive

Any user-defined type can have the Parcel trait automatically derived.

Example

#[derive(protocol::Protocol, Clone, Debug, PartialEq)]
pub struct Handshake;

#[derive(protocol::Protocol, Clone, Debug, PartialEq)]
pub struct Hello {
    id: i64,
    data: Vec<u8>,
}

#[derive(protocol::Protocol, Clone, Debug, PartialEq)]
pub struct Goodbye {
    id: i64,
    reason: String,
}

#[derive(protocol::Protocol, Clone, Debug, PartialEq)]
pub struct Node {
    name: String,
    enabled: bool
}

#[protocol(discriminant = "integer")]
#[derive(protocol::Protocol, Clone, Debug, PartialEq)]
pub enum PacketKind {
    #[protocol(discriminator(0x00))]
    Handshake(Handshake),
    #[protocol(discriminator(0xaa))]
    Hello(Hello),
    #[protocol(discriminator(0xaf))]
    Goodbye(Goodbye),
}

fn main() {
    use std::net::TcpStream;

    let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
    let mut connection = protocol::wire::stream::Connection::new(stream, protocol::wire::middleware::pipeline::default());

    connection.send_packet(&Packet::Handshake(Handshake)).unwrap();
    connection.send_packet(&Packet::Hello(Hello { id: 0, data: vec![ 55 ]})).unwrap();
    connection.send_packet(&Packet::Goodbye(Goodbye { id: 0, reason: "leaving".to_string() })).unwrap();

    loop {
        if let Some(response) = connection.receive_packet().unwrap() {
            println!("{:?}", response);
            break;
        }
    }
}

Enums

Discriminators

Enum values can be transmitted either by their 1-based variant index, or by transmitting the string name of each variant.

NOTE: The default behaviour is to use the variant name as a string (string).

This behaviour can be changed by the #[protocol(discriminant = "<type>")] attribute.

Supported discriminant types:

  • string (default)
    • This transmits the enum variant name as the over-the-wire discriminant
    • This uses more bytes per message, but it very flexible
  • integer
    • This transmits the 1-based variant number as the over-the-wire discriminant
    • If enum variants have explicit discriminators, the
    • Enum variants cannot be reordered in the source without breaking the protocol
#[derive(protocol::Protocol, Clone, Debug, PartialEq)]
#[protocol(discriminant = "string")]
pub enum PlayerState {
  Stationary,
  Flying { velocity: (f32,f32,f32) },
  // Discriminators can be explicitly specified.
  #[protocol(discriminator("ArbitraryOverTheWireName"))]
  Jumping { height: f32 },
}

Misc

You can rename the variant for their serialisation.

#[derive(protocol::Protocol, Clone, Debug, PartialEq)]
#[protocol(discriminant = "string")]
pub enum Foo {
  Bar,
  #[protocol(name = "Biz")] // the Bing variant will be send/received as 'Biz'.
  Bing,
  Baz,
}

More Repositories

1

mdns

A multicast DNS client in Rust
Rust
113
star
2

avr

An AVR emulator
Rust
16
star
3

lit

An integrated testing tool inspired from LLVM's 'lit' tool
Rust
15
star
4

ib-rs

A Rust client to the Interactive Brokers HTTP REST API
Rust
15
star
5

psvr-protocol

Breakdown of the PlayStation VR communication protocols for programmers
12
star
6

javabc

Java bytecode library in Rust
Rust
11
star
7

compiler

A [not-really-working] compiler from the ground-up
Rust
11
star
8

polk

A dotfile manager and symlinker
Rust
9
star
9

gcast

A Rust library for communicating with Google Cast devices
Rust
7
star
10

rurust

Run a Ruby VM from Rust
Rust
7
star
11

simavr-sim

High level Rust bindings to the simavr AVR simulator
Rust
6
star
12

rubic

A Ruby parser
Rust
5
star
13

flep

A FTP server implementation in Rust
Rust
5
star
14

simavr-sys

Low level Rust bindings to the simavr AVR simulator
Rust
3
star
15

mri-sys

Rust bindings to Mat'z Ruby Interpreter
Rust
3
star
16

avr-compiler-integration-tests

AVR compiler test suite
Rust
3
star
17

small_basic_compiler

Microsoft Small Basic LLVM Frontend
C++
3
star
18

delay

[NOTE: Moved to avr-rust/delay] Compile-time delays for Rust on AVR
Rust
2
star
19

xproto

Rust bindings to the X11 protocol library
Rust
2
star
20

hllvm

LLVM bindings for Rust
Rust
2
star
21

vsprintf

Rust bindings to the libc 'vsprintf' function
Rust
1
star
22

mash

3D mesh manipulation library
Rust
1
star
23

llvm.vim

LLVM Vim plugin directly from upstream LLVM
Vim Script
1
star
24

plugger

Plug Rust directly into a Ruby VM
Rust
1
star
25

hmdee

A Rust library for interfacing with the PlayStation VR
Rust
1
star
26

parapet

Peer to peer build system
Rust
1
star
27

minecraft

A Minecraft client written in Rust
Rust
1
star
28

clang-avr-libc-interrupt-example

An example that uses AVR-clang to define interrupt handlers that work with the AVR-GCC CRT runtime libraries
C
1
star
29

rphys

A physics simulation in Ruby
Ruby
1
star
30

c-parser

An [very imcomplete] C parser in Rust
Rust
1
star
31

target-cpu-utils

A Rust library and associated macros for querying the target CPU from the active target specification JSON
Rust
1
star
32

engine

A 3D game engine written in Rust
Rust
1
star