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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#[derive(Debug, PartialEq)]
pub enum FrameType {
    NonFinText,
    FinCont,
    NonFinCont,
    FinText,
}

pub const ECG_FRAME: [u8; 3] = [0x81, 0x01, b'\n'];

/**
 * Write a websockets frame header.
 * @param out, space to write to, should be 10 bytes long.
 * @param message_len the length of the ws frame this header prefixes.
 * @param type frame type
 * @return the amount of bytes in the header, 2, 4 or 10.
 */
pub fn ws_write_frame_hdr(out: &mut Box<[u8]>, message_len: usize, frame_type: FrameType) -> usize {

    match frame_type {
        FrameType::NonFinText => {
            out[0] = 0x01; // non-FIN text
        },
        FrameType::FinCont => {
            out[0] = 0x80; // FIN + cont
        },
        FrameType::NonFinCont => {
            out[0] = 0x00; // non-FIN cont
        },
        FrameType::FinText => {
            out[0] = 0x81; // FIN text
        },
    }

    let mut i: usize = 0;
    if message_len < 126 {
        out[1] = message_len as u8;
        return 2;
    }
    else if message_len <= 0xffff {
        out[1] = 0x7e;
        while i < 2 {
            out[2 + i] = (message_len >> 8 * (1 - i) & 0xff) as u8;
            i += 1;
        }
        return 4;
    }
    else {
        out[1] = 0x7f;
        while i < 8 {
            out[2 + i] = (message_len >> 8 * (7 - i) & 0xff) as u8;
            i += 1;
        }
        return 10;
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use std::borrow::Borrow;

    #[test]
    fn test_frame_hdr() {
        println!("hdr data={:?}", ECG_FRAME);

        let mut out: Box<[u8]> = Box::new([0; 2048]);
        assert_eq!(2, ws_write_frame_hdr(&mut out, 1, FrameType::FinText));
        assert_eq!(1, to_int(&out[1..2], 1));
        println!("hdr data={:?}", out[0..2].borrow());

        assert_eq!(4, ws_write_frame_hdr(&mut out, 0xfffe, FrameType::FinText));
        assert_eq!(0xfffe, to_int(&out[2..4], 2));
        println!("hdr data={:?}", out[0..4].borrow());

        assert_eq!(10, ws_write_frame_hdr(&mut out, 0xfefefefe, FrameType::FinText));
        assert_eq!(0xfefefefe, to_int(&out[6..10], 4));
        println!("hdr data={:?}", out[0..10].borrow());
    }

    fn to_int(out: &[u8], len: usize) -> usize {
        const TWO56: usize = 256;
        return match len {
            1 => out[0] as usize,
            2 => (out[0] as usize * TWO56) + out[1] as usize,
            // N.B should be 8 digits I'm being lazy
            4 => (out[0] as usize * TWO56 * TWO56 * TWO56) + (out[1] as usize * TWO56 * TWO56) + (out[2] as usize * TWO56) + out[3] as usize,
            _ => panic!()
        };
    }
}