use std::fmt;
use std::io::{Read, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use Result;
use Error::ResponseError;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum OpCode {
Reply = 1,
Update = 2001,
Insert = 2002,
Query = 2004,
GetMore = 2005,
}
impl OpCode {
pub fn from_i32(i: i32) -> Option<OpCode> {
match i {
1 => Some(OpCode::Reply),
2001 => Some(OpCode::Update),
2002 => Some(OpCode::Insert),
2004 => Some(OpCode::Query),
2005 => Some(OpCode::GetMore),
_ => None,
}
}
}
impl fmt::Display for OpCode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
OpCode::Reply => fmt.write_str("OP_REPLY"),
OpCode::Update => fmt.write_str("OP_UPDATE"),
OpCode::Insert => fmt.write_str("OP_INSERT"),
OpCode::Query => fmt.write_str("OP_QUERY"),
OpCode::GetMore => fmt.write_str("OP_GET_MORE"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Header {
pub message_length: i32,
pub request_id: i32,
response_to: i32,
pub op_code: OpCode,
}
impl Header {
pub fn new(message_length: i32, request_id: i32, response_to: i32, op_code: OpCode) -> Header {
Header {
message_length,
request_id,
response_to,
op_code,
}
}
fn new_request(message_length: i32, request_id: i32, op_code: OpCode) -> Header {
Header::new(message_length, request_id, 0, op_code)
}
pub fn new_update(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::Update)
}
pub fn new_insert(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::Insert)
}
pub fn new_query(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::Query)
}
pub fn new_get_more(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::GetMore)
}
pub fn write<W: Write>(&self, buffer: &mut W) -> Result<()> {
buffer.write_i32::<LittleEndian>(self.message_length)?;
buffer.write_i32::<LittleEndian>(self.request_id)?;
buffer.write_i32::<LittleEndian>(self.response_to)?;
buffer.write_i32::<LittleEndian>(self.op_code.clone() as i32)?;
let _ = buffer.flush();
Ok(())
}
pub fn read<R: Read>(buffer: &mut R) -> Result<Header> {
let message_length = buffer.read_i32::<LittleEndian>()?;
let request_id = buffer.read_i32::<LittleEndian>()?;
let response_to = buffer.read_i32::<LittleEndian>()?;
let op_code_i32 = buffer.read_i32::<LittleEndian>()?;
let op_code = match OpCode::from_i32(op_code_i32) {
Some(code) => code,
_ => {
return Err(ResponseError(format!(
"Invalid header opcode from server: {}.",
op_code_i32
)))
}
};
Ok(Header::new(
message_length,
request_id,
response_to,
op_code,
))
}
}