From 8bae725a803ee00bf5bc86b9fc0be6853b95115e Mon Sep 17 00:00:00 2001 From: zirkonya Date: Tue, 25 Aug 2026 18:41:28 +0200 Subject: Add getset ; prepare event and backend --- Cargo.lock | 70 ++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/backend.rs | 1 + src/codec/decode.rs | 3 ++ src/codec/encode.rs | 21 +++++++++-- src/codec/error.rs | 2 + src/context.rs | 5 --- src/event.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++++ src/event/handler.rs | 2 + src/event/listener.rs | 1 + src/lib.rs | 3 ++ src/types/prefix/count.rs | 4 ++ src/types/prefix/length.rs | 11 +++--- 13 files changed, 204 insertions(+), 14 deletions(-) create mode 100644 src/backend.rs create mode 100644 src/event.rs create mode 100644 src/event/handler.rs create mode 100644 src/event/listener.rs diff --git a/Cargo.lock b/Cargo.lock index 218b486..b9bf857 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,76 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "getset" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cf442baaabe4213ce7d1239afc26c039180b6456da2cededa316ae2c8a77a77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + [[package]] name = "zr_protocol" version = "0.1.1" +dependencies = [ + "getset", + "zr_protocol_macros", +] + +[[package]] +name = "zr_protocol_macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] diff --git a/Cargo.toml b/Cargo.toml index 07c20eb..776e589 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.1" edition = "2024" [dependencies] +getset = "0.1.7" zr_protocol_macros = { version = "0.1.0", path = "macros", optional = true } [features] diff --git a/src/backend.rs b/src/backend.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/backend.rs @@ -0,0 +1 @@ + diff --git a/src/codec/decode.rs b/src/codec/decode.rs index 31ed725..fa4ae95 100644 --- a/src/codec/decode.rs +++ b/src/codec/decode.rs @@ -1,3 +1,4 @@ +//! Decoding: reading protocol values from a byte stream. use std::{io::Read, sync::Arc}; use crate::{DEFAULT_BUFFER_LEN, codec::error::Result}; @@ -5,6 +6,7 @@ use crate::{DEFAULT_BUFFER_LEN, codec::error::Result}; macro_rules! impl_decode { ($type: ty) => { impl Decode for $type { + // decode number using big endian fn decode(reader: &mut dyn Read, _: &mut Ctx) -> Result where Self: Sized, @@ -18,6 +20,7 @@ macro_rules! impl_decode { }; } +/// Read a value from a byte stream pub trait Decode { fn decode(reader: &mut dyn Read, ctx: &mut Ctx) -> Result where diff --git a/src/codec/encode.rs b/src/codec/encode.rs index bd76605..c8d1c7b 100644 --- a/src/codec/encode.rs +++ b/src/codec/encode.rs @@ -1,9 +1,11 @@ +//! Encoding: writing protocol values into a byte stream. use crate::codec::error::Error; use std::{io::Write, sync::Arc}; macro_rules! impl_encode { ($t: ty) => { impl Encode for $t { + /// write number using big endian fn encode(&self, buffer: &mut dyn Write, _: &mut Ctx) -> Result { let size = buffer.write(&self.to_be_bytes())?; Ok(size) @@ -12,6 +14,7 @@ macro_rules! impl_encode { }; } +/// Write a value into a byte stream pub trait Encode { fn encode(&self, buffer: &mut dyn Write, ctx: &mut Ctx) -> Result; } @@ -24,21 +27,24 @@ impl Encode for bool { } impl> Encode for Option { + /// Encode `T` if Some(T) or do nothing if None fn encode(&self, buffer: &mut dyn Write, ctx: &mut Ctx) -> Result { match self { Some(val) => { - let mut size = 1u8.encode(buffer, ctx)?; - size += val.encode(buffer, ctx)?; + let size = val.encode(buffer, ctx)?; Ok(size) } - None => 0u8.encode(buffer, ctx), + None => Ok(0), } } } impl> Encode for Vec { + /// Encode each element of vector + /// use `CountPrefix` to prefix the vector with number of elements + /// use `LenPrefix` to prefix the vector with encoded byte size fn encode(&self, buffer: &mut dyn Write, ctx: &mut Ctx) -> Result { - let mut size = self.len().encode(buffer, ctx)?; + let mut size = 0; for item in self { size += item.encode(buffer, ctx)?; } @@ -47,6 +53,9 @@ impl> Encode for Vec { } impl Encode for String { + /// Encode the string using utf8 + /// use `CountPrefix` to prefix the string with char length + /// use `LenPrefix` to prefix the string with utf8 bytes length fn encode(&self, buffer: &mut dyn Write, _: &mut Ctx) -> Result { let utf8 = self.as_bytes(); buffer.write_all(utf8)?; @@ -55,6 +64,8 @@ impl Encode for String { } impl Encode for Arc<[u8]> { + /// write raw slice into the buffer + /// use `LenPrefix` to prefix with byte length fn encode(&self, buffer: &mut dyn Write, _: &mut Ctx) -> Result { let len = buffer.write(self)?; Ok(len) @@ -62,6 +73,8 @@ impl Encode for Arc<[u8]> { } impl Encode for [u8; S] { + /// write raw slice into the buffer + /// use `LenPrefix` to prefix with byte length fn encode(&self, buffer: &mut dyn Write, _ctx: &mut Ctx) -> Result { let len = buffer.write(self)?; Ok(len) diff --git a/src/codec/error.rs b/src/codec/error.rs index 6037a9a..c1bd4f7 100644 --- a/src/codec/error.rs +++ b/src/codec/error.rs @@ -1,5 +1,7 @@ use std::fmt::Display; +// TODO : better error (using thiserror) + #[derive(Debug)] pub enum Error { IoError(std::io::Error), diff --git a/src/context.rs b/src/context.rs index 47661d0..8b13789 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1 @@ -use std::any::Any; -pub trait Context { - fn get(&self, key: &str) -> Option<&dyn Any>; - fn set(&mut self, key: &str, value: &dyn Any); -} diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..bbba586 --- /dev/null +++ b/src/event.rs @@ -0,0 +1,94 @@ +use std::{io, net::SocketAddr, time::Instant}; + +use getset::{Getters, Setters}; + +pub mod handler; +pub mod listener; + +pub enum EventKind +where + Uid: PartialEq, +{ + Connection(ConnectionEvent), + PacketReceived(PacketReceivedEvent), + PacketSent(PacketSentEvent), + Disconnect(DisconnectEvent), +} + +// TODO : identification +// TODO : reason type +#[derive(Getters)] +pub struct ConnectionEvent +where + Uid: PartialEq, +{ + #[getset(get = "pub")] + peer_addr: SocketAddr, + #[getset(get = "pub")] + local_addr: SocketAddr, + #[getset(get = "pub")] + connection_id: Uid, +} +#[derive(Getters)] +pub struct PacketReceivedEvent { + #[getset(get = "pub")] + packet: Packet, +} +#[derive(Getters)] +pub struct PacketSentEvent { + #[getset(get = "pub")] + packet: Packet, +} + +// TODO : better error type for protocol violation +pub type ProtocolViolation = String; + +pub enum DisconnectReason { + Normal, + Error(io::Error), + ProtocolError(ProtocolViolation), + Timeout, + ServerShutdown, +} + +#[derive(Getters)] +pub struct DisconnectEvent +where + Uid: PartialEq, +{ + #[getset(get = "pub")] + connection_id: Uid, + #[getset(get = "pub")] + reason: DisconnectReason, +} + +#[derive(Getters, Setters)] +pub struct Event +where + Uid: PartialEq, +{ + #[getset(get = "pub")] + instant: Instant, + #[getset(get = "pub", set = "pub")] + canceled: bool, + #[getset(get = "pub")] + kind: EventKind, +} + +impl Event { + pub fn new(kind: EventKind) -> Self { + Self { + instant: Instant::now(), + canceled: false, + kind, + } + } + + pub fn differed(when: Instant, kind: EventKind) -> Self { + Self { + instant: when, + canceled: false, + kind, + } + } +} diff --git a/src/event/handler.rs b/src/event/handler.rs new file mode 100644 index 0000000..7d8b5b5 --- /dev/null +++ b/src/event/handler.rs @@ -0,0 +1,2 @@ +// TODO : dispatch event through all listener +// TODO : maybe compile listener into one ? diff --git a/src/event/listener.rs b/src/event/listener.rs new file mode 100644 index 0000000..178dda8 --- /dev/null +++ b/src/event/listener.rs @@ -0,0 +1 @@ +// TODO : Listener ; interface to perform action when event occured diff --git a/src/lib.rs b/src/lib.rs index ce2b14c..6ec9647 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,8 @@ +#[doc = include_str!("../README.md")] +pub mod backend; pub mod codec; pub mod context; +pub mod event; pub mod types; #[cfg(feature = "macros")] diff --git a/src/types/prefix/count.rs b/src/types/prefix/count.rs index 5f53e08..0896167 100644 --- a/src/types/prefix/count.rs +++ b/src/types/prefix/count.rs @@ -1,14 +1,18 @@ use std::{io::Read, marker::PhantomData}; +use getset::Getters; + use crate::{ codec::{Codec, decode::Decode, encode::Encode}, types::size::Size, }; +#[derive(Getters)] pub struct CountPrefix where D: IntoIterator, { + #[getset(get = "pub")] data: D, _len: PhantomData, } diff --git a/src/types/prefix/length.rs b/src/types/prefix/length.rs index 160fffc..3bb150a 100644 --- a/src/types/prefix/length.rs +++ b/src/types/prefix/length.rs @@ -1,12 +1,16 @@ use std::{io::Write, marker::PhantomData}; +use getset::Getters; + use crate::{ DEFAULT_BUFFER_LEN, codec::{self, Codec, decode::Decode, encode::Encode}, types::size::Size, }; +#[derive(Getters)] pub struct LenPrefixed { + #[getset(get = "pub")] data: D, _len: PhantomData, } @@ -46,16 +50,13 @@ impl AsMut for LenPrefixed { impl Encode for LenPrefixed where - L: Codec + Size + TryFrom, + L: Codec + Size, D: Codec, { fn encode(&self, writer: &mut dyn Write, ctx: &mut Ctx) -> Result { let mut buf = Vec::with_capacity(DEFAULT_BUFFER_LEN); self.data.encode(&mut buf, ctx)?; - let len: L = buf - .len() - .try_into() - .map_err(|_| codec::error::Error::Custom("length exceeds prefix capacity".into()))?; + let len = L::from_size(buf.len()); let mut l = len.encode(writer, ctx)?; l += writer.write(&buf)?; Ok(l) -- cgit v1.2.3