feat(proto): add protocol primitives

This commit is contained in:
Jindřich Moravec 2023-12-11 16:36:52 +01:00
parent f70fd6250b
commit aa649769d2
7 changed files with 173 additions and 0 deletions

1
proto/src/message/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod primitive;

View file

@ -0,0 +1,7 @@
use bincode::config::{BigEndian, Configuration, Fixint};
pub fn pg_proto_config() -> Configuration<BigEndian, Fixint> {
bincode::config::standard()
.with_big_endian()
.with_fixed_int_encoding()
}

View file

@ -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<Self>;
fn serialize(&self) -> anyhow::Result<Vec<u8>>;
}
impl<T> MessageData for T
where
T: Encode + Decode,
{
#[inline]
fn deserialize(data: &[u8]) -> anyhow::Result<Self> {
Ok(bincode::decode_from_slice(data, pg_proto_config())?.0)
}
#[inline]
fn serialize(&self) -> anyhow::Result<Vec<u8>> {
Ok(bincode::encode_to_vec(self, pg_proto_config())?)
}
}

View file

@ -0,0 +1,4 @@
pub(crate) mod config;
pub(crate) mod data;
pub mod pglist;
pub mod pgstring;

View file

@ -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<T, U>(Vec<T>, PhantomData<U>);
impl<T, U> PgList<T, U> {
pub fn as_slice(&self) -> &[T] {
&self.0
}
}
impl<T, U> From<PgList<T, U>> for Vec<T> {
fn from(pg_list: PgList<T, U>) -> Self {
pg_list.0
}
}
impl<T, U> From<Vec<T>> for PgList<T, U> {
fn from(list: Vec<T>) -> Self {
PgList(list, PhantomData)
}
}
impl<T> Encode for PgList<T, i16>
where
T: Encode,
{
fn encode<E: Encoder>(&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<T> Decode for PgList<T, i16>
where
T: Decode,
{
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let length = i16::decode(decoder)?;
let mut list = Vec::new();
for _ in 0..length {
list.push(T::decode(decoder)?);
}
Ok(PgList(list, PhantomData))
}
}
impl<T> Encode for PgList<T, i32>
where
T: Encode,
{
fn encode<E: Encoder>(&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<T> Decode for PgList<T, i32>
where
T: Decode,
{
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let length = i32::decode(decoder)?;
let mut list = Vec::new();
for _ in 0..length {
list.push(T::decode(decoder)?);
}
Ok(PgList(list, PhantomData))
}
}

View file

@ -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<PgString> for String {
fn from(pg_string: PgString) -> Self {
pg_string.0
}
}
impl From<String> for PgString {
fn from(string: String) -> Self {
PgString(string)
}
}
impl Encode for PgString {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
encoder.writer().write(self.0.as_bytes())?;
encoder.writer().write(b"\0")
}
}
impl Decode for PgString {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let mut string = String::new();
loop {
let byte = u8::decode(decoder)?;
if byte == 0 {
break;
}
string.push(byte as char);
}
Ok(PgString(string))
}
}