try_drop/drop_strategies/write/
mod.rs

1mod thread_unsafe;
2
3use crate::FallibleTryDropStrategy;
4use parking_lot::Mutex;
5use std::io;
6use std::io::Write;
7use std::string::ToString;
8use std::vec::Vec;
9pub use thread_unsafe::*;
10
11/// A drop strategy which writes the message of an error to a writer.
12#[cfg_attr(feature = "derives", derive(Debug))]
13pub struct WriteDropStrategy<W: Write> {
14    /// The writer to write to.
15    pub writer: Mutex<W>,
16
17    /// Whether or not to append a newline to the end of the message.
18    pub new_line: bool,
19
20    /// The message to add at the beginning of the message.
21    pub prelude: Option<Vec<u8>>,
22}
23
24impl<W: Write> WriteDropStrategy<W> {
25    /// Creates a new [`WriteDropStrategy`] with the given writer.
26    pub fn new(writer: W) -> Self {
27        Self {
28            writer: Mutex::new(writer),
29            new_line: true,
30            prelude: None,
31        }
32    }
33
34    /// Sets whether or not to append a newline to the end of the message.
35    pub fn new_line(&mut self, new_line: bool) -> &mut Self {
36        self.new_line = new_line;
37        self
38    }
39
40    /// Sets the message to add at the beginning of the message.
41    pub fn prelude(&mut self, prelude: impl Into<Vec<u8>>) -> &mut Self {
42        self.prelude = Some(prelude.into());
43        self
44    }
45}
46
47impl WriteDropStrategy<io::Stderr> {
48    /// Write to standard error.
49    pub fn stderr() -> Self {
50        let mut this = Self::new(io::stderr());
51        this.new_line(true);
52        this
53    }
54}
55
56impl WriteDropStrategy<io::Stdout> {
57    /// Write to standard output.
58    pub fn stdout() -> Self {
59        let mut this = Self::new(io::stdout());
60        this.new_line(true);
61        this
62    }
63}
64
65impl<W: Write> FallibleTryDropStrategy for WriteDropStrategy<W> {
66    type Error = io::Error;
67
68    fn try_handle_error(&self, error: anyhow::Error) -> Result<(), Self::Error> {
69        let mut message = Vec::new();
70
71        if let Some(prelude) = &self.prelude {
72            message.extend_from_slice(prelude);
73        }
74
75        message.extend_from_slice(error.to_string().as_bytes());
76
77        if self.new_line {
78            message.push(b'\n')
79        }
80
81        self.writer.lock().write_all(&message)
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use crate::drop_strategies::PanicDropStrategy;
89    use crate::test_utils::{ErrorsOnDrop, Fallible};
90    use crate::PureTryDrop;
91    use std::io::Cursor;
92
93    #[test]
94    fn test_write_drop_strategy() {
95        let mut writer = Cursor::new(Vec::new());
96        let mut strategy = WriteDropStrategy::new(&mut writer);
97        strategy.prelude("error: ");
98        let errors =
99            ErrorsOnDrop::<Fallible, _>::given(strategy, PanicDropStrategy::DEFAULT).adapt();
100        drop(errors);
101        assert_eq!(writer.into_inner(), b"error: this will always fail\n",)
102    }
103}