use crate::{CborError, CborResult as Result};
use byteorder::{BigEndian, ByteOrder};
use core::convert::TryFrom;
use libipld_base::cid::Cid;
use libipld_base::ipld::Ipld;
use std::collections::BTreeMap;
pub use std::io::Read;
#[inline]
pub fn read_u8<R: Read>(r: &mut R) -> Result<u8> {
let mut buf = [0; 1];
r.read_exact(&mut buf)?;
Ok(buf[0])
}
#[inline]
pub fn read_u16<R: Read>(r: &mut R) -> Result<u16> {
let mut buf = [0; 2];
r.read_exact(&mut buf)?;
Ok(BigEndian::read_u16(&buf))
}
#[inline]
pub fn read_u32<R: Read>(r: &mut R) -> Result<u32> {
let mut buf = [0; 4];
r.read_exact(&mut buf)?;
Ok(BigEndian::read_u32(&buf))
}
#[inline]
pub fn read_u64<R: Read>(r: &mut R) -> Result<u64> {
let mut buf = [0; 8];
r.read_exact(&mut buf)?;
Ok(BigEndian::read_u64(&buf))
}
#[inline]
pub fn read_f32<R: Read>(r: &mut R) -> Result<f32> {
let mut buf = [0; 4];
r.read_exact(&mut buf)?;
Ok(BigEndian::read_f32(&buf))
}
#[inline]
pub fn read_f64<R: Read>(r: &mut R) -> Result<f64> {
let mut buf = [0; 8];
r.read_exact(&mut buf)?;
Ok(BigEndian::read_f64(&buf))
}
#[inline]
pub fn read_bytes<R: Read>(r: &mut R, len: usize) -> Result<Vec<u8>> {
let mut buf = vec![0; len];
r.read_exact(&mut buf)?;
Ok(buf)
}
#[inline]
pub fn read_str<R: Read>(r: &mut R, len: usize) -> Result<String> {
let bytes = read_bytes(r, len)?;
let string = std::str::from_utf8(&bytes)?;
Ok(string.to_string())
}
#[inline]
pub fn read_key<R: Read>(r: &mut R, key: &str) -> Result<()> {
let key_bytes = key.as_bytes();
let bytes = read_bytes(r, key.len() + 1)?;
if key_bytes == &bytes[1..] {
Ok(())
} else {
Err(CborError::UnexpectedKey)
}
}
#[inline]
pub fn read_list<R: Read, T: ReadCbor>(r: &mut R, len: usize) -> Result<Vec<T>> {
let mut list: Vec<T> = Vec::with_capacity(len);
for _ in 0..len {
list.push(T::read_cbor(r)?);
}
Ok(list)
}
#[inline]
pub fn read_map<R: Read, T: ReadCbor>(r: &mut R, len: usize) -> Result<BTreeMap<String, T>> {
let mut map: BTreeMap<String, T> = BTreeMap::new();
for _ in 0..len {
let key = String::read_cbor(r)?;
let value = T::read_cbor(r)?;
map.insert(key, value);
}
Ok(map)
}
#[inline]
pub fn read_link<R: Read>(r: &mut R) -> Result<Cid> {
let tag = read_u8(r)?;
if tag != 42 {
return Err(CborError::UnknownTag);
}
let ty = read_u8(r)?;
if ty != 0x58 {
return Err(CborError::UnknownTag);
}
let len = read_u8(r)?;
let bytes = read_bytes(r, len as usize)?;
Ok(Cid::try_from(bytes)?)
}
pub trait ReadCbor: Sized {
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>>;
#[inline]
fn read_cbor<R: Read>(r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
if let Some(res) = Self::try_read_cbor(r, major)? {
Ok(res)
} else {
Err(CborError::UnexpectedCode)
}
}
}
impl ReadCbor for bool {
#[inline]
fn try_read_cbor<R: Read>(_: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0xf4 => Ok(Some(false)),
0xf5 => Ok(Some(true)),
_ => Ok(None),
}
}
}
impl ReadCbor for u8 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x00..=0x17 => Ok(Some(major)),
0x18 => Ok(Some(read_u8(r)?)),
_ => Ok(None),
}
}
}
impl ReadCbor for u16 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x00..=0x17 => Ok(Some(major as u16)),
0x18 => Ok(Some(read_u8(r)? as u16)),
0x19 => Ok(Some(read_u16(r)?)),
_ => Ok(None),
}
}
}
impl ReadCbor for u32 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x00..=0x17 => Ok(Some(major as u32)),
0x18 => Ok(Some(read_u8(r)? as u32)),
0x19 => Ok(Some(read_u16(r)? as u32)),
0x1a => Ok(Some(read_u32(r)?)),
_ => Ok(None),
}
}
}
impl ReadCbor for u64 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x00..=0x17 => Ok(Some(major as u64)),
0x18 => Ok(Some(read_u8(r)? as u64)),
0x19 => Ok(Some(read_u16(r)? as u64)),
0x1a => Ok(Some(read_u32(r)? as u64)),
0x1b => Ok(Some(read_u64(r)?)),
_ => Ok(None),
}
}
}
impl ReadCbor for i8 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x20..=0x37 => Ok(Some(-1 - (major - 0x20) as i8)),
0x38 => Ok(Some(-1 - read_u8(r)? as i8)),
_ => Ok(None),
}
}
}
impl ReadCbor for i16 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x20..=0x37 => Ok(Some(-1 - (major - 0x20) as i16)),
0x38 => Ok(Some(-1 - read_u8(r)? as i16)),
0x39 => Ok(Some(-1 - read_u16(r)? as i16)),
_ => Ok(None),
}
}
}
impl ReadCbor for i32 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x20..=0x37 => Ok(Some(-1 - (major - 0x20) as i32)),
0x38 => Ok(Some(-1 - read_u8(r)? as i32)),
0x39 => Ok(Some(-1 - read_u16(r)? as i32)),
0x3a => Ok(Some(-1 - read_u32(r)? as i32)),
_ => Ok(None),
}
}
}
impl ReadCbor for i64 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x20..=0x37 => Ok(Some(-1 - (major - 0x20) as i64)),
0x38 => Ok(Some(-1 - read_u8(r)? as i64)),
0x39 => Ok(Some(-1 - read_u16(r)? as i64)),
0x3a => Ok(Some(-1 - read_u32(r)? as i64)),
0x3b => Ok(Some(-1 - read_u64(r)? as i64)),
_ => Ok(None),
}
}
}
impl ReadCbor for f32 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0xfa => Ok(Some(read_f32(r)?)),
_ => Ok(None),
}
}
}
impl ReadCbor for f64 {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0xfa => Ok(Some(read_f32(r)? as f64)),
0xfb => Ok(Some(read_f64(r)?)),
_ => Ok(None),
}
}
}
impl ReadCbor for String {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
let len = match major {
0x60..=0x77 => major as usize - 0x60,
0x78 => read_u8(r)? as usize,
0x79 => read_u16(r)? as usize,
0x7a => read_u32(r)? as usize,
0x7b => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
len as usize
}
_ => return Ok(None),
};
Ok(Some(read_str(r, len)?))
}
}
impl ReadCbor for Cid {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0xd8 => Ok(Some(read_link(r)?)),
_ => Ok(None),
}
}
}
impl ReadCbor for Box<[u8]> {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
let len = match major {
0x40..=0x57 => major as usize - 0x40,
0x58 => read_u8(r)? as usize,
0x59 => read_u16(r)? as usize,
0x5a => read_u32(r)? as usize,
0x5b => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
len as usize
}
_ => return Ok(None),
};
Ok(Some(read_bytes(r, len)?.into_boxed_slice()))
}
}
impl<T: ReadCbor> ReadCbor for Option<T> {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0xf6 => Ok(Some(None)),
0xf7 => Ok(Some(None)),
_ => {
if let Some(res) = T::try_read_cbor(r, major)? {
Ok(Some(Some(res)))
} else {
Ok(None)
}
}
}
}
}
impl<T: ReadCbor> ReadCbor for Vec<T> {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
let len = match major {
0x80..=0x97 => major as usize - 0x80,
0x98 => read_u8(r)? as usize,
0x99 => read_u16(r)? as usize,
0x9a => read_u32(r)? as usize,
0x9b => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
len as usize
}
_ => return Ok(None),
};
Ok(Some(read_list(r, len)?))
}
}
impl<T: ReadCbor> ReadCbor for BTreeMap<String, T> {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
let len = match major {
0xa0..=0xb7 => major as usize - 0xa0,
0xb8 => read_u8(r)? as usize,
0xb9 => read_u16(r)? as usize,
0xba => read_u32(r)? as usize,
0xbb => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
len as usize
}
_ => return Ok(None),
};
Ok(Some(read_map(r, len)?))
}
}
impl ReadCbor for Ipld {
#[inline]
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
let ipld = match major {
0x00..=0x17 => Ipld::Integer(major as i128),
0x18 => Ipld::Integer(read_u8(r)? as i128),
0x19 => Ipld::Integer(read_u16(r)? as i128),
0x1a => Ipld::Integer(read_u32(r)? as i128),
0x1b => Ipld::Integer(read_u64(r)? as i128),
0x20..=0x37 => Ipld::Integer(-1 - (major - 0x20) as i128),
0x38 => Ipld::Integer(-1 - read_u8(r)? as i128),
0x39 => Ipld::Integer(-1 - read_u16(r)? as i128),
0x3a => Ipld::Integer(-1 - read_u32(r)? as i128),
0x3b => Ipld::Integer(-1 - read_u64(r)? as i128),
0x40..=0x57 => {
let len = major - 0x40;
let bytes = read_bytes(r, len as usize)?;
Ipld::Bytes(bytes)
}
0x58 => {
let len = read_u8(r)?;
let bytes = read_bytes(r, len as usize)?;
Ipld::Bytes(bytes)
}
0x59 => {
let len = read_u16(r)?;
let bytes = read_bytes(r, len as usize)?;
Ipld::Bytes(bytes)
}
0x5a => {
let len = read_u32(r)?;
let bytes = read_bytes(r, len as usize)?;
Ipld::Bytes(bytes)
}
0x5b => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
let bytes = read_bytes(r, len as usize)?;
Ipld::Bytes(bytes)
}
0x60..=0x77 => {
let len = major - 0x60;
let string = read_str(r, len as usize)?;
Ipld::String(string)
}
0x78 => {
let len = read_u8(r)?;
let string = read_str(r, len as usize)?;
Ipld::String(string)
}
0x79 => {
let len = read_u16(r)?;
let string = read_str(r, len as usize)?;
Ipld::String(string)
}
0x7a => {
let len = read_u32(r)?;
let string = read_str(r, len as usize)?;
Ipld::String(string)
}
0x7b => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
let string = read_str(r, len as usize)?;
Ipld::String(string)
}
0x80..=0x97 => {
let len = major - 0x80;
let list = read_list(r, len as usize)?;
Ipld::List(list)
}
0x98 => {
let len = read_u8(r)?;
let list = read_list(r, len as usize)?;
Ipld::List(list)
}
0x99 => {
let len = read_u16(r)?;
let list = read_list(r, len as usize)?;
Ipld::List(list)
}
0x9a => {
let len = read_u32(r)?;
let list = read_list(r, len as usize)?;
Ipld::List(list)
}
0x9b => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
let list = read_list(r, len as usize)?;
Ipld::List(list)
}
0xa0..=0xb7 => {
let len = major - 0xa0;
let map = read_map(r, len as usize)?;
Ipld::Map(map)
}
0xb8 => {
let len = read_u8(r)?;
let map = read_map(r, len as usize)?;
Ipld::Map(map)
}
0xb9 => {
let len = read_u16(r)?;
let map = read_map(r, len as usize)?;
Ipld::Map(map)
}
0xba => {
let len = read_u32(r)?;
let map = read_map(r, len as usize)?;
Ipld::Map(map)
}
0xbb => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(CborError::LengthOutOfRange);
}
let map = read_map(r, len as usize)?;
Ipld::Map(map)
}
0xd8 => Ipld::Link(read_link(r)?),
0xf4 => Ipld::Bool(false),
0xf5 => Ipld::Bool(true),
0xf6 => Ipld::Null,
0xf7 => Ipld::Null,
0xfa => Ipld::Float(read_f32(r)? as f64),
0xfb => Ipld::Float(read_f64(r)?),
_ => return Ok(None),
};
Ok(Some(ipld))
}
}