rakata_formats/ltr/
mod.rs1mod reader;
23mod writer;
24
25pub use reader::{read_ltr, read_ltr_from_bytes};
26pub use writer::{write_ltr, write_ltr_to_vec};
27
28use std::array::from_fn;
29use thiserror::Error;
30
31use crate::binary::{DecodeBinary, EncodeBinary};
32
33const FILE_HEADER_SIZE: usize = 9;
35const LTR_MAGIC: [u8; 4] = *b"LTR ";
37const LTR_VERSION_V10: [u8; 4] = *b"V1.0";
39pub const LTR_CHARACTER_COUNT: usize = 28;
41const LTR_CHARACTER_COUNT_U8: u8 = 28;
42const PROBABILITY_SET_COUNT_PER_BLOCK: usize = 3;
43const FLOAT_SIZE_BYTES: usize = std::mem::size_of::<f32>();
44const BLOCK_FLOAT_COUNT: usize = LTR_CHARACTER_COUNT * PROBABILITY_SET_COUNT_PER_BLOCK;
45const DOUBLE_BLOCK_COUNT: usize = LTR_CHARACTER_COUNT;
46const TRIPLE_BLOCK_COUNT: usize = LTR_CHARACTER_COUNT * LTR_CHARACTER_COUNT;
47const TOTAL_BLOCK_COUNT: usize = 1 + DOUBLE_BLOCK_COUNT + TRIPLE_BLOCK_COUNT;
48const TOTAL_FLOAT_COUNT: usize = TOTAL_BLOCK_COUNT * BLOCK_FLOAT_COUNT;
49const EXPECTED_PAYLOAD_SIZE: usize = TOTAL_FLOAT_COUNT * FLOAT_SIZE_BYTES;
50const EXPECTED_FILE_SIZE: usize = FILE_HEADER_SIZE + EXPECTED_PAYLOAD_SIZE;
51
52#[derive(Debug, Clone, PartialEq)]
59pub struct LtrProbabilityBlock {
60 pub start: [f32; LTR_CHARACTER_COUNT],
62 pub middle: [f32; LTR_CHARACTER_COUNT],
64 pub end: [f32; LTR_CHARACTER_COUNT],
66}
67
68impl Default for LtrProbabilityBlock {
69 fn default() -> Self {
70 Self {
71 start: [0.0; LTR_CHARACTER_COUNT],
72 middle: [0.0; LTR_CHARACTER_COUNT],
73 end: [0.0; LTR_CHARACTER_COUNT],
74 }
75 }
76}
77
78impl LtrProbabilityBlock {
79 pub fn new() -> Self {
81 Self::default()
82 }
83}
84
85#[derive(Debug, Clone, PartialEq)]
87pub struct Ltr {
88 pub singles: LtrProbabilityBlock,
90 pub doubles: Box<[LtrProbabilityBlock; LTR_CHARACTER_COUNT]>,
92 pub triples: Box<[[LtrProbabilityBlock; LTR_CHARACTER_COUNT]; LTR_CHARACTER_COUNT]>,
94}
95
96impl Default for Ltr {
97 fn default() -> Self {
98 Self {
99 singles: LtrProbabilityBlock::new(),
100 doubles: Box::new(from_fn(|_| LtrProbabilityBlock::new())),
101 triples: Box::new(from_fn(|_| from_fn(|_| LtrProbabilityBlock::new()))),
102 }
103 }
104}
105
106impl Ltr {
107 pub fn new() -> Self {
109 Self::default()
110 }
111}
112
113impl DecodeBinary for Ltr {
114 type Error = LtrBinaryError;
115
116 fn decode_binary(bytes: &[u8]) -> Result<Self, Self::Error> {
117 read_ltr_from_bytes(bytes)
118 }
119}
120
121impl EncodeBinary for Ltr {
122 type Error = LtrBinaryError;
123
124 fn encode_binary(&self) -> Result<Vec<u8>, Self::Error> {
125 write_ltr_to_vec(self)
126 }
127}
128
129#[derive(Debug, Error)]
131pub enum LtrBinaryError {
132 #[error(transparent)]
134 Io(#[from] std::io::Error),
135 #[error("invalid LTR magic: {0:?}")]
137 InvalidMagic([u8; 4]),
138 #[error("invalid LTR version: {0:?}")]
140 InvalidVersion([u8; 4]),
141 #[error("invalid LTR header: {0}")]
143 InvalidHeader(String),
144 #[error("invalid LTR data: {0}")]
146 InvalidData(String),
147 #[error("unsupported LTR letter count `{0}` (expected 28)")]
149 UnsupportedLetterCount(u8),
150}