swrite/
lib.rs

1//! [![CI](https://github.com/rusticstuff/swrite/actions/workflows/ci.yml/badge.svg)](https://github.com/rusticstuff/swrite/actions/workflows/ci.yml)
2//! [![crates.io](https://img.shields.io/crates/v/swrite.svg)](https://crates.io/crates/swrite)
3//! [![docs.rs](https://docs.rs/swrite/badge.svg)](https://docs.rs/swrite)
4//! ![Minimum rustc version](https://img.shields.io/badge/rustc-1.30+-lightgray.svg)
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;