rakata_formats/ltr/
mod.rs1mod reader;
30mod writer;
31
32pub use reader::{read_ltr, read_ltr_from_bytes};
33pub use writer::{write_ltr, write_ltr_to_vec};
34
35use std::array::from_fn;
36use thiserror::Error;
37
38use crate::binary::{DecodeBinary, EncodeBinary};
39
40const FILE_HEADER_SIZE: usize = 9;
42const LTR_MAGIC: [u8; 4] = *b"LTR ";
44const LTR_VERSION_V10: [u8; 4] = *b"V1.0";
46pub const LTR_CHARACTER_COUNT: usize = 28;
48const LTR_CHARACTER_COUNT_U8: u8 = 28;
49const PROBABILITY_SET_COUNT_PER_BLOCK: usize = 3;
50const FLOAT_SIZE_BYTES: usize = std::mem::size_of::<f32>();
51const BLOCK_FLOAT_COUNT: usize = LTR_CHARACTER_COUNT * PROBABILITY_SET_COUNT_PER_BLOCK;
52const DOUBLE_BLOCK_COUNT: usize = LTR_CHARACTER_COUNT;
53const TRIPLE_BLOCK_COUNT: usize = LTR_CHARACTER_COUNT * LTR_CHARACTER_COUNT;
54const TOTAL_BLOCK_COUNT: usize = 1 + DOUBLE_BLOCK_COUNT + TRIPLE_BLOCK_COUNT;
55const TOTAL_FLOAT_COUNT: usize = TOTAL_BLOCK_COUNT * BLOCK_FLOAT_COUNT;
56const EXPECTED_PAYLOAD_SIZE: usize = TOTAL_FLOAT_COUNT * FLOAT_SIZE_BYTES;
57const EXPECTED_FILE_SIZE: usize = FILE_HEADER_SIZE + EXPECTED_PAYLOAD_SIZE;
58
59#[derive(Debug, Clone, PartialEq)]
66pub struct LtrProbabilityBlock {
67 pub start: [f32; LTR_CHARACTER_COUNT],
69 pub middle: [f32; LTR_CHARACTER_COUNT],
71 pub end: [f32; LTR_CHARACTER_COUNT],
73}
74
75impl Default for LtrProbabilityBlock {
76 fn default() -> Self {
77 Self {
78 start: [0.0; LTR_CHARACTER_COUNT],
79 middle: [0.0; LTR_CHARACTER_COUNT],
80 end: [0.0; LTR_CHARACTER_COUNT],
81 }
82 }
83}
84
85impl LtrProbabilityBlock {
86 pub fn new() -> Self {
88 Self::default()
89 }
90}
91
92#[derive(Debug, Clone, PartialEq)]
94pub struct Ltr {
95 pub singles: LtrProbabilityBlock,
97 pub doubles: Box<[LtrProbabilityBlock; LTR_CHARACTER_COUNT]>,
99 pub triples: Box<[[LtrProbabilityBlock; LTR_CHARACTER_COUNT]; LTR_CHARACTER_COUNT]>,
101}
102
103impl Default for Ltr {
104 fn default() -> Self {
105 Self {
106 singles: LtrProbabilityBlock::new(),
107 doubles: Box::new(from_fn(|_| LtrProbabilityBlock::new())),
108 triples: Box::new(from_fn(|_| from_fn(|_| LtrProbabilityBlock::new()))),
109 }
110 }
111}
112
113impl Ltr {
114 pub fn new() -> Self {
116 Self::default()
117 }
118}
119
120impl DecodeBinary for Ltr {
121 type Error = LtrBinaryError;
122
123 fn decode_binary(bytes: &[u8]) -> Result<Self, Self::Error> {
124 read_ltr_from_bytes(bytes)
125 }
126}
127
128impl EncodeBinary for Ltr {
129 type Error = LtrBinaryError;
130
131 fn encode_binary(&self) -> Result<Vec<u8>, Self::Error> {
132 write_ltr_to_vec(self)
133 }
134}
135
136#[derive(Debug, Error)]
138pub enum LtrBinaryError {
139 #[error(transparent)]
141 Io(#[from] std::io::Error),
142 #[error("invalid LTR magic: {0:?}")]
144 InvalidMagic([u8; 4]),
145 #[error("invalid LTR version: {0:?}")]
147 InvalidVersion([u8; 4]),
148 #[error("invalid LTR header: {0}")]
150 InvalidHeader(String),
151 #[error("invalid LTR data: {0}")]
153 InvalidData(String),
154 #[error("unsupported LTR letter count `{0}` (expected 28)")]
156 UnsupportedLetterCount(u8),
157}