use std::collections::BTreeMap;
use std::io::Error;
use std::io::Read;
use std::io::Write;
use codeq::config::CodeqConfig;
use codeq::ChecksumReader;
use codeq::Decode;
use codeq::Encode;
use crate::buf;
use crate::typ::Type;
use crate::v001::bincode_config::bincode_config;
use crate::v001::block::invalid;
use crate::v001::block::Block;
use crate::v001::block_encoding_meta::BlockEncodingMeta;
use crate::v001::header::Header;
use crate::v001::prefix::Prefix;
use crate::v001::types::Checksum;
use crate::v001::SeqMarked;
use crate::version::Version;
const COMPRESSION_ZSTD: u8 = 1;
const ZSTD_LEVEL: i32 = 1;
pub(crate) fn block_encode_v002<W: Write>(block: &Block, mut w: W) -> Result<usize, Error> {
let mut n = 0usize;
let mut raw = Vec::new();
bincode::encode_into_std_write(block.prefix.as_str(), &mut raw, bincode_config())
.map_err(invalid)?;
bincode::encode_into_std_write(&block.data, &mut raw, bincode_config()).map_err(invalid)?;
let body = zstd::encode_all(raw.as_slice(), ZSTD_LEVEL)?;
let encoded_size = 1 + body.len() as u64;
let mut cw = Checksum::new_writer(&mut w);
n += block.header.encode(&mut cw)?;
let meta = BlockEncodingMeta::new(block.meta.block_num(), encoded_size);
n += meta.encode(&mut cw)?;
cw.write_all(&[COMPRESSION_ZSTD])?;
cw.write_all(&body)?;
n += encoded_size as usize;
n += cw.write_checksum()?;
Ok(n)
}
pub(crate) fn block_decode_v002<R: Read>(
mut cr: ChecksumReader<Checksum, R>,
) -> Result<Block, Error> {
let meta = BlockEncodingMeta::decode(&mut cr)?;
let data_size = meta.data_encoded_size() as usize;
let mut buf = buf::new_uninitialized(data_size);
cr.read_exact(&mut buf)?;
cr.verify_checksum(|| "Block::decode()")?;
let (tag, body) = buf.split_first().ok_or_else(|| invalid("empty V002 block payload"))?;
let raw = match *tag {
COMPRESSION_ZSTD => zstd::decode_all(body)?,
other => return Err(invalid(format!("unknown V002 compression tag: {other}"))),
};
let (prefix, read): (String, usize) =
bincode::decode_from_slice(&raw, bincode_config()).map_err(invalid)?;
let (data, _): (BTreeMap<String, SeqMarked>, usize) =
bincode::decode_from_slice(&raw[read..], bincode_config()).map_err(invalid)?;
Ok(Block {
header: Header::new(Type::Block, Version::V002),
meta,
prefix: Prefix::new(prefix),
data,
})
}