Skip to main content

co_primitives/library/
block_serializer.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 1io BRANDGUARDIAN GmbH
3
4use crate::{from_cbor, to_cbor, Block, KnownMultiCodec, StoreParams};
5use cid::Cid;
6use serde::Serialize;
7
8#[derive(Debug, thiserror::Error)]
9pub enum BlockSerializerError {
10	#[error("Block size {1} exceeds {0}.")]
11	BlockToLarge(usize, usize),
12
13	#[error("Serialize failed")]
14	Serialize(#[source] anyhow::Error),
15
16	#[error("Deserialize {0} as CBOR failed")]
17	Deserialize(Cid, #[source] anyhow::Error),
18}
19
20/// DagCbor Block Serializer/Deserializer.
21pub struct BlockSerializer {
22	codec: u64,
23	max_block_size: Option<usize>,
24}
25impl BlockSerializer {
26	pub fn new() -> Self {
27		Self::new_codec(KnownMultiCodec::DagCbor)
28	}
29
30	pub fn new_store_params<P: StoreParams>() -> Self {
31		Self::new_codec(KnownMultiCodec::DagCbor).with_max_block_size(P::MAX_BLOCK_SIZE)
32	}
33
34	pub fn new_codec(codec: impl Into<u64>) -> Self {
35		Self { max_block_size: None, codec: codec.into() }
36	}
37
38	pub fn with_codec(mut self, codec: impl Into<u64>) -> Self {
39		self.codec = codec.into();
40		self
41	}
42
43	pub fn with_max_block_size(mut self, max_block_size: usize) -> Self {
44		self.max_block_size = Some(max_block_size);
45		self
46	}
47}
48impl Default for BlockSerializer {
49	fn default() -> Self {
50		Self::new()
51	}
52}
53impl BlockSerializer {
54	/// Serialize item to block.
55	pub fn serialize<T>(&self, item: &T) -> Result<Block, BlockSerializerError>
56	where
57		T: Serialize,
58	{
59		let data = to_cbor(item).map_err(|err| BlockSerializerError::Serialize(err.into()))?;
60		if let Some(max_block_size) = self.max_block_size {
61			if max_block_size < data.len() {
62				return Err(BlockSerializerError::BlockToLarge(max_block_size, data.len()));
63			}
64		}
65		Ok(Block::new_data(self.codec, data))
66	}
67
68	/// Deserialize block to item.
69	pub fn deserialize<'a, T>(&self, item: &'a Block) -> Result<T, BlockSerializerError>
70	where
71		T: serde::de::Deserialize<'a>,
72	{
73		// MultiCodec::with_cbor(item.cid())?;
74		from_cbor(item.data()).map_err(|err| BlockSerializerError::Deserialize(*item.cid(), err.into()))
75	}
76}
77
78#[cfg(test)]
79mod tests {
80	use crate::library::block_serializer::BlockSerializer;
81	use serde::Serialize;
82
83	#[derive(Debug, Serialize)]
84	struct Test {
85		hello: String,
86	}
87
88	#[test]
89	fn should_serialize() {
90		let test = Test { hello: "world".to_owned() };
91		let block = BlockSerializer::default().serialize(&test).unwrap();
92		assert_eq!(block.cid().to_string(), "bafyr4iahzl6dyblh5gjfk5lo46xkkfk7fvxhyot4636rdglz3n5tayegd4");
93		assert_eq!(block.data(), [161, 101, 104, 101, 108, 108, 111, 101, 119, 111, 114, 108, 100]);
94	}
95}