Crates.io | netpack |
lib.rs | netpack |
version | 0.0.1 |
source | src |
created_at | 2021-01-25 18:04:51.994855 |
updated_at | 2021-01-25 18:04:51.994855 |
description | Packing traits and implementations geared towards netcode |
homepage | https://github.com/qwerty01/netpack |
repository | https://github.com/qwerty01/netpack |
max_upload_size | |
id | 346559 |
size | 45,877 |
Documentation coming soon. Geared towards netcode, so all types are serialized in network-byte-order.
Why not just use serde? Serde has basic types, such as strings, which are variable-length and require some sort of format to serialize. This crate chooses to not force a particular protocol on the user, so if you have a variable-length type, you will need to implement a serialization protocol on it yourself.
Sample usage:
use std::io::{self, Cursor, Read, Write};
use netpack::{PackError, Packable, Unpackable, unpack, unpack_from};
// Sample struct with a sub-struct that also implements Packable/Unpackable
#[derive(Debug, PartialEq)]
struct Sample {
num: i128,
sample: SubSample,
b: bool,
}
// Implement Packable for our struct
impl Packable for Sample {
type Error = io::Error; // Error packables use by default
fn pack_into(&self, stream: &mut impl Write) -> Result<(), Self::Error> {
self.num.pack_into(stream)?;
self.sample.pack_into(stream)?;
self.b.pack_into(stream)?;
Ok(())
}
}
// Implement Unpackable for our struct
impl Unpackable for Sample {
type Error = PackError; // Error unpackables use by default
fn unpack_from(rdr: &mut impl Read) -> Result<Self, Self::Error> {
Ok(Self {
num: unpack_from(rdr)?,
sample: unpack_from(rdr)?,
b: unpack_from(rdr)?,
})
}
}
// Embedded structure that's also packable/unpackable
#[derive(Debug, PartialEq)]
struct SubSample {
num: i32,
arr: [u16; 5],
float: f32,
}
impl Packable for SubSample {
type Error = io::Error; // Error packables use by default
fn pack_into(&self, stream: &mut impl Write) -> Result<(), Self::Error> {
self.num.pack_into(stream)?;
self.arr.pack_into(stream)?;
self.float.pack_into(stream)?;
Ok(())
}
}
impl Unpackable for SubSample {
type Error = PackError; // Error unpackables use by default
fn unpack_from(rdr: &mut impl Read) -> Result<Self, Self::Error> {
Ok(Self {
num: unpack_from(rdr)?,
arr: unpack_from(rdr)?,
float: unpack_from(rdr)?,
})
}
}
fn main() {
let sub = SubSample {
num: 20,
arr: [10, 100, 1000, 5, 0],
float: 0.3
};
let sample = Sample {
num: -5,
sample: sub,
b: true
};
let mut v = Vec::new();
// Create a Write stream for the vec
let mut c = Cursor::new(&mut v);
// Serialize our struct into the stream
sample.pack_into(&mut c).unwrap();
// Serialized data is now in the vec
assert_eq!(&v, &vec![
// Sample::num
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251,
// SubSample::num
0, 0, 0, 20,
// SubSample::arr
0, 10, 0, 100, 3, 232, 0, 5, 0, 0,
// SubSample::float
62, 153, 153, 154,
// Sample::b
1
]);
// Can also return a vec
let mut v = sample.pack().unwrap();
// Serialized data is now in the vec
assert_eq!(&v, &vec![255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251, 0, 0, 0, 20, 0, 10, 0, 100, 3, 232, 0, 5, 0, 0, 62, 153, 153, 154, 1]);
// Extra data simulating a buffer with more than just our struct
v.push(0xff);
// Unpacking is just as simple:
let mut c = Cursor::new(&mut v);
let new_sample: Sample = unpack_from(&mut c).unwrap();
assert_eq!(&new_sample, &sample);
// Or from a slice:
let (new_sample, rest): (Sample, &[u8]) = unpack(&v).unwrap();
assert_eq!(&new_sample, &sample);
// rest contains remaining bytes that weren't part of our struct
assert_eq!(&rest, &[0xff]);
}