use super::{
Encoding,
Encoder
};
use super::nom::{
IResult,
ErrorKind,
be_u16
};
use std::mem;
#[repr(u16)]
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
pub enum StatusField {
NoError = 0,
KeyNotFound = 1,
KeyExists = 2,
ValueTooLarge = 3,
InvalidArguments = 4,
ItemNotStored = 5,
IncrDecrNonNumeric = 6,
VBucketNotHere = 7,
AuthError = 8,
AuthContinue = 9,
UnknownCommand = 0x81,
OutOfMemory = 0x82,
NotSupported = 0x83,
InternalError = 0x84,
Busy = 0x85,
TemporaryFailure = 0x86
}
impl StatusField {
#[inline(always)]
pub fn check_status(&self) -> Result<(), StatusField> {
match *self {
StatusField::NoError => Ok(()),
x => Err(x)
}
}
}
impl Into<u16> for StatusField {
#[inline(always)]
fn into(self) -> u16 {
unsafe{ mem::transmute(self) }
}
}
impl Encoding for StatusField {
#[inline(always)]
fn encode(&self, buffer: &mut Encoder) {
let val: u16 = self.clone().into();
val.encode(buffer);
}
}
#[inline(always)]
fn from_u16(x: u16) -> StatusField {
unsafe{ mem::transmute(x) }
}
#[inline(always)]
fn valid_status(val: u16) -> bool {
val <= 9
||
(val >= 0x81 && val <= 0x86)
}
#[allow(dead_code)]
#[inline(always)]
pub fn status_parse<'a>(i: &'a [u8])
-> IResult<&'a [u8], StatusField> {
match be_u16(i) {
IResult::Done(rem,val) => if valid_status(val) {
IResult::Done(rem,from_u16(val))
} else {
IResult::Error(ErrorKind::Custom(0x83))
},
IResult::Error(e) => IResult::Error(e),
IResult::Incomplete(n) => IResult::Incomplete(n)
}
}
#[test]
fn test_status_field() {
use super::{Fault,ParseResult};
macro_rules! ot {
($a: expr, $b: ident) => {
let value: u16 = $a;
let sf: StatusField = StatusField::$b;
assert!(valid_status(value));
assert_eq!(from_u16(value), sf);
let mut v = unsafe{Encoder::with_capacity(20)};
sf.encode(&mut v);
v.encode_u8(0);
assert_eq!(v.len(), 3);
let dut = match ParseResult::from(status_parse(v.as_slice())) {
ParseResult::Ok(x) => x,
ParseResult::Err(e) => panic!("Status {:?} should not return error {:?}",value,e)
};
assert_eq!(dut, sf);
if sf == StatusField::NoError {
assert!(sf.check_status().is_ok());
} else {
assert_eq!(sf.check_status().err(), Option::Some(sf));
}
}
}
macro_rules! bt {
($a: expr) => {
let val: u16 = $a;
assert!( ! valid_status(val));
let mut v = unsafe{Encoder::with_capacity(100)};
val.encode(&mut v);
(0u16).encode(&mut v);
match ParseResult::from(status_parse(v.as_slice())) {
ParseResult::Ok(x) => panic!("u16 {:?} should not be opcode {:?}", val, x),
ParseResult::Err(Fault::BadStatus) => { },
ParseResult::Err(e) => panic!("u16 {:?} should retun `Fault::BadStatus` not {:?}", val, e)
};
}
}
ot!(0, NoError);
ot!(1, KeyNotFound);
ot!(2, KeyExists);
ot!(3, ValueTooLarge);
ot!(4, InvalidArguments);
ot!(5, ItemNotStored);
ot!(6, IncrDecrNonNumeric);
ot!(7, VBucketNotHere);
ot!(8, AuthError);
ot!(9, AuthContinue);
ot!(0x81, UnknownCommand);
ot!(0x82, OutOfMemory);
ot!(0x83, NotSupported);
ot!(0x84, InternalError);
ot!(0x85, Busy);
ot!(0x86, TemporaryFailure);
for code in 10u16..0x81u16 {
bt!(code);
}
for code in 0x87u16..0xFFFFu16 {
bt!(code);
}
bt!(0xFFFFu16);
}