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
use bitbuffer::{BitRead, BitReadSized, BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
use serde::{Deserialize, Serialize};

use crate::demo::message::stringtable::log_base2;
use crate::{ReadResult, Stream};
use std::cmp::min;

#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(BitReadSized, BitWriteSized, Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct ClassInfoEntry {
    #[size = "input_size"]
    class_id: u16,
    class_name: String,
    table_name: String,
}

#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct ClassInfoMessage {
    count: u16,
    create: bool,
    entries: Vec<ClassInfoEntry>,
}

impl BitRead<'_, LittleEndian> for ClassInfoMessage {
    fn read(stream: &mut Stream) -> ReadResult<Self> {
        let count: u16 = stream.read()?;
        let create: bool = stream.read()?;
        let entries = if !create {
            let mut entries = Vec::with_capacity(min(count, 128) as usize);
            let bits = log_base2(count) + 1;
            for _ in 0..count {
                entries.push(stream.read_sized(bits as usize)?);
            }
            entries
        } else {
            Vec::new()
        };

        Ok(ClassInfoMessage {
            count,
            create,
            entries,
        })
    }
}

impl BitWrite<LittleEndian> for ClassInfoMessage {
    fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
        self.count.write(stream)?;
        self.create.write(stream)?;
        if !self.create {
            let bits = log_base2(self.entries.len()) as usize + 1;
            for entry in self.entries.iter() {
                entry.write_sized(stream, bits)?;
            }
        }

        Ok(())
    }
}

#[test]
fn test_class_info_roundtrip() {
    crate::test_roundtrip_write(ClassInfoMessage {
        count: 8,
        create: true,
        entries: Vec::new(),
    });
    crate::test_roundtrip_write(ClassInfoMessage {
        count: 3,
        create: false,
        entries: vec![
            ClassInfoEntry {
                class_id: 0,
                class_name: "foo1".to_string(),
                table_name: "bar1".to_string(),
            },
            ClassInfoEntry {
                class_id: 1,
                class_name: "foo2".to_string(),
                table_name: "bar2".to_string(),
            },
            ClassInfoEntry {
                class_id: 2,
                class_name: "foo3".to_string(),
                table_name: "bar3".to_string(),
            },
        ],
    });
}