#![crate_name = "cbor"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/cbor")]
#![allow(dead_code, unused_imports, unused_mut, unused_variables)]
#![feature(collections, old_io)]
extern crate byteorder;
extern crate "rustc-serialize" as rustc_serialize;
use std::collections::HashMap;
use std::error::FromError;
use std::fmt;
use std::old_io::{IoError, IoErrorKind};
use rustc_serialize::Decoder as RustcDecoder;
use rustc_serialize::Encoder as RustcEncoder;
use rustc_serialize::{Decodable, Encodable};
pub use decoder::Decoder;
pub use encoder::Encoder;
pub use json::ToCbor;
pub use rustc_decoder_direct::CborDecoder as DirectDecoder;
macro_rules! lg {
($($arg:tt)*) => ({
let _ = ::std::old_io::stderr().write_str(&*format!($($arg)*));
let _ = ::std::old_io::stderr().write_str("\n");
});
}
macro_rules! fromerr {
($e:expr) => ($e.map_err(::std::error::FromError::from_error));
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
UInt, UInt8, UInt16, UInt32, UInt64,
Int, Int8, Int16, Int32, Int64,
Float, Float16, Float32, Float64,
Bytes, Unicode, Array, Map, Tag,
Any, Null, Undefined, Bool, Break,
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl Type {
fn from_desc(b: u8) -> ReadResult<Type> {
Ok(match ((b & 0b111_00000) >> 5, b & 0b000_11111) {
(0, 0...23) => Type::UInt8,
(0, 24) => Type::UInt8,
(0, 25) => Type::UInt16,
(0, 26) => Type::UInt32,
(0, 27) => Type::UInt64,
(1, 0...23) => Type::Int8,
(1, 24) => Type::Int8,
(1, 25) => Type::Int16,
(1, 26) => Type::Int32,
(1, 27) => Type::Int64,
(2, _) => Type::Bytes,
(3, _) => Type::Unicode,
(4, _) => Type::Array,
(5, _) => Type::Map,
(6, _) => Type::Tag,
(7, v @ 0...19) => return Err(ReadError::Unassigned {
major: 7, add: v,
}),
(7, 20...21) => Type::Bool,
(7, 22) => Type::Null,
(7, 23) => Type::Undefined,
(7, 25) => Type::Float16,
(7, 26) => Type::Float32,
(7, 27) => Type::Float64,
(7, v @ 28...30) => return Err(ReadError::Unassigned {
major: 7, add: v,
}),
(7, 31) => Type::Break,
(x, y) => return Err(ReadError::Unassigned {
major: x, add: y,
}),
})
}
fn major(self) -> u8 {
match self {
Type::UInt | Type::UInt8 | Type::UInt16
| Type::UInt32 | Type::UInt64 => 0,
Type::Int | Type::Int8 | Type::Int16
| Type::Int32 | Type::Int64 => 1,
Type::Bytes => 2,
Type::Unicode => 3,
Type::Array => 4,
Type::Map => 5,
Type::Tag => 6,
Type::Float | Type::Float16 | Type::Float32 | Type::Float64 => 7,
Type::Null | Type::Undefined | Type::Bool | Type::Break => 7,
Type::Any => unreachable!(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Cbor {
Break, Undefined,
Null,
Bool(bool),
Unsigned(CborUnsigned),
Signed(CborSigned),
Float(CborFloat),
Bytes(CborBytes),
Unicode(String),
Array(Vec<Cbor>),
Map(HashMap<String, Cbor>),
Tag(CborTag),
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, RustcDecodable)]
pub enum CborUnsigned {
UInt8(u8),
UInt16(u16),
UInt32(u32),
UInt64(u64)
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, RustcDecodable)]
pub enum CborSigned {
Int8(i8),
Int16(i16),
Int32(i32),
Int64(i64),
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, RustcDecodable)]
pub enum CborFloat {
Float16(f32),
Float32(f32),
Float64(f64),
}
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, RustcEncodable)]
pub struct CborBytes(pub Vec<u8>);
#[derive(Clone, Debug, PartialEq, RustcEncodable)]
pub struct CborTag {
pub tag: u64,
pub data: Box<Cbor>,
}
#[derive(Clone, Debug, PartialEq, RustcEncodable)]
pub struct CborTagEncode<'a, T: 'a> {
pub tag: u64,
pub data: &'a T,
}
impl Cbor {
fn typ(&self) -> Type {
match *self {
Cbor::Break => Type::Break,
Cbor::Undefined => Type::Undefined,
Cbor::Null => Type::Null,
Cbor::Bool(_) => Type::Bool,
Cbor::Unsigned(v) => v.typ(),
Cbor::Signed(v) => v.typ(),
Cbor::Float(v) => v.typ(),
Cbor::Bytes(_) => Type::Bytes,
Cbor::Unicode(_) => Type::Unicode,
Cbor::Array(_) => Type::Array,
Cbor::Map(_) => Type::Map,
Cbor::Tag(_) => Type::Tag,
}
}
}
impl CborUnsigned {
fn typ(self) -> Type {
match self {
CborUnsigned::UInt8(_) => Type::UInt8,
CborUnsigned::UInt16(_) => Type::UInt16,
CborUnsigned::UInt32(_) => Type::UInt32,
CborUnsigned::UInt64(_) => Type::UInt64,
}
}
fn to_usize(self) -> ReadResult<usize> {
Ok(match self {
CborUnsigned::UInt8(v) => v as usize,
CborUnsigned::UInt16(v) => v as usize,
CborUnsigned::UInt32(v) => v as usize,
CborUnsigned::UInt64(v) => v as usize,
})
}
fn to_u64(self) -> ReadResult<u64> {
Ok(match self {
CborUnsigned::UInt8(v) => v as u64,
CborUnsigned::UInt16(v) => v as u64,
CborUnsigned::UInt32(v) => v as u64,
CborUnsigned::UInt64(v) => v,
})
}
fn to_u32(self) -> ReadResult<u32> {
Ok(match self {
CborUnsigned::UInt8(v) => v as u32,
CborUnsigned::UInt16(v) => v as u32,
CborUnsigned::UInt32(v) => v as u32,
_ => return Err(ReadError::ty_mismatch(Type::UInt32, self.typ())),
})
}
fn to_u16(self) -> ReadResult<u16> {
Ok(match self {
CborUnsigned::UInt8(v) => v as u16,
CborUnsigned::UInt16(v) => v as u16,
_ => return Err(ReadError::ty_mismatch(Type::UInt16, self.typ())),
})
}
fn to_u8(self) -> ReadResult<u8> {
Ok(match self {
CborUnsigned::UInt8(v) => v as u8,
_ => return Err(ReadError::ty_mismatch(Type::UInt8, self.typ())),
})
}
}
impl CborSigned {
fn typ(self) -> Type {
match self {
CborSigned::Int8(_) => Type::Int8,
CborSigned::Int16(_) => Type::Int16,
CborSigned::Int32(_) => Type::Int32,
CborSigned::Int64(_) => Type::Int64,
}
}
fn to_isize(self) -> ReadResult<isize> {
Ok(match self {
CborSigned::Int8(v) => v as isize,
CborSigned::Int16(v) => v as isize,
CborSigned::Int32(v) => v as isize,
CborSigned::Int64(v) => v as isize,
})
}
fn to_i64(self) -> ReadResult<i64> {
Ok(match self {
CborSigned::Int8(v) => v as i64,
CborSigned::Int16(v) => v as i64,
CborSigned::Int32(v) => v as i64,
CborSigned::Int64(v) => v,
})
}
fn to_i32(self) -> ReadResult<i32> {
Ok(match self {
CborSigned::Int8(v) => v as i32,
CborSigned::Int16(v) => v as i32,
CborSigned::Int32(v) => v as i32,
_ => return Err(ReadError::ty_mismatch(Type::Int32, self.typ())),
})
}
fn to_i16(self) -> ReadResult<i16> {
Ok(match self {
CborSigned::Int8(v) => v as i16,
CborSigned::Int16(v) => v as i16,
_ => return Err(ReadError::ty_mismatch(Type::Int16, self.typ())),
})
}
fn to_i8(self) -> ReadResult<i8> {
Ok(match self {
CborSigned::Int8(v) => v as i8,
_ => return Err(ReadError::ty_mismatch(Type::Int8, self.typ())),
})
}
}
impl CborFloat {
fn typ(self) -> Type {
match self {
CborFloat::Float16(_) => Type::Float16,
CborFloat::Float32(_) => Type::Float32,
CborFloat::Float64(_) => Type::Float64,
}
}
fn to_f64(self) -> ReadResult<f64> {
Ok(match self {
CborFloat::Float16(v) => v as f64,
CborFloat::Float32(v) => v as f64,
CborFloat::Float64(v) => v,
})
}
fn to_f32(self) -> ReadResult<f32> {
Ok(match self {
CborFloat::Float16(v) => v,
CborFloat::Float32(v) => v,
_ => return Err(ReadError::ty_mismatch(Type::Float32, self.typ())),
})
}
}
impl Encodable for Cbor {
fn encode<E: RustcEncoder>(&self, e: &mut E) -> Result<(), E::Error> {
match *self {
Cbor::Break => unimplemented!(),
Cbor::Undefined => e.emit_nil(),
Cbor::Null => e.emit_nil(),
Cbor::Bool(v) => v.encode(e),
Cbor::Unsigned(v) => v.encode(e),
Cbor::Signed(v) => v.encode(e),
Cbor::Float(v) => v.encode(e),
Cbor::Bytes(ref v) => v.encode(e),
Cbor::Unicode(ref v) => v.encode(e),
Cbor::Array(ref v) => v.encode(e),
Cbor::Map(ref v) => v.encode(e),
Cbor::Tag(ref v) => v.encode(e),
}
}
}
impl Encodable for CborUnsigned {
fn encode<E: RustcEncoder>(&self, e: &mut E) -> Result<(), E::Error> {
match *self {
CborUnsigned::UInt8(v) => v.encode(e),
CborUnsigned::UInt16(v) => v.encode(e),
CborUnsigned::UInt32(v) => v.encode(e),
CborUnsigned::UInt64(v) => v.encode(e),
}
}
}
impl Encodable for CborSigned {
fn encode<E: RustcEncoder>(&self, e: &mut E) -> Result<(), E::Error> {
match *self {
CborSigned::Int8(v) => v.encode(e),
CborSigned::Int16(v) => v.encode(e),
CborSigned::Int32(v) => v.encode(e),
CborSigned::Int64(v) => v.encode(e),
}
}
}
impl Encodable for CborFloat {
fn encode<E: RustcEncoder>(&self, e: &mut E) -> Result<(), E::Error> {
match *self {
CborFloat::Float16(v) => v.encode(e),
CborFloat::Float32(v) => v.encode(e),
CborFloat::Float64(v) => v.encode(e),
}
}
}
impl ::std::ops::Deref for CborBytes {
type Target = [u8];
fn deref(&self) -> &[u8] { &self.0 }
}
impl ::std::ops::DerefMut for CborBytes {
fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 }
}
impl Decodable for CborBytes {
fn decode<D: RustcDecoder>(d: &mut D) -> Result<CborBytes, D::Error> {
Decodable::decode(d).map(CborBytes)
}
}
pub type CborResult<T> = Result<T, CborError>;
type ReadResult<T> = Result<T, ReadError>;
#[derive(Clone, Debug)]
pub enum CborError {
Io(IoError),
Decode(ReadError), Encode(WriteError),
AtOffset {
kind: ReadError,
offset: usize,
},
}
impl CborError {
fn is_eof(&self) -> bool {
match *self {
CborError::Io(IoError {kind: IoErrorKind::EndOfFile, ..}) => true,
_ => false,
}
}
}
#[derive(Clone, Debug)]
pub enum ReadError {
TypeMismatch {
expected: Type,
got: Type,
},
InvalidAddValue {
ty: Type,
val: u8,
},
Unassigned {
major: u8,
add: u8,
},
Reserved {
major: u8,
add: u8,
},
Other(String),
}
#[derive(Clone, Debug)]
pub enum WriteError {
InvalidMapKey {
got: Option<Type>,
},
}
impl FromError<IoError> for CborError {
fn from_error(err: IoError) -> CborError { CborError::Io(err) }
}
impl ReadError {
fn mismatch(expected: Type, got: &Cbor) -> ReadError {
ReadError::ty_mismatch(expected, got.typ())
}
fn ty_mismatch(expected: Type, got: Type) -> ReadError {
ReadError::TypeMismatch { expected: expected, got: got }
}
fn miss(expected: Type, got: u8) -> ReadError {
let ty = match Type::from_desc(got) {
Ok(ty) => ty,
Err(err) => return err,
};
ReadError::TypeMismatch { expected: expected, got: ty }
}
}
impl fmt::Display for CborError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CborError::Io(ref err) => write!(f, "{}", err),
CborError::Decode(ref err) => {
write!(f, "Error while decoding: {}", err)
}
CborError::Encode(ref err) => {
write!(f, "Error while encoding: {}", err)
}
CborError::AtOffset { ref kind, offset } => {
write!(f, "Error at byte offset {:?}: {}", offset, kind)
}
}
}
}
impl fmt::Display for ReadError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ReadError::TypeMismatch { expected, got } => {
write!(f, "Expected type {:?}, but found {:?}.", expected, got)
}
ReadError::InvalidAddValue { ty, val } => {
write!(f, "Invalid additional information ({:?}) \
for type {:?}", val, ty)
}
ReadError::Unassigned { major, add } => {
write!(f, "Found unassigned value (major type: {:?}, \
additional information: {:?})", major, add)
}
ReadError::Reserved { major, add } => {
write!(f, "Found reserved value (major type: {:?}, \
additional information: {:?})", major, add)
}
ReadError::Other(ref s) => write!(f, "{}", s),
}
}
}
impl fmt::Display for WriteError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
WriteError::InvalidMapKey { got: Some(got) } => {
write!(f, "Found invalid map key ({:?}), \
expected Unicode string.", got)
}
WriteError::InvalidMapKey { got: None } => {
write!(f, "Found invalid map key, expected Unicode string.")
}
}
}
}
mod decoder;
mod encoder;
mod json;
mod rustc_decoder;
mod rustc_decoder_direct;