sentinel_driver/types/
multirange.rs1use bytes::{BufMut, BytesMut};
2
3use crate::error::{Error, Result};
4use crate::types::range::PgRange;
5use crate::types::{FromSql, Oid, ToSql};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct PgMultirange<T> {
13 pub ranges: Vec<PgRange<T>>,
14 pub multirange_oid: Oid,
15 pub range_oid: Oid,
16 pub element_oid: Oid,
17}
18
19impl<T: ToSql> ToSql for PgMultirange<T> {
20 fn oid(&self) -> Oid {
21 self.multirange_oid
22 }
23
24 fn to_sql(&self, buf: &mut BytesMut) -> Result<()> {
25 buf.put_i32(self.ranges.len() as i32);
26
27 for range in &self.ranges {
28 let len_pos = buf.len();
29 buf.put_i32(0); let data_start = buf.len();
31 range.to_sql(buf)?;
32 let data_len = (buf.len() - data_start) as i32;
33 buf[len_pos..len_pos + 4].copy_from_slice(&data_len.to_be_bytes());
34 }
35
36 Ok(())
37 }
38}
39
40impl<T: FromSql> PgMultirange<T> {
41 pub fn from_sql_with_oids(
44 buf: &[u8],
45 multirange_oid: Oid,
46 range_oid: Oid,
47 element_oid: Oid,
48 ) -> Result<Self> {
49 if buf.len() < 4 {
50 return Err(Error::Decode("multirange: header too short".into()));
51 }
52
53 let count = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]) as usize;
54 let mut offset = 4;
55 let mut ranges = Vec::with_capacity(count);
56
57 for _ in 0..count {
58 if offset + 4 > buf.len() {
59 return Err(Error::Decode("multirange: range length truncated".into()));
60 }
61 let range_len = i32::from_be_bytes([
62 buf[offset],
63 buf[offset + 1],
64 buf[offset + 2],
65 buf[offset + 3],
66 ]) as usize;
67 offset += 4;
68
69 if offset + range_len > buf.len() {
70 return Err(Error::Decode("multirange: range data truncated".into()));
71 }
72
73 let range = PgRange::from_sql_with_oids(
74 &buf[offset..offset + range_len],
75 range_oid,
76 element_oid,
77 )?;
78 ranges.push(range);
79 offset += range_len;
80 }
81
82 Ok(PgMultirange {
83 ranges,
84 multirange_oid,
85 range_oid,
86 element_oid,
87 })
88 }
89}