platform_switch/
lib.rs

1// Copyright (c) Jake Swensen
2// SPDX-License-Identifier: MPL-2.0
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8//! Namespace facades for switching between platforms.
9//!
10//! # Motivation
11//! Sometimes code needs to be shared between a contrainted platform
12//! (such as an embedded system) and a target that has a more fully
13//! featured environment. This crate provides a series of module wrappers
14//! that can be used in combination with cargo manifest feature definitions
15//! to switch between options at compile time.
16//!
17//! # Example
18//! Using `thiserror` with `defmt` enabled on an embedded system:
19//!
20//! ```toml
21//! [features]
22//! default = ["std"]
23//! std = ["platform-switch/std_error"]
24//! mcu = ["platform-switch/core_error", "platform-switch/defmt"] # Requires nightly
25//! ```
26//!
27//! ```rust
28//! use platform_switch::log as log;
29//! use platform_switch::thiserror as thiserror;
30//!
31//! #[derive(thiserror::Error, Debug)]
32//! enum ExampleError {
33//!     #[error("Error #1")]
34//!     Error1,
35//!     #[error("Error #2")]
36//!     Error2,
37//! }
38//!
39//! fn error_logger() {
40//!     log::trace!("Trace");
41//!     log::debug!("Debug");
42//!     log::info!("Info");
43//!     log::warn!("Warn");
44//!     log::error!("Error");
45//!
46//!     log::error!("Error: {}", ExampleError::Error1);
47//!     log::error!("Error: {}", ExampleError::Error2);
48//! }
49//! ```
50//! 
51//! ## Stable Toolchain
52//! If a stable toolchain is required, `thiserror` can be disabled with the following features and attributes:
53//! ```toml
54//! [features]
55//! default = ["std"]
56//! std = ["thiserror", "platform-switch/std_error"]
57//! mcu = ["platform-switch/defmt"]
58//! thiserror = []
59//! ```
60//!
61//! ```rust
62//! use platform_switch::log as log;
63//! use platform_switch::thiserror as thiserror;
64//!
65//! #[derive(Debug)]
66//! #[cfg_attr(feature = "thiserror", derive(thiserror::Error))]
67//! enum ExampleError {
68//!     #[cfg_attr(feature = "thiserror", error("Error #1"))]
69//!     Error1,
70//!
71//!     #[cfg_attr(feature = "thiserror", error("Error #2"))]
72//!     Error2,
73//! }
74//! ```
75
76#![cfg_attr(not(feature = "std"), no_std)]
77#![cfg_attr(all(not(any(feature = "std", test)), feature = "core_error"), feature(error_in_core))]
78
79/// A namespace facade around [`thiserror`].
80///
81/// Enables [`thiserror`] to be used in both [`std`] and `no_std` environments.
82/// If configured for `no_std`, this module will use `thiserror-core` (which requires
83/// a nightly toolchain).
84///
85/// ### Note
86/// This module will be marked deprecated once `error_in_core` is
87/// [stabilized](https://github.com/rust-lang/rust/issues/103765) and [`thiserror`]
88/// fully supports using [`core::error`].
89#[cfg(feature = "thiserror")]
90pub mod thiserror {
91    cfg_if::cfg_if! {
92        if #[cfg(not(feature = "core_error"))] {
93            pub use thiserror::*;
94        } else {
95            pub use thiserror_core::*;
96        }
97    }
98}
99
100/// A namespace facade around [`log`] and `defmt`.
101///
102/// Enabling the feature `defmt` will re-export the `defmt` macros for logging.
103/// Otherwise, the `log` macros will be re-exported.
104#[cfg(feature = "log")]
105pub mod log {
106    cfg_if::cfg_if! {
107        if #[cfg(feature = "defmt")] {
108            pub use defmt::debug as debug;
109            pub use defmt::error as error;
110            pub use defmt::info as info;
111            pub use defmt::trace as trace;
112            pub use defmt::warn as warn;
113        } else {
114            pub use log::debug as debug;
115            pub use log::error as error;
116            pub use log::info as info;
117            pub use log::trace as trace;
118            pub use log::warn as warn;
119        }
120    }
121}
122
123/// A namespace facade for formatting.
124pub mod fmt {
125    cfg_if::cfg_if! {
126        if #[cfg(feature = "std")] {
127            pub use std::fmt::Debug as Debug;
128            pub use std::fmt::Display as Display;
129            pub use std::fmt::Formatter as Formatter;
130            pub use std::fmt::Result as Result;
131        } else {
132            pub use core::fmt::Debug as Debug;
133            pub use core::fmt::Display as Display;
134            pub use core::fmt::Formatter as Formatter;
135            pub use core::fmt::Result as Result;
136        }
137    }
138}