rbdc_pg/types/
byte.rs

1use crate::arguments::PgArgumentBuffer;
2use crate::types::decode::Decode;
3use crate::types::encode::{Encode, IsNull};
4use crate::value::{PgValue, PgValueFormat};
5use rbdc::Error;
6use rbs::Value;
7use std::fmt::{Display, Formatter};
8
9#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)]
10#[serde(rename = "Bytea")]
11pub struct Bytea(pub Vec<u8>);
12
13impl Display for Bytea {
14    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15        write!(f, "[len={}]", self.0.len())
16    }
17}
18
19impl Encode for Bytea {
20    fn encode(self, buf: &mut PgArgumentBuffer) -> Result<IsNull, Error> {
21        Encode::encode(self.0, buf)
22    }
23}
24
25impl Decode for Bytea {
26    fn decode(value: PgValue) -> Result<Self, Error> {
27        // note: in the TEXT encoding, a value of "0" here is encoded as an empty string
28        Ok(Self(Vec::<u8>::decode(value)?))
29    }
30}
31
32impl From<Bytea> for Value {
33    fn from(arg: Bytea) -> Self {
34        Value::Ext("Bytea", Box::new(Value::Binary(arg.0)))
35    }
36}
37
38impl Encode for &[u8] {
39    fn encode(self, buf: &mut PgArgumentBuffer) -> Result<IsNull, Error> {
40        buf.extend_from_slice(self);
41        Ok(IsNull::No)
42    }
43}
44
45impl Encode for Vec<u8> {
46    fn encode(self, buf: &mut PgArgumentBuffer) -> Result<IsNull, Error> {
47        buf.extend(self);
48        Ok(IsNull::No)
49    }
50}
51
52impl Decode for Vec<u8> {
53    fn decode(value: PgValue) -> Result<Self, Error> {
54        match value.format() {
55            PgValueFormat::Binary => value.into_bytes(),
56            PgValueFormat::Text => {
57                hex::decode(text_hex_decode_input(&value)?).map_err(|e| Error::from(e.to_string()))
58            }
59        }
60    }
61}
62
63fn text_hex_decode_input(value: &PgValue) -> Result<&[u8], Error> {
64    // BYTEA is formatted as \x followed by hex characters
65    value
66        .as_bytes()?
67        .strip_prefix(b"\\x")
68        .ok_or("text does not start with \\x")
69        .map_err(Into::into)
70}