Skip to content

Instantly share code, notes, and snippets.

@jweinst1
Created August 19, 2024 00:55
Show Gist options
  • Save jweinst1/030d8e03ff3a1b230087ef059b69910a to your computer and use it in GitHub Desktop.
Save jweinst1/030d8e03ff3a1b230087ef059b69910a to your computer and use it in GitHub Desktop.
rust protocol of bytes for tcp/unix communication
use std::str;
use std::collections::HashMap;
use std::io::prelude::*;
use std::io::{ErrorKind};
use std::time::{Duration, Instant};
const PROT_BYTE:u8 = 1;
const PROT_U32:u8 = 2;
const PROT_U64:u8 = 3;
const PROT_STR:u8 = 4;
const PROT_STR_LST:u8 = 5;
fn put_size_u32(lst:&mut Vec<u8>) {
let size_to_write = ((lst.len() - 4) as u32).to_be_bytes();
for i in 0..(size_to_write.len()) {
lst[i] = size_to_write[i];
}
}
fn push_str_type(lst:&mut Vec<u8>, val:&[u8]) {
lst.push(PROT_STR);
lst.extend_from_slice(&(val.len() as u32).to_be_bytes());
lst.extend_from_slice(val);
}
fn push_str_lst_type(lst:&mut Vec<u8>, strlst:&Vec<String>) {
lst.push(PROT_STR_LST);
lst.extend_from_slice(&(strlst.len() as u32).to_be_bytes());
for elem in strlst.iter() {
lst.extend_from_slice(&(elem.len() as u32).to_be_bytes());
lst.extend_from_slice(elem.as_bytes());
}
}
fn push_byte_type(lst:&mut Vec<u8>, val:u8) {
lst.push(PROT_BYTE);
lst.push(val);
}
fn push_u32_type(lst:&mut Vec<u8>, val:u32) {
lst.push(PROT_U32);
lst.extend_from_slice(&val.to_be_bytes());
}
fn push_u64_type(lst:&mut Vec<u8>, val:u64) {
lst.push(PROT_U64);
lst.extend_from_slice(&val.to_be_bytes());
}
fn init_size_u32(lst:&mut Vec<u8>) {
lst.extend_from_slice(&[0;4]);
}
#[derive(Debug)]
enum ProtocolItem {
Byte(u8),
U32(u32),
U64(u64),
Str(String),
StrLst(Vec<String>)
}
impl ProtocolItem {
fn to_bytes(message:&Vec<ProtocolItem>, bytes:&mut Vec<u8>) {
bytes.clear();
init_size_u32(bytes);
for elem in message.iter() {
match elem {
ProtocolItem::Byte(b) => push_byte_type(bytes, *b),
ProtocolItem::U32(n) => push_u32_type(bytes, *n),
ProtocolItem::U64(n) => push_u64_type(bytes, *n),
ProtocolItem::Str(s) => push_str_type(bytes, s.as_bytes()),
ProtocolItem::StrLst(l) => push_str_lst_type(bytes, l)
}
}
put_size_u32(bytes);
}
fn from_bytes(bytes:&Vec<u8>, message:&mut Vec<ProtocolItem>) {
message.clear();
let mut i = 4; // get passed the size
while i < bytes.len() {
match bytes[i] {
0 => panic!("Unexpected 0 byte in from_bytes!"),
PROT_BYTE => {
i += 1;
message.push(ProtocolItem::Byte(bytes[i]));
i += 1;
},
PROT_U32 => {
i += 1;
message.push(ProtocolItem::U32(u32::from_be_bytes(bytes[i..(i+4)].try_into().unwrap())));
i += 4;
},
PROT_U64 => {
i += 1;
message.push(ProtocolItem::U64(u64::from_be_bytes(bytes[i..(i+8)].try_into().unwrap())));
i += 8;
},
PROT_STR => {
i += 1;
let ssize = u32::from_be_bytes(bytes[i..(i+4)].try_into().unwrap()) as usize;
i += 4;
message.push(ProtocolItem::Str(String::from_utf8(bytes[i..(i+ssize)].to_vec()).unwrap()));
i += ssize;
},
PROT_STR_LST => {
i += 1;
let lsize = u32::from_be_bytes(bytes[i..(i+4)].try_into().unwrap()) as usize;
i += 4;
let mut svec = Vec::new();
for _ in 0..lsize {
let ssize = u32::from_be_bytes(bytes[i..(i+4)].try_into().unwrap()) as usize;
i += 4;
svec.push(String::from_utf8(bytes[i..(i+ssize)].to_vec()).unwrap());
i += ssize;
}
message.push(ProtocolItem::StrLst(svec));
},
_ => panic!("Unexpected {} byte in from_bytes!", bytes[i])
}
}
}
}
fn main() {
let mut foo = Vec::new();
foo.push(ProtocolItem::Str("foo".to_string()));
foo.push(ProtocolItem::StrLst(vec!["foo".to_string(), "bar".to_string()]));
foo.push(ProtocolItem::U64(54));
println!("{foo:?}");
let mut bytes = Vec::new();
ProtocolItem::to_bytes(&foo, &mut bytes);
println!("{bytes:?}");
let mut newfoo = Vec::new();
ProtocolItem::from_bytes(&bytes, &mut newfoo);
println!("{newfoo:?}");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment