levin/
header.rs

1use std::io::{Read, Write};
2
3use crate::constants::*;
4use crate::error::Result;
5
6#[derive(Debug, Default)]
7pub struct Header {
8    signature: u64,
9    payload_length: u64,
10    expect_reponse: bool,
11    command: u32,
12    return_code: u32,
13    flags: u32,
14    version: u32,
15}
16
17impl Header {
18    pub fn new_request(command: u32) -> Self {
19        Self::new_unfragmented(true, command, 0, LevinMessage::Request)
20    }
21
22    pub fn new_response(command: u32, return_code: u32) -> Self {
23        Self::new_unfragmented(false, command, return_code, LevinMessage::Response)
24    }
25
26    pub fn new_notification(command: u32) -> Self {
27        Self::new_unfragmented(false, command, 0, LevinMessage::Notification)
28    }
29
30    pub fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
31        let mut res = Self::default();
32        res.signature = read_fixed_u64(&mut reader)?;
33        res.payload_length = read_fixed_u64(&mut reader)?;
34        res.expect_reponse = read_bool(&mut reader)?;
35        res.command = read_fixed_u32(&mut reader)?;
36        res.return_code = read_fixed_u32(&mut reader)?;
37        res.flags = read_fixed_u32(&mut reader)?;
38        res.version = read_fixed_u32(&mut reader)?;
39        Ok(res)
40    }
41
42    pub fn to_writer<W: Write>(&self, mut writer: W) -> Result<()> {
43        write_fixed_u64(&mut writer, self.signature)?;
44        write_fixed_u64(&mut writer, self.payload_length)?;
45        write_bool(&mut writer, self.expect_reponse)?;
46        write_fixed_u32(&mut writer, self.command)?;
47        write_fixed_u32(&mut writer, self.return_code)?;
48        write_fixed_u32(&mut writer, self.flags)?;
49        write_fixed_u32(&mut writer, self.version)?;
50        Ok(())
51    }
52
53    pub fn set_payload_length(&mut self, length: usize) {
54        self.payload_length = length as u64;
55    }
56
57    fn new_unfragmented(
58        expect_reponse: bool,
59        command: u32,
60        return_code: u32,
61        msg_type: LevinMessage,
62    ) -> Self {
63        Self {
64            signature: u64::from_le_bytes(LEVIN_SIGNATURE),
65            payload_length: 0,
66            expect_reponse,
67            command,
68            return_code,
69            flags: make_flags(msg_type, LevinFragment::Unfragmented),
70            version: LEVIN_VERSION,
71        }
72    }
73}
74
75fn make_flags(msg_type: LevinMessage, frag_type: LevinFragment) -> u32 {
76    let msg_mask = match msg_type {
77        LevinMessage::Request => LEVIN_REQUEST_BIT,
78        LevinMessage::Notification => LEVIN_REQUEST_BIT,
79        LevinMessage::Response => LEVIN_RESPONSE_BIT,
80        LevinMessage::Dummy => 0,
81    };
82
83    let frag_mask = match frag_type {
84        LevinFragment::Begin => LEVIN_FRAG_BEGIN_BIT,
85        LevinFragment::Middle => 0,
86        LevinFragment::Unfragmented => 0,
87        LevinFragment::End => LEVIN_FRAG_END_BIT,
88        LevinFragment::Dummy => LEVIN_FRAG_BEGIN_BIT | LEVIN_FRAG_END_BIT,
89    };
90
91    return msg_mask | frag_mask;
92}
93
94fn read_fixed_u32<R: Read>(r: &mut R) -> std::io::Result<u32> {
95    let mut ibytes = [0u8; 4];
96    r.read_exact(&mut ibytes)?;
97    Ok(u32::from_le_bytes(ibytes))
98}
99
100fn read_fixed_u64<R: Read>(r: &mut R) -> std::io::Result<u64> {
101    let mut ibytes = [0u8; 8];
102    r.read_exact(&mut ibytes)?;
103    Ok(u64::from_le_bytes(ibytes))
104}
105
106fn read_bool<R: Read>(r: &mut R) -> std::io::Result<bool> {
107    let mut bbyte = 0u8;
108    r.read_exact(std::slice::from_mut(&mut bbyte))?;
109    Ok(bbyte != 0)
110}
111
112fn write_fixed_u32<W: Write>(w: &mut W, val: u32) -> std::io::Result<()> {
113    let ibytes = val.to_le_bytes();
114    w.write_all(&ibytes)
115}
116
117fn write_fixed_u64<W: Write>(w: &mut W, val: u64) -> std::io::Result<()> {
118    let ibytes = val.to_le_bytes();
119    w.write_all(&ibytes)
120}
121
122fn write_bool<W: Write>(w: &mut W, val: bool) -> std::io::Result<()> {
123    let bbyte = if val { 1u8 } else { 0 };
124    w.write(std::slice::from_ref(&bbyte))?;
125    Ok(())
126}