nectar_primitives/chunk/
any_chunk.rs1use bytes::Bytes;
7
8use crate::bmt::DEFAULT_BODY_SIZE;
9use crate::error::Result;
10
11use super::chunk_type::ChunkType;
12use super::content::ContentChunk;
13use super::single_owner::SingleOwnerChunk;
14use super::traits::{Chunk, ChunkAddress};
15use super::type_id::ChunkTypeId;
16
17#[derive(Debug, Clone)]
46pub enum AnyChunk<const BODY_SIZE: usize = DEFAULT_BODY_SIZE> {
47 Content(ContentChunk<BODY_SIZE>),
49 SingleOwner(SingleOwnerChunk<BODY_SIZE>),
51 Custom {
56 type_id: ChunkTypeId,
58 address: ChunkAddress,
60 data: Bytes,
62 },
63}
64
65impl<const BODY_SIZE: usize> AnyChunk<BODY_SIZE> {
66 pub fn address(&self) -> &ChunkAddress {
68 match self {
69 Self::Content(c) => c.address(),
70 Self::SingleOwner(c) => c.address(),
71 Self::Custom { address, .. } => address,
72 }
73 }
74
75 pub fn data(&self) -> &Bytes {
77 match self {
78 Self::Content(c) => c.data(),
79 Self::SingleOwner(c) => c.data(),
80 Self::Custom { data, .. } => data,
81 }
82 }
83
84 pub const fn type_id(&self) -> ChunkTypeId {
86 match self {
87 Self::Content(_) => ChunkTypeId::CONTENT,
88 Self::SingleOwner(_) => ChunkTypeId::SINGLE_OWNER,
89 Self::Custom { type_id, .. } => *type_id,
90 }
91 }
92
93 pub fn size(&self) -> usize {
95 match self {
96 Self::Content(c) => c.size(),
97 Self::SingleOwner(c) => c.size(),
98 Self::Custom { data, .. } => data.len(),
99 }
100 }
101
102 pub fn span(&self) -> u64 {
107 match self {
108 Self::Content(c) => super::traits::BmtChunk::span(c),
109 Self::SingleOwner(c) => super::traits::BmtChunk::span(c),
110 Self::Custom { .. } => 0, }
112 }
113
114 pub fn verify(&self, expected: &ChunkAddress) -> Result<()> {
116 match self {
117 Self::Content(c) => c.verify(expected),
118 Self::SingleOwner(c) => c.verify(expected),
119 Self::Custom { address, .. } => {
120 if address != expected {
121 return Err(
122 super::error::ChunkError::verification_failed(*expected, *address).into(),
123 );
124 }
125 Ok(())
126 }
127 }
128 }
129
130 pub fn into_bytes(self) -> Bytes {
132 match self {
133 Self::Content(c) => c.into(),
134 Self::SingleOwner(c) => c.into(),
135 Self::Custom { data, .. } => data,
136 }
137 }
138
139 pub fn is<T: ChunkType>(&self) -> bool {
141 self.type_id() == T::TYPE_ID
142 }
143
144 pub const fn is_content(&self) -> bool {
146 matches!(self, Self::Content(_))
147 }
148
149 pub const fn is_single_owner(&self) -> bool {
151 matches!(self, Self::SingleOwner(_))
152 }
153
154 pub const fn is_custom(&self) -> bool {
156 matches!(self, Self::Custom { .. })
157 }
158
159 pub const fn as_content(&self) -> Option<&ContentChunk<BODY_SIZE>> {
161 match self {
162 Self::Content(c) => Some(c),
163 _ => None,
164 }
165 }
166
167 pub const fn as_single_owner(&self) -> Option<&SingleOwnerChunk<BODY_SIZE>> {
169 match self {
170 Self::SingleOwner(c) => Some(c),
171 _ => None,
172 }
173 }
174
175 pub fn into_content(self) -> Option<ContentChunk<BODY_SIZE>> {
177 match self {
178 Self::Content(c) => Some(c),
179 _ => None,
180 }
181 }
182
183 pub fn into_single_owner(self) -> Option<SingleOwnerChunk<BODY_SIZE>> {
185 match self {
186 Self::SingleOwner(c) => Some(c),
187 _ => None,
188 }
189 }
190}
191
192impl<const BODY_SIZE: usize> From<ContentChunk<BODY_SIZE>> for AnyChunk<BODY_SIZE> {
193 fn from(chunk: ContentChunk<BODY_SIZE>) -> Self {
194 Self::Content(chunk)
195 }
196}
197
198impl<const BODY_SIZE: usize> From<SingleOwnerChunk<BODY_SIZE>> for AnyChunk<BODY_SIZE> {
199 fn from(chunk: SingleOwnerChunk<BODY_SIZE>) -> Self {
200 Self::SingleOwner(chunk)
201 }
202}
203
204impl<const BODY_SIZE: usize> PartialEq for AnyChunk<BODY_SIZE> {
205 fn eq(&self, other: &Self) -> bool {
206 self.address() == other.address()
207 }
208}
209
210impl<const BODY_SIZE: usize> Eq for AnyChunk<BODY_SIZE> {}
211
212#[cfg(test)]
213mod tests {
214 use super::super::traits::Chunk;
215 use super::*;
216
217 type DefaultContentChunk = ContentChunk<DEFAULT_BODY_SIZE>;
218 type DefaultSingleOwnerChunk = SingleOwnerChunk<DEFAULT_BODY_SIZE>;
219 type DefaultAnyChunk = AnyChunk<DEFAULT_BODY_SIZE>;
220
221 #[test]
222 fn test_content_chunk_conversion() {
223 let content = DefaultContentChunk::new(&b"hello world"[..]).unwrap();
224 let address = *content.address();
225
226 let any: DefaultAnyChunk = content.into();
227
228 assert!(any.is_content());
229 assert!(!any.is_single_owner());
230 assert!(!any.is_custom());
231 assert_eq!(any.type_id(), ChunkTypeId::CONTENT);
232 assert_eq!(*any.address(), address);
233 }
234
235 #[test]
236 fn test_as_content() {
237 let content = DefaultContentChunk::new(&b"test data"[..]).unwrap();
238 let expected_addr = *content.address();
239
240 let any: DefaultAnyChunk = content.into();
241 let recovered = any.as_content().unwrap();
242
243 assert_eq!(*recovered.address(), expected_addr);
244 }
245
246 #[test]
247 fn test_into_content() {
248 let content = DefaultContentChunk::new(&b"test data"[..]).unwrap();
249 let expected_addr = *content.address();
250
251 let any: DefaultAnyChunk = content.into();
252 let recovered = any.into_content().unwrap();
253
254 assert_eq!(*recovered.address(), expected_addr);
255 }
256
257 #[test]
258 fn test_is_methods() {
259 let content: DefaultAnyChunk = DefaultContentChunk::new(&b"test"[..]).unwrap().into();
260
261 assert!(content.is::<DefaultContentChunk>());
262 assert!(!content.is::<DefaultSingleOwnerChunk>());
263 }
264
265 #[test]
266 fn test_clone() {
267 let content = DefaultContentChunk::new(&b"test"[..]).unwrap();
268 let any: DefaultAnyChunk = content.into();
269 let cloned = any.clone();
270
271 assert_eq!(any.address(), cloned.address());
272 assert_eq!(any.type_id(), cloned.type_id());
273 }
274}