sml_rs/lib.rs
1//! Smart Message Language (SML) parser written in Rust.
2//!
3//! Modern German power meters periodically send SML-encoded data via an optical interface.
4//! The main use-case of this library is to decode that data.
5//!
6//! See the [`transport`] module for encoding / decoding the SML transport protocol v1 and the
7//! [`parser`] module for parsing decoded data into SML data structures.
8//!
9//! Complete examples of how to use the library can be found on github in the [`examples`](https://github.com/felixwrt/sml-rs/tree/main/examples) folder.
10//!
11//! # Feature flags
12//! - **`std`** (default) — Remove this feature to make the library `no_std` compatible.
13//! - **`alloc`** (default) — Implementations using allocations (`alloc::Vec` et al.).
14//! - **`embedded_hal`** — Allows using pins implementing `embedded_hal::serial::Read` in [`SmlReader`](SmlReader::from_eh_reader).
15//! - **`nb`** - Enables non-blocking APIs using the `nb` crate.
16//!
17#![cfg_attr(not(feature = "std"), no_std)]
18#![cfg_attr(docsrs, feature(doc_auto_cfg))]
19#![deny(unsafe_code)]
20#![warn(missing_docs)]
21
22use core::fmt;
23use core::{borrow::Borrow, marker::PhantomData};
24
25#[cfg(feature = "alloc")]
26use parser::complete::{parse, File};
27use parser::streaming::Parser;
28use parser::ParseError;
29use transport::{DecodeErr, DecoderReader, ReadDecodedError};
30use util::{ArrayBuf, Buffer};
31
32#[cfg(feature = "alloc")]
33extern crate alloc;
34
35pub mod parser;
36pub mod transport;
37pub mod util;
38
39use util::ByteSource;
40
41/// Error returned by functions parsing sml data read from a reader
42#[derive(Debug)]
43pub enum ReadParsedError<ReadErr>
44where
45 ReadErr: core::fmt::Debug,
46{
47 /// Error while parsing
48 ParseErr(ParseError),
49 /// Error while decoding the data (e.g. checksum mismatch)
50 DecodeErr(DecodeErr),
51 /// Error while reading from the internal byte source
52 ///
53 /// (inner_error, num_discarded_bytes)
54 IoErr(ReadErr, usize),
55}
56
57impl<ReadErr> From<ReadDecodedError<ReadErr>> for ReadParsedError<ReadErr>
58where
59 ReadErr: core::fmt::Debug,
60{
61 fn from(value: ReadDecodedError<ReadErr>) -> Self {
62 match value {
63 ReadDecodedError::DecodeErr(x) => ReadParsedError::DecodeErr(x),
64 ReadDecodedError::IoErr(x, num_discarded) => ReadParsedError::IoErr(x, num_discarded),
65 }
66 }
67}
68
69impl<ReadErr> From<ParseError> for ReadParsedError<ReadErr>
70where
71 ReadErr: core::fmt::Debug,
72{
73 fn from(value: ParseError) -> Self {
74 ReadParsedError::ParseErr(value)
75 }
76}
77
78impl<ReadErr> fmt::Display for ReadParsedError<ReadErr>
79where
80 ReadErr: core::fmt::Debug,
81{
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 <Self as fmt::Debug>::fmt(self, f)
84 }
85}
86
87#[cfg(feature = "std")]
88impl<ReadErr> std::error::Error for ReadParsedError<ReadErr> where ReadErr: core::fmt::Debug {}
89
90// ===========================================================================
91// ===========================================================================
92// `SmlReader` + impls
93// ===========================================================================
94// ===========================================================================
95
96/// Main API of `sml-rs`
97///
98/// `SmlReader` is used to read sml data. It allows reading from various data
99/// sources and can produce different output depending on the use-case.
100///
101/// ## Example
102///
103/// The following example shows how to parse an sml data set from a file:
104///
105/// ```
106/// # #[cfg(feature = "std")] {
107/// # use sml_rs::{parser::complete::File, SmlReader};
108/// use std::fs;
109/// let f = fs::File::open("sample.bin").unwrap();
110/// let mut reader = SmlReader::from_reader(f);
111/// match reader.read::<File>() {
112/// Ok(x) => println!("Got result: {:#?}", x),
113/// Err(e) => println!("Error: {:?}", e),
114/// }
115/// # }
116/// ```
117/// ### Data Source
118///
119/// The `SmlReader` struct can be used with several kinds of data providers:
120///
121/// | Constructor (`SmlReader::...`) | Expected data type | Usage examples |
122/// |-----------------------------------------------------|-----------|------------|
123/// |[`from_reader`](SmlReader::from_reader) **¹** | `impl std::io::Read` | files, sockets, serial ports (see `serialport-rs` crate) |
124/// |[`from_eh_reader`](SmlReader::from_eh_reader) **²** | `impl embedded_hal::serial::Read<u8>` | microcontroller pins |
125/// |[`from_slice`](SmlReader::from_slice) | `&[u8]` | arrays, vectors, ... |
126/// |[`from_iterator`](SmlReader::from_iterator) | `impl IntoIterator<Item = impl Borrow<u8>>)` | anything that can be turned into an iterator over bytes |
127///
128/// ***¹** requires feature `std` (on by default); **²** requires optional feature `embedded_hal`*
129///
130/// ### Internal Buffer
131///
132/// `SmlReader` reads sml messages into an internal buffer. By default, a static
133/// buffer with a size of 8 KiB is used, which should be more than enough for
134/// typical messages.
135///
136/// It is possible to use a different static buffer size or use a dynamically
137/// allocated buffer that can grow as necessary. `SmlReader` provides two associated
138/// functions for this purpose:
139///
140/// - [`SmlReader::with_static_buffer<N>()`](SmlReader::with_static_buffer)
141/// - [`SmlReader::with_vec_buffer()`](SmlReader::with_vec_buffer) *(requires feature `alloc` (on by default))*
142///
143/// These functions return a builder object ([`SmlReaderBuilder`]) that provides methods to create an [`SmlReader`]
144/// from the different data sources shown above.
145///
146/// **Examples**
147///
148/// Creating a reader with a static 1KiB buffer from a slice:
149///
150/// ```
151/// # use sml_rs::SmlReader;
152/// let data = [1, 2, 3, 4, 5];
153/// let reader = SmlReader::with_static_buffer::<1024>().from_slice(&data);
154/// ```
155///
156/// Creating a reader with a dynamically-sized buffer from an iterable:
157///
158/// ```
159/// # #[cfg(feature = "alloc")] {
160/// # use sml_rs::SmlReader;
161/// let data = [1, 2, 3, 4, 5];
162/// let reader_2 = SmlReader::with_vec_buffer().from_iterator(&data);
163/// # }
164/// ```
165///
166/// ### Reading transmissions
167///
168/// Once a `SmlReader` is instantiated, it can be used to read, decode and parse SML messages. `SmlReader`
169/// provides two functions for this, [`read<T>`](DecoderReader::read) and [`next<T>`](DecoderReader::next).
170///
171/// ```
172/// # use sml_rs::{SmlReader, DecodedBytes};
173/// let data = include_bytes!("../sample.bin");
174/// let mut reader = SmlReader::from_slice(data.as_slice());
175///
176/// let bytes = reader.read::<DecodedBytes>();
177/// assert!(matches!(bytes, Ok(bytes)));
178/// let bytes = reader.read::<DecodedBytes>();
179/// assert!(matches!(bytes, Err(_)));
180///
181/// let mut reader = SmlReader::from_slice(data.as_slice());
182///
183/// let bytes = reader.next::<DecodedBytes>();
184/// assert!(matches!(bytes, Some(Ok(bytes))));
185/// let bytes = reader.next::<DecodedBytes>();
186/// assert!(matches!(bytes, None));
187/// ```
188///
189/// ### Target Type
190///
191/// [`read<T>`](DecoderReader::read) and [`next<T>`](DecoderReader::next) can be used to parse sml
192/// transmissions into several different representations:
193///
194/// - [`DecodedBytes`]: a slice of bytes containing the decoded message. No parsing is done.
195/// - [`File`]: a struct containing completely parsed sml data. (requires feature `"alloc"`)
196/// - [`Parser`]: an streaming parser for sml data.
197///
198/// **Examples**
199///
200/// ```
201/// # use sml_rs::{SmlReader, DecodedBytes, parser::streaming::Parser};
202/// # #[cfg(feature = "alloc")]
203/// # use sml_rs::parser::complete::File;
204/// let data = include_bytes!("../sample.bin");
205/// let mut reader = SmlReader::from_slice(data.as_slice());
206///
207/// let bytes = reader.read::<DecodedBytes>();
208/// # #[cfg(feature = "alloc")] {
209/// let file = reader.read::<File>();
210/// # }
211/// let parser = reader.read::<Parser>();
212/// ```
213pub struct SmlReader<R, Buf>
214where
215 R: ByteSource,
216 Buf: Buffer,
217{
218 decoder: DecoderReader<Buf, R>,
219}
220
221pub(crate) type DummySmlReader = SmlReader<util::SliceReader<'static>, ArrayBuf<0>>;
222
223impl DummySmlReader {
224 /// Returns a builder with a static internal buffer of size `N`.
225 ///
226 /// Use the `from_*` methods on the builder to create an `SmlReader`.
227 ///
228 /// # Examples
229 ///
230 /// ```
231 /// # use sml_rs::SmlReader;
232 /// let data = [1, 2, 3];
233 /// let reader = SmlReader::with_static_buffer::<1024>().from_slice(&data);
234 /// ```
235 pub fn with_static_buffer<const N: usize>() -> SmlReaderBuilder<ArrayBuf<N>> {
236 SmlReaderBuilder { buf: PhantomData }
237 }
238
239 /// Returns a builder with a dynamically-sized internal buffer.
240 ///
241 /// Use the `from_*` methods on the builder to create an `SmlReader`.
242 ///
243 /// *This function is available only if sml-rs is built with the `"alloc"` feature.*
244 ///
245 /// # Examples
246 ///
247 /// ```
248 /// # use sml_rs::SmlReader;
249 /// let data = [1, 2, 3];
250 /// let reader = SmlReader::with_vec_buffer().from_slice(&data);
251 /// ```
252 #[cfg(feature = "alloc")]
253 pub fn with_vec_buffer() -> SmlReaderBuilder<alloc::vec::Vec<u8>> {
254 SmlReaderBuilder { buf: PhantomData }
255 }
256
257 /// Build an `SmlReader` from a type implementing `std::io::Read`.
258 ///
259 /// *This function is available only if sml-rs is built with the `"std"` feature.*
260 ///
261 /// # Examples
262 ///
263 /// ```
264 /// # use sml_rs::SmlReader;
265 /// let data = [1, 2, 3];
266 /// let cursor = std::io::Cursor::new(data); // implements std::io::Read
267 /// let reader = SmlReader::from_reader(cursor);
268 /// ```
269 #[cfg(feature = "std")]
270 pub fn from_reader<R>(reader: R) -> SmlReader<util::IoReader<R>, DefaultBuffer>
271 where
272 R: std::io::Read,
273 {
274 SmlReader {
275 decoder: DecoderReader::new(util::IoReader::new(reader)),
276 }
277 }
278
279 /// Build an `SmlReader` from a type implementing `embedded_hal::serial::Read<u8>`.
280 ///
281 /// *This function is available only if sml-rs is built with the `"embedded-hal"` feature.*
282 ///
283 /// # Examples
284 ///
285 /// ```
286 /// # use sml_rs::SmlReader;
287 /// // usually provided by hardware abstraction layers (HALs) for specific chips
288 /// // let pin = ...;
289 /// # struct Pin;
290 /// # impl embedded_hal::serial::Read<u8> for Pin {
291 /// # type Error = ();
292 /// # fn read(&mut self) -> nb::Result<u8, Self::Error> { Ok(123) }
293 /// # }
294 /// # let pin = Pin;
295 ///
296 /// let reader = SmlReader::from_eh_reader(pin);
297 /// ```
298 #[cfg(feature = "embedded_hal")]
299 pub fn from_eh_reader<R, E>(reader: R) -> SmlReader<util::EhReader<R, E>, DefaultBuffer>
300 where
301 R: embedded_hal::serial::Read<u8, Error = E>,
302 {
303 SmlReader {
304 decoder: DecoderReader::new(util::EhReader::new(reader)),
305 }
306 }
307
308 /// Build an `SmlReader` from a slice of bytes.
309 ///
310 /// # Examples
311 ///
312 /// ```
313 /// # use sml_rs::SmlReader;
314 /// let data: &[u8] = &[1, 2, 3];
315 /// let reader = SmlReader::from_slice(data);
316 /// ```
317 pub fn from_slice(reader: &[u8]) -> SmlReader<util::SliceReader<'_>, DefaultBuffer> {
318 SmlReader {
319 decoder: DecoderReader::new(util::SliceReader::new(reader)),
320 }
321 }
322
323 /// Build an `SmlReader` from a type that can be turned into a byte iterator.
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// # use sml_rs::SmlReader;
329 /// let data: [u8; 3] = [1, 2, 3];
330 /// let reader = SmlReader::from_iterator(data.clone()); // [u8; 3]
331 /// let reader = SmlReader::from_iterator(&data); // &[u8; 3]
332 /// let reader = SmlReader::from_iterator(data.as_slice()); // &[u8]
333 /// let reader = SmlReader::from_iterator(data.iter()); // impl Iterator<Item = &u8>
334 /// let reader = SmlReader::from_iterator(data.into_iter()); // impl Iterator<Item = u8>
335 /// ```
336 pub fn from_iterator<B, I>(
337 iter: I,
338 ) -> SmlReader<util::IterReader<I::IntoIter, B>, DefaultBuffer>
339 where
340 I: IntoIterator<Item = B>,
341 B: Borrow<u8>,
342 {
343 SmlReader {
344 decoder: DecoderReader::new(util::IterReader::new(iter.into_iter())),
345 }
346 }
347}
348
349impl<R, ReadErr, Buf> SmlReader<R, Buf>
350where
351 R: ByteSource<ReadError = ReadErr>,
352 ReadErr: core::fmt::Debug,
353 Buf: Buffer,
354{
355 /// Reads, decodes and possibly parses sml data.
356 ///
357 /// ```
358 /// # use sml_rs::{SmlReader, DecodedBytes};
359 /// let data = include_bytes!("../sample.bin");
360 /// let mut reader = SmlReader::from_slice(data.as_slice());
361 ///
362 /// let bytes = reader.read::<DecodedBytes>();
363 /// assert!(matches!(bytes, Ok(bytes)));
364 /// let bytes = reader.read::<DecodedBytes>();
365 /// assert!(matches!(bytes, Err(_)));
366 /// ```
367 ///
368 /// This method can be used to parse sml data into several representations.
369 /// See the module documentation for more information.
370 ///
371 /// When reading from a finite data source (such as a file containing a certain
372 /// number of transmissions), it's easier to use [`next`](SmlReader::next) instead,
373 /// which returns `None` when an EOF is read when trying to read the next transmission.
374 ///
375 /// See also [`read_nb`](DecoderReader::read_nb), which provides a convenient API for
376 /// non-blocking byte sources.
377 pub fn read<'i, T>(&'i mut self) -> Result<T, T::Error>
378 where
379 T: SmlParse<'i, Result<&'i [u8], ReadDecodedError<ReadErr>>>,
380 {
381 T::parse_from(self.decoder.read())
382 }
383
384 /// Tries to read, decode and possibly parse sml data.
385 ///
386 /// ```
387 /// # use sml_rs::{SmlReader, DecodedBytes};
388 /// let data = include_bytes!("../sample.bin");
389 /// let mut reader = SmlReader::from_slice(data.as_slice());
390 ///
391 /// let bytes = reader.next::<DecodedBytes>();
392 /// assert!(matches!(bytes, Some(Ok(bytes))));
393 /// let bytes = reader.next::<DecodedBytes>();
394 /// assert!(matches!(bytes, None));
395 /// ```
396 ///
397 /// This method can be used to parse sml data into several representations.
398 /// See the module documentation for more information.
399 ///
400 /// When reading from a data source that will provide data infinitely (such
401 /// as from a serial port), it's easier to use [`read`](SmlReader::read) instead.
402 ///
403 /// See also [`next_nb`](SmlReader::next_nb), which provides a convenient API for
404 /// non-blocking byte sources.
405 pub fn next<'i, T>(&'i mut self) -> Option<Result<T, T::Error>>
406 where
407 T: SmlParse<'i, Result<&'i [u8], ReadDecodedError<ReadErr>>>,
408 {
409 Some(T::parse_from(self.decoder.next()?))
410 }
411
412 /// Reads, decodes and possibly parses sml data (non-blocking).
413 ///
414 /// ```
415 /// # use sml_rs::{SmlReader, DecodedBytes};
416 /// let data = include_bytes!("../sample.bin");
417 /// let mut reader = SmlReader::from_slice(data.as_slice());
418 ///
419 /// let bytes = nb::block!(reader.read_nb::<DecodedBytes>());
420 /// assert!(matches!(bytes, Ok(bytes)));
421 /// let bytes = nb::block!(reader.read_nb::<DecodedBytes>());
422 /// assert!(matches!(bytes, Err(_)));
423 /// ```
424 ///
425 /// Same as [`read`](SmlReader::read) except that it returns `nb::Result`.
426 /// If reading from the byte source indicates that data isn't available yet,
427 /// this method returns `Err(nb::Error::WouldBlock)`.
428 ///
429 /// Using `nb::Result` allows this method to be awaited using the `nb::block!` macro.
430 ///
431 /// *This function is available only if sml-rs is built with the `"nb"` or `"embedded_hal"` features.*
432 #[cfg(feature = "nb")]
433 pub fn read_nb<'i, T>(&'i mut self) -> nb::Result<T, T::Error>
434 where
435 T: SmlParse<'i, Result<&'i [u8], ReadDecodedError<ReadErr>>>,
436 {
437 // TODO: this could probably be written better
438 let res = match self.decoder.read_nb() {
439 Ok(x) => Ok(x),
440 Err(nb::Error::WouldBlock) => return Err(nb::Error::WouldBlock),
441 Err(nb::Error::Other(e)) => Err(e),
442 };
443 T::parse_from(res).map_err(nb::Error::Other)
444 }
445
446 /// Tries to read, decode and possibly parse sml data (non-blocking).
447 ///
448 /// ```
449 /// # use sml_rs::{SmlReader, DecodedBytes};
450 /// let data = include_bytes!("../sample.bin");
451 /// let mut reader = SmlReader::from_slice(data.as_slice());
452 ///
453 /// let bytes = nb::block!(reader.next_nb::<DecodedBytes>());
454 /// assert!(matches!(bytes, Ok(Some(bytes))));
455 /// let bytes = nb::block!(reader.next_nb::<DecodedBytes>());
456 /// assert!(matches!(bytes, Ok(None)));
457 /// ```
458 ///
459 /// Same as [`next`](SmlReader::next) except that it returns `nb::Result`.
460 /// If reading from the byte source indicates that data isn't available yet,
461 /// this method returns `Err(nb::Error::WouldBlock)`.
462 ///
463 /// Using `nb::Result` allows this method to be awaited using the `nb::block!` macro.
464 ///
465 /// *This function is available only if sml-rs is built with the `"nb"` or `"embedded_hal"` features.*
466 #[cfg(feature = "nb")]
467 pub fn next_nb<'i, T>(&'i mut self) -> nb::Result<Option<T>, T::Error>
468 where
469 T: SmlParse<'i, Result<&'i [u8], ReadDecodedError<ReadErr>>>,
470 {
471 // TODO: this could probably be written better
472 let res = match self.decoder.next_nb() {
473 Ok(None) => return Ok(None),
474 Ok(Some(x)) => Ok(x),
475 Err(nb::Error::WouldBlock) => return Err(nb::Error::WouldBlock),
476 Err(nb::Error::Other(e)) => Err(e),
477 };
478 T::parse_from(res).map(Some).map_err(nb::Error::Other)
479 }
480}
481
482type DefaultBuffer = ArrayBuf<{ 8 * 1024 }>;
483
484/// Builder struct for `SmlReader` that allows configuring the internal buffer type.
485///
486/// See [here](SmlReader#internal-buffer) for an explanation of the different internal
487/// buffer types and how to use the builder to customize them.
488pub struct SmlReaderBuilder<Buf: Buffer> {
489 buf: PhantomData<Buf>,
490}
491
492impl<Buf: Buffer> Clone for SmlReaderBuilder<Buf> {
493 fn clone(&self) -> Self {
494 Self { buf: PhantomData }
495 }
496}
497
498impl<Buf: Buffer> SmlReaderBuilder<Buf> {
499 /// Build an `SmlReader` from a type implementing `std::io::Read`.
500 ///
501 /// *This function is available only if sml-rs is built with the `"std"` feature.*
502 ///
503 /// # Examples
504 ///
505 /// ```
506 /// # use sml_rs::SmlReader;
507 /// let data = [1, 2, 3];
508 /// let cursor = std::io::Cursor::new(data); // implements std::io::Read
509 /// let reader = SmlReader::with_static_buffer::<1024>().from_reader(cursor);
510 /// ```
511 #[cfg(feature = "std")]
512 pub fn from_reader<R: std::io::Read>(self, reader: R) -> SmlReader<util::IoReader<R>, Buf> {
513 SmlReader {
514 decoder: DecoderReader::new(util::IoReader::new(reader)),
515 }
516 }
517
518 /// Build an `SmlReader` from a type implementing `embedded_hal::serial::Read<u8>`.
519 ///
520 /// *This function is available only if sml-rs is built with the `"embedded-hal"` feature.*
521 ///
522 /// # Examples
523 ///
524 /// ```
525 /// # use sml_rs::SmlReader;
526 /// // usually provided by hardware abstraction layers (HALs) for specific chips
527 /// // let pin = ...;
528 /// # struct Pin;
529 /// # impl embedded_hal::serial::Read<u8> for Pin {
530 /// # type Error = ();
531 /// # fn read(&mut self) -> nb::Result<u8, Self::Error> { Ok(123) }
532 /// # }
533 /// # let pin = Pin;
534 ///
535 /// let reader = SmlReader::with_static_buffer::<1024>().from_eh_reader(pin);
536 /// ```
537 #[cfg(feature = "embedded_hal")]
538 pub fn from_eh_reader<R: embedded_hal::serial::Read<u8, Error = E>, E>(
539 self,
540 reader: R,
541 ) -> SmlReader<util::EhReader<R, E>, Buf> {
542 SmlReader {
543 decoder: DecoderReader::new(util::EhReader::new(reader)),
544 }
545 }
546
547 /// Build an `SmlReader` from a slice of bytes.
548 ///
549 /// # Examples
550 ///
551 /// ```
552 /// # use sml_rs::SmlReader;
553 /// let data: &[u8] = &[1, 2, 3];
554 /// let reader = SmlReader::with_static_buffer::<1024>().from_slice(data);
555 /// ```
556 pub fn from_slice(self, reader: &[u8]) -> SmlReader<util::SliceReader<'_>, Buf> {
557 SmlReader {
558 decoder: DecoderReader::new(util::SliceReader::new(reader)),
559 }
560 }
561
562 /// Build an `SmlReader` from a type that can be turned into a byte iterator.
563 ///
564 /// # Examples
565 ///
566 /// ```
567 /// # use sml_rs::SmlReader;
568 /// let data: [u8; 3] = [1, 2, 3];
569 /// let builder = SmlReader::with_static_buffer::<1024>();
570 /// let reader = builder.clone().from_iterator(data.clone()); // [u8; 3]
571 /// let reader = builder.clone().from_iterator(&data); // &[u8; 3]
572 /// let reader = builder.clone().from_iterator(data.as_slice()); // &[u8]
573 /// let reader = builder.clone().from_iterator(data.iter()); // impl Iterator<Item = &u8>
574 /// let reader = builder.clone().from_iterator(data.into_iter()); // impl Iterator<Item = u8>
575 /// ```
576 pub fn from_iterator<B, I>(self, iter: I) -> SmlReader<util::IterReader<I::IntoIter, B>, Buf>
577 where
578 I: IntoIterator<Item = B>,
579 B: Borrow<u8>,
580 {
581 SmlReader {
582 decoder: DecoderReader::new(util::IterReader::new(iter.into_iter())),
583 }
584 }
585}
586
587/// Helper trait implemented for types that can be built from decoded bytes.
588pub trait SmlParse<'i, T>: Sized + util::private::Sealed {
589 /// The error produced if parsing fails or the input contained an error.
590 type Error;
591
592 /// Takes the result of decoding and parses it into the resulting type.
593 fn parse_from(value: T) -> Result<Self, Self::Error>;
594}
595
596/// Type alias for decoded bytes.
597pub type DecodedBytes<'i> = &'i [u8];
598
599type ReadDecodedRes<'i, ReadErr> = Result<&'i [u8], ReadDecodedError<ReadErr>>;
600
601impl<'i, ReadErr> SmlParse<'i, ReadDecodedRes<'i, ReadErr>> for DecodedBytes<'i>
602where
603 ReadErr: core::fmt::Debug,
604{
605 type Error = ReadDecodedError<ReadErr>;
606
607 fn parse_from(value: ReadDecodedRes<'i, ReadErr>) -> Result<Self, Self::Error> {
608 value
609 }
610}
611
612impl<'i> SmlParse<'i, &'i [u8]> for DecodedBytes<'i> {
613 type Error = core::convert::Infallible;
614
615 fn parse_from(value: &'i [u8]) -> Result<Self, Self::Error> {
616 Ok(value)
617 }
618}
619
620impl<'i> util::private::Sealed for DecodedBytes<'i> {}
621
622#[cfg(feature = "alloc")]
623impl<'i, ReadErr> SmlParse<'i, ReadDecodedRes<'i, ReadErr>> for File<'i>
624where
625 ReadErr: core::fmt::Debug,
626{
627 type Error = ReadParsedError<ReadErr>;
628
629 fn parse_from(value: ReadDecodedRes<'i, ReadErr>) -> Result<Self, Self::Error> {
630 Ok(parse(value?)?)
631 }
632}
633
634#[cfg(feature = "alloc")]
635impl<'i> SmlParse<'i, &'i [u8]> for File<'i> {
636 type Error = ParseError;
637
638 fn parse_from(value: &'i [u8]) -> Result<Self, Self::Error> {
639 parse(value)
640 }
641}
642
643#[cfg(feature = "alloc")]
644impl<'i> util::private::Sealed for File<'i> {}
645
646impl<'i, ReadErr> SmlParse<'i, ReadDecodedRes<'i, ReadErr>> for Parser<'i>
647where
648 ReadErr: core::fmt::Debug,
649{
650 type Error = ReadDecodedError<ReadErr>;
651
652 fn parse_from(value: ReadDecodedRes<'i, ReadErr>) -> Result<Self, Self::Error> {
653 Ok(Parser::new(value?))
654 }
655}
656
657impl<'i> SmlParse<'i, &'i [u8]> for Parser<'i> {
658 type Error = core::convert::Infallible;
659
660 fn parse_from(value: &'i [u8]) -> Result<Self, Self::Error> {
661 Ok(Parser::new(value))
662 }
663}
664
665impl<'i> util::private::Sealed for Parser<'i> {}
666
667#[test]
668fn test_smlreader_construction() {
669 let arr = [1, 2, 3, 4, 5];
670
671 // no deps
672
673 // using default buffer
674 SmlReader::from_slice(&arr);
675 SmlReader::from_iterator(&arr);
676 SmlReader::from_iterator(arr.iter().map(|x| x + 1));
677 #[cfg(feature = "std")]
678 SmlReader::from_reader(std::io::Cursor::new(&arr));
679
680 // using static buffer
681 SmlReader::with_static_buffer::<1234>().from_slice(&arr);
682 SmlReader::with_static_buffer::<1234>().from_iterator(arr.iter().map(|x| x + 1));
683 #[cfg(feature = "std")]
684 SmlReader::with_static_buffer::<1234>().from_reader(std::io::Cursor::new(&arr));
685
686 // using dynamic buffer
687 #[cfg(feature = "alloc")]
688 SmlReader::with_vec_buffer().from_slice(&arr);
689 #[cfg(feature = "alloc")]
690 SmlReader::with_vec_buffer().from_iterator(arr.iter().map(|x| x + 1));
691 #[cfg(feature = "std")]
692 SmlReader::with_vec_buffer().from_reader(std::io::Cursor::new(&arr));
693}
694
695#[test]
696#[cfg(feature = "embedded_hal")]
697fn test_smlreader_eh_construction() {
698 // dummy struct implementing `Read`
699 struct Pin;
700 impl embedded_hal::serial::Read<u8> for Pin {
701 type Error = i16;
702
703 fn read(&mut self) -> nb::Result<u8, Self::Error> {
704 Ok(123)
705 }
706 }
707
708 // using default buffer
709 SmlReader::from_eh_reader(Pin);
710
711 // using static buffer
712 SmlReader::with_static_buffer::<1234>().from_eh_reader(Pin);
713
714 // using dynamic buffer
715 #[cfg(feature = "alloc")]
716 SmlReader::with_vec_buffer().from_eh_reader(Pin);
717}
718
719mod read_tests {
720 #[test]
721 fn test_smlreader_reading() {
722 // check that different types can be used with read and next
723 #[cfg(feature = "alloc")]
724 use super::File;
725 use super::{DecodedBytes, Parser, SmlReader};
726
727 let bytes = [1, 2, 3, 4];
728 let mut reader = SmlReader::from_slice(&bytes);
729
730 let _ = reader.read::<DecodedBytes>();
731 let _: Result<DecodedBytes, _> = reader.read();
732
733 #[cfg(feature = "alloc")]
734 let _ = reader.read::<File>();
735 let _ = reader.read::<Parser>();
736
737 let _ = reader.next::<DecodedBytes>();
738 #[cfg(feature = "alloc")]
739 let _ = reader.next::<File>();
740 let _ = reader.next::<Parser>();
741 }
742
743 #[test]
744 #[cfg(feature = "nb")]
745 fn test_smlreader_reading_nb() {
746 // check that different types can be used with read_nb and next_nb
747 #[cfg(feature = "alloc")]
748 use super::File;
749 use super::{DecodedBytes, Parser, SmlReader};
750
751 let bytes = [1, 2, 3, 4];
752 let mut reader = SmlReader::from_slice(&bytes);
753
754 let _ = reader.next_nb::<DecodedBytes>();
755 #[cfg(feature = "alloc")]
756 let _ = reader.next_nb::<File>();
757 let _ = reader.next_nb::<Parser>();
758
759 let _ = reader.read_nb::<DecodedBytes>();
760 #[cfg(feature = "alloc")]
761 let _ = reader.read_nb::<File>();
762 let _ = reader.read_nb::<Parser>();
763 }
764}