19 releases

0.3.6 Jun 13, 2018
0.3.4 Feb 21, 2018
0.3.3 Jan 20, 2018
0.3.1 Aug 11, 2017
0.1.10 Sep 18, 2016

#2 in #udp

Download history 21/week @ 2018-08-22 18/week @ 2018-09-05 3/week @ 2018-09-12 6/week @ 2018-09-19 19/week @ 2018-09-26 62/week @ 2018-10-03 1/week @ 2018-10-10 23/week @ 2018-10-17 20/week @ 2018-10-24 14/week @ 2018-10-31 202/week @ 2018-11-07 41/week @ 2018-11-14

135 downloads per month
Used in 2 crates

MIT license

79KB
1.5K SLoC


lib.rs:

Simple packet-based protocol definitions in Rust.

  • The Parcel trait defines any type that can be serialized to a connection.
  • The wire module deals with transmission of Parcels.

Examples

Get the raw bytes representing a parcel.

extern crate protocol;
#[macro_use] extern crate protocol_derive;

#[derive(Protocol, Debug, PartialEq)]
pub struct Health(pub u8);

#[derive(Protocol, Debug, PartialEq)]
pub struct Player {
    pub name: String,
    pub health: Health,
    pub position: (i16, i16, i16),
    pub velocity: (i16, i16, i16),
}

use protocol::Parcel;

assert_eq!(vec![
    0, 0, 0, 3, // "Bob" string length prefix
    b'B', b'o', b'b', // The string "Bob".
    100, // The health byte.
    0, 10, 0, 81, 255, 151, // 2-byte x-position, y-position, and z-position.
    0, 0, 0, 0, 0, 0, // 2-byte x-velocity, y-velocity, and z-velocity.
], Player {
    name: "Bob".to_owned(),
    health: Health(100),
    position: (10, 81, -105),
    velocity: (0, 0, 0),
}.raw_bytes(&protocol::Settings::default()).unwrap());

Enums

Every enum has a value for each variant used to distinguish between each variant. This can be as simple as a 32-bit integer representing the variant's index. This is called the discriminator.

String discriminators

extern crate protocol;
#[macro_use] extern crate protocol_derive;

// This enum, like all enums, defaults to using String discriminators.
#[derive(Protocol, Debug, PartialEq)]
enum Foo { A, B, C }

// This enum explicitly specifies a string discriminant.
//
// This is the default anyway and thus it is identical in layout
// to the previous enum.
#[derive(Protocol, Debug, PartialEq)]
#[protocol(discriminant = "string")]
enum Bar { A, B, C }

By default, enums have String discriminators. This means that when serializing enum values to and from bytes, unless otherwise specified the variant's full name will be transmitted as a string.

This allows variants to be added, modified, or reordered in a backwards-compatible way.

Integer discriminators

extern crate protocol;
#[macro_use] extern crate protocol_derive;

// An enum with integer discriminators.
#[derive(Protocol, Debug, PartialEq)]
#[protocol(discriminant = "integer")]
enum Baz {
    Fizz = 0, // override the default first discriminator of 1
    Buzz, // defaults to `prior discriminator + 1`, therefore has a discriminator of 1.
    Bing, // defaults to `prior discriminator + 1`, therefore has a discriminator of 2.
    Boo = 1234,
    Beez, // defaults to `prior discriminator + 1`, therefore has a discriminator of 1235.
}

use protocol::{Enum, Parcel};

// By default, integer discriminators are 32-bits.
assert_eq!([0u8, 0, 0, 2], &Baz::Bing.discriminator().raw_bytes(&protocol::Settings::default()).unwrap()[..]);

assert_eq!(0, Baz::Fizz.discriminator());
assert_eq!(1, Baz::Buzz.discriminator());
assert_eq!(2, Baz::Bing.discriminator());
assert_eq!(1234, Baz::Boo.discriminator());
assert_eq!(1235, Baz::Beez.discriminator());

It is possible to set the underlying integer type via the #[repr(<type>)] attribute.

extern crate protocol;
#[macro_use] extern crate protocol_derive;

#[derive(Protocol, Debug, PartialEq)]
#[protocol(discriminant = "integer")]
#[repr(u8)] // Force discriminators to be 8-bit.
pub enum Hello {
    World(String), SolarSystem(String), LocalGroup(String),
    Universe(String), Everything(String),
}

use protocol::{Enum, Parcel};

assert_eq!([2, // 1-byte discriminator
            0, 0, 0, 3, // string length
            b'f', b'o', b'o', // the string
            ], &Hello::SolarSystem("foo".to_owned()).raw_bytes(&protocol::Settings::default()).unwrap()[..]);

Discriminators can be overriden on a per-variant basis via the #[protocol(discriminator(<value>))] attribute.

In the case of trivial enums with no fields, the Variant = <discriminator> syntax may be used.

extern crate protocol;
#[macro_use] extern crate protocol_derive;

#[derive(Protocol, Debug, PartialEq)]
#[protocol(discriminant = "integer")]
#[repr(u8)] // Force discriminators to be 8-bit.
enum Numbered {
    A = 1, B = 2, C = 111, D = 67,
}

#[derive(Protocol, Debug, PartialEq)]
#[protocol(discriminant = "integer")]
#[repr(u8)] // Force discriminators to be 8-bit.
pub enum Hello {
    World(String), SolarSystem(String), LocalGroup(String),
    #[protocol(discriminator(100))]
    Universe(String),
    Everything(String),
}

use protocol::{Enum, Parcel};

assert_eq!(111, Numbered::C.discriminator());
assert_eq!(67, Numbered::D.discriminator());

assert_eq!(1, Hello::World("foo".to_owned()).discriminator());
assert_eq!(100, Hello::Universe("foo".to_owned()).discriminator());
assert_eq!(101, Hello::Everything("foo".to_owned()).discriminator());

Dependencies

~2.5MB
~47K SLoC