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