Skip to main content

rbdc_pg/message/
data_row.rs

1use std::ops::Range;
2
3use byteorder::{BigEndian, ByteOrder};
4use bytes::Bytes;
5use rbdc::io::Decode;
6use rbdc::Error;
7
8/// A row of data from the database.
9#[derive(Debug)]
10pub struct DataRow {
11    pub storage: Vec<Option<Vec<u8>>>,
12    /// Ranges into the stored row data.
13    /// This uses `u32` instead of usize to reduce the size of this type. Values cannot be larger
14    /// than `i32` in postgres.
15    pub values: Vec<Option<Range<usize>>>,
16}
17
18impl DataRow {
19    #[inline]
20    pub(crate) fn get(&self, index: usize) -> Option<&'_ [u8]> {
21        let mut idx = 0;
22        for x in &self.values {
23            if index == idx {
24                match x {
25                    None => return None,
26                    Some(_) => match &self.storage[idx] {
27                        None => {
28                            return None;
29                        }
30                        Some(v) => {
31                            return Some(v);
32                        }
33                    },
34                }
35            }
36            idx += 1;
37        }
38        None
39    }
40
41    #[inline]
42    pub(crate) fn take(&mut self, index: usize) -> Option<Vec<u8>> {
43        let mut idx = 0;
44        for x in &self.values {
45            if index == idx {
46                match x {
47                    None => return None,
48                    Some(_) => {
49                        return match self.storage[idx].take() {
50                            None => None,
51                            Some(v) => Some(v),
52                        }
53                    }
54                }
55            }
56            idx += 1;
57        }
58        None
59    }
60}
61
62impl Decode<'_> for DataRow {
63    fn decode_with(buf: Bytes, _: ()) -> Result<Self, Error> {
64        let cnt = BigEndian::read_u16(&buf) as usize;
65
66        let mut values = Vec::with_capacity(cnt);
67        let mut offset = 2;
68
69        for _ in 0..cnt {
70            // Length of the column value, in bytes (this count does not include itself).
71            // Can be zero. As a special case, -1 indicates a NULL column value.
72            // No value bytes follow in the NULL case.
73            let length = BigEndian::read_i32(&buf[(offset as usize)..]);
74            offset += 4;
75
76            if length < 0 {
77                values.push(None);
78            } else {
79                values.push(Some(offset as usize..(offset + length as u32) as usize));
80                offset += length as u32;
81            }
82        }
83        let mut storage = Vec::with_capacity(values.len());
84        for x in &values {
85            match x {
86                None => {
87                    storage.push(None);
88                }
89                Some(v) => storage.push(Some(buf[v.start..v.end].to_vec())),
90            }
91        }
92        Ok(Self {
93            storage: storage,
94            values: values,
95        })
96    }
97}
98
99#[test]
100fn test_decode_data_row() {
101    const DATA: &[u8] = b"\x00\x08\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\n\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00(\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00P";
102
103    let row = DataRow::decode(DATA.into()).unwrap();
104
105    assert_eq!(row.values.len(), 8);
106
107    assert!(row.get(0).is_none());
108    assert_eq!(row.get(1).unwrap(), &[0_u8, 0, 0, 10][..]);
109    assert!(row.get(2).is_none());
110    assert_eq!(row.get(3).unwrap(), &[0_u8, 0, 0, 20][..]);
111    assert!(row.get(4).is_none());
112    assert_eq!(row.get(5).unwrap(), &[0_u8, 0, 0, 40][..]);
113    assert!(row.get(6).is_none());
114    assert_eq!(row.get(7).unwrap(), &[0_u8, 0, 0, 80][..]);
115}
116
117#[cfg(all(test, not(debug_assertions)))]
118#[bench]
119fn bench_data_row_get(b: &mut test::Bencher) {
120    const DATA: &[u8] = b"\x00\x08\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\n\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00(\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00P";
121
122    let row = DataRow::decode(test::black_box(Bytes::from_static(DATA))).unwrap();
123
124    b.iter(|| {
125        let _value = test::black_box(&row).get(3);
126    });
127}
128
129#[cfg(all(test, not(debug_assertions)))]
130#[bench]
131fn bench_decode_data_row(b: &mut test::Bencher) {
132    const DATA: &[u8] = b"\x00\x08\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\n\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00(\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00P";
133
134    b.iter(|| {
135        let _ = DataRow::decode(test::black_box(Bytes::from_static(DATA)));
136    });
137}