Select Git revision
header.rs 8.07 KiB
#[derive(Default, Debug, RustcEncodable, RustcDecodable)]
pub struct HeaderRaw {
ver_type_tkl: u8,
code: u8,
message_id: u16,
}
#[derive(Debug)]
pub struct Header {
ver_type_tkl: u8,
pub code: MessageClass,
message_id: u16,
}
#[derive(Debug, PartialEq)]
pub enum MessageClass {
Empty,
RequestType(Requests),
ResponseType(Responses),
Reserved,
}
#[derive(Debug, PartialEq)]
pub enum Requests {
Get,
Post,
Put,
Delete,
}
#[derive(Debug, PartialEq)]
pub enum Responses {
// 200 Codes
Created,
Deleted,
Valid,
Changed,
Content,
// 400 Codes
BadRequest,
Unauthorized,
BadOption,
Forbidden,
NotFound,
MethodNotAllowed,
NotAcceptable,
PreconditionFailed,
RequestEntityTooLarge,
UnsupportedContentFormat,
// 500 Codes
InternalServerError,
NotImplemented,
BadGateway,
ServiceUnavailable,
GatewayTimeout,
ProxyingNotSupported,
}
#[derive(PartialEq, Eq, Debug)]
pub enum MessageType {
Confirmable,
NonConfirmable,
Acknowledgement,
Reset,
Invalid,
}
impl Header {
pub fn new() -> Header {
return Header::from_raw(&HeaderRaw::default());
}
pub fn from_raw(raw: &HeaderRaw) -> Header {
return Header {
ver_type_tkl: raw.ver_type_tkl,
code: code_to_class(&raw.code),
message_id: raw.message_id,
};
}
pub fn to_raw(&self) -> HeaderRaw {
return HeaderRaw {
ver_type_tkl: self.ver_type_tkl,
code: class_to_code(&self.code),
message_id: self.message_id,
};
}
#[inline]
pub fn set_version(&mut self, v: u8) {
let type_tkl = 0x3F & self.ver_type_tkl;
self.ver_type_tkl = v << 6 | type_tkl;
}
#[inline]
pub fn get_version(&self) -> u8 {
return self.ver_type_tkl >> 6;
}
#[inline]
pub fn set_type(&mut self, t: MessageType) {
let tn = match t {
MessageType::Confirmable => 0,
MessageType::NonConfirmable => 1,
MessageType::Acknowledgement => 2,
MessageType::Reset => 3,
_ => unreachable!(),
};
let ver_tkl = 0xCF & self.ver_type_tkl;
self.ver_type_tkl = tn << 4 | ver_tkl;
}
#[inline]
pub fn get_type(&self) -> MessageType {
let tn = (0x30 & self.ver_type_tkl) >> 4;
match tn {
0 => MessageType::Confirmable,
1 => MessageType::NonConfirmable,
2 => MessageType::Acknowledgement,
3 => MessageType::Reset,
_ => MessageType::Invalid,
}
}
#[inline]
pub fn set_token_length(&mut self, tkl: u8) {
assert_eq!(0xF0 & tkl, 0);
let ver_type = 0xF0 & self.ver_type_tkl;
self.ver_type_tkl = tkl | ver_type;
}
#[inline]
pub fn get_token_length(&self) -> u8 {
return 0x0F & self.ver_type_tkl;
}
pub fn set_code(&mut self, code: &str) {
let code_vec: Vec<&str> = code.split('.').collect();
assert_eq!(code_vec.len(), 2);
let class_code = code_vec[0].parse::<u8>().unwrap();
let detail_code = code_vec[1].parse::<u8>().unwrap();
assert_eq!(0xF8 & class_code, 0);
assert_eq!(0xE0 & detail_code, 0);
self.code = code_to_class(&(class_code << 5 | detail_code));
}
pub fn get_code(&self) -> String {
class_to_str(&self.code)
}
#[inline]
pub fn set_message_id(&mut self, message_id: u16) {
self.message_id = message_id;
}
#[inline]
pub fn get_message_id(&self) -> u16 {
return self.message_id;
}
}
pub fn class_to_code(class: &MessageClass) -> u8 {
return match *class {
MessageClass::Empty => 0x00,
MessageClass::RequestType(Requests::Get) => 0x01,
MessageClass::RequestType(Requests::Post) => 0x02,
MessageClass::RequestType(Requests::Put) => 0x03,
MessageClass::RequestType(Requests::Delete) => 0x04,
MessageClass::ResponseType(Responses::Created) => 0x41,
MessageClass::ResponseType(Responses::Deleted) => 0x42,
MessageClass::ResponseType(Responses::Valid) => 0x43,
MessageClass::ResponseType(Responses::Changed) => 0x44,
MessageClass::ResponseType(Responses::Content) => 0x45,
MessageClass::ResponseType(Responses::BadRequest) => 0x80,
MessageClass::ResponseType(Responses::Unauthorized) => 0x81,
MessageClass::ResponseType(Responses::BadOption) => 0x82,
MessageClass::ResponseType(Responses::Forbidden) => 0x83,
MessageClass::ResponseType(Responses::NotFound) => 0x84,
MessageClass::ResponseType(Responses::MethodNotAllowed) => 0x85,
MessageClass::ResponseType(Responses::NotAcceptable) => 0x86,
MessageClass::ResponseType(Responses::PreconditionFailed) => 0x8C,
MessageClass::ResponseType(Responses::RequestEntityTooLarge) => 0x8D,
MessageClass::ResponseType(Responses::UnsupportedContentFormat) => 0x8F,
MessageClass::ResponseType(Responses::InternalServerError) => 0x90,
MessageClass::ResponseType(Responses::NotImplemented) => 0x91,
MessageClass::ResponseType(Responses::BadGateway) => 0x92,
MessageClass::ResponseType(Responses::ServiceUnavailable) => 0x93,
MessageClass::ResponseType(Responses::GatewayTimeout) => 0x94,
MessageClass::ResponseType(Responses::ProxyingNotSupported) => 0x95,
_ => 0xFF,
} as u8;
}
pub fn code_to_class(code: &u8) -> MessageClass {
match *code {
0x00 => MessageClass::Empty,
0x01 => MessageClass::RequestType(Requests::Get),
0x02 => MessageClass::RequestType(Requests::Post),
0x03 => MessageClass::RequestType(Requests::Put),
0x04 => MessageClass::RequestType(Requests::Delete),
0x41 => MessageClass::ResponseType(Responses::Created),
0x42 => MessageClass::ResponseType(Responses::Deleted),
0x43 => MessageClass::ResponseType(Responses::Valid),
0x44 => MessageClass::ResponseType(Responses::Changed),
0x45 => MessageClass::ResponseType(Responses::Content),
0x80 => MessageClass::ResponseType(Responses::BadRequest),
0x81 => MessageClass::ResponseType(Responses::Unauthorized),
0x82 => MessageClass::ResponseType(Responses::BadOption),
0x83 => MessageClass::ResponseType(Responses::Forbidden),
0x84 => MessageClass::ResponseType(Responses::NotFound),
0x85 => MessageClass::ResponseType(Responses::MethodNotAllowed),
0x86 => MessageClass::ResponseType(Responses::NotAcceptable),
0x8C => MessageClass::ResponseType(Responses::PreconditionFailed),
0x8D => MessageClass::ResponseType(Responses::RequestEntityTooLarge),
0x8F => MessageClass::ResponseType(Responses::UnsupportedContentFormat),
0x90 => MessageClass::ResponseType(Responses::InternalServerError),
0x91 => MessageClass::ResponseType(Responses::NotImplemented),
0x92 => MessageClass::ResponseType(Responses::BadGateway),
0x93 => MessageClass::ResponseType(Responses::ServiceUnavailable),
0x94 => MessageClass::ResponseType(Responses::GatewayTimeout),
0x95 => MessageClass::ResponseType(Responses::ProxyingNotSupported),
_ => MessageClass::Reserved,
}
}
pub fn code_to_str(code: &u8) -> String {
let class_code = (0xE0 & code) >> 5;
let detail_code = 0x1F & code;
return format!("{}.{:02}", class_code, detail_code);
}
pub fn class_to_str(class: &MessageClass) -> String {
return code_to_str(&class_to_code(class));
}
#[cfg(test)]
mod test {
use message::header::*;
#[test]
fn test_header_codes() {
for code in 0..255 {
let class = code_to_class(&code);
let code_str = code_to_str(&code);
let class_str = class_to_str(&class);
// Reserved class could technically be many codes
// so only check valid items
if class != MessageClass::Reserved {
assert_eq!(class_to_code(&class), code);
assert_eq!(code_str, class_str);
}
}
}
}