sericom_core/
lib.rs

1//! `sericom-core` is the underlying library for [`sericom`](https://crates.io/crates/sericom)
2//!
3//! As it sits right now, this library is largely meant to be solely used by `sericom`
4//! directly. Therefore, it is not intended to be used within other projects/crates.
5//!
6//! If other projects develop a need to use this library within their projects, please
7//! create an [issue](https://github.com/tkatter/sericom) so I can become aware and work
8//! towards making `sericom-core` a generalized/compatible library that is better suited
9//! for use among other crates.
10
11pub mod cli;
12pub mod configs;
13pub mod debug;
14pub mod screen_buffer;
15pub mod serial_actor;
16
17mod macros {
18    //! This module holds generic macros that are used throughout sericom.
19
20    /// Takes a [`&Path`][std::path::Path] and first checks whether it exists or if it is a
21    /// directory. If it doesn't exist or is not a directory, it will create
22    /// the directory recursively; creating the necessary parent directories.
23    #[macro_export]
24    macro_rules! create_recursive {
25        ($path:expr) => {
26            let create_recursive_dir = |p: &std::path::Path| {
27                if !p.exists() || !p.is_dir() {
28                    let mut builder = std::fs::DirBuilder::new();
29                    builder.recursive(true);
30                    builder.create(p).expect("Recursive mode won't panic");
31                }
32            };
33
34            create_recursive_dir($path)
35        };
36    }
37
38    /// Used to add a `.map_err()` to function calls that return a `Result<T, E>`
39    /// to provide better context for the error and print it nicely to stdout.
40    ///
41    /// Takes 2 arguements and optionally a third and fourth:
42    /// - The first argument is the expression or function call that would return a `Result<T, E>`
43    /// - The second argument is context that better describes the returned error
44    /// - The optional third argument is the 'USAGE: sericom ...' that would typically be printed by `clap`
45    ///   for the respective command
46    /// - The optional fourth argument is an additional "help:" message
47    ///
48    /// ## Example
49    /// ```
50    /// use serial2_tokio::SerialPort;
51    /// use crossterm::style::Stylize;
52    /// use sericom::map_miette;
53    /// fn returns_err() -> miette::Result<()> {
54    ///     let baud: u32 = 9600;
55    ///     let port = "/dev/fakeport";
56    ///     let x = map_miette!(
57    ///         SerialPort::open(port, baud),
58    ///         format!("Failed to open port '{}'", port),
59    ///         format!("{} {} [OPTIONS] [PORT] [COMMAND]",
60    ///             "USAGE:".bold().underlined(),
61    ///             "sericom".bold()
62    ///         ),
63    ///         help = format!(
64    ///             "To see available ports, try `{}`.",
65    ///             "sericom list-ports".bold().cyan()
66    ///         )
67    ///     )?;
68    ///     Ok(())
69    /// }
70    /// let fn_err = returns_err();
71    /// assert!(fn_err.is_err());
72    /// ```
73    #[macro_export]
74    macro_rules! map_miette {
75        // Clap-style USAGE: && additional "help" message
76        ($expr:expr, $wrap_msg:expr, $usage:expr, help = $add_help:expr) => {
77            $expr.map_err(|e| {
78                use crossterm::style::Stylize;
79                miette::miette!(
80                    help = format!("{}\nFor more information, try `sericom --help`.", $add_help),
81                    "{e}"
82                )
83                .wrap_err(format!("{}\n\n{}\n", $wrap_msg, $usage).red())
84            })
85        };
86
87        // Clap-style USAGE: && default "help" message
88        ($expr:expr, $wrap_msg:expr, $usage:expr) => {
89            $expr.map_err(|e| {
90                use crossterm::style::Stylize;
91                miette::miette!(help = "For more information, try `sericom --help`.", "{e}")
92                    .wrap_err(format!("{}\n\n{}\n", $wrap_msg, $usage).red())
93            })
94        };
95
96        // Additional "help" message
97        ($expr:expr, $wrap_msg:expr, help = $add_help:expr) => {
98            $expr.map_err(|e| {
99                use crossterm::style::Stylize;
100                miette::miette!(
101                    help = format!("{}\nFor more information, try `sericom --help`.", $add_help),
102                    "{e}"
103                )
104                .wrap_err(format!("{}", $wrap_msg).red())
105            })
106        };
107
108        // Default "help" message
109        ($expr:expr, $wrap_msg:expr) => {
110            $expr.map_err(|e| {
111                use crossterm::style::Stylize;
112                miette::miette!(help = "For more information, try `sericom --help`.", "{e}")
113                    .wrap_err(format!("{}", $wrap_msg).red())
114            })
115        };
116    }
117}