Skip to main content

protocache_core/
serialize.rs

1//! Serialization surface matching `serialize.h`.
2
3pub use crate::Buffer;
4
5use crate::Scalar;
6use crate::hash::hash128;
7
8#[derive(Clone, Copy, Debug, Default)]
9pub struct Segment {
10    pub pos: usize,
11    pub len: usize,
12}
13
14impl Segment {
15    #[inline(always)]
16    pub fn end(self) -> usize {
17        self.pos - self.len
18    }
19}
20
21#[derive(Clone, Copy, Debug, Default)]
22pub struct Unit {
23    inline_len: usize,
24    inline_data: [u32; 3],
25    segment: Segment,
26}
27
28impl Unit {
29    #[inline(always)]
30    pub fn empty() -> Self {
31        Self::default()
32    }
33
34    #[inline(always)]
35    pub fn inline(words: &[u32]) -> Self {
36        assert!(words.len() <= 3);
37        let mut data = [0u32; 3];
38        data[..words.len()].copy_from_slice(words);
39        Self {
40            inline_len: words.len(),
41            inline_data: data,
42            segment: Segment::default(),
43        }
44    }
45
46    #[inline(always)]
47    pub fn segment(last: usize, now: usize) -> Self {
48        Self {
49            inline_len: 0,
50            inline_data: [0; 3],
51            segment: Segment {
52                pos: now,
53                len: now - last,
54            },
55        }
56    }
57
58    #[inline(always)]
59    pub fn size(&self) -> usize {
60        if self.inline_len != 0 {
61            self.inline_len
62        } else {
63            self.segment.len
64        }
65    }
66
67    #[inline(always)]
68    pub fn is_empty(&self) -> bool {
69        self.size() == 0
70    }
71
72    #[inline(always)]
73    pub fn is_segment(&self) -> bool {
74        self.inline_len == 0 && self.segment.len != 0
75    }
76
77    #[inline(always)]
78    pub fn inline_words(&self) -> &[u32] {
79        &self.inline_data[..self.inline_len]
80    }
81
82    #[inline(always)]
83    pub fn segment_info(&self) -> Segment {
84        self.segment
85    }
86}
87
88#[inline(always)]
89fn write_varint(buf: &mut [u8; 5], mut n: u32) -> usize {
90    let mut written = 0usize;
91    while (n & !0x7f) != 0 {
92        buf[written] = 0x80 | (n as u8 & 0x7f);
93        written += 1;
94        n >>= 7;
95    }
96    buf[written] = n as u8;
97    written + 1
98}
99
100#[inline(always)]
101fn offset(off: usize) -> u32 {
102    ((off as u32) << 2) | 3
103}
104
105#[inline(always)]
106fn copy_inline(body: &mut [u32], body_index: &mut usize, pos: &mut usize, field: &Unit) {
107    let len = field.inline_len;
108    body[*body_index..*body_index + len].copy_from_slice(field.inline_words());
109    *body_index += len;
110    *pos -= len;
111}
112
113#[inline(always)]
114fn unit_words<'a>(unit: &'a Unit, buffer: &'a Buffer) -> Option<&'a [u32]> {
115    if unit.inline_len != 0 {
116        return Some(unit.inline_words());
117    }
118    if unit.segment.len == 0 {
119        return Some(&[]);
120    }
121    let start = buffer.len().checked_sub(unit.segment.pos)?;
122    buffer.view().get(start..start + unit.segment.len)
123}
124
125#[inline(always)]
126fn pick_unit(unit: &mut Unit, buffer: &mut Buffer, tail: &mut usize, width: usize) {
127    if unit.inline_len != 0 {
128        return;
129    }
130
131    let seg = unit.segment;
132    if seg.len <= width {
133        let start = buffer.len() - seg.pos;
134        let words = &buffer.head()[start..start + seg.len];
135        unit.inline_len = seg.len;
136        unit.inline_data[..seg.len].copy_from_slice(words);
137        return;
138    }
139
140    let start = buffer.len() - seg.pos;
141    let end = start + seg.len;
142    if *tail > end {
143        let new_start = *tail - seg.len;
144        buffer.head_mut().copy_within(start..end, new_start);
145        unit.segment.pos -= new_start - start;
146        *tail = new_start;
147    } else {
148        debug_assert!(*tail >= seg.len);
149        *tail -= seg.len;
150    }
151}
152
153#[inline(always)]
154fn mark_unit(unit: &Unit, buffer: &mut Buffer, width: usize) {
155    let expanded_len = buffer.len() + width;
156    let cell = buffer.expand(width);
157    if unit.inline_len != 0 {
158        cell[..unit.inline_len].copy_from_slice(unit.inline_words());
159        for word in &mut cell[unit.inline_len..] {
160            *word = 0;
161        }
162    } else {
163        cell[0] = offset(expanded_len - unit.segment.pos);
164        for word in &mut cell[1..] {
165            *word = 0;
166        }
167    }
168}
169
170#[inline(always)]
171fn best_array_size(elements: &[Unit]) -> (usize, usize) {
172    let mut sizes = [0usize; 3];
173    for element in elements {
174        sizes[0] += 1;
175        sizes[1] += 2;
176        sizes[2] += 3;
177        let len = element.size();
178        if len <= 1 {
179            continue;
180        }
181        sizes[0] += len;
182        if len <= 2 {
183            continue;
184        }
185        sizes[1] += len;
186        if len <= 3 {
187            continue;
188        }
189        sizes[2] += len;
190    }
191
192    let mut mode = 0usize;
193    for idx in 1..3 {
194        if sizes[idx] < sizes[mode] {
195            mode = idx;
196        }
197    }
198    (sizes[mode], mode + 1)
199}
200
201#[inline(always)]
202fn best_array_size_pairs(elements: &[(Unit, Unit)]) -> ((usize, usize), (usize, usize)) {
203    let mut key_sizes = [0usize; 3];
204    let mut value_sizes = [0usize; 3];
205    for (key, value) in elements {
206        for sizes in [&mut key_sizes, &mut value_sizes] {
207            sizes[0] += 1;
208            sizes[1] += 2;
209            sizes[2] += 3;
210        }
211
212        let key_len = key.size();
213        if key_len > 1 {
214            key_sizes[0] += key_len;
215            if key_len > 2 {
216                key_sizes[1] += key_len;
217                if key_len > 3 {
218                    key_sizes[2] += key_len;
219                }
220            }
221        }
222
223        let value_len = value.size();
224        if value_len > 1 {
225            value_sizes[0] += value_len;
226            if value_len > 2 {
227                value_sizes[1] += value_len;
228                if value_len > 3 {
229                    value_sizes[2] += value_len;
230                }
231            }
232        }
233    }
234
235    let mut key_mode = 0usize;
236    let mut value_mode = 0usize;
237    for idx in 1..3 {
238        if key_sizes[idx] < key_sizes[key_mode] {
239            key_mode = idx;
240        }
241        if value_sizes[idx] < value_sizes[value_mode] {
242            value_mode = idx;
243        }
244    }
245
246    (
247        (key_sizes[key_mode], key_mode + 1),
248        (value_sizes[value_mode], value_mode + 1),
249    )
250}
251
252#[inline(always)]
253fn perfect_hash_section(size: usize) -> usize {
254    ((size * 105).saturating_add(255) / 256).max(10)
255}
256
257#[inline(always)]
258fn perfect_hash_bitmap_size(section: usize) -> usize {
259    ((section * 3 + 31) & !31) / 4
260}
261
262#[inline(always)]
263fn set_bit2(vec: &mut [u8], pos: usize, val: u8) {
264    let shift = ((pos & 3) << 1) as u8;
265    let idx = pos >> 2;
266    vec[idx] &= !(3u8 << shift);
267    vec[idx] |= (val & 3) << shift;
268}
269
270#[inline(always)]
271fn get_bit2(vec: &[u8], pos: usize) -> u8 {
272    (vec[pos >> 2] >> ((pos & 3) << 1)) & 3
273}
274
275#[derive(Clone, Copy)]
276struct Edge {
277    slots: [usize; 3],
278}
279
280#[inline(always)]
281fn peel_graph(edges: &[Edge], slot_cnt: usize) -> Option<Vec<usize>> {
282    const NONE: usize = usize::MAX;
283
284    #[derive(Clone, Copy)]
285    struct Vertex {
286        slot: usize,
287        prev: usize,
288        next: usize,
289    }
290
291    let mut heads = vec![NONE; slot_cnt];
292    let mut vertices = vec![
293        Vertex {
294            slot: NONE,
295            prev: NONE,
296            next: NONE,
297        };
298        edges.len() * 3
299    ];
300
301    for (edge_idx, edge) in edges.iter().enumerate() {
302        for (slot_index, &slot) in edge.slots.iter().enumerate() {
303            let node = edge_idx * 3 + slot_index;
304            let head = heads[slot];
305            vertices[node] = Vertex {
306                slot,
307                prev: NONE,
308                next: head,
309            };
310            if head != NONE {
311                vertices[head].prev = node;
312            }
313            heads[slot] = node;
314        }
315    }
316
317    let mut queue = Vec::with_capacity(slot_cnt);
318    for (slot, &head) in heads.iter().enumerate() {
319        if head != NONE && vertices[head].next == NONE {
320            queue.push(slot);
321        }
322    }
323    let mut queue_head = 0usize;
324
325    let mut order = Vec::with_capacity(edges.len());
326
327    while let Some(&slot) = queue.get(queue_head) {
328        queue_head += 1;
329        let head = heads[slot];
330        if head == NONE || vertices[head].next != NONE {
331            continue;
332        }
333        let edge_idx = head / 3;
334        order.push(edge_idx);
335
336        for offset in 0..3 {
337            let node = edge_idx * 3 + offset;
338            let vertex = vertices[node];
339            if vertex.slot == NONE {
340                continue;
341            }
342
343            if vertex.prev != NONE {
344                vertices[vertex.prev].next = vertex.next;
345            } else {
346                heads[vertex.slot] = vertex.next;
347            }
348            if vertex.next != NONE {
349                vertices[vertex.next].prev = vertex.prev;
350            }
351
352            let head = heads[vertex.slot];
353            if head != NONE && vertices[head].next == NONE {
354                queue.push(vertex.slot);
355            }
356            vertices[node].slot = NONE;
357        }
358    }
359
360    if order.len() == edges.len() {
361        Some(order)
362    } else {
363        None
364    }
365}
366
367#[inline(always)]
368fn count_valid_slots(bitmap: &[u8], block: usize) -> usize {
369    let start = block * 8;
370    let bits = u64::from_le_bytes(
371        bitmap[start..start + 8]
372            .try_into()
373            .expect("bitmap block must fit"),
374    );
375    count_valid_slots_in_word(bits)
376}
377
378#[inline(always)]
379fn locate_in_perfect_hash(index: &[u8], key: &[u8]) -> Option<usize> {
380    let size = u32::from_le_bytes(index.get(..4)?.try_into().ok()?) as usize & 0x0fff_ffff;
381    if size < 2 {
382        return Some(0);
383    }
384    let section = perfect_hash_section(size);
385    let section_u32 = section as u32;
386    let section_magic = fast_mod_magic(section_u32);
387    let bitmap_size = perfect_hash_bitmap_size(section);
388    let bitmap = index.get(8..8 + bitmap_size)?;
389    let table = index.get(8 + bitmap_size..)?;
390    let seed = u32::from_le_bytes(index.get(4..8)?.try_into().ok()?) as u64;
391    let code = hash128(key, seed);
392    let slots = [
393        fast_mod_u32(code[0], section_u32, section_magic) as usize,
394        fast_mod_u32(code[1], section_u32, section_magic) as usize + section,
395        fast_mod_u32(code[2], section_u32, section_magic) as usize + section * 2,
396    ];
397    let m = get_bit2(bitmap, slots[0]) as usize
398        + get_bit2(bitmap, slots[1]) as usize
399        + get_bit2(bitmap, slots[2]) as usize;
400    let slot = slots[m % 3];
401    let block = slot >> 5;
402    let bit = slot & 31;
403
404    let off = if size > u16::MAX as usize {
405        u32::from_le_bytes(table.get(block * 4..block * 4 + 4)?.try_into().ok()?) as usize
406    } else if size > u8::MAX as usize {
407        u16::from_le_bytes(table.get(block * 2..block * 2 + 2)?.try_into().ok()?) as usize
408    } else if size > 24 {
409        *table.get(block)? as usize
410    } else {
411        0
412    };
413
414    let word_start = block * 8;
415    let bits = u64::from_le_bytes(bitmap.get(word_start..word_start + 8)?.try_into().ok()?);
416    let masked = bits | (u64::MAX << (bit << 1));
417    Some(off + count_valid_slots_in_word(masked))
418}
419
420#[inline(always)]
421fn count_valid_slots_in_word(bits: u64) -> usize {
422    let invalid = ((bits & 0x5555_5555_5555_5555) & (bits >> 1)).count_ones() as usize;
423    32 - invalid
424}
425
426#[inline(always)]
427fn fast_mod_magic(divisor: u32) -> u64 {
428    u64::MAX / divisor as u64 + 1
429}
430
431#[inline(always)]
432fn fast_mod_u32(value: u32, divisor: u32, magic: u64) -> u32 {
433    let low = magic.wrapping_mul(value as u64);
434    (((low as u128) * divisor as u128) >> 64) as u32
435}
436
437#[inline(always)]
438pub fn build_perfect_hash_index<K: AsRef<[u8]>>(keys: &[K]) -> Option<Vec<u8>> {
439    Some(build_perfect_hash_index_with_positions(keys)?.0)
440}
441
442#[inline(always)]
443pub fn build_perfect_hash_index_with_positions<K: AsRef<[u8]>>(
444    keys: &[K],
445) -> Option<(Vec<u8>, Vec<usize>)> {
446    let total = keys.len();
447    if total >= (1usize << 28) {
448        return None;
449    }
450    if total <= 1 {
451        return Some(((total as u32).to_le_bytes().to_vec(), vec![0; total]));
452    }
453
454    let section = perfect_hash_section(total);
455    let section_u32 = section as u32;
456    let section_magic = fast_mod_magic(section_u32);
457    let slot_cnt = section * 3;
458    let bitmap_size = perfect_hash_bitmap_size(section);
459
460    let mut seed = 0u32;
461    let (edges, order) = loop {
462        let edges: Vec<_> = keys
463            .iter()
464            .map(|key| {
465                let code = hash128(key.as_ref(), seed as u64);
466                Edge {
467                    slots: [
468                        fast_mod_u32(code[0], section_u32, section_magic) as usize,
469                        fast_mod_u32(code[1], section_u32, section_magic) as usize + section,
470                        fast_mod_u32(code[2], section_u32, section_magic) as usize + section * 2,
471                    ],
472                }
473            })
474            .collect();
475        if let Some(order) = peel_graph(&edges, slot_cnt) {
476            break (edges, order);
477        }
478        seed = seed.wrapping_add(1);
479        if seed == 0 {
480            return None;
481        }
482    };
483
484    let mut bitmap = vec![0xffu8; bitmap_size];
485    let mut taken = vec![false; slot_cnt];
486    for &edge_idx in order.iter().rev() {
487        let [a, b, c] = edges[edge_idx].slots;
488        let (chosen, target) = if !taken[a] {
489            taken[a] = true;
490            taken[b] = true;
491            taken[c] = true;
492            (a, 0u8)
493        } else if !taken[b] {
494            taken[b] = true;
495            taken[c] = true;
496            (b, 1u8)
497        } else {
498            taken[c] = true;
499            (c, 2u8)
500        };
501
502        let sum = match chosen {
503            x if x == a => get_bit2(&bitmap, b) as u16 + get_bit2(&bitmap, c) as u16,
504            x if x == b => get_bit2(&bitmap, a) as u16 + get_bit2(&bitmap, c) as u16,
505            _ => get_bit2(&bitmap, a) as u16 + get_bit2(&bitmap, b) as u16,
506        };
507        let chosen_val = ((target as i16 - (sum % 3) as i16 + 3) % 3) as u8;
508        set_bit2(&mut bitmap, chosen, chosen_val);
509    }
510
511    let mut out = Vec::with_capacity(8 + bitmap_size + bitmap_size / 2);
512    out.extend_from_slice(&(total as u32).to_le_bytes());
513    out.extend_from_slice(&seed.to_le_bytes());
514    out.extend_from_slice(&bitmap);
515
516    if total > u16::MAX as usize {
517        let mut cnt = 0u32;
518        for block in 0..(bitmap_size / 8) {
519            out.extend_from_slice(&cnt.to_le_bytes());
520            cnt += count_valid_slots(&bitmap, block) as u32;
521        }
522    } else if total > u8::MAX as usize {
523        let mut cnt = 0u16;
524        for block in 0..(bitmap_size / 8) {
525            out.extend_from_slice(&cnt.to_le_bytes());
526            cnt += count_valid_slots(&bitmap, block) as u16;
527        }
528    } else if total > 24 {
529        let mut cnt = 0u8;
530        for block in 0..(bitmap_size / 8) {
531            out.push(cnt);
532            cnt += count_valid_slots(&bitmap, block) as u8;
533        }
534    }
535
536    let mut positions = Vec::with_capacity(keys.len());
537    for key in keys.iter() {
538        positions.push(locate_in_perfect_hash(&out, key.as_ref())?);
539    }
540
541    Some((out, positions))
542}
543
544#[inline(always)]
545pub fn fold_field(buffer: &mut Buffer, unit: &mut Unit) {
546    if !unit.is_segment() || unit.segment.len >= 4 || unit.segment.pos != buffer.len() {
547        return;
548    }
549    let seg = unit.segment;
550    let head = buffer.view();
551    unit.inline_len = seg.len;
552    unit.inline_data[..seg.len].copy_from_slice(&head[..seg.len]);
553    unit.segment = Segment::default();
554    buffer.shrink(seg.len);
555}
556
557#[inline(always)]
558pub fn serialize_scalar<T: Scalar>(value: T) -> Unit {
559    let mut words = [0u32; 3];
560    let word_len = T::WIDTH;
561    value
562        .write_words(&mut words[..word_len])
563        .expect("scalar width must match");
564    Unit {
565        inline_len: word_len,
566        inline_data: words,
567        segment: Segment::default(),
568    }
569}
570
571#[inline(always)]
572pub fn serialize_bool(value: bool) -> Unit {
573    Unit::inline(&[u32::from(value)])
574}
575
576#[inline(always)]
577pub fn serialize_bytes(bytes: &[u8], buffer: &mut Buffer) -> Option<Unit> {
578    if bytes.len() >= (1usize << 30) {
579        return None;
580    }
581    let mark = (bytes.len() as u32) << 2;
582    let mut header = [0u8; 5];
583    let header_size = write_varint(&mut header, mark);
584    let total_words = (header_size + bytes.len()).div_ceil(4);
585
586    let last = buffer.len();
587    let mut inline = [0u32; 3];
588    if total_words == 1 {
589        let raw = unsafe { core::slice::from_raw_parts_mut(inline.as_mut_ptr().cast::<u8>(), 4) };
590        raw.fill(0);
591        raw[..header_size].copy_from_slice(&header[..header_size]);
592        raw[header_size..header_size + bytes.len()].copy_from_slice(bytes);
593        Some(Unit {
594            inline_len: 1,
595            inline_data: inline,
596            segment: Segment::default(),
597        })
598    } else {
599        let words = buffer.expand(total_words);
600        words[total_words - 1] = 0;
601        let raw = unsafe {
602            core::slice::from_raw_parts_mut(words.as_mut_ptr().cast::<u8>(), total_words * 4)
603        };
604        raw[..header_size].copy_from_slice(&header[..header_size]);
605        raw[header_size..header_size + bytes.len()].copy_from_slice(bytes);
606        Some(Unit::segment(last, buffer.len()))
607    }
608}
609
610#[inline(always)]
611pub fn serialize_str(value: &str, buffer: &mut Buffer) -> Option<Unit> {
612    serialize_bytes(value.as_bytes(), buffer)
613}
614
615#[inline(always)]
616pub fn serialize_message_at(fields: &mut [Unit], buffer: &mut Buffer, last: usize) -> Option<Unit> {
617    if fields.is_empty() {
618        return None;
619    }
620    let used_len = fields
621        .iter()
622        .rposition(|unit| !unit.is_empty())
623        .map(|index| index + 1)
624        .unwrap_or(0);
625    if used_len == 0 {
626        let last = buffer.len();
627        buffer.put(0);
628        return Some(Unit::segment(last, buffer.len()));
629    }
630    let fields = &mut fields[..used_len];
631
632    let mut body_size = 0usize;
633    let mut size = 0usize;
634    for field in fields.iter().rev() {
635        if field.inline_len != 0 {
636            body_size += field.inline_len;
637            size += field.inline_len;
638        } else if field.segment.len != 0 {
639            body_size += 1;
640            size += field.segment.len;
641        }
642    }
643    if size >= (1usize << 30) {
644        return None;
645    }
646
647    let section = (fields.len() + 12) / 25;
648    if section > 0xff {
649        return None;
650    }
651
652    let head_size = 1 + section * 2;
653    let current_size = buffer.len();
654    let total_size = current_size + head_size + body_size;
655    let block = buffer.expand(head_size + body_size);
656    let (head, body) = block.split_at_mut(head_size);
657    let mut body_index = 0usize;
658    let mut pos = total_size - head_size;
659    head.fill(0);
660    head[0] = section as u32;
661
662    let mut cnt = 0u32;
663    for (i, field) in fields.iter().take(12).enumerate() {
664        if field.inline_len != 0 {
665            head[0] |= (field.inline_len as u32) << (8 + i * 2);
666            cnt += field.inline_len as u32;
667            copy_inline(body, &mut body_index, &mut pos, field);
668        } else if field.segment.len != 0 {
669            head[0] |= 1u32 << (8 + i * 2);
670            cnt += 1;
671            body[body_index] = offset(pos - field.segment.pos);
672            body_index += 1;
673            pos -= 1;
674        }
675    }
676
677    for sec in 0..section {
678        let start = 12 + sec * 25;
679        let end = fields.len().min(start + 25);
680        let mut mark = (cnt as u64) << 50;
681        let mut shift = 0usize;
682        for field in &fields[start..end] {
683            if field.inline_len != 0 {
684                mark |= (field.inline_len as u64) << shift;
685                cnt += field.inline_len as u32;
686                copy_inline(body, &mut body_index, &mut pos, field);
687            } else if field.segment.len != 0 {
688                mark |= 1u64 << shift;
689                cnt += 1;
690                body[body_index] = offset(pos - field.segment.pos);
691                body_index += 1;
692                pos -= 1;
693            }
694            shift += 2;
695        }
696        head[1 + sec * 2] = mark as u32;
697        head[1 + sec * 2 + 1] = (mark >> 32) as u32;
698    }
699
700    Some(Unit::segment(last, buffer.len()))
701}
702
703#[inline(always)]
704pub fn serialize_message(fields: &mut [Unit], buffer: &mut Buffer) -> Option<Unit> {
705    serialize_message_at(fields, buffer, buffer.len())
706}
707
708#[inline(always)]
709pub fn serialize_array_at_mut(
710    elements: &mut [Unit],
711    buffer: &mut Buffer,
712    last: usize,
713) -> Option<Unit> {
714    if elements.is_empty() {
715        return Some(Unit::inline(&[1]));
716    }
717
718    let (size, width) = best_array_size(elements);
719    if size >= (1usize << 30) {
720        return None;
721    }
722
723    let mut tail = buffer.len().checked_sub(last)?;
724    for unit in elements.iter_mut().rev() {
725        pick_unit(unit, buffer, &mut tail, width);
726    }
727    buffer.shrink(tail);
728    for unit in elements.iter().rev() {
729        mark_unit(unit, buffer, width);
730    }
731    buffer.put(((elements.len() as u32) << 2) | width as u32);
732    Some(Unit::segment(last, buffer.len()))
733}
734
735#[inline(always)]
736pub fn serialize_array_at(elements: &[Unit], buffer: &mut Buffer, last: usize) -> Option<Unit> {
737    if elements.is_empty() {
738        return Some(Unit::inline(&[1]));
739    }
740
741    let (size, width) = best_array_size(elements);
742    if size >= (1usize << 30) {
743        return None;
744    }
745
746    let mut payloads = Vec::with_capacity(size.saturating_sub(elements.len() * width));
747    let mut cells = vec![0u32; elements.len() * width];
748    let cells_len = cells.len();
749    for (index, unit) in elements.iter().enumerate() {
750        let words = unit_words(unit, buffer)?;
751        let cell = &mut cells[index * width..(index + 1) * width];
752        if words.len() <= width {
753            cell[..words.len()].copy_from_slice(words);
754        } else {
755            let payload_start = cells_len.checked_add(payloads.len())?;
756            let cell_start = index.checked_mul(width)?;
757            cell[0] = offset(payload_start.checked_sub(cell_start)?);
758            payloads.extend_from_slice(words);
759        }
760    }
761    buffer.shrink(buffer.len().checked_sub(last)?);
762    buffer.put_words(&payloads);
763    buffer.put_words(&cells);
764    buffer.put(((elements.len() as u32) << 2) | width as u32);
765    Some(Unit::segment(last, buffer.len()))
766}
767
768#[inline(always)]
769pub fn serialize_array(elements: &[Unit], buffer: &mut Buffer) -> Option<Unit> {
770    serialize_array_at(elements, buffer, buffer.len())
771}
772
773#[inline(always)]
774pub fn serialize_map_at_mut(
775    index: &[u8],
776    keys: &mut [Unit],
777    values: &mut [Unit],
778    buffer: &mut Buffer,
779    last: usize,
780) -> Option<Unit> {
781    if keys.len() != values.len() {
782        return None;
783    }
784    if keys.is_empty() {
785        return Some(Unit::inline(&[5u32 << 28]));
786    }
787
788    let (key_size, key_width) = best_array_size(keys);
789    let (value_size, value_width) = best_array_size(values);
790    let index_words = index.len().div_ceil(4);
791    let size = index_words + key_size + value_size;
792    if size >= (1usize << 30) {
793        return None;
794    }
795
796    let mut tail = buffer.len().checked_sub(last)?;
797    for index in (0..keys.len()).rev() {
798        pick_unit(&mut values[index], buffer, &mut tail, value_width);
799        pick_unit(&mut keys[index], buffer, &mut tail, key_width);
800    }
801    buffer.shrink(tail);
802    for index in (0..keys.len()).rev() {
803        mark_unit(&values[index], buffer, value_width);
804        mark_unit(&keys[index], buffer, key_width);
805    }
806
807    let head = buffer.expand(index_words);
808    head.fill(0);
809    let raw =
810        unsafe { core::slice::from_raw_parts_mut(head.as_mut_ptr().cast::<u8>(), index_words * 4) };
811    raw[..index.len()].copy_from_slice(index);
812    head[0] |= (key_width as u32) << 30 | (value_width as u32) << 28;
813    Some(Unit::segment(last, buffer.len()))
814}
815
816#[inline(always)]
817pub(crate) fn serialize_map_pairs_at_mut(
818    index: &[u8],
819    pairs: &mut [(Unit, Unit)],
820    buffer: &mut Buffer,
821    last: usize,
822) -> Option<Unit> {
823    if pairs.is_empty() {
824        return Some(Unit::inline(&[5u32 << 28]));
825    }
826
827    let ((key_size, key_width), (value_size, value_width)) = best_array_size_pairs(pairs);
828    let index_words = index.len().div_ceil(4);
829    let size = index_words + key_size + value_size;
830    if size >= (1usize << 30) {
831        return None;
832    }
833
834    let mut tail = buffer.len().checked_sub(last)?;
835    for (key, value) in pairs.iter_mut().rev() {
836        pick_unit(value, buffer, &mut tail, value_width);
837        pick_unit(key, buffer, &mut tail, key_width);
838    }
839    buffer.shrink(tail);
840    for (key, value) in pairs.iter().rev() {
841        mark_unit(value, buffer, value_width);
842        mark_unit(key, buffer, key_width);
843    }
844
845    let head = buffer.expand(index_words);
846    head.fill(0);
847    let raw =
848        unsafe { core::slice::from_raw_parts_mut(head.as_mut_ptr().cast::<u8>(), index_words * 4) };
849    raw[..index.len()].copy_from_slice(index);
850    head[0] |= (key_width as u32) << 30 | (value_width as u32) << 28;
851    Some(Unit::segment(last, buffer.len()))
852}
853
854#[inline(always)]
855pub fn serialize_map_at(
856    index: &[u8],
857    keys: &[Unit],
858    values: &[Unit],
859    buffer: &mut Buffer,
860    last: usize,
861) -> Option<Unit> {
862    if keys.len() != values.len() {
863        return None;
864    }
865    if keys.is_empty() {
866        return Some(Unit::inline(&[5u32 << 28]));
867    }
868
869    let (key_size, key_width) = best_array_size(keys);
870    let (value_size, value_width) = best_array_size(values);
871    let index_words = index.len().div_ceil(4);
872    let size = index_words + key_size + value_size;
873    if size >= (1usize << 30) {
874        return None;
875    }
876
877    let pair_width = key_width + value_width;
878    let mut payloads = Vec::with_capacity(size.saturating_sub(keys.len() * pair_width));
879    let mut cells = vec![0u32; keys.len() * pair_width];
880    let cells_len = cells.len();
881    for index in 0..keys.len() {
882        let key_words = unit_words(&keys[index], buffer)?;
883        let value_words = unit_words(&values[index], buffer)?;
884        let cell_start = index.checked_mul(pair_width)?;
885        let (key_cell, value_cell) =
886            cells[cell_start..cell_start + pair_width].split_at_mut(key_width);
887
888        if key_words.len() <= key_width {
889            key_cell[..key_words.len()].copy_from_slice(key_words);
890        } else {
891            let payload_start = cells_len.checked_add(payloads.len())?;
892            key_cell[0] = offset(payload_start.checked_sub(cell_start)?);
893            payloads.extend_from_slice(key_words);
894        }
895
896        let value_cell_start = cell_start + key_width;
897        if value_words.len() <= value_width {
898            value_cell[..value_words.len()].copy_from_slice(value_words);
899        } else {
900            let payload_start = cells_len.checked_add(payloads.len())?;
901            value_cell[0] = offset(payload_start.checked_sub(value_cell_start)?);
902            payloads.extend_from_slice(value_words);
903        }
904    }
905    buffer.shrink(buffer.len().checked_sub(last)?);
906    buffer.put_words(&payloads);
907    buffer.put_words(&cells);
908
909    let head = buffer.expand(index_words);
910    head.fill(0);
911    let raw =
912        unsafe { core::slice::from_raw_parts_mut(head.as_mut_ptr().cast::<u8>(), index_words * 4) };
913    raw[..index.len()].copy_from_slice(index);
914    head[0] |= (key_width as u32) << 30 | (value_width as u32) << 28;
915    Some(Unit::segment(last, buffer.len()))
916}
917
918#[inline(always)]
919pub fn serialize_map(
920    index: &[u8],
921    keys: &[Unit],
922    values: &[Unit],
923    buffer: &mut Buffer,
924) -> Option<Unit> {
925    serialize_map_at(index, keys, values, buffer, buffer.len())
926}
927
928#[cfg(test)]
929mod tests {
930    use super::{
931        Unit, build_perfect_hash_index, build_perfect_hash_index_with_positions, fold_field,
932        serialize_array, serialize_array_at, serialize_bool, serialize_map, serialize_message,
933        serialize_scalar, serialize_str,
934    };
935    use crate::{ArrayView, Buffer, MapView, MessageView, StringView, ViewArray};
936
937    #[test]
938    fn serializes_inline_string() {
939        let mut buffer = Buffer::new();
940        let unit = serialize_str("hi", &mut buffer).unwrap();
941        assert_eq!(unit.inline_words().len(), 1);
942        assert!(buffer.is_empty());
943    }
944
945    #[test]
946    fn folds_segmented_field_when_small() {
947        let mut buffer = Buffer::new();
948        let mut unit = serialize_str("hello", &mut buffer).unwrap();
949        assert!(unit.is_segment());
950        fold_field(&mut buffer, &mut unit);
951        assert_eq!(unit.inline_words().len(), 2);
952        assert!(buffer.is_empty());
953
954        let mut small = serialize_str("abc", &mut buffer).unwrap();
955        assert_eq!(small.inline_words().len(), 1);
956        fold_field(&mut buffer, &mut small);
957        assert_eq!(small.inline_words().len(), 1);
958    }
959
960    #[test]
961    fn serializes_simple_message_roundtrip() {
962        let mut buffer = Buffer::new();
963        let field0 = serialize_scalar::<i32>(42);
964        let field1 = serialize_bool(true);
965        let field3 = serialize_str("hi", &mut buffer).unwrap();
966        let mut fields = vec![field0, field1, Unit::empty(), field3];
967        let _message = serialize_message(&mut fields, &mut buffer).unwrap();
968
969        let view = MessageView::new(buffer.view()).unwrap();
970        assert_eq!(view.scalar::<i32>(0), Some(42));
971        assert_eq!(view.scalar::<bool>(1), Some(true));
972        assert_eq!(view.string(3).unwrap().as_str(), Some("hi"));
973        assert!(view.scalar::<i32>(2).is_none());
974    }
975
976    #[test]
977    fn serializes_all_empty_fields_as_empty_message() {
978        let mut buffer = Buffer::new();
979        let mut fields = vec![Unit::empty(), Unit::empty()];
980        let _message = serialize_message(&mut fields, &mut buffer).unwrap();
981        let view = MessageView::new(buffer.view()).unwrap();
982        assert!(!view.has_field(0));
983        assert!(!view.has_field(1));
984    }
985
986    #[test]
987    fn serializes_scalar_array_roundtrip() {
988        let mut buffer = Buffer::new();
989        let elements = vec![serialize_scalar::<i32>(1), serialize_scalar::<i32>(2)];
990        let _array = serialize_array(&elements, &mut buffer).unwrap();
991        let view = ArrayView::new(buffer.view()).unwrap();
992        let scalars = view.scalars::<i32>().unwrap();
993        assert_eq!(scalars.get(0), Some(1));
994        assert_eq!(scalars.get(1), Some(2));
995    }
996
997    #[test]
998    fn serializes_string_array_roundtrip() {
999        let mut buffer = Buffer::new();
1000        let a = serialize_str("abc", &mut buffer).unwrap();
1001        let b = serialize_str("apple", &mut buffer).unwrap();
1002        let elements = vec![a, b];
1003        let _array = serialize_array(&elements, &mut buffer).unwrap();
1004        let view = ArrayView::new(buffer.view()).unwrap();
1005        let strings = ViewArray::<StringView<'_>>::new(view);
1006        assert_eq!(strings.get(0).unwrap().as_str(), Some("abc"));
1007        assert_eq!(strings.get(1).unwrap().as_str(), Some("apple"));
1008    }
1009
1010    #[test]
1011    fn builds_index_and_serializes_string_int_map_roundtrip() {
1012        let keys_bytes = vec![b"abc-1".to_vec(), b"abc-2".to_vec()];
1013        let (index, positions) = build_perfect_hash_index_with_positions(&keys_bytes).unwrap();
1014
1015        let mut buffer = Buffer::new();
1016        let key0 = serialize_str("abc-1", &mut buffer).unwrap();
1017        let key1 = serialize_str("abc-2", &mut buffer).unwrap();
1018        let mut keys = vec![Unit::empty(); 2];
1019        let mut values = vec![Unit::empty(); 2];
1020        keys[positions[0]] = key0;
1021        keys[positions[1]] = key1;
1022        values[positions[0]] = serialize_scalar::<i32>(1);
1023        values[positions[1]] = serialize_scalar::<i32>(2);
1024        let _map = serialize_map(&index, &keys, &values, &mut buffer).unwrap();
1025
1026        let view = MapView::new(buffer.view()).unwrap();
1027        assert_eq!(
1028            view.find_str("abc-1").unwrap().value().scalar::<i32>(),
1029            Some(1)
1030        );
1031        assert_eq!(
1032            view.find_str("abc-2").unwrap().value().scalar::<i32>(),
1033            Some(2)
1034        );
1035        assert!(view.find_str("abc-3").is_none());
1036    }
1037
1038    #[test]
1039    fn index_builder_matches_reader_expectations() {
1040        let keys = vec![b"abc-1".to_vec(), b"abc-2".to_vec(), b"abc-4".to_vec()];
1041        let index = build_perfect_hash_index(&keys).unwrap();
1042        let mut seen = std::collections::BTreeSet::new();
1043        for key in &keys {
1044            seen.insert(super::locate_in_perfect_hash(&index, key).unwrap());
1045        }
1046        assert_eq!(seen.len(), keys.len());
1047    }
1048
1049    #[test]
1050    fn serializes_short_string_key_float_array_map_roundtrip() {
1051        let keys_bytes = vec![b"lv5".to_vec(), b"lv9".to_vec()];
1052        let (index, positions) = build_perfect_hash_index_with_positions(&keys_bytes).unwrap();
1053
1054        let mut buffer = Buffer::new();
1055        let key0 = serialize_str("lv5", &mut buffer).unwrap();
1056        let key1 = serialize_str("lv9", &mut buffer).unwrap();
1057
1058        let last = buffer.len();
1059        let value0 = serialize_array_at(
1060            &[
1061                serialize_scalar::<f32>(51.0),
1062                serialize_scalar::<f32>(52.0),
1063                serialize_scalar::<f32>(53.0),
1064            ],
1065            &mut buffer,
1066            last,
1067        )
1068        .unwrap();
1069        let last = buffer.len();
1070        let value1 = serialize_array_at(
1071            &[serialize_scalar::<f32>(91.0), serialize_scalar::<f32>(92.0)],
1072            &mut buffer,
1073            last,
1074        )
1075        .unwrap();
1076
1077        let mut keys = vec![Unit::empty(); 2];
1078        let mut values = vec![Unit::empty(); 2];
1079        keys[positions[0]] = key0;
1080        keys[positions[1]] = key1;
1081        values[positions[0]] = value0;
1082        values[positions[1]] = value1;
1083        let _map = serialize_map(&index, &keys, &values, &mut buffer).unwrap();
1084
1085        let view = MapView::new(buffer.view()).unwrap();
1086        let lv5 = view.find_str("lv5").unwrap().value().array().unwrap();
1087        assert_eq!(
1088            lv5.scalars::<f32>().unwrap().iter().collect::<Vec<_>>(),
1089            vec![51.0, 52.0, 53.0]
1090        );
1091        let lv9 = view.find_str("lv9").unwrap().value().array().unwrap();
1092        assert_eq!(
1093            lv9.scalars::<f32>().unwrap().iter().collect::<Vec<_>>(),
1094            vec![91.0, 92.0]
1095        );
1096    }
1097
1098    #[test]
1099    fn serializes_multi_entry_short_string_key_float_array_map_roundtrip() {
1100        let keys = ["lv1", "lv2", "lv3", "lv4", "lv5", "lv9"];
1101        let key_bytes = keys
1102            .iter()
1103            .map(|key| key.as_bytes().to_vec())
1104            .collect::<Vec<_>>();
1105        let (index, positions) = build_perfect_hash_index_with_positions(&key_bytes).unwrap();
1106
1107        let values_src = [
1108            vec![11.0f32, 12.0],
1109            vec![21.0, 22.0],
1110            vec![31.0, 32.0],
1111            vec![41.0, 42.0],
1112            vec![51.0, 52.0, 53.0],
1113            vec![91.0, 92.0],
1114        ];
1115
1116        let mut buffer = Buffer::new();
1117        let encoded_keys = keys
1118            .iter()
1119            .map(|key| serialize_str(key, &mut buffer).unwrap())
1120            .collect::<Vec<_>>();
1121        let encoded_values = values_src
1122            .iter()
1123            .map(|values| {
1124                let units = values
1125                    .iter()
1126                    .map(|value| serialize_scalar::<f32>(*value))
1127                    .collect::<Vec<_>>();
1128                serialize_array(&units, &mut buffer).unwrap()
1129            })
1130            .collect::<Vec<_>>();
1131
1132        let mut keys = vec![Unit::empty(); positions.len()];
1133        let mut values = vec![Unit::empty(); positions.len()];
1134        for (idx, pos) in positions.iter().copied().enumerate() {
1135            keys[pos] = encoded_keys[idx];
1136            values[pos] = encoded_values[idx];
1137        }
1138
1139        let _map = serialize_map(&index, &keys, &values, &mut buffer).unwrap();
1140        let view = MapView::new(buffer.view()).unwrap();
1141        for (key, expected) in ["lv1", "lv2", "lv3", "lv4", "lv5", "lv9"]
1142            .into_iter()
1143            .zip(values_src.iter())
1144        {
1145            let array = view.find_str(key).unwrap().value().array().unwrap();
1146            assert_eq!(
1147                array.scalars::<f32>().unwrap().iter().collect::<Vec<_>>(),
1148                expected.clone()
1149            );
1150        }
1151    }
1152}