use crate::error::LibError; use num_enum::{IntoPrimitive, TryFromPrimitive}; #[derive(Debug, Clone, Copy)] pub struct Status { status_code: StatusCode, reply_type: ReplyType, second_digit: u8, } #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] #[num_enum(error_type(name = LibError, constructor = LibError::status_out_of_range))] #[repr(u8)] pub enum ReplyType { Input = 1, Success, Redirect, TempFail, PermFail, Auth, } #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] #[num_enum(error_type(name = LibError, constructor = LibError::status_out_of_range))] #[repr(u8)] pub enum StatusCode { Input = 10, InputSensitive = 11, Success = 20, TempRedirect = 30, PermRedirect = 31, TempFail = 40, ServerUnavailable = 41, CgiError = 42, ProxyError = 43, SlowDown = 44, PermFail = 50, NotFound = 51, Gone = 52, ProxyRequestRefused = 53, BadRequest = 59, ClientCerts = 60, CertNotAuthorized = 61, CertNotValid = 62, // 1..6 first digit range check is still // covered by conversion into ReplyType // (see Status::parse_status) #[num_enum(catch_all)] Unknown(u8), } const ASCII_ZERO: u8 = 48; // '0' impl Status { pub fn parse_status(buf: &[u8]) -> Result { // simple decimal digit conversion // '2' - '0' = 50 - 48 = 2 (from byte '2' to uint 2) let first = buf[0] - ASCII_ZERO; let second = buf[1] - ASCII_ZERO; let code = first * 10 + second; Ok(Status { // get enum item for 2-digit status code status_code: StatusCode::try_from_primitive(code)?, // get enum entry for first digit reply_type: ReplyType::try_from_primitive(first)?, // provide separate field for the 2nd digit second_digit: second, }) } pub fn status_code(self: &Self) -> StatusCode { self.status_code } pub fn num(self: &Self) -> u8 { self.status_code.into() } pub fn reply_type(self: &Self) -> ReplyType { self.reply_type } pub fn second_digit(self: &Self) -> u8 { self.second_digit } }