use crate::{
http::status::StatusCode,
parse::{AutoParse, CAutoParse, ParseWebResult},
};
use serde::{Deserialize, Serialize};
use std::{
any::Any,
borrow::Cow,
collections::HashMap,
ffi::{c_char, CStr, CString},
};
#[derive(Serialize, Debug, Clone, Deserialize)]
pub struct WebResult<T> {
pub code: u16,
pub msg: Cow<'static, str>,
pub data: T,
}
impl<T: Serialize> WebResult<T> {
pub fn to_s(res: &Result<T>) -> Result<String> {
Ok(serde_json::to_string(&res.res_web()?)?)
}
}
impl From<&'static str> for Error {
fn from(s: &'static str) -> Self {
Self::Str(Cow::Borrowed(s))
}
}
impl From<String> for Error {
fn from(s: String) -> Self {
Self::Str(Cow::Owned(s))
}
}
pub type Result<T> = std::result::Result<T, Error>;
impl<T> From<Result<T>> for CResult<T> {
fn from(result: Result<T>) -> Self {
match result {
Result::Ok(value) => CResult::Ok(value),
Result::Err(error) => CResult::Err(CError::cstr_err(error.to_string())),
}
}
}
impl<T> From<CResult<T>> for Result<T> {
fn from(result: CResult<T>) -> Self {
match result {
CResult::Ok(value) => Result::Ok(value),
CResult::Err(error) => Result::Err(Error::String(
unsafe { CStr::from_ptr(error.to_string()) }
.to_str()
.unwrap_or_default()
.to_string(),
)),
}
}
}
#[repr(C)]
#[derive(Debug)]
pub enum CResult<T> {
Ok(T),
Err(CError),
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("400 拒绝请求")]
BadRequest,
#[error("Exists: {0}")]
Exists(Cow<'static, str>),
#[error("400 SerdeJson错误: {0}")]
SerdeJson(#[from] serde_json::Error),
#[error("Str: {0}")]
Str(Cow<'static, str>),
#[error("String: {0}")]
String(String),
#[error("regex error: {0}")]
Regex(#[from] regex::Error),
#[error("authentication required: {0}")]
Unauthorized(&'static str),
#[error("user may not perform that action")]
Forbidden,
#[error("request path not found: {0}")]
NotFound(Cow<'static, str>),
#[error("Option<{0}>")]
Option(Cow<'static, str>),
#[error("Not support: {0}")]
Unsupport(Cow<'static, str>),
#[error("error in the request body: {errors:?}")]
UnprocessableEntity {
errors: HashMap<Cow<'static, str>, Vec<Cow<'static, str>>>,
},
#[error("TryFromSlice: {0}")]
TryFromSlice(#[from] std::array::TryFromSliceError),
#[error("an error occurred with the std io: {0}")]
Io(#[from] std::io::Error),
#[error("env var error : {0}")]
Env(#[from] std::env::VarError),
#[error("Empty")]
Empty,
#[error("an error occurred with the std Error: {0}")]
Std(#[from] Box<dyn std::error::Error + Send + Sync>),
#[error("an error occurred with the parse Error: {0}")]
ParseNumber(#[from] std::num::ParseIntError),
#[error("an error occurred with the parse Error: {0}")]
ParseFloatError(#[from] std::num::ParseFloatError),
#[error("Log: {0}")]
Log(Cow<'static, str>),
#[error("CString: {0}")]
Nul(#[from] std::ffi::NulError),
#[error("Any Error: ")]
Any {
err: Box<dyn std::any::Any + Send + Sync>,
},
}
impl Error {
pub fn unprocessable_entity<K, V>(errors: impl IntoIterator<Item = (K, V)>) -> Self
where
K: Into<Cow<'static, str>>,
V: Into<Cow<'static, str>>,
{
Self::UnprocessableEntity {
errors: errors
.into_iter()
.map(|(key, val)| (key.into(), vec![val.into()]))
.collect(),
}
}
pub fn any(err: Box<dyn Any + Send + Sync>) -> Self {
Self::Any { err }
}
pub fn status_code(&self) -> StatusCode {
match self {
Self::BadRequest
| Self::Str(..)
| Self::SerdeJson(..)
| Self::ParseNumber(_)
| Self::Regex(_)
| Self::Env(_)
| Self::Log(_)
| Self::String(_)
| Self::Exists(_)
| Self::Empty
| Self::Nul(_)
| Self::Option(_)
| Self::TryFromSlice(_)
| Self::Unsupport(_)
| Self::ParseFloatError(_) => StatusCode::BAD_REQUEST,
Self::Unauthorized(_) => StatusCode::UNAUTHORIZED,
Self::Forbidden => StatusCode::FORBIDDEN,
Self::NotFound(_) => StatusCode::NOT_FOUND,
Self::UnprocessableEntity { .. } => StatusCode::UNPROCESSABLE_ENTITY,
Self::Io(_) | Self::Std(_) | Self::Any { .. } => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
#[repr(C)]
#[derive(thiserror::Error, Debug)]
pub enum CError {
#[error("C 400 拒绝请求")]
BadRequest,
#[error("C Str: ")]
Str(*const c_char),
#[error("C Not Support: ")]
Unsupport(*const c_char),
}
impl CError {
pub fn cstr<S: AsRef<str>>(s: S) -> *const c_char {
CString::new(s.as_ref()).unwrap_or_default().into_raw()
}
pub fn cstr_err<S: AsRef<str>>(s: S) -> CError {
Self::Str(Self::cstr(s))
}
pub fn status_code(&self) -> StatusCode {
match self {
Self::BadRequest | Self::Str(..) | Self::Unsupport(_) => StatusCode::BAD_REQUEST,
}
}
}
impl CError {
pub unsafe extern "C" fn to_string(&self) -> *const c_char {
match self {
Self::BadRequest => format!("C BadRequest"),
Self::Str(x) => format!("C Str<{}>", x.c_to_string()),
Self::Unsupport(x) => format!("C Unsupport<{}>", x.c_to_string()),
}
.to_c_char()
}
}