11

I'm writing a small client/server program for encrypted network communications and have the following struct to allow the endpoints to negotiate capabilities.

struct KeyExchangePacket {
    kexinit: u8,
    replay_cookie: [u8; 32],
    kex_algorithms: String,
    kgen_algorithms: String,
    encryption_algorithms: String,
    mac_algorithms: String,
    compression_algorithms: String,
    supported_languages: String,
}

I need to convert the fields into bytes in order to send them over a TcpStream, but I currently have to convert them one at a time.

send_buffer.extend_from_slice(kex_algorithms.as_bytes());
send_buffer.extend_from_slice(kgen_algorithms.as_bytes());
etc...

Is there a way to iterate over the fields and push their byte values into a buffer for sending?

Herohtar
  • 5,347
  • 4
  • 31
  • 41
William Murphy
  • 113
  • 1
  • 1
  • 4

2 Answers2

12

Is there a way to iterate over the fields

No. You have to implement it yourself, or find a macro / compiler plugin that will do it for you.

See How to iterate or map over tuples? for a similar question.

Think about how iterators work. An iterator has to yield a single type for each iteration. What would that type be for your struct composed of at least 3 different types?

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    Pretty sure serde could be useful here if a compiler plugin/nightly is acceptable. – mcarton Jun 29 '16 at 23:51
  • 1
    @mcarton are you aware of a serde adaptor for generic bytes? Or do you think OP would have to write such an adaptor? – Shepmaster Jun 30 '16 at 00:34
  • 1
    what do you mean? serde itself can serialize from/to `Vec`. – mcarton Jun 30 '16 at 00:51
  • 1
    @mcarton interesting! I assumed that serde could output a struct using something like JSON or XML or MessagePack to a `Vec`, but didn't know that there was a mode to smush all the bytes of a struct together. How would I tell serde to output OP's data without any serialization format? – Shepmaster Jun 30 '16 at 00:55
3

Bincode does this.

let packet = KeyExchangePacket { /* ... */ };
let size_limit = bincode::SizeLimit::Infinite;
let encoded: Vec<u8> = bincode::serde::serialize(&packet, size_limit).unwrap();

From the readme:

The encoding (and thus decoding) proceeds unsurprisingly -- primitive types are encoded according to the underlying Writer, tuples and structs are encoded by encoding their fields one-by-one, and enums are encoded by first writing out the tag representing the variant and then the contents.

dtolnay
  • 9,621
  • 5
  • 41
  • 62