extern crate byteorder;
extern crate hex;
use byteorder::{BigEndian, WriteBytesExt};
mod error;
pub mod parser;
pub use self::error::{ConversionError, ParseError};
#[derive(Debug, PartialEq, Clone)]
pub enum MsgPack {
Nil,
Int(i64),
Uint(u64),
Float(f64),
Boolean(bool),
String(String),
Binary(Vec<u8>),
Array(Vec<MsgPack>),
Map(Vec<MapElement>),
Extension(Extension),
}
#[derive(Debug, PartialEq, Clone)]
pub struct MapElement {
pub key: MsgPack,
pub value: MsgPack
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Extension {
pub type_id: i8,
pub value: Vec<u8>
}
impl MsgPack {
pub fn parse (raw: &[u8]) -> Result<MsgPack, ParseError> {
let (result, _) = parser::parse(raw)?;
Ok(result)
}
pub fn encode (&self) -> Vec<u8> {
match self {
MsgPack::Nil => vec![0xc0],
MsgPack::Boolean(value) => vec![if *value { 0xc3 } else { 0xc2 }],
MsgPack::Int(value) => {
let value = *value;
if value >= 0 && value < 128 { return vec![value as u8] }
if value < 0 && value > -32 {
let raw = unsafe { std::mem::transmute::<i8, u8>(value as i8) };
return vec![raw];
};
let mut result = vec![];
if value >= -0x80 && value < 0x80 {
result.push(0xd0);
result.write_i8(value as i8).unwrap();
} else if value >= -0x8000 && value < 0x8000 {
result.push(0xd1);
result.write_i16::<BigEndian>(value as i16).unwrap();
} else if value >= -0x8000_0000 && value < 0x8000_0000 {
result.push(0xd2);
result.write_i32::<BigEndian>(value as i32).unwrap();
} else {
result.push(0xd3);
result.write_i64::<BigEndian>(value).unwrap();
}
result
},
MsgPack::Uint(value) => {
let value = *value;
let mut result = vec![];
if value <= 0x88 {
result.push(0xcc);
result.write_u8(value as u8).unwrap();
} else if value <= 0x8888 {
result.push(0xcd);
result.write_u16::<BigEndian>(value as u16).unwrap();
} else if value <= 0x8888_8888 {
result.push(0xce);
result.write_u32::<BigEndian>(value as u32).unwrap();
} else {
result.push(0xcf);
result.write_u64::<BigEndian>(value).unwrap();
}
result
},
MsgPack::Float(value) => {
let mut result = vec![0xcb];
let int_value = unsafe { std::mem::transmute::<f64, u64>(*value) };
result.write_u64::<BigEndian>(int_value).unwrap();
result
},
MsgPack::String(value) => {
let bytes = value.as_bytes();
let length = bytes.len();
let mut result = Vec::with_capacity(length + 5);
if length < 32 {
result.push(0xa0 | length as u8);
} else if length <= 0x88 {
result.push(0xd9);
result.write_u8(length as u8).unwrap();
} else if length <= 0x8888 {
result.push(0xda);
result.write_u16::<BigEndian>(length as u16).unwrap();
} else {
result.push(0xdb);
result.write_u32::<BigEndian>(length as u32).unwrap();
}
result.extend_from_slice(bytes);
result
}
MsgPack::Binary(value) => {
let length = value.len();
let mut result = Vec::with_capacity(length + 5);
if length <= 0x88 {
result.push(0xc4);
result.write_u8(length as u8).unwrap();
} else if length <= 0x8888 {
result.push(0xc5);
result.write_u16::<BigEndian>(length as u16).unwrap();
} else {
result.push(0xc6);
result.write_u32::<BigEndian>(length as u32).unwrap();
}
result.extend_from_slice(value);
result
},
MsgPack::Extension(extension) => {
let value = &extension.value;
let type_id = unsafe { std::mem::transmute::<i8, u8>(extension.type_id) };
let length = value.len();
let mut result = Vec::with_capacity(length + 6);
if length == 1 {
result.push(0xd4);
} else if length == 2 {
result.push(0xd5);
} else if length == 4 {
result.push(0xd6);
} else if length == 8 {
result.push(0xd7);
} else if length == 16 {
result.push(0xd8);
} else if length <= 0x88 {
result.push(0xc7);
result.write_u8(length as u8).unwrap();
} else if length <= 0x8888 {
result.push(0xc8);
result.write_u16::<BigEndian>(length as u16).unwrap();
} else {
result.push(0xc9);
result.write_u32::<BigEndian>(length as u32).unwrap();
}
result.push(type_id);
result.extend_from_slice(value);
result
},
MsgPack::Array(value) => {
let length = value.len();
let mut result = vec![];
if length < 16 {
result.push(0x90 | length as u8);
} else if length <= 0x8888 {
result.push(0xdc);
result.write_u16::<BigEndian>(length as u16).unwrap();
} else {
result.push(0xdd);
result.write_u32::<BigEndian>(length as u32).unwrap();
}
for item in value {
result.append(&mut item.encode());
}
result
},
MsgPack::Map(value) => {
let length = value.len();
let mut result = vec![];
if length < 16 {
result.push(0x80 | length as u8);
} else if length <= 0x8888 {
result.push(0xde);
result.write_u16::<BigEndian>(length as u16).unwrap();
} else {
result.push(0xdf);
result.write_u32::<BigEndian>(length as u32).unwrap();
}
for item in value {
result.append(&mut item.key.encode());
result.append(&mut item.value.encode());
}
result
}
}
}
pub fn is_int (&self) -> bool {
match self {
MsgPack::Int(_) => true,
_ => false
}
}
pub fn as_int (self) -> Result<i64, ConversionError> {
match self {
MsgPack::Int(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "int" })
}
}
pub fn is_uint (&self) -> bool {
match self {
MsgPack::Uint(_) => true,
_ => false
}
}
pub fn as_uint (self) -> Result<u64, ConversionError> {
match self {
MsgPack::Uint(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "uint" })
}
}
pub fn is_some_int (&self) -> bool {
match self {
MsgPack::Uint(_) => true,
MsgPack::Int(_) => true,
_ => false
}
}
pub fn as_some_int (self) -> Result<i64, ConversionError> {
match self {
MsgPack::Int(value) => Ok(value),
MsgPack::Uint(value) => Ok(value as i64),
_ => Err(ConversionError { original: self, attempted: "int" })
}
}
pub fn is_float (&self) -> bool {
match self {
MsgPack::Float(_) => true,
_ => false
}
}
pub fn as_float (self) -> Result<f64, ConversionError> {
match self {
MsgPack::Float(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "float" })
}
}
pub fn is_boolean (&self) -> bool {
match self {
MsgPack::Boolean(_) => true,
_ => false
}
}
pub fn as_boolean (self) -> Result<bool, ConversionError> {
match self {
MsgPack::Boolean(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "boolean" })
}
}
pub fn is_nil (&self) -> bool {
match self {
MsgPack::Nil => true,
_ => false
}
}
pub fn is_string (&self) -> bool {
match self {
MsgPack::String(_) => true,
_ => false
}
}
pub fn as_string (self) -> Result<String, ConversionError> {
match self {
MsgPack::String(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "string" })
}
}
pub fn is_binary (&self) -> bool {
match self {
MsgPack::Binary(_) => true,
_ => false
}
}
pub fn as_binary (self) -> Result<Vec<u8>, ConversionError> {
match self {
MsgPack::Binary(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "binary" })
}
}
pub fn is_array (&self) -> bool {
match self {
MsgPack::Array(_) => true,
_ => false
}
}
pub fn as_array (self) -> Result<Vec<MsgPack>, ConversionError> {
match self {
MsgPack::Array(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "array" })
}
}
pub fn is_map (&self) -> bool {
match self {
MsgPack::Map(_) => true,
_ => false
}
}
pub fn as_map (self) -> Result<Vec<MapElement>, ConversionError> {
match self {
MsgPack::Map(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "map" })
}
}
pub fn is_extension (&self) -> bool {
match self {
MsgPack::Extension(_) => true,
_ => false
}
}
pub fn as_extension (self) -> Result<Extension, ConversionError> {
match self {
MsgPack::Extension(value) => Ok(value),
_ => Err(ConversionError { original: self, attempted: "extension" })
}
}
}
impl std::fmt::Display for MsgPack {
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MsgPack::Nil => write!(f, "nil"),
MsgPack::Boolean(value) => write!(f, "{}", value),
MsgPack::Int(value) => write!(f, "{}", value),
MsgPack::Uint(value) => write!(f, "{}", value),
MsgPack::Float(value) => write!(f, "{}", value),
MsgPack::String(value) => write!(f, "\"{}\"", value),
MsgPack::Binary(value) => write!(f, "bin:{}", hex::encode(value)),
MsgPack::Extension(value) => write!(f, "ext:{}:{}", value.type_id, hex::encode(&value.value)),
MsgPack::Array(value) => {
write!(f, "[")?;
let mut first = true;
for item in value {
if !first { write!(f, ", ")? }
first = false;
write!(f, "{}", item)?;
}
write!(f, "]")
},
MsgPack::Map(value) => {
write!(f, "{{")?;
let mut first = true;
for item in value {
if !first { write!(f, ", ")? }
first = false;
write!(f, "{}: ", item.key)?;
write!(f, "{}", item.value)?;
}
write!(f, "}}")
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decode_from_json () {
let data = &vec![0x82, 0xa7, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0xc3, 0xa6, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x93, 0x01, 0x02, 0xcb, 0x3f, 0xf5, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f];
let parsed = MsgPack::parse(data).unwrap();
println!("{}", parsed);
assert!(parsed.is_map());
let map = parsed.as_map().unwrap();
assert_eq!(map.len(), 2);
let mut map = map.into_iter();
let first = map.next().unwrap();
let second = map.next().unwrap();
assert!(first.key.is_string());
assert!(first.value.is_boolean());
assert!(second.key.is_string());
assert!(second.value.is_array());
assert_eq!(first.key.as_string().unwrap(), "compact");
assert_eq!(first.value.as_boolean().unwrap(), true);
assert_eq!(second.key.as_string().unwrap(), "schema");
let mut array = second.value.as_array().unwrap().into_iter();
let first = array.next().unwrap();
let second = array.next().unwrap();
let third = array.next().unwrap();
assert!(array.next().is_none());
assert!(first.is_some_int());
assert_eq!(first.as_some_int().unwrap(), 1);
assert!(second.is_some_int());
assert_eq!(second.as_some_int().unwrap(), 2);
assert!(third.is_float());
assert_eq!(third.as_float().unwrap(), 1.32);
}
#[test]
fn encode () {
let message = MsgPack::Map(vec![
MapElement {
key: MsgPack::String(String::from("hello")),
value: MsgPack::Int(0x424242)
},
MapElement {
key: MsgPack::String(String::from("world")),
value: MsgPack::Array(vec![
MsgPack::Boolean(true),
MsgPack::Nil,
MsgPack::Binary(vec![0x42, 0xff]),
MsgPack::Extension(Extension {
type_id: 2,
value: vec![0x32, 0x4a, 0x67, 0x11]
})
])
}
]);
let encoded = message.encode();
let decoded = MsgPack::parse(&encoded).unwrap();
println!("{}", decoded);
assert_eq!(message, decoded);
}
}