use super::Error;
use bondrewd::Bitfields;
#[derive(Bitfields, Debug, PartialEq, Eq, Copy, Clone)]
#[bondrewd(default_endianness = "big", enforce_bytes = 1)]
pub(crate) struct EncodedCode {
#[bondrewd(bit_length = 3)]
pub(crate) class: u8,
#[bondrewd(bit_length = 5)]
pub(crate) detail: u8,
}
impl From<Code> for EncodedCode {
fn from(code: Code) -> EncodedCode {
let (class, detail) = match code {
Code::Empty => (0, 0),
Code::Request(code) => match code {
RequestCode::Get => (0, 1),
RequestCode::Post => (0, 2),
RequestCode::Put => (0, 3),
RequestCode::Delete => (0, 4),
},
Code::Response(code) => match code {
ResponseCode::Success(code) => match code {
SuccessCode::Created => (2, 1),
SuccessCode::Deleted => (2, 2),
SuccessCode::Valid => (2, 3),
SuccessCode::Changed => (2, 4),
SuccessCode::Content => (2, 5),
},
ResponseCode::ClientError(code) => match code {
ClientErrorCode::BadRequest => (4, 0),
ClientErrorCode::Unauthorized => (4, 1),
ClientErrorCode::BadOption => (4, 2),
ClientErrorCode::Forbidden => (4, 3),
ClientErrorCode::NotFound => (4, 4),
ClientErrorCode::MethodNotAllowed => (4, 5),
ClientErrorCode::NotAcceptable => (4, 6),
ClientErrorCode::PreconditionFailed => (4, 12),
ClientErrorCode::RequestEntityTooLarge => (4, 13),
ClientErrorCode::UnsupportedContentFormat => (4, 15),
},
ResponseCode::ServerError(code) => match code {
ServerErrorCode::InternalServerError => (5, 0),
ServerErrorCode::NotImplemented => (5, 1),
ServerErrorCode::BadGateway => (5, 2),
ServerErrorCode::ServiceUnavailable => (5, 3),
ServerErrorCode::GatewayTimeout => (5, 4),
ServerErrorCode::ProxyingNotSupported => (5, 5),
},
},
};
EncodedCode { class, detail }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Code {
Empty,
Request(RequestCode),
Response(ResponseCode),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RequestCode {
Get,
Post,
Put,
Delete,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResponseCode {
Success(SuccessCode),
ClientError(ClientErrorCode),
ServerError(ServerErrorCode),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SuccessCode {
Created,
Deleted,
Valid,
Changed,
Content,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClientErrorCode {
BadRequest,
Unauthorized,
BadOption,
Forbidden,
NotFound,
MethodNotAllowed,
NotAcceptable,
PreconditionFailed,
RequestEntityTooLarge,
UnsupportedContentFormat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServerErrorCode {
InternalServerError,
NotImplemented,
BadGateway,
ServiceUnavailable,
GatewayTimeout,
ProxyingNotSupported,
}
impl From<RequestCode> for Code {
fn from(code: RequestCode) -> Code {
Code::Request(code)
}
}
impl TryFrom<Code> for RequestCode {
type Error = ();
fn try_from(value: Code) -> Result<Self, Self::Error> {
match value {
Code::Request(code) => Ok(code),
_ => Err(()),
}
}
}
impl From<ResponseCode> for Code {
fn from(code: ResponseCode) -> Code {
Code::Response(code)
}
}
impl TryFrom<Code> for ResponseCode {
type Error = ();
fn try_from(value: Code) -> Result<Self, Self::Error> {
match value {
Code::Response(code) => Ok(code),
_ => Err(()),
}
}
}
impl From<SuccessCode> for ResponseCode {
fn from(code: SuccessCode) -> ResponseCode {
ResponseCode::Success(code)
}
}
impl From<SuccessCode> for Code {
fn from(code: SuccessCode) -> Code {
ResponseCode::Success(code).into()
}
}
impl TryFrom<Code> for SuccessCode {
type Error = ();
fn try_from(value: Code) -> Result<Self, Self::Error> {
match value {
Code::Response(ResponseCode::Success(code)) => Ok(code),
_ => Err(()),
}
}
}
impl From<ClientErrorCode> for ResponseCode {
fn from(code: ClientErrorCode) -> ResponseCode {
ResponseCode::ClientError(code)
}
}
impl From<ClientErrorCode> for Code {
fn from(code: ClientErrorCode) -> Code {
ResponseCode::ClientError(code).into()
}
}
impl TryFrom<Code> for ClientErrorCode {
type Error = ();
fn try_from(value: Code) -> Result<Self, Self::Error> {
match value {
Code::Response(ResponseCode::ClientError(code)) => Ok(code),
_ => Err(()),
}
}
}
impl From<ServerErrorCode> for ResponseCode {
fn from(code: ServerErrorCode) -> ResponseCode {
ResponseCode::ServerError(code)
}
}
impl From<ServerErrorCode> for Code {
fn from(code: ServerErrorCode) -> Code {
ResponseCode::ServerError(code).into()
}
}
impl TryFrom<Code> for ServerErrorCode {
type Error = ();
fn try_from(value: Code) -> Result<Self, Self::Error> {
match value {
Code::Response(ResponseCode::ServerError(code)) => Ok(code),
_ => Err(()),
}
}
}
impl TryFrom<EncodedCode> for Code {
type Error = Error;
fn try_from(code: EncodedCode) -> Result<Code, Self::Error> {
let code = match (code.class, code.detail) {
(0, 0) => Code::Empty,
(0, 1) => RequestCode::Get.into(),
(0, 2) => RequestCode::Post.into(),
(0, 3) => RequestCode::Put.into(),
(0, 4) => RequestCode::Delete.into(),
(2, 1) => SuccessCode::Created.into(),
(2, 2) => SuccessCode::Deleted.into(),
(2, 3) => SuccessCode::Valid.into(),
(2, 4) => SuccessCode::Changed.into(),
(2, 5) => SuccessCode::Content.into(),
(4, 0) => ClientErrorCode::BadRequest.into(),
(4, 1) => ClientErrorCode::Unauthorized.into(),
(4, 2) => ClientErrorCode::BadOption.into(),
(4, 3) => ClientErrorCode::Forbidden.into(),
(4, 4) => ClientErrorCode::NotFound.into(),
(4, 5) => ClientErrorCode::MethodNotAllowed.into(),
(4, 6) => ClientErrorCode::NotAcceptable.into(),
(4, 12) => ClientErrorCode::PreconditionFailed.into(),
(4, 13) => ClientErrorCode::RequestEntityTooLarge.into(),
(4, 15) => ClientErrorCode::UnsupportedContentFormat.into(),
(5, 0) => ServerErrorCode::InternalServerError.into(),
(5, 1) => ServerErrorCode::NotImplemented.into(),
(5, 2) => ServerErrorCode::BadGateway.into(),
(5, 3) => ServerErrorCode::ServiceUnavailable.into(),
(5, 4) => ServerErrorCode::GatewayTimeout.into(),
(5, 5) => ServerErrorCode::ProxyingNotSupported.into(),
(_, _) => return Err(Error::InvalidCode),
};
Ok(code)
}
}