use std::fmt::Display;
pub(crate) trait ResponseSender: Send {
fn send(&mut self, result: Result<(&str, &[u8]), String>);
}
#[must_use]
pub struct Responder(Option<Inner>);
impl std::fmt::Debug for Responder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Responder").finish_non_exhaustive()
}
}
impl Responder {
pub(crate) fn new(encoding: impl Into<String>, sender: Box<dyn ResponseSender>) -> Self {
Self(Some(Inner {
encoding: encoding.into(),
sender,
}))
}
pub fn set_encoding(&mut self, encoding: impl Into<String>) {
if let Some(inner) = self.0.as_mut() {
inner.encoding = encoding.into();
}
}
pub fn respond<T, E>(self, result: Result<T, E>)
where
T: AsRef<[u8]>,
E: Display,
{
match result {
Ok(data) => self.respond_ok(data),
Err(e) => self.respond_err(e.to_string()),
}
}
pub fn respond_ok(mut self, data: impl AsRef<[u8]>) {
if let Some(mut inner) = self.0.take() {
inner.sender.send(Ok((&inner.encoding, data.as_ref())));
}
}
pub fn respond_err(mut self, message: String) {
if let Some(mut inner) = self.0.take() {
inner.sender.send(Err(message));
}
}
}
impl Drop for Responder {
fn drop(&mut self) {
if let Some(mut inner) = self.0.take() {
inner.sender.send(Err(
"Internal server error: service failed to send a response".into(),
));
}
}
}
struct Inner {
encoding: String,
sender: Box<dyn ResponseSender>,
}