syslog_client/writer/
mod.rs1use core::fmt;
3
4use crate::syslog::Severity;
5
6#[cfg(feature = "std")]
7mod std;
8pub mod transport {
10 #[cfg(feature = "std")]
11 pub use super::std::*;
12}
13
14pub trait MakeTransport {
16 type Error: TransportError;
18 type Transport: Transport<Self::Error>;
20
21 fn create(&self) -> Result<Self::Transport, Self::Error>;
25}
26
27pub trait TransportError: fmt::Debug {
29 fn is_terminal(&self) -> bool;
33}
34
35pub trait Transport<ERR: TransportError> {
37 fn write(&mut self, severity: Severity, msg: &str) -> Result<(), ERR>;
41}
42
43impl<IO: MakeTransport> MakeTransport for &'_ IO {
44 type Error = IO::Error;
45 type Transport = IO::Transport;
46
47 #[inline(always)]
48 fn create(&self) -> Result<Self::Transport, Self::Error> {
49 MakeTransport::create(*self)
50 }
51}
52
53pub(crate) struct Writer<IO: MakeTransport> {
54 transport: IO,
55 cached_writer: Option<IO::Transport>,
56}
57
58impl<IO: MakeTransport> Writer<IO> {
59 #[inline(always)]
60 pub(crate) const fn new(transport: IO) -> Self {
61 Self {
62 transport,
63 cached_writer: None,
64 }
65 }
66
67 pub(crate) fn write_buffer(&mut self, buffer: &str, severity: Severity, retry_count: u8) -> Result<(), IO::Error> {
68 let mut retry_attempts = retry_count.saturating_add(1);
70
71 loop {
72 retry_attempts = retry_attempts.saturating_sub(1);
73
74 let mut writer = match self.cached_writer.take() {
75 Some(writer) => writer,
76 None => match self.transport.create() {
77 Ok(writer) => writer,
78 Err(error) if error.is_terminal() => return Err(error),
80 Err(_) if retry_attempts > 0 => continue,
81 Err(error) => break Err(error),
82 },
83 };
84
85 match writer.write(severity, buffer) {
86 Ok(()) => {
87 self.cached_writer = Some(writer);
89 break Ok(());
90 }
91 Err(error) if error.is_terminal() => continue,
94 Err(_) if retry_attempts > 0 => {
95 self.cached_writer = Some(writer);
96 },
97 Err(error) => break Err(error),
98 }
99 }
100 }
101}