nextest_runner/write_str.rs
1// Copyright (c) The nextest Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Support for string-only writes.
5//!
6//! There are potential situations where nextest needs to abstract over multiple kinds of writers,
7//! but some of them do not accept arbitrary bytes -- they must be valid UTF-8.
8//!
9//! This is similar to [`std::fmt::Write`], but it returns [`std::io::Error`] instead for better
10//! error handling.
11
12use std::{fmt, io};
13
14/// A trait that abstracts over writing strings to a writer.
15///
16/// For more, see the [module-level documentation](self).
17pub trait WriteStr {
18 /// Writes a string to the writer.
19 fn write_str(&mut self, s: &str) -> io::Result<()>;
20
21 /// Flushes the writer, ensuring that all intermediately buffered contents reach their
22 /// destination.
23 fn write_str_flush(&mut self) -> io::Result<()>;
24
25 /// Writes a single character to the writer.
26 fn write_char(&mut self, c: char) -> io::Result<()> {
27 self.write_str(c.encode_utf8(&mut [0; 4]))
28 }
29
30 /// Writes a formatted string to the writer.
31 fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
32 // This code is adapted from the `write_fmt` implementation for `std::io::Write`, and is
33 // used under the terms of the MIT and Apache-2.0 licenses.
34
35 // Create a shim which translates self to a fmt::Write and saves off errors instead of
36 // discarding them.
37 struct Adapter<'a, T: ?Sized> {
38 inner: &'a mut T,
39 error: Result<(), io::Error>,
40 }
41
42 impl<T: ?Sized + WriteStr> fmt::Write for Adapter<'_, T> {
43 fn write_str(&mut self, s: &str) -> fmt::Result {
44 match self.inner.write_str(s) {
45 Ok(()) => Ok(()),
46 Err(e) => {
47 self.error = Err(e);
48 Err(fmt::Error)
49 }
50 }
51 }
52 }
53
54 let mut output = Adapter {
55 inner: self,
56 error: Ok(()),
57 };
58 match fmt::write(&mut output, fmt) {
59 Ok(()) => Ok(()),
60 Err(_) => {
61 // check if the error came from the underlying `Write` or not
62 if output.error.is_err() {
63 output.error
64 } else {
65 Err(io::Error::new(io::ErrorKind::Other, "formatter error"))
66 }
67 }
68 }
69 }
70}
71
72impl WriteStr for String {
73 fn write_str(&mut self, s: &str) -> io::Result<()> {
74 self.push_str(s);
75 Ok(())
76 }
77
78 fn write_str_flush(&mut self) -> io::Result<()> {
79 Ok(())
80 }
81
82 fn write_char(&mut self, c: char) -> io::Result<()> {
83 self.push(c);
84 Ok(())
85 }
86}
87
88impl<T: WriteStr + ?Sized> WriteStr for &mut T {
89 fn write_str(&mut self, s: &str) -> io::Result<()> {
90 (**self).write_str(s)
91 }
92
93 fn write_str_flush(&mut self) -> io::Result<()> {
94 (**self).write_str_flush()
95 }
96
97 fn write_char(&mut self, c: char) -> io::Result<()> {
98 (**self).write_char(c)
99 }
100
101 fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
102 (**self).write_fmt(fmt)
103 }
104}
105
106// Add more impls as needed.