use cid::Cid;
use fvm_shared::MAX_CID_LEN;
use crate::{SyscallResult, sys};
pub const UNIT: u32 = sys::ipld::UNIT;
pub fn put(mh_code: u64, mh_size: u32, codec: u64, data: &[u8]) -> SyscallResult<Cid> {
unsafe {
let id = sys::ipld::block_create(codec, data.as_ptr(), data.len() as u32)?;
let mut buf = [0u8; MAX_CID_LEN];
let len = sys::ipld::block_link(id, mh_code, mh_size, buf.as_mut_ptr(), buf.len() as u32)?;
Ok(Cid::read_bytes(&buf[..len as usize]).expect("runtime returned an invalid CID"))
}
}
pub fn get(cid: &Cid) -> SyscallResult<Vec<u8>> {
unsafe {
let mut cid_buf = [0u8; MAX_CID_LEN];
cid.write_bytes(&mut cid_buf[..])
.expect("CID encoding should not fail");
let fvm_shared::sys::out::ipld::IpldOpen { id, size, .. } =
sys::ipld::block_open(cid_buf.as_mut_ptr())?;
let mut block = Vec::with_capacity(size as usize);
let remaining = sys::ipld::block_read(id, 0, block.as_mut_ptr(), size)?;
assert_eq!(remaining, 0, "expected to read the block exactly");
block.set_len(size as usize);
Ok(block)
}
}
pub fn get_block(id: fvm_shared::sys::BlockId, size_hint: Option<u32>) -> SyscallResult<Vec<u8>> {
if id == UNIT {
return Ok(Vec::new());
}
let mut buf = Vec::with_capacity(size_hint.unwrap_or(1024) as usize);
unsafe {
let mut remaining = sys::ipld::block_read(id, 0, buf.as_mut_ptr(), buf.capacity() as u32)?;
if remaining > 0 {
buf.set_len(buf.capacity());
buf.reserve_exact(remaining as usize);
remaining = sys::ipld::block_read(
id,
buf.len() as u32,
buf.as_mut_ptr_range().end,
(buf.capacity() - buf.len()) as u32,
)?;
assert!(remaining <= 0, "should have read whole block");
}
let size = (buf.capacity() as i64) + (remaining as i64);
assert!(size >= 0, "size can't be negative");
assert!(
size <= buf.capacity() as i64,
"size shouldn't exceed capacity"
);
buf.set_len(size as usize);
}
Ok(buf)
}
pub fn put_block(
codec: fvm_shared::sys::Codec,
data: &[u8],
) -> SyscallResult<fvm_shared::sys::BlockId> {
unsafe { sys::ipld::block_create(codec, data.as_ptr(), data.len() as u32) }
}