Skip to main content

reifydb_value/value/container/
blob.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{
5	fmt::{self, Debug},
6	result::Result as StdResult,
7};
8
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10
11use crate::{
12	Result,
13	util::bitvec::BitVec,
14	value::{Value, blob::Blob, container::varlen::VarlenContainer, value_type::ValueType},
15};
16
17pub struct BlobContainer {
18	inner: VarlenContainer,
19}
20
21impl Clone for BlobContainer {
22	fn clone(&self) -> Self {
23		Self {
24			inner: self.inner.clone(),
25		}
26	}
27}
28
29impl Debug for BlobContainer
30where
31	VarlenContainer: Debug,
32{
33	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34		f.debug_struct("BlobContainer").field("inner", &self.inner).finish()
35	}
36}
37
38impl PartialEq for BlobContainer
39where
40	VarlenContainer: PartialEq,
41{
42	fn eq(&self, other: &Self) -> bool {
43		self.inner == other.inner
44	}
45}
46
47impl Serialize for BlobContainer {
48	fn serialize<Ser: Serializer>(&self, serializer: Ser) -> StdResult<Ser::Ok, Ser::Error> {
49		self.inner.serialize(serializer)
50	}
51}
52
53impl<'de> Deserialize<'de> for BlobContainer {
54	fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
55		let inner = VarlenContainer::deserialize(deserializer)?;
56		Ok(Self {
57			inner,
58		})
59	}
60}
61
62impl BlobContainer {
63	pub fn new(data: Vec<Blob>) -> Self {
64		Self::from_vec(data)
65	}
66
67	pub fn from_vec(data: Vec<Blob>) -> Self {
68		let inner = VarlenContainer::from_byte_slices(data.iter().map(|b| b.as_bytes()));
69		Self {
70			inner,
71		}
72	}
73
74	pub fn with_capacity(capacity: usize) -> Self {
75		Self {
76			inner: VarlenContainer::with_capacity(capacity, capacity * 32),
77		}
78	}
79
80	pub fn from_bytes_offsets(data: Vec<u8>, offsets: Vec<u64>) -> Self {
81		Self {
82			inner: VarlenContainer::from_raw_parts(data, offsets),
83		}
84	}
85}
86
87impl BlobContainer {
88	pub fn from_inner(inner: VarlenContainer) -> Self {
89		Self {
90			inner,
91		}
92	}
93
94	pub fn from_storage_parts(data: Vec<u8>, offsets: Vec<u64>) -> Self {
95		Self {
96			inner: VarlenContainer::from_storage_parts(data, offsets),
97		}
98	}
99
100	pub fn data_storage(&self) -> &Vec<u8> {
101		self.inner.data()
102	}
103
104	pub fn offsets_storage(&self) -> &Vec<u64> {
105		self.inner.offsets_data()
106	}
107
108	pub fn len(&self) -> usize {
109		self.inner.len()
110	}
111
112	pub fn capacity(&self) -> usize {
113		self.inner.capacity()
114	}
115
116	pub fn heap_size(&self) -> usize {
117		self.inner.heap_size()
118	}
119
120	pub fn is_empty(&self) -> bool {
121		self.inner.is_empty()
122	}
123
124	pub fn clear(&mut self) {
125		self.inner.clear_generic();
126	}
127
128	pub fn get(&self, index: usize) -> Option<&[u8]> {
129		self.inner.get_bytes(index)
130	}
131
132	pub fn is_defined(&self, idx: usize) -> bool {
133		idx < self.len()
134	}
135
136	pub fn data_bytes(&self) -> &[u8] {
137		self.inner.data_bytes()
138	}
139
140	pub fn offsets(&self) -> &[u64] {
141		self.inner.offsets()
142	}
143
144	pub fn inner(&self) -> &VarlenContainer {
145		&self.inner
146	}
147
148	pub fn as_string(&self, index: usize) -> String {
149		match self.get(index) {
150			Some(bytes) => Blob::new(bytes.to_vec()).to_string(),
151			None => "none".to_string(),
152		}
153	}
154
155	pub fn get_value(&self, index: usize) -> Value {
156		match self.get(index) {
157			Some(bytes) => Value::Blob(Blob::new(bytes.to_vec())),
158			None => Value::none_of(ValueType::Blob),
159		}
160	}
161
162	pub fn iter(&self) -> impl Iterator<Item = Option<&[u8]>> + '_ {
163		(0..self.len()).map(|i| self.get(i))
164	}
165
166	pub fn iter_bytes(&self) -> impl Iterator<Item = &[u8]> + '_ {
167		(0..self.len()).map(|i| self.get(i).unwrap_or(&[]))
168	}
169}
170
171impl BlobContainer {
172	pub fn push(&mut self, value: Blob) {
173		self.inner.push_bytes(value.as_bytes());
174	}
175
176	pub fn push_bytes(&mut self, value: &[u8]) {
177		self.inner.push_bytes(value);
178	}
179
180	pub fn push_default(&mut self) {
181		self.inner.push_bytes(&[]);
182	}
183
184	pub fn extend(&mut self, other: &Self) -> Result<()> {
185		self.inner.extend_from(&other.inner);
186		Ok(())
187	}
188
189	pub fn slice(&self, start: usize, end: usize) -> Self {
190		Self {
191			inner: self.inner.slice(start, end),
192		}
193	}
194
195	pub fn filter(&mut self, mask: &BitVec) {
196		let bits: Vec<bool> = mask.iter().collect();
197		self.inner.filter_in_place(|i| bits.get(i).copied().unwrap_or(false));
198	}
199
200	pub fn reorder(&mut self, indices: &[usize]) {
201		self.inner.reorder_in_place(indices);
202	}
203
204	pub fn take(&self, num: usize) -> Self {
205		Self {
206			inner: self.inner.take_n(num),
207		}
208	}
209}
210
211impl Default for BlobContainer {
212	fn default() -> Self {
213		Self::with_capacity(0)
214	}
215}
216
217#[cfg(test)]
218pub mod tests {
219	use postcard::to_allocvec as postcard_to_allocvec;
220
221	use super::*;
222
223	#[test]
224	fn test_new() {
225		let blob1 = Blob::new(vec![1, 2, 3]);
226		let blob2 = Blob::new(vec![4, 5, 6]);
227		let blobs = vec![blob1.clone(), blob2.clone()];
228		let container = BlobContainer::new(blobs);
229
230		assert_eq!(container.len(), 2);
231		assert_eq!(container.get(0), Some(blob1.as_bytes()));
232		assert_eq!(container.get(1), Some(blob2.as_bytes()));
233	}
234
235	#[test]
236	fn test_from_vec() {
237		let blob1 = Blob::new(vec![10, 20, 30]);
238		let blob2 = Blob::new(vec![40, 50]);
239		let blobs = vec![blob1.clone(), blob2.clone()];
240		let container = BlobContainer::from_vec(blobs);
241
242		assert_eq!(container.len(), 2);
243		assert_eq!(container.get(0), Some(blob1.as_bytes()));
244		assert_eq!(container.get(1), Some(blob2.as_bytes()));
245
246		for i in 0..2 {
247			assert!(container.is_defined(i));
248		}
249	}
250
251	#[test]
252	fn test_with_capacity() {
253		let container = BlobContainer::with_capacity(10);
254		assert_eq!(container.len(), 0);
255		assert!(container.is_empty());
256		assert!(container.capacity() >= 10);
257	}
258
259	#[test]
260	fn test_push_with_default() {
261		let mut container = BlobContainer::with_capacity(3);
262		let blob1 = Blob::new(vec![1, 2, 3]);
263		let blob2 = Blob::new(vec![7, 8, 9]);
264
265		container.push(blob1.clone());
266		container.push_default();
267		container.push(blob2.clone());
268
269		assert_eq!(container.len(), 3);
270		assert_eq!(container.get(0), Some(blob1.as_bytes()));
271		assert_eq!(container.get(1), Some(b"".as_slice()));
272		assert_eq!(container.get(2), Some(blob2.as_bytes()));
273
274		assert!(container.is_defined(0));
275		assert!(container.is_defined(1));
276		assert!(container.is_defined(2));
277	}
278
279	#[test]
280	fn testault() {
281		let container = BlobContainer::default();
282		assert_eq!(container.len(), 0);
283		assert!(container.is_empty());
284	}
285
286	#[test]
287	fn test_data_bytes_and_offsets_match_zero_copy_layout() {
288		let container = BlobContainer::from_vec(vec![Blob::new(vec![0xAA, 0xBB]), Blob::new(vec![0xCC])]);
289		assert_eq!(container.data_bytes(), &[0xAAu8, 0xBB, 0xCC]);
290		assert_eq!(container.offsets(), &[0u64, 2, 3]);
291	}
292
293	#[test]
294	fn test_postcard_wire_compat() {
295		// The inner VarlenContainer is byte-compatible with `Vec<Vec<u8>>`
296		// via postcard. `Blob` derefs to `Vec<u8>`, so a `Vec<Blob>` is
297		// also byte-compatible.
298		let blobs = vec![Blob::new(vec![1, 2, 3]), Blob::new(vec![4, 5])];
299		let blobs_bytes: Vec<u8> = postcard_to_allocvec(&blobs).unwrap();
300
301		let container = BlobContainer::from_vec(blobs.clone());
302		let container_bytes: Vec<u8> = postcard_to_allocvec(&container).unwrap();
303
304		assert_eq!(blobs_bytes, container_bytes);
305	}
306}