#![cfg_attr(docsrs, doc(cfg(feature = "simd")))]
use http::StatusCode;
use http::header::HeaderValue;
use http::header::{self};
use http_body_util::BodyExt;
use serde::Serialize;
use serde::de::DeserializeOwned;
use crate::body::TakoBody;
use crate::extractors::FromRequest;
use crate::responder::Responder;
use crate::types::Request;
use crate::types::Response;
#[doc(alias = "simdjson")]
pub struct SimdJson<T>(pub T);
#[derive(Debug)]
pub enum SimdJsonError {
InvalidContentType,
MissingContentType,
BodyReadError(String),
DeserializationError(String),
}
impl Responder for SimdJsonError {
fn into_response(self) -> Response {
match self {
SimdJsonError::InvalidContentType => (
StatusCode::BAD_REQUEST,
"Invalid content type; expected JSON",
)
.into_response(),
SimdJsonError::MissingContentType => {
(StatusCode::BAD_REQUEST, "Missing content type header").into_response()
}
SimdJsonError::BodyReadError(err) => (
StatusCode::BAD_REQUEST,
format!("Failed to read request body: {}", err),
)
.into_response(),
SimdJsonError::DeserializationError(err) => (
StatusCode::BAD_REQUEST,
format!("Failed to deserialize JSON: {}", err),
)
.into_response(),
}
}
}
use crate::extractors::is_json_content_type;
impl<'a, T> FromRequest<'a> for SimdJson<T>
where
T: DeserializeOwned + Send + 'static,
{
type Error = SimdJsonError;
fn from_request(
req: &'a mut Request,
) -> impl core::future::Future<Output = core::result::Result<Self, Self::Error>> + Send + 'a {
async move {
if !is_json_content_type(req.headers()) {
return Err(SimdJsonError::InvalidContentType);
}
let bytes = req
.body_mut()
.collect()
.await
.map_err(|e| SimdJsonError::BodyReadError(e.to_string()))?
.to_bytes();
let mut owned = bytes.to_vec();
let data = simd_json::from_slice::<T>(&mut owned)
.map_err(|e| SimdJsonError::DeserializationError(e.to_string()))?;
Ok(SimdJson(data))
}
}
}
impl<T> Responder for SimdJson<T>
where
T: Serialize,
{
fn into_response(self) -> Response {
match simd_json::to_vec(&self.0) {
Ok(buf) => {
let mut res = Response::new(TakoBody::from(buf));
res.headers_mut().insert(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
);
res
}
Err(err) => {
let mut res = Response::new(TakoBody::from(err.to_string()));
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
res.headers_mut().insert(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
);
res
}
}
}
}
#[doc(alias = "sonicjson")]
pub struct SonicJson<T>(pub T);
impl<'a, T> FromRequest<'a> for SonicJson<T>
where
T: DeserializeOwned + Send + 'static,
{
type Error = SimdJsonError;
fn from_request(
req: &'a mut Request,
) -> impl core::future::Future<Output = core::result::Result<Self, Self::Error>> + Send + 'a {
async move {
if !is_json_content_type(req.headers()) {
return Err(SimdJsonError::InvalidContentType);
}
let bytes = req
.body_mut()
.collect()
.await
.map_err(|e| SimdJsonError::BodyReadError(e.to_string()))?
.to_bytes();
let mut owned = bytes.to_vec();
let data = sonic_rs::from_slice::<T>(&mut owned)
.map_err(|e| SimdJsonError::DeserializationError(e.to_string()))?;
Ok(SonicJson(data))
}
}
}
impl<T> Responder for SonicJson<T>
where
T: Serialize,
{
fn into_response(self) -> Response {
match sonic_rs::to_vec(&self.0) {
Ok(buf) => {
let mut res = Response::new(TakoBody::from(buf));
res.headers_mut().insert(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
);
res
}
Err(err) => {
let mut res = Response::new(TakoBody::from(err.to_string()));
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
res.headers_mut().insert(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
);
res
}
}
}
}