use crate::cid::Cid;
use crate::error::BlockError;
use crate::hash::{digest, Hash};
use crate::ipld::Ipld;
use crate::MAX_BLOCK_SIZE;
use dag_cbor::{decode::Read, Codec, DagCborCodec, ReadCbor, WriteCbor};
pub fn validate(cid: &Cid, data: &[u8]) -> Result<(), BlockError> {
if data.len() > MAX_BLOCK_SIZE {
return Err(BlockError::BlockToLarge(data.len()));
}
let hash = digest(cid.hash().algorithm(), &data);
if hash.as_ref() != cid.hash() {
return Err(BlockError::InvalidHash(hash));
}
Ok(())
}
pub fn create_raw_block<H: Hash>(data: Box<[u8]>) -> Result<(Cid, Box<[u8]>), BlockError> {
if data.len() > MAX_BLOCK_SIZE {
return Err(BlockError::BlockToLarge(data.len()));
}
let hash = H::digest(&data);
let cid = Cid::new_v1(cid::Codec::Raw, hash);
Ok((cid, data))
}
pub async fn create_cbor_block<H: Hash, C: WriteCbor>(
c: &C,
) -> Result<(Cid, Box<[u8]>), BlockError> {
let mut data = Vec::new();
c.write_cbor(&mut data).await?;
if data.len() > MAX_BLOCK_SIZE {
return Err(BlockError::BlockToLarge(data.len()));
}
let hash = H::digest(&data);
let cid = Cid::new_v1(DagCborCodec::CODEC, hash);
Ok((cid, data.into_boxed_slice()))
}
pub async fn decode_ipld(cid: &Cid, data: &[u8]) -> Result<Ipld, BlockError> {
let ipld = match cid.codec() {
DagCborCodec::CODEC => DagCborCodec::decode(&data).await?,
cid::Codec::Raw => Ipld::Bytes(data.to_vec()),
_ => return Err(BlockError::UnsupportedCodec(cid.codec())),
};
Ok(ipld)
}
pub async fn decode_cbor<C: ReadCbor>(cid: &Cid, mut data: &[u8]) -> Result<C, BlockError> {
decode_cbor_read(cid, &mut data).await
}
pub async fn decode_cbor_read<R: Read + Unpin + Send, C: ReadCbor>(
cid: &Cid,
reader: &mut R,
) -> Result<C, BlockError> {
if cid.codec() != DagCborCodec::CODEC {
return Err(BlockError::UnsupportedCodec(cid.codec()));
}
let res = C::read_cbor(reader).await?;
Ok(res)
}