swrite/lib.rs
1//! [](https://github.com/rusticstuff/swrite/actions/workflows/ci.yml)
2//! [](https://crates.io/crates/swrite)
3//! [](https://docs.rs/swrite)
4//! 
5//!
6//! `swrite` is a tiny Rust crate providing the `swrite!` and `swriteln!` macros as
7//! infallible alternatives to `write!` and `writeln!` for Strings. This is safe because
8//! writing to a String never returns `Err(_)`.
9//!
10//! The implementation uses the `SWrite` trait. It is implemented for `String`.
11//! With the `osstring` feature is enabled, it is also implemented for `std::ffi::OsString`.
12//!
13//! Minimum Supported Rust Version (MSRV):
14//! - Without the `osstring` feature (default): 1.30.0
15//! - With the `osstring` feature: 1.64.0
16//!
17//! # Usage
18//!
19//! In `Cargo.toml`:
20//!
21//! ```toml
22//! [dependencies]
23//! swrite = "0.1.0"
24//! ```
25//!
26//! In your Rust code:
27//!
28//! ```rust
29//! use swrite::{SWrite, swrite, swriteln};
30//! ```
31//!
32//! # Examples
33//!
34//! Using `swrite!` and `swriteln!` with a `String`:
35//!
36//! ```rust
37//! use swrite::{SWrite, swrite, swriteln};
38//!
39//! let mut s = String::new();
40//! swrite!(s, "Hello, {}! ", "world");
41//! swriteln!(s, "The answer is {}.", 42);
42//!
43//! println!("{}", s);
44//! ```
45//!
46//! Output:
47//!
48//! ```not_rust
49//! Hello, world! The answer is 42.
50//! ```
51//!
52//! # License
53//!
54//! This project is dual-licensed under [Apache 2.0](LICENSE-APACHE) and [MIT](LICENSE-MIT) licenses.
55
56/// Write formatted text to the given `String`.
57///
58/// # Example
59/// ```
60/// use swrite::{SWrite, swrite};
61/// let mut s = String::new();
62/// swrite!(s, "The answer is {}.", 42);
63/// ```
64#[macro_export]
65macro_rules! swrite {
66 ($dst:expr, $($arg:tt)*) => {
67 $dst.swrite_fmt(format_args!($($arg)*))
68 };
69}
70
71/// Write formatted text to the given `String`, followed by a newline.
72///
73/// # Example
74/// ```
75/// use swrite::{SWrite, swriteln};
76/// let mut s = String::new();
77/// swriteln!(s, "The answer is {}.", 42);
78/// ```
79#[macro_export]
80macro_rules! swriteln {
81 ($dst:expr) => {
82 $crate::swrite!($dst, "\n")
83 };
84 ($dst:expr,) => {
85 $crate::swrite!($dst, "\n")
86 };
87 ($dst:expr, $($arg:tt)*) => {
88 $dst.swrite_fmt_nl(format_args!($($arg)*))
89 };
90}
91
92/// Implementing this trait allows using the `swrite!` and `swriteln!` macros.
93pub trait SWrite {
94 /// Write formatted text.
95 ///
96 /// For types implementing `std::fmt::Write` this is usually done with
97 /// just a call to `std::fmt::Write::write_fmt` ignoring the result.
98 ///
99 /// Make sure that `write_fmt()` never returns `Err(_)`.
100 fn swrite_fmt(&mut self, fmt: std::fmt::Arguments<'_>);
101
102 /// Write formatted text to the given `String`, followed by a newline.
103 ///
104 /// For types implementing `std::fmt::Write` this is usually done with
105 /// just a call to `std::fmt::Write::write_fmt`, followed by a type-specific
106 /// way of appending a newline.
107 ///
108 /// Make sure that `write_fmt()` never returns `Err(_)`.
109 fn swrite_fmt_nl(&mut self, fmt: std::fmt::Arguments<'_>);
110}
111
112impl SWrite for String {
113 #[inline]
114 fn swrite_fmt(&mut self, fmt: std::fmt::Arguments<'_>) {
115 // write_fmt() never fails for Strings.
116 let _ = std::fmt::Write::write_fmt(self, fmt);
117 }
118
119 #[inline]
120 fn swrite_fmt_nl(&mut self, fmt: std::fmt::Arguments<'_>) {
121 self.swrite_fmt(fmt);
122 self.push('\n');
123 }
124}
125
126#[cfg(feature = "osstring")]
127impl SWrite for std::ffi::OsString {
128 #[inline]
129 fn swrite_fmt(&mut self, fmt: std::fmt::Arguments<'_>) {
130 // write_fmt() never fails for OsStrings.
131 let _ = std::fmt::Write::write_fmt(self, fmt);
132 }
133
134 #[inline]
135 fn swrite_fmt_nl(&mut self, fmt: std::fmt::Arguments<'_>) {
136 self.swrite_fmt(fmt);
137 self.push("\n");
138 }
139}
140
141#[cfg(all(test, feature = "osstring"))]
142mod osstring_tests;