1use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
3use bytes::{BufMut, BytesMut};
4use fallible_iterator::FallibleIterator;
5use std::boxed::Box as StdBox;
6use std::error::Error;
7use std::io::Read;
8use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
9use std::str;
10
11use crate::{write_nullable, FromUsize, IsNull, Lsn, Oid};
12
13#[cfg(test)]
14mod test;
15
16const RANGE_UPPER_UNBOUNDED: u8 = 0b0001_0000;
17const RANGE_LOWER_UNBOUNDED: u8 = 0b0000_1000;
18const RANGE_UPPER_INCLUSIVE: u8 = 0b0000_0100;
19const RANGE_LOWER_INCLUSIVE: u8 = 0b0000_0010;
20const RANGE_EMPTY: u8 = 0b0000_0001;
21
22const PGSQL_AF_INET: u8 = 2;
23const PGSQL_AF_INET6: u8 = 3;
24
25#[inline]
27pub fn bool_to_sql(v: bool, buf: &mut BytesMut) {
28 buf.put_u8(v as u8);
29}
30
31#[inline]
33pub fn bool_from_sql(buf: &[u8]) -> Result<bool, StdBox<dyn Error + Sync + Send>> {
34 if buf.len() != 1 {
35 return Err("invalid buffer size".into());
36 }
37
38 Ok(buf[0] != 0)
39}
40
41#[inline]
43pub fn bytea_to_sql(v: &[u8], buf: &mut BytesMut) {
44 buf.put_slice(v);
45}
46
47#[inline]
49pub fn bytea_from_sql(buf: &[u8]) -> &[u8] {
50 buf
51}
52
53#[inline]
55pub fn text_to_sql(v: &str, buf: &mut BytesMut) {
56 buf.put_slice(v.as_bytes());
57}
58
59#[inline]
61pub fn text_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
62 Ok(str::from_utf8(buf)?)
63}
64
65#[inline]
67pub fn char_to_sql(v: i8, buf: &mut BytesMut) {
68 buf.put_i8(v);
69}
70
71#[inline]
73pub fn char_from_sql(mut buf: &[u8]) -> Result<i8, StdBox<dyn Error + Sync + Send>> {
74 let v = buf.read_i8()?;
75 if !buf.is_empty() {
76 return Err("invalid buffer size".into());
77 }
78 Ok(v)
79}
80
81#[inline]
83pub fn int2_to_sql(v: i16, buf: &mut BytesMut) {
84 buf.put_i16(v);
85}
86
87#[inline]
89pub fn int2_from_sql(mut buf: &[u8]) -> Result<i16, StdBox<dyn Error + Sync + Send>> {
90 let v = buf.read_i16::<BigEndian>()?;
91 if !buf.is_empty() {
92 return Err("invalid buffer size".into());
93 }
94 Ok(v)
95}
96
97#[inline]
99pub fn int4_to_sql(v: i32, buf: &mut BytesMut) {
100 buf.put_i32(v);
101}
102
103#[inline]
105pub fn int4_from_sql(mut buf: &[u8]) -> Result<i32, StdBox<dyn Error + Sync + Send>> {
106 let v = buf.read_i32::<BigEndian>()?;
107 if !buf.is_empty() {
108 return Err("invalid buffer size".into());
109 }
110 Ok(v)
111}
112
113#[inline]
115pub fn oid_to_sql(v: Oid, buf: &mut BytesMut) {
116 buf.put_u32(v);
117}
118
119#[inline]
121pub fn oid_from_sql(mut buf: &[u8]) -> Result<Oid, StdBox<dyn Error + Sync + Send>> {
122 let v = buf.read_u32::<BigEndian>()?;
123 if !buf.is_empty() {
124 return Err("invalid buffer size".into());
125 }
126 Ok(v)
127}
128
129#[inline]
131pub fn int8_to_sql(v: i64, buf: &mut BytesMut) {
132 buf.put_i64(v);
133}
134
135#[inline]
137pub fn int8_from_sql(mut buf: &[u8]) -> Result<i64, StdBox<dyn Error + Sync + Send>> {
138 let v = buf.read_i64::<BigEndian>()?;
139 if !buf.is_empty() {
140 return Err("invalid buffer size".into());
141 }
142 Ok(v)
143}
144
145#[inline]
147pub fn lsn_to_sql(v: Lsn, buf: &mut BytesMut) {
148 buf.put_u64(v);
149}
150
151#[inline]
153pub fn lsn_from_sql(mut buf: &[u8]) -> Result<Lsn, StdBox<dyn Error + Sync + Send>> {
154 let v = buf.read_u64::<BigEndian>()?;
155 if !buf.is_empty() {
156 return Err("invalid buffer size".into());
157 }
158 Ok(v)
159}
160
161#[inline]
163pub fn float4_to_sql(v: f32, buf: &mut BytesMut) {
164 buf.put_f32(v);
165}
166
167#[inline]
169pub fn float4_from_sql(mut buf: &[u8]) -> Result<f32, StdBox<dyn Error + Sync + Send>> {
170 let v = buf.read_f32::<BigEndian>()?;
171 if !buf.is_empty() {
172 return Err("invalid buffer size".into());
173 }
174 Ok(v)
175}
176
177#[inline]
179pub fn float8_to_sql(v: f64, buf: &mut BytesMut) {
180 buf.put_f64(v);
181}
182
183#[inline]
185pub fn float8_from_sql(mut buf: &[u8]) -> Result<f64, StdBox<dyn Error + Sync + Send>> {
186 let v = buf.read_f64::<BigEndian>()?;
187 if !buf.is_empty() {
188 return Err("invalid buffer size".into());
189 }
190 Ok(v)
191}
192
193#[inline]
195pub fn hstore_to_sql<'a, I>(
196 values: I,
197 buf: &mut BytesMut,
198) -> Result<(), StdBox<dyn Error + Sync + Send>>
199where
200 I: IntoIterator<Item = (&'a str, Option<&'a str>)>,
201{
202 let base = buf.len();
203 buf.put_i32(0);
204
205 let mut count = 0;
206 for (key, value) in values {
207 count += 1;
208
209 write_pascal_string(key, buf)?;
210
211 match value {
212 Some(value) => {
213 write_pascal_string(value, buf)?;
214 }
215 None => buf.put_i32(-1),
216 }
217 }
218
219 let count = i32::from_usize(count)?;
220 BigEndian::write_i32(&mut buf[base..], count);
221
222 Ok(())
223}
224
225fn write_pascal_string(s: &str, buf: &mut BytesMut) -> Result<(), StdBox<dyn Error + Sync + Send>> {
226 let size = i32::from_usize(s.len())?;
227 buf.put_i32(size);
228 buf.put_slice(s.as_bytes());
229 Ok(())
230}
231
232#[inline]
234pub fn hstore_from_sql(
235 mut buf: &[u8],
236) -> Result<HstoreEntries<'_>, StdBox<dyn Error + Sync + Send>> {
237 let count = buf.read_i32::<BigEndian>()?;
238 if count < 0 {
239 return Err("invalid entry count".into());
240 }
241
242 Ok(HstoreEntries {
243 remaining: count,
244 buf,
245 })
246}
247
248pub struct HstoreEntries<'a> {
250 remaining: i32,
251 buf: &'a [u8],
252}
253
254impl<'a> FallibleIterator for HstoreEntries<'a> {
255 type Item = (&'a str, Option<&'a str>);
256 type Error = StdBox<dyn Error + Sync + Send>;
257
258 #[inline]
259 #[allow(clippy::type_complexity)]
260 fn next(
261 &mut self,
262 ) -> Result<Option<(&'a str, Option<&'a str>)>, StdBox<dyn Error + Sync + Send>> {
263 if self.remaining == 0 {
264 if !self.buf.is_empty() {
265 return Err("invalid buffer size".into());
266 }
267 return Ok(None);
268 }
269
270 self.remaining -= 1;
271
272 let key_len = self.buf.read_i32::<BigEndian>()?;
273 if key_len < 0 {
274 return Err("invalid key length".into());
275 }
276 let (key, buf) = self.buf.split_at(key_len as usize);
277 let key = str::from_utf8(key)?;
278 self.buf = buf;
279
280 let value_len = self.buf.read_i32::<BigEndian>()?;
281 let value = if value_len < 0 {
282 None
283 } else {
284 let (value, buf) = self.buf.split_at(value_len as usize);
285 let value = str::from_utf8(value)?;
286 self.buf = buf;
287 Some(value)
288 };
289
290 Ok(Some((key, value)))
291 }
292
293 #[inline]
294 fn size_hint(&self) -> (usize, Option<usize>) {
295 let len = self.remaining as usize;
296 (len, Some(len))
297 }
298}
299
300#[inline]
302pub fn varbit_to_sql<I>(
303 len: usize,
304 v: I,
305 buf: &mut BytesMut,
306) -> Result<(), StdBox<dyn Error + Sync + Send>>
307where
308 I: Iterator<Item = u8>,
309{
310 let len = i32::from_usize(len)?;
311 buf.put_i32(len);
312
313 for byte in v {
314 buf.put_u8(byte);
315 }
316
317 Ok(())
318}
319
320#[inline]
322pub fn varbit_from_sql(mut buf: &[u8]) -> Result<Varbit<'_>, StdBox<dyn Error + Sync + Send>> {
323 let len = buf.read_i32::<BigEndian>()?;
324 if len < 0 {
325 return Err("invalid varbit length: varbit < 0".into());
326 }
327 let bytes = (len as usize + 7) / 8;
328 if buf.len() != bytes {
329 return Err("invalid message length: varbit mismatch".into());
330 }
331
332 Ok(Varbit {
333 len: len as usize,
334 bytes: buf,
335 })
336}
337
338pub struct Varbit<'a> {
340 len: usize,
341 bytes: &'a [u8],
342}
343
344impl<'a> Varbit<'a> {
345 #[inline]
347 pub fn len(&self) -> usize {
348 self.len
349 }
350
351 #[inline]
353 pub fn is_empty(&self) -> bool {
354 self.len == 0
355 }
356
357 #[inline]
359 pub fn bytes(&self) -> &'a [u8] {
360 self.bytes
361 }
362}
363
364#[inline]
368pub fn timestamp_to_sql(v: i64, buf: &mut BytesMut) {
369 buf.put_i64(v);
370}
371
372#[inline]
376pub fn timestamp_from_sql(mut buf: &[u8]) -> Result<i64, StdBox<dyn Error + Sync + Send>> {
377 let v = buf.read_i64::<BigEndian>()?;
378 if !buf.is_empty() {
379 return Err("invalid message length: timestamp not drained".into());
380 }
381 Ok(v)
382}
383
384#[inline]
388pub fn date_to_sql(v: i32, buf: &mut BytesMut) {
389 buf.put_i32(v);
390}
391
392#[inline]
396pub fn date_from_sql(mut buf: &[u8]) -> Result<i32, StdBox<dyn Error + Sync + Send>> {
397 let v = buf.read_i32::<BigEndian>()?;
398 if !buf.is_empty() {
399 return Err("invalid message length: date not drained".into());
400 }
401 Ok(v)
402}
403
404#[inline]
408pub fn time_to_sql(v: i64, buf: &mut BytesMut) {
409 buf.put_i64(v);
410}
411
412#[inline]
416pub fn time_from_sql(mut buf: &[u8]) -> Result<i64, StdBox<dyn Error + Sync + Send>> {
417 let v = buf.read_i64::<BigEndian>()?;
418 if !buf.is_empty() {
419 return Err("invalid message length: time not drained".into());
420 }
421 Ok(v)
422}
423
424#[inline]
426pub fn macaddr_to_sql(v: [u8; 6], buf: &mut BytesMut) {
427 buf.put_slice(&v);
428}
429
430#[inline]
432pub fn macaddr_from_sql(buf: &[u8]) -> Result<[u8; 6], StdBox<dyn Error + Sync + Send>> {
433 if buf.len() != 6 {
434 return Err("invalid message length: macaddr length mismatch".into());
435 }
436 let mut out = [0; 6];
437 out.copy_from_slice(buf);
438 Ok(out)
439}
440
441#[inline]
443pub fn uuid_to_sql(v: [u8; 16], buf: &mut BytesMut) {
444 buf.put_slice(&v);
445}
446
447#[inline]
449pub fn uuid_from_sql(buf: &[u8]) -> Result<[u8; 16], StdBox<dyn Error + Sync + Send>> {
450 if buf.len() != 16 {
451 return Err("invalid message length: uuid size mismatch".into());
452 }
453 let mut out = [0; 16];
454 out.copy_from_slice(buf);
455 Ok(out)
456}
457
458#[inline]
460pub fn array_to_sql<T, I, J, F>(
461 dimensions: I,
462 element_type: Oid,
463 elements: J,
464 mut serializer: F,
465 buf: &mut BytesMut,
466) -> Result<(), StdBox<dyn Error + Sync + Send>>
467where
468 I: IntoIterator<Item = ArrayDimension>,
469 J: IntoIterator<Item = T>,
470 F: FnMut(T, &mut BytesMut) -> Result<IsNull, StdBox<dyn Error + Sync + Send>>,
471{
472 let dimensions_idx = buf.len();
473 buf.put_i32(0);
474 let flags_idx = buf.len();
475 buf.put_i32(0);
476 buf.put_u32(element_type);
477
478 let mut num_dimensions = 0;
479 for dimension in dimensions {
480 num_dimensions += 1;
481 buf.put_i32(dimension.len);
482 buf.put_i32(dimension.lower_bound);
483 }
484
485 let num_dimensions = i32::from_usize(num_dimensions)?;
486 BigEndian::write_i32(&mut buf[dimensions_idx..], num_dimensions);
487
488 let mut has_nulls = false;
489 for element in elements {
490 write_nullable(
491 |buf| {
492 let r = serializer(element, buf);
493 if let Ok(IsNull::Yes) = r {
494 has_nulls = true;
495 }
496 r
497 },
498 buf,
499 )?;
500 }
501
502 BigEndian::write_i32(&mut buf[flags_idx..], has_nulls as i32);
503
504 Ok(())
505}
506
507#[inline]
509pub fn array_from_sql(mut buf: &[u8]) -> Result<Array<'_>, StdBox<dyn Error + Sync + Send>> {
510 let dimensions = buf.read_i32::<BigEndian>()?;
511 if dimensions < 0 {
512 return Err("invalid dimension count".into());
513 }
514 let has_nulls = buf.read_i32::<BigEndian>()? != 0;
515 let element_type = buf.read_u32::<BigEndian>()?;
516
517 let mut r = buf;
518 let mut elements = 1i32;
519 for _ in 0..dimensions {
520 let len = r.read_i32::<BigEndian>()?;
521 if len < 0 {
522 return Err("invalid dimension size".into());
523 }
524 let _lower_bound = r.read_i32::<BigEndian>()?;
525 elements = match elements.checked_mul(len) {
526 Some(elements) => elements,
527 None => return Err("too many array elements".into()),
528 };
529 }
530
531 if dimensions == 0 {
532 elements = 0;
533 }
534
535 Ok(Array {
536 dimensions,
537 has_nulls,
538 element_type,
539 elements,
540 buf,
541 })
542}
543
544pub struct Array<'a> {
546 dimensions: i32,
547 has_nulls: bool,
548 element_type: Oid,
549 elements: i32,
550 buf: &'a [u8],
551}
552
553impl<'a> Array<'a> {
554 #[inline]
556 pub fn has_nulls(&self) -> bool {
557 self.has_nulls
558 }
559
560 #[inline]
562 pub fn element_type(&self) -> Oid {
563 self.element_type
564 }
565
566 #[inline]
568 pub fn dimensions(&self) -> ArrayDimensions<'a> {
569 ArrayDimensions(&self.buf[..self.dimensions as usize * 8])
570 }
571
572 #[inline]
574 pub fn values(&self) -> ArrayValues<'a> {
575 ArrayValues {
576 remaining: self.elements,
577 buf: &self.buf[self.dimensions as usize * 8..],
578 }
579 }
580}
581
582pub struct ArrayDimensions<'a>(&'a [u8]);
584
585impl FallibleIterator for ArrayDimensions<'_> {
586 type Item = ArrayDimension;
587 type Error = StdBox<dyn Error + Sync + Send>;
588
589 #[inline]
590 fn next(&mut self) -> Result<Option<ArrayDimension>, StdBox<dyn Error + Sync + Send>> {
591 if self.0.is_empty() {
592 return Ok(None);
593 }
594
595 let len = self.0.read_i32::<BigEndian>()?;
596 let lower_bound = self.0.read_i32::<BigEndian>()?;
597
598 Ok(Some(ArrayDimension { len, lower_bound }))
599 }
600
601 #[inline]
602 fn size_hint(&self) -> (usize, Option<usize>) {
603 let len = self.0.len() / 8;
604 (len, Some(len))
605 }
606}
607
608#[derive(Debug, Copy, Clone, PartialEq, Eq)]
610pub struct ArrayDimension {
611 pub len: i32,
613
614 pub lower_bound: i32,
616}
617
618pub struct ArrayValues<'a> {
620 remaining: i32,
621 buf: &'a [u8],
622}
623
624impl<'a> FallibleIterator for ArrayValues<'a> {
625 type Item = Option<&'a [u8]>;
626 type Error = StdBox<dyn Error + Sync + Send>;
627
628 #[inline]
629 fn next(&mut self) -> Result<Option<Option<&'a [u8]>>, StdBox<dyn Error + Sync + Send>> {
630 if self.remaining == 0 {
631 if !self.buf.is_empty() {
632 return Err("invalid message length: arrayvalue not drained".into());
633 }
634 return Ok(None);
635 }
636 self.remaining -= 1;
637
638 let len = self.buf.read_i32::<BigEndian>()?;
639 let val = if len < 0 {
640 None
641 } else {
642 if self.buf.len() < len as usize {
643 return Err("invalid value length".into());
644 }
645
646 let (val, buf) = self.buf.split_at(len as usize);
647 self.buf = buf;
648 Some(val)
649 };
650
651 Ok(Some(val))
652 }
653
654 fn size_hint(&self) -> (usize, Option<usize>) {
655 let len = self.remaining as usize;
656 (len, Some(len))
657 }
658}
659
660#[inline]
662pub fn empty_range_to_sql(buf: &mut BytesMut) {
663 buf.put_u8(RANGE_EMPTY);
664}
665
666pub fn range_to_sql<F, G>(
668 lower: F,
669 upper: G,
670 buf: &mut BytesMut,
671) -> Result<(), StdBox<dyn Error + Sync + Send>>
672where
673 F: FnOnce(&mut BytesMut) -> Result<RangeBound<IsNull>, StdBox<dyn Error + Sync + Send>>,
674 G: FnOnce(&mut BytesMut) -> Result<RangeBound<IsNull>, StdBox<dyn Error + Sync + Send>>,
675{
676 let tag_idx = buf.len();
677 buf.put_u8(0);
678 let mut tag = 0;
679
680 match write_bound(lower, buf)? {
681 RangeBound::Inclusive(()) => tag |= RANGE_LOWER_INCLUSIVE,
682 RangeBound::Exclusive(()) => {}
683 RangeBound::Unbounded => tag |= RANGE_LOWER_UNBOUNDED,
684 }
685
686 match write_bound(upper, buf)? {
687 RangeBound::Inclusive(()) => tag |= RANGE_UPPER_INCLUSIVE,
688 RangeBound::Exclusive(()) => {}
689 RangeBound::Unbounded => tag |= RANGE_UPPER_UNBOUNDED,
690 }
691
692 buf[tag_idx] = tag;
693
694 Ok(())
695}
696
697fn write_bound<F>(
698 bound: F,
699 buf: &mut BytesMut,
700) -> Result<RangeBound<()>, StdBox<dyn Error + Sync + Send>>
701where
702 F: FnOnce(&mut BytesMut) -> Result<RangeBound<IsNull>, StdBox<dyn Error + Sync + Send>>,
703{
704 let base = buf.len();
705 buf.put_i32(0);
706
707 let (null, ret) = match bound(buf)? {
708 RangeBound::Inclusive(null) => (Some(null), RangeBound::Inclusive(())),
709 RangeBound::Exclusive(null) => (Some(null), RangeBound::Exclusive(())),
710 RangeBound::Unbounded => (None, RangeBound::Unbounded),
711 };
712
713 match null {
714 Some(null) => {
715 let len = match null {
716 IsNull::No => i32::from_usize(buf.len() - base - 4)?,
717 IsNull::Yes => -1,
718 };
719 BigEndian::write_i32(&mut buf[base..], len);
720 }
721 None => buf.truncate(base),
722 }
723
724 Ok(ret)
725}
726
727pub enum RangeBound<T> {
729 Inclusive(T),
731 Exclusive(T),
733 Unbounded,
735}
736
737#[inline]
739pub fn range_from_sql(mut buf: &[u8]) -> Result<Range<'_>, StdBox<dyn Error + Sync + Send>> {
740 let tag = buf.read_u8()?;
741
742 if tag == RANGE_EMPTY {
743 if !buf.is_empty() {
744 return Err("invalid message size".into());
745 }
746 return Ok(Range::Empty);
747 }
748
749 let lower = read_bound(&mut buf, tag, RANGE_LOWER_UNBOUNDED, RANGE_LOWER_INCLUSIVE)?;
750 let upper = read_bound(&mut buf, tag, RANGE_UPPER_UNBOUNDED, RANGE_UPPER_INCLUSIVE)?;
751
752 if !buf.is_empty() {
753 return Err("invalid message size".into());
754 }
755
756 Ok(Range::Nonempty(lower, upper))
757}
758
759#[inline]
760fn read_bound<'a>(
761 buf: &mut &'a [u8],
762 tag: u8,
763 unbounded: u8,
764 inclusive: u8,
765) -> Result<RangeBound<Option<&'a [u8]>>, StdBox<dyn Error + Sync + Send>> {
766 if tag & unbounded != 0 {
767 Ok(RangeBound::Unbounded)
768 } else {
769 let len = buf.read_i32::<BigEndian>()?;
770 let value = if len < 0 {
771 None
772 } else {
773 let len = len as usize;
774 if buf.len() < len {
775 return Err("invalid message size".into());
776 }
777 let (value, tail) = buf.split_at(len);
778 *buf = tail;
779 Some(value)
780 };
781
782 if tag & inclusive != 0 {
783 Ok(RangeBound::Inclusive(value))
784 } else {
785 Ok(RangeBound::Exclusive(value))
786 }
787 }
788}
789
790pub enum Range<'a> {
792 Empty,
794 Nonempty(RangeBound<Option<&'a [u8]>>, RangeBound<Option<&'a [u8]>>),
796}
797
798#[inline]
800pub fn point_to_sql(x: f64, y: f64, buf: &mut BytesMut) {
801 buf.put_f64(x);
802 buf.put_f64(y);
803}
804
805#[inline]
807pub fn point_from_sql(mut buf: &[u8]) -> Result<Point, StdBox<dyn Error + Sync + Send>> {
808 let x = buf.read_f64::<BigEndian>()?;
809 let y = buf.read_f64::<BigEndian>()?;
810 if !buf.is_empty() {
811 return Err("invalid buffer size".into());
812 }
813 Ok(Point { x, y })
814}
815
816#[derive(Copy, Clone)]
818pub struct Point {
819 x: f64,
820 y: f64,
821}
822
823impl Point {
824 #[inline]
826 pub fn x(&self) -> f64 {
827 self.x
828 }
829
830 #[inline]
832 pub fn y(&self) -> f64 {
833 self.y
834 }
835}
836
837#[inline]
839pub fn box_to_sql(x1: f64, y1: f64, x2: f64, y2: f64, buf: &mut BytesMut) {
840 buf.put_f64(x1);
841 buf.put_f64(y1);
842 buf.put_f64(x2);
843 buf.put_f64(y2);
844}
845
846#[inline]
848pub fn box_from_sql(mut buf: &[u8]) -> Result<Box, StdBox<dyn Error + Sync + Send>> {
849 let x1 = buf.read_f64::<BigEndian>()?;
850 let y1 = buf.read_f64::<BigEndian>()?;
851 let x2 = buf.read_f64::<BigEndian>()?;
852 let y2 = buf.read_f64::<BigEndian>()?;
853 if !buf.is_empty() {
854 return Err("invalid buffer size".into());
855 }
856 Ok(Box {
857 upper_right: Point { x: x1, y: y1 },
858 lower_left: Point { x: x2, y: y2 },
859 })
860}
861
862#[derive(Copy, Clone)]
864pub struct Box {
865 upper_right: Point,
866 lower_left: Point,
867}
868
869impl Box {
870 #[inline]
872 pub fn upper_right(&self) -> Point {
873 self.upper_right
874 }
875
876 #[inline]
878 pub fn lower_left(&self) -> Point {
879 self.lower_left
880 }
881}
882
883#[inline]
885pub fn path_to_sql<I>(
886 closed: bool,
887 points: I,
888 buf: &mut BytesMut,
889) -> Result<(), StdBox<dyn Error + Sync + Send>>
890where
891 I: IntoIterator<Item = (f64, f64)>,
892{
893 buf.put_u8(closed as u8);
894 let points_idx = buf.len();
895 buf.put_i32(0);
896
897 let mut num_points = 0;
898 for (x, y) in points {
899 num_points += 1;
900 buf.put_f64(x);
901 buf.put_f64(y);
902 }
903
904 let num_points = i32::from_usize(num_points)?;
905 BigEndian::write_i32(&mut buf[points_idx..], num_points);
906
907 Ok(())
908}
909
910#[inline]
912pub fn path_from_sql(mut buf: &[u8]) -> Result<Path<'_>, StdBox<dyn Error + Sync + Send>> {
913 let closed = buf.read_u8()? != 0;
914 let points = buf.read_i32::<BigEndian>()?;
915
916 Ok(Path {
917 closed,
918 points,
919 buf,
920 })
921}
922
923pub struct Path<'a> {
925 closed: bool,
926 points: i32,
927 buf: &'a [u8],
928}
929
930impl<'a> Path<'a> {
931 #[inline]
933 pub fn closed(&self) -> bool {
934 self.closed
935 }
936
937 #[inline]
939 pub fn points(&self) -> PathPoints<'a> {
940 PathPoints {
941 remaining: self.points,
942 buf: self.buf,
943 }
944 }
945}
946
947pub struct PathPoints<'a> {
949 remaining: i32,
950 buf: &'a [u8],
951}
952
953impl FallibleIterator for PathPoints<'_> {
954 type Item = Point;
955 type Error = StdBox<dyn Error + Sync + Send>;
956
957 #[inline]
958 fn next(&mut self) -> Result<Option<Point>, StdBox<dyn Error + Sync + Send>> {
959 if self.remaining == 0 {
960 if !self.buf.is_empty() {
961 return Err("invalid message length: path points not drained".into());
962 }
963 return Ok(None);
964 }
965 self.remaining -= 1;
966
967 let x = self.buf.read_f64::<BigEndian>()?;
968 let y = self.buf.read_f64::<BigEndian>()?;
969
970 Ok(Some(Point { x, y }))
971 }
972
973 #[inline]
974 fn size_hint(&self) -> (usize, Option<usize>) {
975 let len = self.remaining as usize;
976 (len, Some(len))
977 }
978}
979
980#[inline]
982pub fn inet_to_sql(addr: IpAddr, netmask: u8, buf: &mut BytesMut) {
983 let family = match addr {
984 IpAddr::V4(_) => PGSQL_AF_INET,
985 IpAddr::V6(_) => PGSQL_AF_INET6,
986 };
987 buf.put_u8(family);
988 buf.put_u8(netmask);
989 buf.put_u8(0); match addr {
991 IpAddr::V4(addr) => {
992 buf.put_u8(4);
993 buf.put_slice(&addr.octets());
994 }
995 IpAddr::V6(addr) => {
996 buf.put_u8(16);
997 buf.put_slice(&addr.octets());
998 }
999 }
1000}
1001
1002#[inline]
1004pub fn inet_from_sql(mut buf: &[u8]) -> Result<Inet, StdBox<dyn Error + Sync + Send>> {
1005 let family = buf.read_u8()?;
1006 let netmask = buf.read_u8()?;
1007 buf.read_u8()?; let len = buf.read_u8()?;
1009
1010 let addr = match family {
1011 PGSQL_AF_INET => {
1012 if netmask > 32 {
1013 return Err("invalid IPv4 netmask".into());
1014 }
1015 if len != 4 {
1016 return Err("invalid IPv4 address length".into());
1017 }
1018 let mut addr = [0; 4];
1019 buf.read_exact(&mut addr)?;
1020 IpAddr::V4(Ipv4Addr::from(addr))
1021 }
1022 PGSQL_AF_INET6 => {
1023 if netmask > 128 {
1024 return Err("invalid IPv6 netmask".into());
1025 }
1026 if len != 16 {
1027 return Err("invalid IPv6 address length".into());
1028 }
1029 let mut addr = [0; 16];
1030 buf.read_exact(&mut addr)?;
1031 IpAddr::V6(Ipv6Addr::from(addr))
1032 }
1033 _ => return Err("invalid IP family".into()),
1034 };
1035
1036 if !buf.is_empty() {
1037 return Err("invalid buffer size".into());
1038 }
1039
1040 Ok(Inet { addr, netmask })
1041}
1042
1043pub struct Inet {
1045 addr: IpAddr,
1046 netmask: u8,
1047}
1048
1049impl Inet {
1050 #[inline]
1052 pub fn addr(&self) -> IpAddr {
1053 self.addr
1054 }
1055
1056 #[inline]
1058 pub fn netmask(&self) -> u8 {
1059 self.netmask
1060 }
1061}
1062
1063#[inline]
1065pub fn ltree_to_sql(v: &str, buf: &mut BytesMut) {
1066 buf.put_u8(1);
1068 buf.put_slice(v.as_bytes());
1070}
1071
1072#[inline]
1074pub fn ltree_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
1075 match buf {
1076 [1u8, rest @ ..] => Ok(str::from_utf8(rest)?),
1078 _ => Err("ltree version 1 only supported".into()),
1079 }
1080}
1081
1082#[inline]
1084pub fn lquery_to_sql(v: &str, buf: &mut BytesMut) {
1085 buf.put_u8(1);
1087 buf.put_slice(v.as_bytes());
1089}
1090
1091#[inline]
1093pub fn lquery_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
1094 match buf {
1095 [1u8, rest @ ..] => Ok(str::from_utf8(rest)?),
1097 _ => Err("lquery version 1 only supported".into()),
1098 }
1099}
1100
1101#[inline]
1103pub fn ltxtquery_to_sql(v: &str, buf: &mut BytesMut) {
1104 buf.put_u8(1);
1106 buf.put_slice(v.as_bytes());
1108}
1109
1110#[inline]
1112pub fn ltxtquery_from_sql(buf: &[u8]) -> Result<&str, StdBox<dyn Error + Sync + Send>> {
1113 match buf {
1114 [1u8, rest @ ..] => Ok(str::from_utf8(rest)?),
1116 _ => Err("ltxtquery version 1 only supported".into()),
1117 }
1118}