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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use byteorder::NetworkEndian;
use byteorder::WriteBytesExt;

pub trait Tag: std::fmt::Debug {
    fn id(&self) -> u8;

    fn data(&self) -> Vec<u8>;

    /// constructs the tag for sending by packet
    ///
    /// # Examples
    ///
    /// ```
    /// use frcds::ds_to_rio::udp::tags::Tag;
    /// let tag = frcds::ds_to_rio::udp::tags::Countdown(12.2); //can be any tag
    /// assert_eq!(tag.construct(), vec![0x05,0x07,0x41,0x43,0x33,0x33]);
    /// ```
    fn construct(&self) -> Vec<u8> {
        let mut buf = vec![self.id()];
        buf.extend_from_slice(self.data().as_slice());
        buf.insert(0, buf.len() as u8);
        buf
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Countdown(pub f32);

#[derive(Debug, Clone)]
pub struct Joystick {
    pub axes: Vec<i8>,
    pub buttons: Vec<bool>,
    pub povs: Vec<i16>,
}

impl Tag for Countdown {
    fn id(&self) -> u8 {
        0x07
    }

    fn data(&self) -> Vec<u8> {
        let mut buf = vec![];
        buf.write_f32::<NetworkEndian>(self.0).unwrap();
        buf
    }
}

impl Joystick {
    pub fn new(axes: Vec<i8>, buttons: Vec<bool>, povs: Vec<i16>) -> Joystick {
        Joystick {
            axes,
            buttons,
            povs,
        }
    }
}

impl Tag for Joystick {
    fn id(&self) -> u8 {
        0x0c
    }

    fn data(&self) -> Vec<u8> {
        let mut buf = vec![];
        buf.push(self.axes.len() as u8);
        for item in &self.axes {
            buf.write_i8(*item).unwrap();
        }
        buf.push(self.buttons.len() as u8);
        buf.extend_from_slice(as_u8_vec(&self.buttons).as_slice());
        buf.push(self.povs.len() as u8);
        for item in &self.povs {
            buf.write_i16::<NetworkEndian>(*item).unwrap();
        }

        buf
    }
}

fn as_u8_vec(vec: &Vec<bool>) -> Vec<u8> {
    let mut buf = Vec::new();

    for i in (0..vec.len()).step_by(8) {
        let mut num: u8 = 0;
        for j in i..i + 8 {
            num <<= 1;
            num |= *match vec.get(j) {
                Some(a) => a,
                None => &false,
            } as u8;
        }
        buf.push(num);
    }

    buf
}

#[cfg(test)]
mod tests {
    use super::*;
    use byteorder::WriteBytesExt;

    #[test]
    fn bool_as_u8_vec() {
        let mut vec = vec![];
        vec.write_u16::<NetworkEndian>(0xBA40).unwrap();
        assert_eq!(
            as_u8_vec(&vec!(
                true, false, true, true, true, false, true, false, false, true, false
            )),
            vec
        );
    }

    #[test]
    fn countdown_to_u8_vec() {
        let mut vec = vec![];
        vec.write_u32::<NetworkEndian>(0x3f80_0000).unwrap();
        assert_eq!(Countdown(1.0).data(), vec);
    }
}