diff --git a/proto/src/lib.rs b/proto/src/lib.rs index e69de29..e216a50 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -0,0 +1 @@ +pub mod message; diff --git a/proto/src/message/mod.rs b/proto/src/message/mod.rs new file mode 100644 index 0000000..2d8afe5 --- /dev/null +++ b/proto/src/message/mod.rs @@ -0,0 +1 @@ +pub mod primitive; diff --git a/proto/src/message/primitive/config.rs b/proto/src/message/primitive/config.rs new file mode 100644 index 0000000..5aa74f5 --- /dev/null +++ b/proto/src/message/primitive/config.rs @@ -0,0 +1,7 @@ +use bincode::config::{BigEndian, Configuration, Fixint}; + +pub fn pg_proto_config() -> Configuration { + bincode::config::standard() + .with_big_endian() + .with_fixed_int_encoding() +} diff --git a/proto/src/message/primitive/data.rs b/proto/src/message/primitive/data.rs new file mode 100644 index 0000000..41af0f6 --- /dev/null +++ b/proto/src/message/primitive/data.rs @@ -0,0 +1,22 @@ +use crate::message::primitive::config::pg_proto_config; +use bincode::{Decode, Encode}; + +pub trait MessageData: Sized { + fn deserialize(data: &[u8]) -> anyhow::Result; + fn serialize(&self) -> anyhow::Result>; +} + +impl MessageData for T +where + T: Encode + Decode, +{ + #[inline] + fn deserialize(data: &[u8]) -> anyhow::Result { + Ok(bincode::decode_from_slice(data, pg_proto_config())?.0) + } + + #[inline] + fn serialize(&self) -> anyhow::Result> { + Ok(bincode::encode_to_vec(self, pg_proto_config())?) + } +} diff --git a/proto/src/message/primitive/mod.rs b/proto/src/message/primitive/mod.rs new file mode 100644 index 0000000..e275e6e --- /dev/null +++ b/proto/src/message/primitive/mod.rs @@ -0,0 +1,4 @@ +pub(crate) mod config; +pub(crate) mod data; +pub mod pglist; +pub mod pgstring; diff --git a/proto/src/message/primitive/pglist.rs b/proto/src/message/primitive/pglist.rs new file mode 100644 index 0000000..aa95ca2 --- /dev/null +++ b/proto/src/message/primitive/pglist.rs @@ -0,0 +1,84 @@ +use bincode::de::Decoder; +use bincode::enc::Encoder; +use bincode::error::{DecodeError, EncodeError}; +use bincode::{BorrowDecode, Decode, Encode}; +use std::marker::PhantomData; + +#[derive(Debug, Clone, PartialEq, BorrowDecode)] +pub struct PgList(Vec, PhantomData); + +impl PgList { + pub fn as_slice(&self) -> &[T] { + &self.0 + } +} + +impl From> for Vec { + fn from(pg_list: PgList) -> Self { + pg_list.0 + } +} + +impl From> for PgList { + fn from(list: Vec) -> Self { + PgList(list, PhantomData) + } +} + +impl Encode for PgList +where + T: Encode, +{ + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + let length = self.0.len() as i16; + length.encode(encoder)?; + for item in &self.0 { + item.encode(encoder)?; + } + Ok(()) + } +} + +impl Decode for PgList +where + T: Decode, +{ + fn decode(decoder: &mut D) -> Result { + let length = i16::decode(decoder)?; + let mut list = Vec::new(); + for _ in 0..length { + list.push(T::decode(decoder)?); + } + + Ok(PgList(list, PhantomData)) + } +} + +impl Encode for PgList +where + T: Encode, +{ + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + let length = self.0.len() as i32; + length.encode(encoder)?; + for item in &self.0 { + item.encode(encoder)?; + } + Ok(()) + } +} + +impl Decode for PgList +where + T: Decode, +{ + fn decode(decoder: &mut D) -> Result { + let length = i32::decode(decoder)?; + let mut list = Vec::new(); + for _ in 0..length { + list.push(T::decode(decoder)?); + } + + Ok(PgList(list, PhantomData)) + } +} diff --git a/proto/src/message/primitive/pgstring.rs b/proto/src/message/primitive/pgstring.rs new file mode 100644 index 0000000..2c6cd7b --- /dev/null +++ b/proto/src/message/primitive/pgstring.rs @@ -0,0 +1,54 @@ +use bincode::de::Decoder; +use bincode::enc::write::Writer; +use bincode::enc::Encoder; +use bincode::error::{DecodeError, EncodeError}; +use bincode::{BorrowDecode, Decode, Encode}; + +#[derive(Debug, Clone, BorrowDecode)] +pub struct PgString(String); + +impl PgString { + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From<&str> for PgString { + fn from(string: &str) -> Self { + PgString(string.to_string()) + } +} + +impl From for String { + fn from(pg_string: PgString) -> Self { + pg_string.0 + } +} + +impl From for PgString { + fn from(string: String) -> Self { + PgString(string) + } +} + +impl Encode for PgString { + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.writer().write(self.0.as_bytes())?; + encoder.writer().write(b"\0") + } +} + +impl Decode for PgString { + fn decode(decoder: &mut D) -> Result { + let mut string = String::new(); + loop { + let byte = u8::decode(decoder)?; + if byte == 0 { + break; + } + string.push(byte as char); + } + + Ok(PgString(string)) + } +}