use crate::{
error::{InvalidCidPrefix, LengthOutOfRange, UnexpectedCode, UnexpectedEof, UnknownTag},
RawCborCodec,
};
use byteorder::{BigEndian, ByteOrder};
use core::convert::TryFrom;
use libipld_core::{
cid::Cid,
codec::{Decode, References},
error::Result,
ipld::Ipld,
raw_value::SkipOne,
};
use std::{
collections::BTreeMap,
io::{Read, Seek, SeekFrom},
sync::Arc,
};
pub fn read_u8<R: Read + Seek>(r: &mut R) -> Result<u8> {
let mut buf = [0; 1];
r.read_exact(&mut buf)?;
Ok(buf[0])
}
pub fn read_u16<R: Read + Seek>(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 + Seek>(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 + Seek>(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 + Seek>(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 + Seek>(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 + Seek>(r: &mut R, len: usize) -> Result<Vec<u8>> {
let mut buf = Vec::with_capacity(len.min(16 * 1024));
r.take(len as u64).read_to_end(&mut buf)?;
if buf.len() != len {
return Err(UnexpectedEof.into());
}
Ok(buf)
}
pub fn read_str<R: Read + Seek>(r: &mut R, len: usize) -> Result<String> {
let bytes = read_bytes(r, len)?;
Ok(String::from_utf8(bytes)?)
}
pub fn read_list<R: Read + Seek, T: Decode<RawCborCodec>>(r: &mut R, len: usize) -> Result<Vec<T>> {
let max_alloc = (16 * 1024) / std::mem::size_of::<T>();
let mut list: Vec<T> = Vec::with_capacity(len.min(max_alloc));
for _ in 0..len {
list.push(T::decode(RawCborCodec, r)?);
}
Ok(list)
}
pub fn read_list_il<R: Read + Seek, T: Decode<RawCborCodec>>(r: &mut R) -> Result<Vec<T>> {
let mut list: Vec<T> = Vec::new();
loop {
let major = read_u8(r)?;
if major == 0xff {
break;
}
r.seek(SeekFrom::Current(-1))?;
let value = T::decode(RawCborCodec, r)?;
list.push(value);
}
Ok(list)
}
pub fn read_map<R: Read + Seek, K: Decode<RawCborCodec> + Ord, T: Decode<RawCborCodec>>(
r: &mut R,
len: usize,
) -> Result<BTreeMap<K, T>> {
let mut map: BTreeMap<K, T> = BTreeMap::new();
for _ in 0..len {
let key = K::decode(RawCborCodec, r)?;
let value = T::decode(RawCborCodec, r)?;
map.insert(key, value);
}
Ok(map)
}
pub fn read_map_il<R: Read + Seek, K: Decode<RawCborCodec> + Ord, T: Decode<RawCborCodec>>(
r: &mut R,
) -> Result<BTreeMap<K, T>> {
let mut map: BTreeMap<K, T> = BTreeMap::new();
loop {
let major = read_u8(r)?;
if major == 0xff {
break;
}
r.seek(SeekFrom::Current(-1))?;
let key = K::decode(RawCborCodec, r)?;
let value = T::decode(RawCborCodec, r)?;
map.insert(key, value);
}
Ok(map)
}
pub fn read_link<R: Read + Seek>(r: &mut R) -> Result<Cid> {
let ty = read_u8(r)?;
if ty != 0x58 {
return Err(UnknownTag(ty).into());
}
let len = read_u8(r)?;
if len == 0 {
return Err(LengthOutOfRange::new::<Cid>().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 + Seek>(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::new::<usize>().into());
}
len as usize
}
major => return Err(UnexpectedCode::new::<usize>(major).into()),
})
}
impl Decode<RawCborCodec> for bool {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0xf4 => false,
0xf5 => true,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for u8 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x00..=0x17 => major,
0x18 => read_u8(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for u16 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x00..=0x17 => major as u16,
0x18 => read_u8(r)? as u16,
0x19 => read_u16(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for u32 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x00..=0x17 => major as u32,
0x18 => read_u8(r)? as u32,
0x19 => read_u16(r)? as u32,
0x1a => read_u32(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for u64 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x00..=0x17 => major as u64,
0x18 => read_u8(r)? as u64,
0x19 => read_u16(r)? as u64,
0x1a => read_u32(r)? as u64,
0x1b => read_u64(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for i8 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x20..=0x37 => -1 - (major - 0x20) as i8,
0x38 => -1 - read_u8(r)? as i8,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for i16 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x20..=0x37 => -1 - (major - 0x20) as i16,
0x38 => -1 - read_u8(r)? as i16,
0x39 => -1 - read_u16(r)? as i16,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for i32 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x20..=0x37 => -1 - (major - 0x20) as i32,
0x38 => -1 - read_u8(r)? as i32,
0x39 => -1 - read_u16(r)? as i32,
0x3a => -1 - read_u32(r)? as i32,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for i64 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x20..=0x37 => -1 - (major - 0x20) as i64,
0x38 => -1 - read_u8(r)? as i64,
0x39 => -1 - read_u16(r)? as i64,
0x3a => -1 - read_u32(r)? as i64,
0x3b => -1 - read_u64(r)? as i64,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for f32 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0xfa => read_f32(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for f64 {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0xfa => read_f32(r)? as f64,
0xfb => read_f64(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for String {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x60..=0x7b => {
let len = read_len(r, major - 0x60)?;
read_str(r, len)?
}
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for Cid {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
if major == 0xd8 {
if let Ok(tag) = read_u8(r) {
if tag == 42 {
return read_link(r);
}
}
}
Err(UnexpectedCode::new::<Self>(major).into())
}
}
impl Decode<RawCborCodec> for Box<[u8]> {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x40..=0x5b => {
let len = read_len(r, major - 0x40)?;
read_bytes(r, len)?.into_boxed_slice()
}
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl<T: Decode<RawCborCodec>> Decode<RawCborCodec> for Option<T> {
fn decode<R: Read + Seek>(c: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0xf6 => None,
0xf7 => None,
_ => {
r.seek(SeekFrom::Current(-1))?;
Some(T::decode(c, r)?)
}
};
Ok(result)
}
}
impl<T: Decode<RawCborCodec>> Decode<RawCborCodec> for Vec<T> {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x80..=0x9b => {
let len = read_len(r, major - 0x80)?;
read_list(r, len)?
}
0x9f => read_list_il(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl<K: Decode<RawCborCodec> + Ord, T: Decode<RawCborCodec>> Decode<RawCborCodec> for BTreeMap<K, T> {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0xa0..=0xbb => {
let len = read_len(r, major - 0xa0)?;
read_map(r, len)?
}
0xbf => read_map_il(r)?,
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl Decode<RawCborCodec> for Ipld {
fn decode<R: Read + Seek>(_: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
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)
}
0x9f => {
let list = read_list_il(r)?;
Self::List(list)
}
0xa0..=0xbb => {
let len = read_len(r, major - 0xa0)?;
Self::Map(read_map(r, len as usize)?)
}
0xbf => Self::Map(read_map_il(r)?),
0xd8 => {
let tag = read_u8(r)?;
if tag == 42 {
Self::Link(read_link(r)?)
} else {
return Err(UnknownTag(tag).into());
}
}
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 Err(UnexpectedCode::new::<Self>(major).into()),
};
Ok(ipld)
}
}
impl References<RawCborCodec> for Ipld {
fn references<R: Read + Seek, E: Extend<Cid>>(
c: RawCborCodec,
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<RawCborCodec>>::references(c, r, set)?;
}
}
0x9f => loop {
let major = read_u8(r)?;
if major == 0xff {
break;
}
r.seek(SeekFrom::Current(-1))?;
<Self as References<RawCborCodec>>::references(c, r, set)?;
},
0xa0..=0xbb => {
let len = read_len(r, major - 0xa0)?;
for _ in 0..len {
<Self as References<RawCborCodec>>::references(c, r, set)?;
<Self as References<RawCborCodec>>::references(c, r, set)?;
}
}
0xbf => loop {
let major = read_u8(r)?;
if major == 0xff {
break;
}
r.seek(SeekFrom::Current(-1))?;
<Self as References<RawCborCodec>>::references(c, r, set)?;
<Self as References<RawCborCodec>>::references(c, r, set)?;
},
0xd8 => {
let tag = read_u8(r)?;
if tag == 42 {
set.extend(std::iter::once(read_link(r)?));
} else {
<Self as References<RawCborCodec>>::references(c, r, set)?;
}
}
0xf4..=0xf7 => {}
0xf8 => {
r.seek(SeekFrom::Current(1))?;
}
0xf9 => {
r.seek(SeekFrom::Current(2))?;
}
0xfa => {
r.seek(SeekFrom::Current(4))?;
}
0xfb => {
r.seek(SeekFrom::Current(8))?;
}
major => return Err(UnexpectedCode::new::<Ipld>(major).into()),
};
Ok(())
}
}
impl<T: Decode<RawCborCodec>> Decode<RawCborCodec> for Arc<T> {
fn decode<R: Read + Seek>(c: RawCborCodec, r: &mut R) -> Result<Self> {
Ok(Arc::new(T::decode(c, r)?))
}
}
impl Decode<RawCborCodec> for () {
fn decode<R: Read + Seek>(_c: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
match major {
0x80 => {}
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(())
}
}
impl<A: Decode<RawCborCodec>> Decode<RawCborCodec> for (A,) {
fn decode<R: Read + Seek>(c: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x81 => (A::decode(c, r)?,),
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl<A: Decode<RawCborCodec>, B: Decode<RawCborCodec>> Decode<RawCborCodec> for (A, B) {
fn decode<R: Read + Seek>(c: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x82 => (A::decode(c, r)?, B::decode(c, r)?),
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl<A: Decode<RawCborCodec>, B: Decode<RawCborCodec>, C: Decode<RawCborCodec>> Decode<RawCborCodec>
for (A, B, C)
{
fn decode<R: Read + Seek>(c: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x83 => (A::decode(c, r)?, B::decode(c, r)?, C::decode(c, r)?),
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl<A: Decode<RawCborCodec>, B: Decode<RawCborCodec>, C: Decode<RawCborCodec>, D: Decode<RawCborCodec>>
Decode<RawCborCodec> for (A, B, C, D)
{
fn decode<R: Read + Seek>(c: RawCborCodec, r: &mut R) -> Result<Self> {
let major = read_u8(r)?;
let result = match major {
0x84 => (
A::decode(c, r)?,
B::decode(c, r)?,
C::decode(c, r)?,
D::decode(c, r)?,
),
_ => {
return Err(UnexpectedCode::new::<Self>(major).into());
}
};
Ok(result)
}
}
impl SkipOne for RawCborCodec {
fn skip<R: Read + Seek>(&self, r: &mut R) -> 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.skip(r)?;
}
}
0x9f => loop {
let major = read_u8(r)?;
if major == 0xff {
break;
}
r.seek(SeekFrom::Current(-1))?;
self.skip(r)?;
},
0xa0..=0xbb => {
let len = read_len(r, major - 0xa0)?;
for _ in 0..len {
self.skip(r)?;
self.skip(r)?;
}
}
0xbf => loop {
let major = read_u8(r)?;
if major == 0xff {
break;
}
r.seek(SeekFrom::Current(-1))?;
self.skip(r)?;
self.skip(r)?;
},
0xc0..=0xd7 => {
self.skip(r)?;
}
0xd8 => {
r.seek(SeekFrom::Current(1))?;
self.skip(r)?;
}
0xd9 => {
r.seek(SeekFrom::Current(2))?;
self.skip(r)?;
}
0xda => {
r.seek(SeekFrom::Current(4))?;
self.skip(r)?;
}
0xdb => {
r.seek(SeekFrom::Current(8))?;
self.skip(r)?;
}
0xf4..=0xf7 => {}
0xf8 => {
r.seek(SeekFrom::Current(1))?;
}
0xf9 => {
r.seek(SeekFrom::Current(2))?;
}
0xfa => {
r.seek(SeekFrom::Current(4))?;
}
0xfb => {
r.seek(SeekFrom::Current(8))?;
}
major => return Err(UnexpectedCode::new::<Ipld>(major).into()),
};
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{error::UnexpectedEof, RawCborCodec};
use libipld_core::codec::Codec;
use libipld_macro::ipld;
#[test]
fn il_map() {
let bytes = [
0xBF, 0x63, 0x46, 0x75, 0x6e, 0xF5, 0x63, 0x41, 0x6d, 0x74, 0x21, 0xFF, ];
let ipld = ipld!({
"Fun": true,
"Amt": -2,
});
let ipld2: Ipld = RawCborCodec.decode(&bytes).unwrap();
assert_eq!(ipld, ipld2);
}
#[test]
fn bad_list() {
let bytes = [
0x5b, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, ];
RawCborCodec
.decode::<Ipld>(&bytes)
.expect_err("decoding large truncated buffer should have failed")
.downcast::<UnexpectedEof>()
.expect("expected an unexpected eof");
}
#[test]
#[allow(clippy::let_unit_value)]
fn tuples() -> Result<()> {
let data = ();
let bytes = RawCborCodec.encode(&data)?;
let _data2: () = RawCborCodec.decode(&bytes)?;
let data = ("hello".to_string(),);
let bytes = RawCborCodec.encode(&data)?;
let data2: (String,) = RawCborCodec.decode(&bytes)?;
assert_eq!(data, data2);
let data = ("hello".to_string(), "world".to_string());
let bytes = RawCborCodec.encode(&data)?;
let data2: (String, String) = RawCborCodec.decode(&bytes)?;
assert_eq!(data, data2);
let data = ("hello".to_string(), "world".to_string(), 42);
let bytes = RawCborCodec.encode(&data)?;
let data2: (String, String, u32) = RawCborCodec.decode(&bytes)?;
assert_eq!(data, data2);
let data = ("hello".to_string(), "world".to_string(), 42, 64);
let bytes = RawCborCodec.encode(&data)?;
let data2: (String, String, u32, u8) = RawCborCodec.decode(&bytes)?;
assert_eq!(data, data2);
Ok(())
}
}