1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use async_std::io::Error;

/// A SMC message.
#[derive(Debug)]
pub struct Message {
    pub channel: u64,
    pub typ: u8,
    pub message: Vec<u8>,
}

impl Message {
    /// Create a new message.
    pub fn new(channel: u64, typ: u8, message: Vec<u8>) -> Message {
        Message {
            channel,
            typ,
            message,
        }
    }

    /// Decode a message from `buf` (bytes).
    ///
    /// Note: `buf` has to have a valid length, and the length
    /// prefix has to be removed already.
    pub fn from_buf(buf: &[u8]) -> Result<Message, Error> {
        decode_message(buf)
    }

    /// Encode a message body into a buffer.
    ///
    /// The result can be sent directly over any medium.
    /// It is length-prefixed, so chunking should not be an issue.
    pub fn encode(&self) -> Vec<u8> {
        encode_message(self)
    }
}

/// Decode a message from `buf` (bytes).
///
/// Note: `buf` has to have a valid length, and the length prefixed
/// has to be removed already.
pub fn decode_message(buf: &[u8]) -> Result<Message, Error> {
    let mut header = 0 as u64;
    let headerlen = varinteger::decode(buf, &mut header);
    let msg = &buf[headerlen..];
    let channel = header >> 4;
    let typ = header & 0b1111;
    let message = Message {
        channel: channel,
        typ: typ as u8,
        message: msg.to_vec(),
    };
    Ok(message)
}

/// Encode a message body into a buffer.
pub fn encode_message(msg: &Message) -> Vec<u8> {
    let header = msg.channel << 4 | msg.typ as u64;
    let len_header = varinteger::length(header);
    let len_body = msg.message.len() + len_header;
    let len_prefix = varinteger::length(len_body as u64);

    let mut buf = vec![0; len_body + len_prefix];

    varinteger::encode(len_body as u64, &mut buf[..len_prefix]);
    let end = len_prefix + len_header;
    varinteger::encode(header, &mut buf[len_prefix..end]);
    &mut buf[end..].copy_from_slice(&msg.message);
    buf
}