1use nom::{
2 Compare, IResult, Input, Parser,
3 bytes::streaming::tag,
4 combinator::{iterator, opt},
5 number::streaming::le_u16,
6};
7
8use crate::parse::compact::binary::blocks::{
9 BlockHeader, BlockType, EncodingType, GCodeEncodingType, ThumbnailParameters, parse_block,
10};
11
12type Block<P, I> = (BlockHeader, P, I, Option<u32>);
13
14#[derive(Debug)]
16pub struct File<I> {
17 pub header: FileHeader,
18 pub file_meta: Option<Block<EncodingType, I>>,
19 pub printer_meta: Block<EncodingType, I>,
20 pub thumbnails: Vec<Block<ThumbnailParameters, I>>,
21 pub print_meta: Block<EncodingType, I>,
22 pub slicer_meta: Block<EncodingType, I>,
23 pub gcode_blocks: Vec<Block<GCodeEncodingType, I>>,
24}
25
26impl<I: Input<Item = u8> + for<'a> Compare<&'a [u8]>> File<I> {
27 pub fn parse(input: I) -> IResult<I, File<I>> {
29 let stage = FileHeaderParser;
30 let (input, (header, stage)) = stage.parser().parse(input)?;
31 let (input, (file_meta, stage)) = stage.parser().parse(input)?;
32 let (input, (printer_meta, stage)) = stage.parser().parse(input)?;
33 let (input, (thumbnails, stage)) = stage.parser().parse(input)?;
34 let (input, (print_meta, stage)) = stage.parser().parse(input)?;
35 let (input, (slicer_meta, stage)) = stage.parser().parse(input)?;
36 let (input, gcode_blocks) = stage.parser().parse(input)?;
37
38 Ok((
39 input,
40 Self {
41 header,
42 file_meta,
43 printer_meta,
44 thumbnails,
45 print_meta,
46 slicer_meta,
47 gcode_blocks,
48 },
49 ))
50 }
51}
52
53pub struct FileHeaderParser;
54
55impl FileHeaderParser {
56 pub fn parser<I>(
57 &self,
58 ) -> impl Parser<I, Output = (FileHeader, FileMetaParser), Error = nom::error::Error<I>>
59 where
60 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
61 {
62 FileHeader::parser().map(move |header| {
63 let checksum_type = header.checksum_type;
64 (header, FileMetaParser(checksum_type))
65 })
66 }
67}
68
69pub struct FileMetaParser(ChecksumType);
70
71impl FileMetaParser {
72 pub fn parser<I>(
73 &self,
74 ) -> impl Parser<
75 I,
76 Output = (Option<Block<EncodingType, I>>, PrinterMetaParser),
77 Error = nom::error::Error<I>,
78 >
79 where
80 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
81 {
82 let checksum_type = self.0;
83 opt(move |input| {
84 parse_block(
85 BlockType::FileMetadata,
86 checksum_type,
87 EncodingType::parser(),
88 input,
89 )
90 })
91 .map(move |opt| (opt, PrinterMetaParser(checksum_type)))
92 }
93}
94
95pub struct PrinterMetaParser(ChecksumType);
96
97impl PrinterMetaParser {
98 pub fn parser<I>(
99 &self,
100 ) -> impl Parser<
101 I,
102 Output = (
103 (BlockHeader, EncodingType, I, Option<u32>),
104 ThumbnailsParser,
105 ),
106 Error = nom::error::Error<I>,
107 >
108 where
109 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
110 {
111 let checksum_type = self.0;
112 (move |input| {
113 parse_block(
114 BlockType::PrinterMetadata,
115 checksum_type,
116 EncodingType::parser(),
117 input,
118 )
119 })
120 .map(move |block| (block, ThumbnailsParser(checksum_type)))
121 }
122}
123
124pub struct ThumbnailsParser(ChecksumType);
125
126impl ThumbnailsParser {
127 pub fn parser<I>(
128 &self,
129 ) -> impl Parser<
130 I,
131 Output = (Vec<Block<ThumbnailParameters, I>>, PrintMetaParser),
132 Error = nom::error::Error<I>,
133 >
134 where
135 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
136 {
137 let checksum_type = self.0;
138 move |input| {
139 let mut it = iterator(input, move |input| {
140 parse_block(
141 BlockType::Thumbnail,
142 checksum_type,
143 ThumbnailParameters::parser(),
144 input,
145 )
146 });
147
148 let thumbnails = (&mut it).collect::<Vec<_>>();
149 it.finish()
150 .map(|(input, ())| (input, (thumbnails, PrintMetaParser(checksum_type))))
151 }
152 }
153}
154
155pub struct PrintMetaParser(ChecksumType);
156
157impl PrintMetaParser {
158 pub fn parser<I>(
159 &self,
160 ) -> impl Parser<
161 I,
162 Output = (
163 (BlockHeader, EncodingType, I, Option<u32>),
164 SlicerMetaParser,
165 ),
166 Error = nom::error::Error<I>,
167 >
168 where
169 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
170 {
171 let checksum_type = self.0;
172 (move |input| {
173 parse_block(
174 BlockType::PrintMetadata,
175 checksum_type,
176 EncodingType::parser(),
177 input,
178 )
179 })
180 .map(move |block| (block, SlicerMetaParser(checksum_type)))
181 }
182}
183
184pub struct SlicerMetaParser(ChecksumType);
185
186impl SlicerMetaParser {
187 pub fn parser<I>(
188 &self,
189 ) -> impl Parser<
190 I,
191 Output = (
192 (BlockHeader, EncodingType, I, Option<u32>),
193 GCodeBlocksParser,
194 ),
195 Error = nom::error::Error<I>,
196 >
197 where
198 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
199 {
200 let checksum_type = self.0;
201 (move |input| {
202 parse_block(
203 BlockType::SlicerMetadata,
204 checksum_type,
205 EncodingType::parser(),
206 input,
207 )
208 })
209 .map(move |block| (block, GCodeBlocksParser(checksum_type)))
210 }
211}
212
213pub struct GCodeBlocksParser(ChecksumType);
214
215impl GCodeBlocksParser {
216 pub fn parser<I>(
217 &self,
218 ) -> impl Parser<
219 I,
220 Output = Vec<(BlockHeader, GCodeEncodingType, I, Option<u32>)>,
221 Error = nom::error::Error<I>,
222 >
223 where
224 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
225 {
226 let checksum_type = self.0;
227 move |input| {
228 let mut it = iterator(input, move |input| {
229 parse_block(
230 BlockType::Thumbnail,
231 checksum_type,
232 GCodeEncodingType::parser(),
233 input,
234 )
235 });
236
237 let gcode_blocks = (&mut it).collect::<Vec<_>>();
238 it.finish().map(|(input, ())| (input, gcode_blocks))
239 }
240 }
241}
242
243#[derive(Debug, Clone, PartialEq, Eq)]
247pub struct FileHeader {
248 pub checksum_type: ChecksumType,
249}
250
251impl FileHeader {
252 pub fn parser<I>() -> impl Parser<I, Output = Self, Error = nom::error::Error<I>>
253 where
254 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
255 {
256 const MAGIC_NUMBER: &[u8; 4] = b"GCDE";
257 const VERSION_BYTES: [u8; 4] = 1u32.to_le_bytes();
258
259 tag(MAGIC_NUMBER.as_slice())
260 .and(tag(VERSION_BYTES.as_slice()))
261 .and(ChecksumType::parser())
262 .map(|((_magic_number, _version), checksum)| Self {
263 checksum_type: checksum,
264 })
265 }
266}
267
268#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269#[repr(u16)]
270pub enum ChecksumType {
271 None = 0,
272 CRC32 = 1,
276}
277
278impl ChecksumType {
279 pub fn parser<I>() -> impl Parser<I, Output = Self, Error = nom::error::Error<I>>
280 where
281 I: Input<Item = u8> + for<'a> Compare<&'a [u8]>,
282 {
283 le_u16.map_res(|value| match value {
284 0 => Ok(Self::None),
285 1 => Ok(Self::CRC32),
286 _other => Err(()),
287 })
288 }
289}