1use libz_ng_sys::*;
9use crate::PathMap;
10use crate::TrieValue;
11use crate::alloc::Allocator;
12use crate::zipper::{
13 ZipperReadOnlyConditionalIteration,
14 ZipperWriting,
15 ZipperIteration,
16 ZipperValues,
17};
18
19#[cfg(feature="nightly")]
20#[path="paths_serialization_nightly.rs"]
21mod paths_serialization_nightly;
22#[cfg(feature="nightly")]
23pub use paths_serialization_nightly::*;
24
25#[derive(Debug, Clone, Copy)]
27pub struct SerializationStats {
28 pub bytes_out : usize,
30 pub bytes_in : usize,
32 pub path_count : usize
34}
35
36#[derive(Debug, Clone, Copy)]
38pub struct DeserializationStats {
39 pub bytes_in : usize,
41 pub bytes_out : usize,
43 pub path_count : usize
45}
46
47pub fn serialize_paths<'a, V, W, RZ>(rz: RZ, target: &mut W) -> std::io::Result<SerializationStats>
49 where
50 V: TrieValue,
51 RZ: ZipperReadOnlyConditionalIteration<'a, V>,
52 W: std::io::Write
53{
54 serialize_paths_with_auxdata(rz, target, |_, _, _| {})
55}
56
57pub fn serialize_paths_with_auxdata<'a, V : TrieValue, RZ : ZipperValues<V> + ZipperIteration, W: std::io::Write, F: FnMut(usize, &[u8], &V) -> ()>(mut rz: RZ, target: &mut W, mut fv: F) -> std::io::Result<SerializationStats> {
62 let mut k = 0;
63 serialize_paths_from_funcs(target, &mut rz, |rz| Ok(rz.to_next_val()), |rz| {
81 let path = rz.path();
82 fv(k, path, rz.val().unwrap());
83 k += 1;
84 Some(path)
85 })
86}
87
88pub fn serialize_paths_from_funcs<PathSrc, AdvanceF, PathF, W>(target: &mut W, src: &mut PathSrc, mut advance_f: AdvanceF, mut path_f: PathF) -> std::io::Result<SerializationStats>
101where
102 AdvanceF: FnMut(&mut PathSrc) -> std::io::Result<bool>,
103 PathF: FnMut(&PathSrc) -> Option<&[u8]>,
104 W: std::io::Write,
105{
106 const CHUNK: usize = 4096; let mut buffer = [0u8; CHUNK];
108
109 #[allow(invalid_value)] let mut strm: z_stream = unsafe { std::mem::MaybeUninit::zeroed().assume_init() };
113 let mut ret = unsafe { zng_deflateInit(&mut strm, 7) };
114 assert_eq!(ret, Z_OK);
115
116 let mut total_paths : usize = 0;
117 while advance_f(src)? {
118 let p = match path_f(src) {
119 Some(p) => p,
120 None => continue,
121 };
122
123 let l = p.len();
125 let mut lin = (l as u32).to_le_bytes();
127 strm.avail_in = 4;
128 strm.next_in = lin.as_mut_ptr();
129
130 loop {
132 strm.avail_out = CHUNK as _;
133 strm.next_out = buffer.as_mut_ptr();
134 ret = unsafe { deflate(&mut strm, Z_NO_FLUSH) };
135 assert_ne!(ret, Z_STREAM_ERROR);
136 let have = CHUNK - strm.avail_out as usize;
137 target.write_all(&mut buffer[..have])?;
138 if strm.avail_out != 0 { break }
139 }
140 assert_eq!(strm.avail_in, 0);
141
142 strm.avail_in = l as _;
143 strm.next_in = p.as_ptr().cast_mut();
144 loop {
145 strm.avail_out = CHUNK as _;
146 strm.next_out = buffer.as_mut_ptr();
147 ret = unsafe { deflate(&mut strm, Z_NO_FLUSH) };
148 assert_ne!(ret, Z_STREAM_ERROR);
149 let have = CHUNK - strm.avail_out as usize;
150 target.write_all(&mut buffer[..have])?;
151 if strm.avail_out != 0 { break }
152 }
153 assert_eq!(strm.avail_in, 0);
154
155
156 total_paths += 1;
157 }
158 loop {
159 strm.avail_out = CHUNK as _;
160 strm.next_out = buffer.as_mut_ptr();
161 ret = unsafe { deflate(&mut strm, Z_FINISH) };
162 let have = CHUNK - strm.avail_out as usize;
163 target.write_all(&buffer[..have])?;
164 if ret == Z_STREAM_END { break; }
165 assert_eq!(ret, Z_OK);
166 }
167 ret = unsafe { deflateEnd(&mut strm) };
168 assert_eq!(ret, Z_OK);
169
170 Ok(SerializationStats {
171 bytes_out : strm.total_out,
172 bytes_in : strm.total_in,
173 path_count : total_paths
174 })
175}
176
177pub fn deserialize_paths<V: TrieValue, A: Allocator, WZ : ZipperWriting<V, A>, R: std::io::Read>(wz: WZ, source: R, v: V) -> std::io::Result<DeserializationStats> {
180 deserialize_paths_with_auxdata(wz, source, |_, _| v.clone())
181}
182
183pub fn deserialize_paths_with_auxdata<V: TrieValue, A: Allocator, WZ : ZipperWriting<V, A>, R: std::io::Read, F: Fn(usize, &[u8]) -> V>(mut wz: WZ, source: R, fv: F) -> std::io::Result<DeserializationStats> {
189 let mut submap = PathMap::new_in(wz.alloc());
190 let r = for_each_deserialized_path(source, |k, p| {
191 let v = fv(k, p);
192 submap.set_val_at(p, v);
193 Ok(())
194 });
195 wz.graft_map(submap);
196 r
197}
198
199pub fn for_each_deserialized_path<R: std::io::Read, F: FnMut(usize, &[u8]) -> std::io::Result<()>>(mut source: R, mut f: F) -> std::io::Result<DeserializationStats> {
201 use libz_ng_sys::*;
202 const IN: usize = 1024;
203 const OUT: usize = 2048;
204 let mut ibuffer = [0u8; IN];
205 let mut obuffer = [0u8; OUT];
206 let mut l = 0u32;
207 let mut lbuf = [0u8; 4];
208 let mut lbuf_offset = 0;
209 let mut finished_path = true;
210 let mut total_paths : usize = 0usize;
211 #[allow(invalid_value)] let mut strm: z_stream = unsafe { std::mem::MaybeUninit::zeroed().assume_init() };
213 let mut ret = unsafe { zng_inflateInit(&mut strm) };
214 if ret != Z_OK { return Err(std::io::Error::new(std::io::ErrorKind::Other, "failed to init zlib-ng inflate")) }
215 let mut wz_buf = vec![];
216 'reading: loop {
218 strm.avail_in = source.read(&mut ibuffer)? as _;
219 if strm.avail_in == 0 { break; }
220 strm.next_in = &mut ibuffer as _;
221
222 'decompressing: loop {
223 strm.avail_out = OUT as _;
224 strm.next_out = obuffer.as_mut_ptr();
225 let mut pos = 0usize;
226
227 ret = unsafe { inflate(&mut strm, Z_NO_FLUSH) };
228 if ret == Z_STREAM_ERROR { return Err(std::io::Error::new(std::io::ErrorKind::Other, "Z_STREAM_ERROR")) }
229 if strm.avail_out as usize == OUT {
230 if ret == Z_STREAM_END { break 'reading }
231 else { continue 'reading }
232 }
233 let end = OUT - strm.avail_out as usize;
234
235 'descending: loop {
236 if finished_path {
237 let have = (end - pos).min(4-lbuf_offset);
238 lbuf[lbuf_offset..lbuf_offset+have].copy_from_slice(&obuffer[pos..pos+have]);
239 pos += have;
240 lbuf_offset += have;
241 if lbuf_offset == 4 {
242 l = u32::from_le_bytes(lbuf);
243 lbuf_offset = 0;
244 } else {
245 if strm.avail_in == 0 { continue 'reading }
246 else { continue 'decompressing }
247 }
248 }
249
250 if pos + l as usize <= end {
251 wz_buf.extend(&obuffer[pos..pos + l as usize]);
252 f(total_paths, &wz_buf[..])?;
253 wz_buf.clear();
254 total_paths += 1;
255 pos += l as usize;
256 finished_path = true;
257 if pos == end { continue 'decompressing }
258 else { continue 'descending }
259 } else {
260 wz_buf.extend(&obuffer[pos..end]);
261 finished_path = false;
262 l -= (end-pos) as u32;
263 if strm.avail_in == 0 { continue 'reading }
264 else { continue 'decompressing }
265 }
266 }
267 }
268 }
269
270 unsafe { inflateEnd(&mut strm) };
271
272 Ok(DeserializationStats {
273 bytes_in : strm.total_in,
274 bytes_out : strm.total_out,
275 path_count : total_paths
276 })
277}
278
279#[cfg(test)]
280mod test {
281 use crate::zipper::{ZipperIteration, ZipperValues, ZipperMoving};
282 use super::*;
283
284 #[cfg(not(miri))] #[test]
286 fn path_serialize_deserialize() {
287 let mut btm = PathMap::new();
288 let rs = ["arrow", "bow", "cannon", "roman", "romane", "romanus", "romulus", "rubens", "ruber", "rubicon", "rubicundus", "rom'i"];
289 rs.iter().for_each(|r| { btm.set_val_at(r.as_bytes(), ()); });
290 let mut v = vec![];
291 match serialize_paths(btm.read_zipper(), &mut v) {
292 Ok(SerializationStats { bytes_out : c, bytes_in : bw, path_count : pw}) => {
293 println!("ser {} {} {}", c, bw, pw);
294 println!("vlen {}", v.len());
295
296 let mut restored_btm = PathMap::new();
297 match deserialize_paths(restored_btm.write_zipper(), v.as_slice(), ()) {
298 Ok(DeserializationStats { bytes_in : c, bytes_out : bw, path_count : pw}) => {
299 println!("de {} {} {}", c, bw, pw);
300
301 let mut lrz = restored_btm.read_zipper();
302 while lrz.to_next_val() {
303 assert!(btm.contains(lrz.path()), "{}", std::str::from_utf8(lrz.path()).unwrap());
304 }
305
306 let mut rrz = btm.read_zipper();
307 while rrz.to_next_val() {
308 assert!(restored_btm.contains(rrz.path()));
309 }
310 }
311 Err(e) => { println!("de e {}", e) }
312 }
313 }
314 Err(e) => { println!("ser e {}", e) }
315 }
316 }
317
318 #[cfg(not(miri))] #[test]
320 fn path_serialize_deserialize_blow_out_buffer() {
321 for zeros in 0..10 {
322 println!("{zeros} zeros");
323 let mut btm = PathMap::new();
324 let mut rs = vec![];
325 for i in 0..400 {
326 rs.push(format!("{}{}{}{}", "0".repeat(zeros), i/100, (i/10)%10, i%10))
327 }
328 rs.iter().for_each(|r| { btm.set_val_at(r.as_bytes(), ()); });
329
330 let mut v = vec![];
331 match serialize_paths(btm.read_zipper(), &mut v) {
332 Ok(SerializationStats { bytes_out : c, bytes_in : bw, path_count : pw}) => {
333 println!("ser {} {} {}", c, bw, pw);
334 println!("vlen {}", v.len());
335
336 let mut restored_btm = PathMap::new();
337 match deserialize_paths(restored_btm.write_zipper(), v.as_slice(), ()) {
338 Ok(DeserializationStats { bytes_in : c, bytes_out : bw, path_count : pw}) => {
339 println!("de {} {} {}", c, bw, pw);
340
341 let mut lrz = restored_btm.read_zipper();
342 while lrz.to_next_val() {
343 assert!(btm.contains(lrz.path()), "{}", std::str::from_utf8(lrz.path()).unwrap());
344 }
345
346 let mut rrz = btm.read_zipper();
347 while rrz.to_next_val() {
348 assert!(restored_btm.contains(rrz.path()));
349 }
350 }
351 Err(e) => { println!("de e {}", e) }
352 }
353 }
354 Err(e) => { println!("ser e {}", e) }
355 }
356 }
357 }
358
359 #[cfg(not(miri))] #[test]
361 fn path_serialize_deserialize_values() {
362 let mut btm = PathMap::new();
363 let rs = ["arrow", "bow", "cannon", "roman", "romane", "romanus", "romulus", "rubens", "ruber", "rubicon", "rubicundus", "rom'i"];
364 rs.iter().enumerate().for_each(|(i, r)| { btm.set_val_at(r.as_bytes(), i); });
365 let mut values = vec![];
366 let mut v = vec![];
367 match serialize_paths_with_auxdata(btm.read_zipper(), &mut v,
368 |c, _p, value| { assert_eq!(values.len(), c); values.push(*value) }) {
369 Ok(SerializationStats { bytes_out : c, bytes_in : bw, path_count : pw}) => {
370 println!("ser {} {} {}", c, bw, pw);
371 println!("vlen {}", v.len());
372
373 let mut restored_btm = PathMap::new();
374 match deserialize_paths_with_auxdata(restored_btm.write_zipper(), v.as_slice(), |c, _p| values[c]) {
375 Ok(DeserializationStats { bytes_in : c, bytes_out : bw, path_count : pw}) => {
376 println!("de {} {} {}", c, bw, pw);
377
378 let mut lrz = restored_btm.read_zipper();
379 while lrz.to_next_val() {
380 assert_eq!(btm.get_val_at(lrz.path()), Some(lrz.val().unwrap()));
381 }
382
383 let mut rrz = btm.read_zipper();
384 while rrz.to_next_val() {
385 assert_eq!(restored_btm.get_val_at(rrz.path()), Some(rrz.val().unwrap()));
386 }
387 }
388 Err(e) => { println!("de e {}", e) }
389 }
390 }
391 Err(e) => { println!("ser e {}", e) }
392 }
393 }
394
395 #[cfg(not(miri))] #[test]
397 fn path_serialize_deserialize_long_paths_cross_chunk_boundary() {
398 let mut state = 0x9e3779b97f4a7c15_u64;
404 let mut next = move || { state ^= state << 13; state ^= state >> 7; state ^= state << 17; state };
405 #[cfg(feature = "all_dense_nodes")]
406 let lengths = [7usize, 2049, 2049];
407 #[cfg(not(feature = "all_dense_nodes"))]
408 let lengths = [7usize, 2049, 4097, 24000];
409 let mut btm = PathMap::new();
410 let mut paths = vec![];
411 for &len in &lengths {
412 let path: Vec<u8> = (0..len).map(|_| (next() >> 33) as u8).collect();
413 btm.set_val_at(&path[..], ());
414 paths.push(path);
415 }
416
417 let mut v = vec![];
418 let ser = serialize_paths(btm.read_zipper(), &mut v).unwrap();
419 assert_eq!(ser.path_count, lengths.len());
420 assert!(ser.bytes_in > 4096, "the input must span the compression chunk size");
421
422 let mut restored = PathMap::new();
423 let de = deserialize_paths(restored.write_zipper(), v.as_slice(), ()).unwrap();
424 assert_eq!(de.path_count, lengths.len());
425
426 for path in &paths {
427 assert!(restored.contains(&path[..]), "path of len {} lost in round-trip", path.len());
428 }
429 let mut rz = restored.read_zipper();
430 let mut restored_count = 0;
431 while rz.to_next_val() { restored_count += 1; }
432 assert_eq!(restored_count, lengths.len(), "no extra paths may appear");
433 }
434
435 #[cfg(all(not(miri), not(feature = "all_dense_nodes")))]
436 #[test]
437 fn path_serialize_deserialize_very_long_paths_cross_multiple_chunks() {
438 let mut state = 0x9e3779b97f4a7c15_u64;
442 let mut next = move || { state ^= state << 13; state ^= state >> 7; state ^= state << 17; state };
443 let lengths = [7usize, 2049, 4097, 24000];
444 let mut btm = PathMap::new();
445 let mut paths = vec![];
446 for &len in &lengths {
447 let path: Vec<u8> = (0..len).map(|_| (next() >> 33) as u8).collect();
448 btm.set_val_at(&path[..], ());
449 paths.push(path);
450 }
451
452 let mut v = vec![];
453 let ser = serialize_paths(btm.read_zipper(), &mut v).unwrap();
454 assert_eq!(ser.path_count, lengths.len());
455 assert!(ser.bytes_in > 4096, "the input must span the compression chunk size");
456
457 let mut restored = PathMap::new();
458 let de = deserialize_paths(restored.write_zipper(), v.as_slice(), ()).unwrap();
459 assert_eq!(de.path_count, lengths.len());
460
461 for path in &paths {
462 assert!(restored.contains(&path[..]), "path of len {} lost in round-trip", path.len());
463 }
464 let mut rz = restored.read_zipper();
465 let mut restored_count = 0;
466 while rz.to_next_val() { restored_count += 1; }
467 assert_eq!(restored_count, lengths.len(), "no extra paths may appear");
468 }
469}