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_core::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}