sqlx_postgres/types/
bytes.rs

1use crate::decode::Decode;
2use crate::encode::{Encode, IsNull};
3use crate::error::BoxDynError;
4use crate::types::Type;
5use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
6
7impl PgHasArrayType for u8 {
8    fn array_type_info() -> PgTypeInfo {
9        PgTypeInfo::BYTEA
10    }
11}
12
13impl PgHasArrayType for &'_ [u8] {
14    fn array_type_info() -> PgTypeInfo {
15        PgTypeInfo::BYTEA_ARRAY
16    }
17}
18
19impl<const N: usize> PgHasArrayType for &'_ [u8; N] {
20    fn array_type_info() -> PgTypeInfo {
21        PgTypeInfo::BYTEA_ARRAY
22    }
23}
24
25impl PgHasArrayType for Box<[u8]> {
26    fn array_type_info() -> PgTypeInfo {
27        <[&[u8]] as Type<Postgres>>::type_info()
28    }
29}
30
31impl PgHasArrayType for Vec<u8> {
32    fn array_type_info() -> PgTypeInfo {
33        <[&[u8]] as Type<Postgres>>::type_info()
34    }
35}
36
37impl<const N: usize> PgHasArrayType for [u8; N] {
38    fn array_type_info() -> PgTypeInfo {
39        <[&[u8]] as Type<Postgres>>::type_info()
40    }
41}
42
43impl Encode<'_, Postgres> for &'_ [u8] {
44    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
45        buf.extend_from_slice(self);
46
47        IsNull::No
48    }
49}
50
51impl Encode<'_, Postgres> for Box<[u8]> {
52    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
53        <&[u8] as Encode<Postgres>>::encode(self.as_ref(), buf)
54    }
55}
56
57impl Encode<'_, Postgres> for Vec<u8> {
58    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
59        <&[u8] as Encode<Postgres>>::encode(self, buf)
60    }
61}
62
63impl<const N: usize> Encode<'_, Postgres> for [u8; N] {
64    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
65        <&[u8] as Encode<Postgres>>::encode(self.as_slice(), buf)
66    }
67}
68
69impl<'r> Decode<'r, Postgres> for &'r [u8] {
70    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
71        match value.format() {
72            PgValueFormat::Binary => value.as_bytes(),
73            PgValueFormat::Text => {
74                Err("unsupported decode to `&[u8]` of BYTEA in a simple query; use a prepared query or decode to `Vec<u8>`".into())
75            }
76        }
77    }
78}
79
80fn text_hex_decode_input(value: PgValueRef<'_>) -> Result<&[u8], BoxDynError> {
81    // BYTEA is formatted as \x followed by hex characters
82    value
83        .as_bytes()?
84        .strip_prefix(b"\\x")
85        .ok_or("text does not start with \\x")
86        .map_err(Into::into)
87}
88
89impl Decode<'_, Postgres> for Box<[u8]> {
90    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
91        Ok(match value.format() {
92            PgValueFormat::Binary => Box::from(value.as_bytes()?),
93            PgValueFormat::Text => Box::from(hex::decode(text_hex_decode_input(value)?)?),
94        })
95    }
96}
97
98impl Decode<'_, Postgres> for Vec<u8> {
99    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
100        Ok(match value.format() {
101            PgValueFormat::Binary => value.as_bytes()?.to_owned(),
102            PgValueFormat::Text => hex::decode(text_hex_decode_input(value)?)?,
103        })
104    }
105}
106
107impl<const N: usize> Decode<'_, Postgres> for [u8; N] {
108    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
109        let mut bytes = [0u8; N];
110        match value.format() {
111            PgValueFormat::Binary => {
112                bytes = value.as_bytes()?.try_into()?;
113            }
114            PgValueFormat::Text => hex::decode_to_slice(text_hex_decode_input(value)?, &mut bytes)?,
115        };
116        Ok(bytes)
117    }
118}