use crate::router::request::Request;
pub use coap_lite::ResponseType as StatusCode;
use std::convert::Infallible;
#[derive(Debug, Clone, Default)]
pub struct Response {
pub status_code: Option<StatusCode>,
pub payload: Option<Vec<u8>>,
}
impl Response {
pub fn new() -> Self {
Self {
status_code: None,
payload: None,
}
}
pub fn set_status_code(mut self, status_code: StatusCode) -> Self {
self.status_code = Some(status_code);
self
}
pub fn set_payload(mut self, payload: Vec<u8>) -> Self {
self.payload = Some(payload);
self
}
pub fn fill_response(self, request: &mut Request) {
if let Some(response) = request.response_mut() {
if let Some(status_code) = self.status_code {
response.set_status(status_code);
}
if let Some(payload) = &self.payload {
response.message.payload = payload.clone();
}
}
}
}
pub trait IntoResponse {
fn into_response(self) -> Response;
}
impl IntoResponse for Response {
fn into_response(self) -> Response {
self
}
}
impl IntoResponse for () {
fn into_response(self) -> Response {
Response::new()
}
}
impl IntoResponse for StatusCode {
fn into_response(self) -> Response {
Response::new().set_status_code(self)
}
}
impl IntoResponse for Infallible {
fn into_response(self) -> Response {
match self {}
}
}
impl<T: IntoResponse, E: IntoResponse> IntoResponse for Result<T, E> {
fn into_response(self) -> Response {
match self {
Ok(value) => value.into_response(),
Err(err) => err.into_response(),
}
}
}
impl IntoResponse for Vec<u8> {
fn into_response(self) -> Response {
Response::new().set_payload(self)
}
}
impl<const N: usize> IntoResponse for &[u8; N] {
fn into_response(self) -> Response {
self.to_vec().into_response()
}
}
impl<const N: usize> IntoResponse for [u8; N] {
fn into_response(self) -> Response {
(&self).into_response()
}
}
impl IntoResponse for &[u8] {
fn into_response(self) -> Response {
self.to_vec().into_response()
}
}
impl IntoResponse for &str {
fn into_response(self) -> Response {
self.as_bytes().into_response()
}
}
impl IntoResponse for String {
fn into_response(self) -> Response {
self.as_str().into_response()
}
}
impl<T: IntoResponse> IntoResponse for Box<T> {
fn into_response(self) -> Response {
(*self).into_response()
}
}
impl<T: IntoResponse> IntoResponse for (StatusCode, T) {
fn into_response(self) -> Response {
let (status, payload) = self;
payload.into_response().set_status_code(status)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::router::route::RouteError;
#[test]
fn test_response() {
let response = IntoResponse::into_response(());
assert_eq!(response.status_code, None);
assert_eq!(response.payload, None);
let response = IntoResponse::into_response(response);
assert_eq!(response.status_code, None);
assert_eq!(response.payload, None);
}
#[test]
fn test_status_code() {
let status = StatusCode::NotFound;
let response = IntoResponse::into_response(status);
assert_eq!(response.status_code, Some(StatusCode::NotFound));
assert_eq!(response.payload, None);
}
#[test]
fn test_result() {
let response: Result<StatusCode, RouteError> = Ok(StatusCode::Content);
let response = IntoResponse::into_response(response);
assert_eq!(response.status_code, Some(StatusCode::Content));
assert_eq!(response.payload, None);
let response: Result<StatusCode, RouteError> = Err(RouteError::NotFound);
let response = IntoResponse::into_response(response);
assert_eq!(response.status_code, Some(StatusCode::NotFound));
assert_eq!(response.payload, b"Not found".to_vec().into());
}
#[test]
fn test_array() {
let payload = [1, 2, 3];
let response = IntoResponse::into_response(payload);
assert_eq!(response.status_code, None);
assert_eq!(response.payload, Some(vec![1, 2, 3]));
let response = IntoResponse::into_response(payload.as_slice());
assert_eq!(response.status_code, None);
assert_eq!(response.payload, Some(vec![1, 2, 3]));
}
#[test]
fn test_string() {
let status = StatusCode::Content;
let payload = Box::new(String::from("Hello, world!"));
let response = IntoResponse::into_response((status, payload));
assert_eq!(response.status_code, Some(StatusCode::Content));
assert_eq!(response.payload, Some(b"Hello, world!".to_vec()));
}
}