use crate::error::{InvalidCidPrefix, LengthOutOfRange, UnexpectedCode, UnexpectedKey, UnknownTag};
use crate::DagCborCodec as DagCbor;
use byteorder::{BigEndian, ByteOrder};
use core::convert::TryFrom;
use libipld_core::cid::Cid;
use libipld_core::codec::{Decode, References};
use libipld_core::error::Result;
use libipld_core::ipld::Ipld;
use std::collections::BTreeMap;
use std::io::{Read, Seek, SeekFrom};
pub fn read_u8<R: Read>(r: &mut R) -> Result<u8> {
let mut buf = [0; 1];
r.read_exact(&mut buf)?;
Ok(buf[0])
}
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))
}
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))
}
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))
}
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))
}
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))
}
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)
}
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())
}
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(UnexpectedKey.into())
}
}
pub fn read<R: Read, T: TryReadCbor>(r: &mut R) -> Result<T> {
let major = crate::decode::read_u8(r)?;
if let Some(res) = T::try_read_cbor(r, major)? {
Ok(res)
} else {
Err(UnexpectedCode.into())
}
}
pub fn read_list<R: Read, T: TryReadCbor>(r: &mut R, len: usize) -> Result<Vec<T>> {
let mut list: Vec<T> = Vec::with_capacity(len);
for _ in 0..len {
list.push(read(r)?);
}
Ok(list)
}
pub fn read_map<R: Read, T: TryReadCbor>(r: &mut R, len: usize) -> Result<BTreeMap<String, T>> {
let mut map: BTreeMap<String, T> = BTreeMap::new();
for _ in 0..len {
let key = read(r)?;
let value = read(r)?;
map.insert(key, value);
}
Ok(map)
}
pub fn read_link<R: Read>(r: &mut R) -> Result<Cid> {
let tag = read_u8(r)?;
if tag != 42 {
return Err(UnknownTag.into());
}
let ty = read_u8(r)?;
if ty != 0x58 {
return Err(UnknownTag.into());
}
let len = read_u8(r)?;
if len == 0 {
return Err(LengthOutOfRange.into());
}
let bytes = read_bytes(r, len as usize)?;
if bytes[0] != 0 {
return Err(InvalidCidPrefix(bytes[0]).into());
}
Ok(Cid::try_from(&bytes[1..])?)
}
pub fn read_len<R: Read>(r: &mut R, major: u8) -> Result<usize> {
Ok(match major {
0x00..=0x17 => major as usize,
0x18 => read_u8(r)? as usize,
0x19 => read_u16(r)? as usize,
0x1a => read_u32(r)? as usize,
0x1b => {
let len = read_u64(r)?;
if len > usize::max_value() as u64 {
return Err(LengthOutOfRange.into());
}
len as usize
}
_ => return Err(UnexpectedCode.into()),
})
}
pub trait TryReadCbor: Sized {
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>>;
}
macro_rules! impl_decode {
($ty:ident) => {
impl Decode<DagCbor> for $ty {
fn decode<R: Read>(_: DagCbor, r: &mut R) -> Result<Self> {
read(r)
}
}
};
($ty:ident<T>) => {
impl<T: TryReadCbor> Decode<DagCbor> for $ty<T> {
fn decode<R: Read>(_: DagCbor, r: &mut R) -> Result<Self> {
read(r)
}
}
};
($ty:ident<$param:ident, T>) => {
impl<T: TryReadCbor> Decode<DagCbor> for $ty<$param, T> {
fn decode<R: Read>(_: DagCbor, r: &mut R) -> Result<Self> {
read(r)
}
}
};
($ty:ident<[u8]>) => {
impl Decode<DagCbor> for $ty<[u8]> {
fn decode<R: Read>(_: DagCbor, r: &mut R) -> Result<Self> {
read(r)
}
}
};
}
impl TryReadCbor for bool {
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_decode!(bool);
impl TryReadCbor for u8 {
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_decode!(u8);
impl TryReadCbor for u16 {
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_decode!(u16);
impl TryReadCbor for u32 {
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_decode!(u32);
impl TryReadCbor for u64 {
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_decode!(u64);
impl TryReadCbor for i8 {
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_decode!(i8);
impl TryReadCbor for i16 {
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_decode!(i16);
impl TryReadCbor for i32 {
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_decode!(i32);
impl TryReadCbor for i64 {
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_decode!(i64);
impl TryReadCbor for f32 {
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_decode!(f32);
impl TryReadCbor for f64 {
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_decode!(f64);
impl TryReadCbor for String {
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x60..=0x7b => {
let len = read_len(r, major - 0x60)?;
Ok(Some(read_str(r, len)?))
}
_ => Ok(None),
}
}
}
impl_decode!(String);
impl TryReadCbor for Cid {
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_decode!(Cid);
impl TryReadCbor for Box<[u8]> {
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x40..=0x5b => {
let len = read_len(r, major - 0x40)?;
Ok(Some(read_bytes(r, len)?.into_boxed_slice()))
}
_ => Ok(None),
}
}
}
impl_decode!(Box<[u8]>);
impl<T: TryReadCbor> TryReadCbor for Option<T> {
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_decode!(Option<T>);
impl<T: TryReadCbor> TryReadCbor for Vec<T> {
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0x80..=0x9b => {
let len = read_len(r, major - 0x80)?;
Ok(Some(read_list(r, len)?))
}
_ => Ok(None),
}
}
}
impl_decode!(Vec<T>);
impl<T: TryReadCbor> TryReadCbor for BTreeMap<String, T> {
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
match major {
0xa0..=0xbb => {
let len = read_len(r, major - 0xa0)?;
Ok(Some(read_map(r, len)?))
}
_ => Ok(None),
}
}
}
impl_decode!(BTreeMap<String, T>);
impl TryReadCbor for Ipld {
fn try_read_cbor<R: Read>(r: &mut R, major: u8) -> Result<Option<Self>> {
let ipld = match major {
0x00..=0x17 => Self::Integer(major as i128),
0x18 => Self::Integer(read_u8(r)? as i128),
0x19 => Self::Integer(read_u16(r)? as i128),
0x1a => Self::Integer(read_u32(r)? as i128),
0x1b => Self::Integer(read_u64(r)? as i128),
0x20..=0x37 => Self::Integer(-1 - (major - 0x20) as i128),
0x38 => Self::Integer(-1 - read_u8(r)? as i128),
0x39 => Self::Integer(-1 - read_u16(r)? as i128),
0x3a => Self::Integer(-1 - read_u32(r)? as i128),
0x3b => Self::Integer(-1 - read_u64(r)? as i128),
0x40..=0x5b => {
let len = read_len(r, major - 0x40)?;
let bytes = read_bytes(r, len as usize)?;
Self::Bytes(bytes)
}
0x60..=0x7b => {
let len = read_len(r, major - 0x60)?;
let string = read_str(r, len as usize)?;
Self::String(string)
}
0x80..=0x9b => {
let len = read_len(r, major - 0x80)?;
let list = read_list(r, len as usize)?;
Self::List(list)
}
0xa0..=0xbb => {
let len = read_len(r, major - 0xa0)?;
let map = read_map(r, len as usize)?;
Self::Map(map)
}
0xd8 => Self::Link(read_link(r)?),
0xf4 => Self::Bool(false),
0xf5 => Self::Bool(true),
0xf6 => Self::Null,
0xf7 => Self::Null,
0xfa => Self::Float(read_f32(r)? as f64),
0xfb => Self::Float(read_f64(r)?),
_ => return Ok(None),
};
Ok(Some(ipld))
}
}
impl_decode!(Ipld);
impl References<DagCbor> for Ipld {
fn references<R: Read + Seek, E: Extend<Cid>>(
c: DagCbor,
r: &mut R,
set: &mut E,
) -> Result<()> {
let major = read_u8(r)?;
match major {
0x00..=0x17 => {}
0x18 => {
r.seek(SeekFrom::Current(1))?;
}
0x19 => {
r.seek(SeekFrom::Current(2))?;
}
0x1a => {
r.seek(SeekFrom::Current(4))?;
}
0x1b => {
r.seek(SeekFrom::Current(8))?;
}
0x20..=0x37 => {}
0x38 => {
r.seek(SeekFrom::Current(1))?;
}
0x39 => {
r.seek(SeekFrom::Current(2))?;
}
0x3a => {
r.seek(SeekFrom::Current(4))?;
}
0x3b => {
r.seek(SeekFrom::Current(8))?;
}
0x40..=0x5b => {
let len = read_len(r, major - 0x40)?;
r.seek(SeekFrom::Current(len as _))?;
}
0x60..=0x7b => {
let len = read_len(r, major - 0x60)?;
r.seek(SeekFrom::Current(len as _))?;
}
0x80..=0x9b => {
let len = read_len(r, major - 0x80)?;
for _ in 0..len {
<Self as References<DagCbor>>::references(c, r, set)?;
}
}
0xa0..=0xb7 => {
let len = read_len(r, major - 0xa0)?;
for _ in 0..len {
<Self as References<DagCbor>>::references(c, r, set)?;
<Self as References<DagCbor>>::references(c, r, set)?;
}
}
0xd8 => {
set.extend(std::iter::once(read_link(r)?));
}
0xf4..=0xf7 => {}
0xfa => {
r.seek(SeekFrom::Current(4))?;
}
0xfb => {
r.seek(SeekFrom::Current(8))?;
}
_ => return Err(UnexpectedCode.into()),
};
Ok(())
}
}