evtc_parse/
header.rs

1use crate::{
2    util::{read_string_buffer, write_string_buffer, Endian},
3    Parse, ParseError, Save,
4};
5use byteorder::{ReadBytesExt, WriteBytesExt};
6use std::io;
7
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11/// An EVTC log header.
12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14pub struct Header {
15    /// Date this log was recorded.
16    pub date: String,
17
18    /// EVTC API revision used.
19    pub revision: u8,
20
21    /// Boss id of the log target.
22    ///
23    /// An id of `1` indicates a WvW log.
24    /// An id of `2` indicates a map log.
25    pub boss_id: u16,
26}
27
28impl Header {
29    /// Size of the date string.
30    pub const DATE_SIZE: usize = 12;
31}
32
33impl Parse for Header {
34    type Error = ParseError;
35
36    fn parse(input: &mut impl io::Read) -> Result<Self, Self::Error> {
37        let evtc = read_string_buffer::<4>(input)?;
38        if evtc != "EVTC" {
39            return Err(ParseError::NotEvtc);
40        }
41
42        let date = read_string_buffer::<{ Self::DATE_SIZE - 4 }>(input)?;
43        let revision = input.read_u8()?;
44        let boss_id = input.read_u16::<Endian>()?;
45
46        // unused byte in arc header
47        input.read_u8()?;
48
49        Ok(Self {
50            date: evtc + &date,
51            revision,
52            boss_id,
53        })
54    }
55}
56
57impl Save for Header {
58    type Error = io::Error;
59
60    fn save(&self, output: &mut impl io::Write) -> Result<(), Self::Error> {
61        write_string_buffer::<{ Self::DATE_SIZE }>(output, &self.date)?;
62        output.write_u8(self.revision)?;
63        output.write_u16::<Endian>(self.boss_id)?;
64
65        // unused byte
66        output.write_u8(0)
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn header() {
76        let header = Header {
77            date: "EVTC20230328".into(),
78            revision: 1,
79            boss_id: 123,
80        };
81
82        let mut vec = Vec::with_capacity(64);
83        header.save(&mut vec).unwrap();
84
85        let parsed = Header::parse(&mut vec.as_slice()).unwrap();
86        assert_eq!(parsed, header);
87    }
88}