use super::IntoResponse;
use crate::{Body, Response, dep::http::StatusCode};
use bytes::buf::Writer;
use bytes::{BufMut, BytesMut};
use csv;
use rama_core::error::OpaqueError;
use rama_http_headers::ContentType;
use rama_utils::macros::impl_deref;
use serde::Serialize;
use std::fmt;
use super::Headers;
pub struct Csv<T>(pub T);
impl<T: fmt::Debug> fmt::Debug for Csv<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Csv").field(&self.0).finish()
}
}
impl<T: Clone> Clone for Csv<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl_deref!(Csv);
impl<T> From<T> for Csv<T> {
fn from(inner: T) -> Self {
Self(inner)
}
}
impl<T> IntoResponse for Csv<T>
where
T: IntoIterator<Item: Serialize> + std::fmt::Debug,
{
fn into_response(self) -> Response {
fn make_respone(
res: csv::Result<Vec<()>>,
mut wtr: csv::Writer<Writer<BytesMut>>,
) -> Response {
if let Err(err) = res {
return (
StatusCode::INTERNAL_SERVER_ERROR,
Headers::single(ContentType::text_utf8()),
err.to_string(),
)
.into_response();
}
if let Err(err) = wtr.flush() {
return (
StatusCode::INTERNAL_SERVER_ERROR,
Headers::single(ContentType::text_utf8()),
err.to_string(),
)
.into_response();
}
let bw = match wtr.into_inner() {
Ok(bw) => bw,
Err(err) => {
return (
StatusCode::INTERNAL_SERVER_ERROR,
Headers::single(ContentType::text_utf8()),
err.to_string(),
)
.into_response();
}
};
(
Headers::single(ContentType::csv_utf8()),
bw.into_inner().freeze(),
)
.into_response()
}
let buf = BytesMut::with_capacity(128).writer();
let mut wtr = csv::Writer::from_writer(buf);
let res: Result<Vec<_>, _> = self.0.into_iter().map(|rec| wtr.serialize(rec)).collect();
make_respone(res, wtr)
}
}
impl<T> TryInto<Body> for Csv<T>
where
T: IntoIterator<Item: Serialize>,
{
type Error = OpaqueError;
fn try_into(self) -> Result<Body, Self::Error> {
let mut buf = BytesMut::with_capacity(128).writer();
{
let mut wtr = csv::Writer::from_writer(&mut buf);
let res: Result<Vec<_>, _> = self.0.into_iter().map(|rec| wtr.serialize(rec)).collect();
if let Err(err) = res {
return Err(OpaqueError::from_std(err));
}
if let Err(err) = wtr.flush() {
return Err(OpaqueError::from_std(err));
}
}
Ok(buf.into_inner().freeze().into())
}
}