260915.1 · 24198d904a074f2943b2a3be925e53134c994734
fix: Better sanitizing
This refactors the sanitization code somewhat, to provide a couple benefits:
- Ensure we sanitize output in error messages (#2119), while not
escaping newlines from error messages.
- Avoids some unnecessary allocations and string copies
- Makes `print_error` a little nicer to use. As a macro, it avoids
needing a separate call to `format!`.
The main downside is added complexity.
Fixes: #2119
reading declarations
Changes to src/error.rs. All files
@@ -1,3 +1,51 @@-pub fn print_error(msg: impl std::fmt::Display) {- eprintln!("[fd error]: {msg}");+use std::fmt::Display;+use std::io;++use crate::sanitize::write_sanitized;++/// Print an error message using a format string, sanitizing any arguments if necessary+macro_rules! print_error {+ ($fmt:literal, $($arg:expr),*) => {+ eprintln!(concat!("[fd error]: ", $fmt), $($crate::error::SanitizeErr::sanitize($arg)),*)+ }+}++/// Trait for specifying how to sanitize a type for error display, if needed.+pub(crate) trait SanitizeErr {+ type Sanitized: Display;++ fn sanitize(self) -> Self::Sanitized;+}++impl SanitizeErr for &str {+ type Sanitized = Self;++ fn sanitize(self) -> Self {+ self+ }+}++impl SanitizeErr for io::Error {+ type Sanitized = SanitizedError<io::Error>;++ fn sanitize(self) -> Self::Sanitized {+ SanitizedError(self)+ }+}++impl SanitizeErr for ignore::Error {+ type Sanitized = SanitizedError<ignore::Error>;++ fn sanitize(self) -> Self::Sanitized {+ SanitizedError(self)+ }+}++pub struct SanitizedError<E>(E);++impl<E: std::error::Error> Display for SanitizedError<E> {+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {+ let raw = self.0.to_string();+ write_sanitized(f, &raw)+ } }