1use reifydb_value::{
5 reifydb_assertions,
6 value::{blob::Blob, value_type::ValueType},
7};
8
9use crate::encoded::{row::EncodedRow, shape::RowShape};
10
11impl RowShape {
12 pub fn set_blob(&self, row: &mut EncodedRow, index: usize, value: &Blob) {
13 reifydb_assertions! {
14 assert!(
15 row.len() >= self.total_static_size(),
16 "row/shape size mismatch: row.len()={} < total_static_size()={}",
17 row.len(),
18 self.total_static_size()
19 );
20 assert_eq!(*self.fields()[index].constraint.get_type().inner_type(), ValueType::Blob);
21 }
22 self.replace_dynamic_data(row, index, value.as_bytes());
23 }
24
25 pub fn get_blob(&self, row: &EncodedRow, index: usize) -> Blob {
26 let field = &self.fields()[index];
27 reifydb_assertions! {
28 assert!(
29 row.len() >= self.total_static_size(),
30 "row/shape size mismatch: row.len()={} < total_static_size()={}",
31 row.len(),
32 self.total_static_size()
33 );
34 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Blob);
35 }
36
37 let ref_slice = &row.as_slice()[field.offset as usize..field.offset as usize + 8];
38 let offset = u32::from_le_bytes([ref_slice[0], ref_slice[1], ref_slice[2], ref_slice[3]]) as usize;
39 let length = u32::from_le_bytes([ref_slice[4], ref_slice[5], ref_slice[6], ref_slice[7]]) as usize;
40
41 let dynamic_start = self.dynamic_section_start();
42 let blob_start = dynamic_start + offset;
43 let blob_slice = &row.as_slice()[blob_start..blob_start + length];
44
45 Blob::from_slice(blob_slice)
46 }
47
48 pub fn try_get_blob(&self, row: &EncodedRow, index: usize) -> Option<Blob> {
49 if row.is_defined(index) && self.fields()[index].constraint.get_type() == ValueType::Blob {
50 Some(self.get_blob(row, index))
51 } else {
52 None
53 }
54 }
55}
56
57#[cfg(test)]
58pub mod tests {
59 use reifydb_value::value::{blob::Blob, value_type::ValueType};
60
61 use crate::encoded::shape::RowShape;
62
63 #[test]
64 fn test_set_get_blob() {
65 let shape = RowShape::testing(&[ValueType::Blob]);
66 let mut row = shape.allocate();
67
68 let blob = Blob::from_slice(&[1, 2, 3, 4, 5]);
69 shape.set_blob(&mut row, 0, &blob);
70 assert_eq!(shape.get_blob(&row, 0), blob);
71 }
72
73 #[test]
74 fn test_try_get_blob() {
75 let shape = RowShape::testing(&[ValueType::Blob]);
76 let mut row = shape.allocate();
77
78 assert_eq!(shape.try_get_blob(&row, 0), None);
79
80 let blob = Blob::from_slice(&[1, 2, 3, 4, 5]);
81 shape.set_blob(&mut row, 0, &blob);
82 assert_eq!(shape.try_get_blob(&row, 0), Some(blob));
83 }
84
85 #[test]
86 fn test_empty() {
87 let shape = RowShape::testing(&[ValueType::Blob]);
88 let mut row = shape.allocate();
89
90 let empty_blob = Blob::from_slice(&[]);
91 shape.set_blob(&mut row, 0, &empty_blob);
92 assert_eq!(shape.get_blob(&row, 0), empty_blob);
93 assert_eq!(shape.try_get_blob(&row, 0), Some(empty_blob));
94 }
95
96 #[test]
97 fn test_binary_data() {
98 let shape = RowShape::testing(&[ValueType::Blob]);
99 let mut row = shape.allocate();
100
101 let binary_data = vec![
103 0x00, 0xFF, 0xAA, 0x55, 0xCC, 0x33, 0x00, 0xFF, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
104 ];
105 let blob = Blob::from_slice(&binary_data);
106 shape.set_blob(&mut row, 0, &blob);
107 assert_eq!(shape.get_blob(&row, 0), blob);
108 }
109
110 #[test]
111 fn test_large_data() {
112 let shape = RowShape::testing(&[ValueType::Blob]);
113 let mut row = shape.allocate();
114
115 let large_data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
117 let large_blob = Blob::from_slice(&large_data);
118 shape.set_blob(&mut row, 0, &large_blob);
119 assert_eq!(shape.get_blob(&row, 0), large_blob);
120 }
121
122 #[test]
123 fn test_multiple_fields() {
124 let shape = RowShape::testing(&[ValueType::Blob, ValueType::Blob, ValueType::Blob]);
125 let mut row = shape.allocate();
126
127 let blob1 = Blob::from_slice(&[1, 2, 3]);
128 let blob2 = Blob::from_slice(&[4, 5, 6, 7, 8]);
129 let blob3 = Blob::from_slice(&[9]);
130
131 shape.set_blob(&mut row, 0, &blob1);
132 shape.set_blob(&mut row, 1, &blob2);
133 shape.set_blob(&mut row, 2, &blob3);
134
135 assert_eq!(shape.get_blob(&row, 0), blob1);
136 assert_eq!(shape.get_blob(&row, 1), blob2);
137 assert_eq!(shape.get_blob(&row, 2), blob3);
138 }
139
140 #[test]
141 fn test_mixed_with_static_fields() {
142 let shape = RowShape::testing(&[ValueType::Boolean, ValueType::Blob, ValueType::Int4, ValueType::Blob]);
143 let mut row = shape.allocate();
144
145 let blob1 = Blob::from_slice(&[0xFF, 0x00, 0xAA]);
146 let blob2 = Blob::from_slice(&[0x11, 0x22, 0x33, 0x44]);
147
148 shape.set_bool(&mut row, 0, true);
149 shape.set_blob(&mut row, 1, &blob1);
150 shape.set_i32(&mut row, 2, -12345);
151 shape.set_blob(&mut row, 3, &blob2);
152
153 assert_eq!(shape.get_bool(&row, 0), true);
154 assert_eq!(shape.get_blob(&row, 1), blob1);
155 assert_eq!(shape.get_i32(&row, 2), -12345);
156 assert_eq!(shape.get_blob(&row, 3), blob2);
157 }
158
159 #[test]
160 fn test_different_sizes() {
161 let shape = RowShape::testing(&[ValueType::Blob, ValueType::Blob, ValueType::Blob]);
162 let mut row = shape.allocate();
163
164 let empty_blob = Blob::from_slice(&[]);
165 let medium_blob = Blob::from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
166 let single_byte_blob = Blob::from_slice(&[42]);
167
168 shape.set_blob(&mut row, 0, &empty_blob);
169 shape.set_blob(&mut row, 1, &medium_blob);
170 shape.set_blob(&mut row, 2, &single_byte_blob);
171
172 assert_eq!(shape.get_blob(&row, 0), empty_blob);
173 assert_eq!(shape.get_blob(&row, 1), medium_blob);
174 assert_eq!(shape.get_blob(&row, 2), single_byte_blob);
175 }
176
177 #[test]
178 fn test_arbitrary_setting_order() {
179 let shape = RowShape::testing(&[ValueType::Blob, ValueType::Blob, ValueType::Blob, ValueType::Blob]);
180 let mut row = shape.allocate();
181
182 let blob0 = Blob::from_slice(&[10, 20]);
183 let blob1 = Blob::from_slice(&[30, 40, 50]);
184 let blob2 = Blob::from_slice(&[60]);
185 let blob3 = Blob::from_slice(&[70, 80, 90, 100]);
186
187 shape.set_blob(&mut row, 3, &blob3);
189 shape.set_blob(&mut row, 1, &blob1);
190 shape.set_blob(&mut row, 0, &blob0);
191 shape.set_blob(&mut row, 2, &blob2);
192
193 assert_eq!(shape.get_blob(&row, 0), blob0);
194 assert_eq!(shape.get_blob(&row, 1), blob1);
195 assert_eq!(shape.get_blob(&row, 2), blob2);
196 assert_eq!(shape.get_blob(&row, 3), blob3);
197 }
198
199 #[test]
200 fn test_undefined_handling() {
201 let shape = RowShape::testing(&[ValueType::Blob, ValueType::Blob, ValueType::Blob]);
202 let mut row = shape.allocate();
203
204 let blob = Blob::from_slice(&[1, 2, 3, 4]);
205
206 shape.set_blob(&mut row, 0, &blob);
208 shape.set_blob(&mut row, 2, &blob);
209
210 assert_eq!(shape.try_get_blob(&row, 0), Some(blob.clone()));
211 assert_eq!(shape.try_get_blob(&row, 1), None);
212 assert_eq!(shape.try_get_blob(&row, 2), Some(blob.clone()));
213
214 shape.set_none(&mut row, 0);
216 assert_eq!(shape.try_get_blob(&row, 0), None);
217 assert_eq!(shape.try_get_blob(&row, 2), Some(blob));
218 }
219
220 #[test]
221 fn test_all_byte_values() {
222 let shape = RowShape::testing(&[ValueType::Blob]);
223 let mut row = shape.allocate();
224
225 let all_bytes: Vec<u8> = (0..=255).collect();
227 let full_range_blob = Blob::from_slice(&all_bytes);
228 shape.set_blob(&mut row, 0, &full_range_blob);
229 assert_eq!(shape.get_blob(&row, 0), full_range_blob);
230 }
231
232 #[test]
233 fn test_try_get_blob_wrong_type() {
234 let shape = RowShape::testing(&[ValueType::Boolean]);
235 let mut row = shape.allocate();
236
237 shape.set_bool(&mut row, 0, true);
238
239 assert_eq!(shape.try_get_blob(&row, 0), None);
240 }
241
242 #[test]
243 fn test_update_blob() {
244 let shape = RowShape::testing(&[ValueType::Blob]);
245 let mut row = shape.allocate();
246
247 let blob1 = Blob::from_slice(&[1, 2, 3]);
248 shape.set_blob(&mut row, 0, &blob1);
249 assert_eq!(shape.get_blob(&row, 0), blob1);
250
251 let blob2 = Blob::from_slice(&[4, 5, 6, 7, 8]);
253 shape.set_blob(&mut row, 0, &blob2);
254 assert_eq!(shape.get_blob(&row, 0), blob2);
255
256 let blob3 = Blob::from_slice(&[9]);
258 shape.set_blob(&mut row, 0, &blob3);
259 assert_eq!(shape.get_blob(&row, 0), blob3);
260 assert_eq!(row.len(), shape.total_static_size() + 1);
261
262 let empty = Blob::from_slice(&[]);
264 shape.set_blob(&mut row, 0, &empty);
265 assert_eq!(shape.get_blob(&row, 0), empty);
266 assert_eq!(row.len(), shape.total_static_size());
267 }
268
269 #[test]
270 fn test_update_blob_with_other_dynamic_fields() {
271 let shape = RowShape::testing(&[ValueType::Blob, ValueType::Utf8, ValueType::Blob]);
272 let mut row = shape.allocate();
273
274 shape.set_blob(&mut row, 0, &Blob::from_slice(&[1, 2, 3]));
275 shape.set_utf8(&mut row, 1, "hello");
276 shape.set_blob(&mut row, 2, &Blob::from_slice(&[4, 5]));
277
278 shape.set_blob(&mut row, 0, &Blob::from_slice(&[10, 20, 30, 40, 50]));
280
281 assert_eq!(shape.get_blob(&row, 0), Blob::from_slice(&[10, 20, 30, 40, 50]));
282 assert_eq!(shape.get_utf8(&row, 1), "hello");
283 assert_eq!(shape.get_blob(&row, 2), Blob::from_slice(&[4, 5]));
284 }
285}