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
//! # Low-level [`std::io`] writer

use std::{hint::unreachable_unchecked, io};

use assembly_fdb_core::file::{
    ArrayHeader, FDBBucketHeader, FDBColumnHeader, FDBFieldData, FDBRowHeader,
    FDBRowHeaderListEntry, FDBTableDataHeader, FDBTableDefHeader, FDBTableHeader,
};
use latin1str::Latin1Str;

#[allow(clippy::upper_case_acronyms)]
/// A trait to write assembly data to file
pub trait WriteLE {
    /// Write `self` as little-endian bytes to `IO`
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()>;
}

impl WriteLE for Latin1Str {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(self.as_bytes())?;
        match self.len() % 4 {
            0 => out.write_all(&[0, 0, 0, 0])?,
            1 => out.write_all(&[0, 0, 0])?,
            2 => out.write_all(&[0, 0])?,
            3 => out.write_all(&[0])?,
            _ => unsafe { unreachable_unchecked() },
        }
        Ok(())
    }
}

impl WriteLE for ArrayHeader {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(&self.count.to_le_bytes())?;
        out.write_all(&self.base_offset.to_le_bytes())?;
        Ok(())
    }
}

impl WriteLE for FDBTableHeader {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(&self.table_def_header_addr.to_le_bytes())?;
        out.write_all(&self.table_data_header_addr.to_le_bytes())?;
        Ok(())
    }
}

impl WriteLE for FDBTableDefHeader {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(&self.column_count.to_le_bytes())?;
        out.write_all(&self.table_name_addr.to_le_bytes())?;
        out.write_all(&self.column_header_list_addr.to_le_bytes())?;
        Ok(())
    }
}

impl WriteLE for FDBColumnHeader {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(&self.column_data_type.to_le_bytes())?;
        out.write_all(&self.column_name_addr.to_le_bytes())?;
        Ok(())
    }
}

impl WriteLE for FDBTableDataHeader {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        self.buckets.write_le(out)
    }
}

impl WriteLE for FDBBucketHeader {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(&self.row_header_list_head_addr.to_le_bytes())
    }
}

impl WriteLE for FDBRowHeaderListEntry {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(&self.row_header_addr.to_le_bytes())?;
        out.write_all(&self.row_header_list_next_addr.to_le_bytes())?;
        Ok(())
    }
}

impl WriteLE for FDBRowHeader {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        self.fields.write_le(out)
    }
}

impl WriteLE for FDBFieldData {
    fn write_le<IO: io::Write>(&self, out: &mut IO) -> io::Result<()> {
        out.write_all(&u32::to_le_bytes(self.data_type))?;
        out.write_all(&self.value)?;
        Ok(())
    }
}