1use alloc::{format, string::String, vec::Vec};
3use core::{convert::TryFrom, ops::Deref};
4
5use crate::cid::Cid;
6use crate::error::{Result, UnsupportedCodec};
7use crate::io::{Cursor, Read, Seek, Write};
8use crate::ipld::Ipld;
9
10pub trait Codec:
12 Copy + Unpin + Send + Sync + 'static + Sized + TryFrom<u64, Error = UnsupportedCodec> + Into<u64>
13{
14 fn encode<T: Encode<Self> + ?Sized>(&self, obj: &T) -> Result<Vec<u8>> {
16 let mut buf = Vec::with_capacity(u16::MAX as usize);
17 obj.encode(*self, &mut buf)?;
18 Ok(buf)
19 }
20
21 fn decode<T: Decode<Self>>(&self, bytes: &[u8]) -> Result<T> {
23 T::decode(*self, &mut Cursor::new(bytes))
24 }
25
26 fn references<T: References<Self>, E: Extend<Cid>>(
28 &self,
29 bytes: &[u8],
30 set: &mut E,
31 ) -> Result<()> {
32 T::references(*self, &mut Cursor::new(bytes), set)
33 }
34}
35
36pub trait Encode<C: Codec> {
41 fn encode<W: Write>(&self, c: C, w: &mut W) -> Result<()>;
46}
47
48impl<C: Codec, T: Encode<C>> Encode<C> for &T {
49 fn encode<W: Write>(&self, c: C, w: &mut W) -> Result<()> {
50 self.deref().encode(c, w)
51 }
52}
53
54pub trait Decode<C: Codec>: Sized {
59 fn decode<R: Read + Seek>(c: C, r: &mut R) -> Result<Self>;
64}
65
66pub trait References<C: Codec>: Sized {
71 fn references<R: Read + Seek, E: Extend<Cid>>(c: C, r: &mut R, set: &mut E) -> Result<()>;
76}
77
78pub fn assert_roundtrip<C, T>(c: C, data: &T, ipld: &Ipld)
82where
83 C: Codec,
84 T: Decode<C> + Encode<C> + core::fmt::Debug + PartialEq,
85 Ipld: Decode<C> + Encode<C>,
86{
87 fn hex(bytes: &[u8]) -> String {
88 bytes.iter().map(|byte| format!("{:02x}", byte)).collect()
89 }
90 let mut bytes = Vec::new();
91 data.encode(c, &mut bytes).unwrap();
92 let mut bytes2 = Vec::new();
93 ipld.encode(c, &mut bytes2).unwrap();
94 if bytes != bytes2 {
95 panic!(
96 r#"assertion failed: `(left == right)`
97 left: `{}`,
98 right: `{}`"#,
99 hex(&bytes),
100 hex(&bytes2)
101 );
102 }
103 let ipld2: Ipld = Decode::decode(c, &mut Cursor::new(bytes.as_slice())).unwrap();
104 assert_eq!(&ipld2, ipld);
105 let data2: T = Decode::decode(c, &mut Cursor::new(bytes.as_slice())).unwrap();
106 assert_eq!(&data2, data);
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use crate::ipld::Ipld;
113 use anyhow::anyhow;
114
115 #[derive(Clone, Copy, Debug)]
116 struct CodecImpl;
117
118 impl Codec for CodecImpl {}
119
120 impl From<CodecImpl> for u64 {
121 fn from(_: CodecImpl) -> Self {
122 0
123 }
124 }
125
126 impl TryFrom<u64> for CodecImpl {
127 type Error = UnsupportedCodec;
128
129 fn try_from(_: u64) -> core::result::Result<Self, Self::Error> {
130 Ok(Self)
131 }
132 }
133
134 impl Encode<CodecImpl> for Ipld {
135 fn encode<W: Write>(&self, _: CodecImpl, w: &mut W) -> Result<()> {
136 match self {
137 Self::Null => Ok(w.write_all(&[0]).map_err(anyhow::Error::msg)?),
138 _ => Err(anyhow!("not null")),
139 }
140 }
141 }
142
143 impl Decode<CodecImpl> for Ipld {
144 fn decode<R: Read>(_: CodecImpl, r: &mut R) -> Result<Self> {
145 let mut buf = [0; 1];
146 r.read_exact(&mut buf).map_err(anyhow::Error::msg)?;
147 if buf[0] == 0 {
148 Ok(Ipld::Null)
149 } else {
150 Err(anyhow!("not null"))
151 }
152 }
153 }
154
155 #[test]
156 fn test_codec() {
157 let bytes = CodecImpl.encode(&Ipld::Null).unwrap();
158 let ipld: Ipld = CodecImpl.decode(&bytes).unwrap();
159 assert_eq!(ipld, Ipld::Null);
160 }
161}