Skip to content
Merged

Proto #121

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
[workspace]
members = ["oxish"]
members = ["oxish", "oxish-proto"]
resolver = "2"

[workspace.dependencies]
anyhow = "1.0.95"
aws-lc-rs = { version = "1.12", features = ["prebuilt-nasm"] }
bitflags = "2"
clap = { version = "4.5.24", features = ["derive"] }
data-encoding = "2.10"
libc = "0.2"
listenfd = "1.0.2"
proto = { package = "oxish-proto", version = "0.1", path = "oxish-proto" }
thiserror = "2.0.9"
tokio = { version = "1.42", features = ["io-util", "macros", "net", "process", "rt-multi-thread", "time"] }
tokio-stream = "0.1.18"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
rustix = { version = "1", features = ["termios", "pty", "process", "fs", "stdio"] }

[workspace.lints.rust]
elided_lifetimes_in_paths = "warn"
trivial_numeric_casts = "warn"
Expand Down
13 changes: 13 additions & 0 deletions oxish-proto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "oxish-proto"
version = "0.1.0"
edition = "2021"
rust-version = "1.83"
license = "Apache-2.0 OR MIT"

[dependencies]
thiserror = { workspace = true }
tracing = { workspace = true }

[lints]
workspace = true
58 changes: 32 additions & 26 deletions oxish/src/messages/base.rs → oxish-proto/src/base.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use core::fmt;

use crate::Error;
use super::ProtoError;

pub(crate) struct IncomingPacket<'a> {
pub(crate) sequence_number: u32,
pub(crate) message_type: MessageType,
pub(crate) payload: &'a [u8],
pub struct IncomingPacket<'a> {
pub sequence_number: u32,
pub message_type: MessageType,
pub payload: &'a [u8],
}

impl fmt::Debug for IncomingPacket<'_> {
Expand All @@ -24,7 +24,7 @@ impl fmt::Debug for IncomingPacket<'_> {
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum MessageType {
pub enum MessageType {
Disconnect,
Ignore,
Unimplemented,
Expand Down Expand Up @@ -65,7 +65,7 @@ impl Encode for MessageType {
}

impl<'a> Decode<'a> for MessageType {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, Error> {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, ProtoError> {
let Decoded { value, next } = u8::decode(bytes)?;
Ok(Decoded {
value: Self::from(value),
Expand Down Expand Up @@ -151,14 +151,18 @@ impl From<MessageType> for u8 {
}

impl<'a> Decode<'a> for &'a [u8] {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, Error> {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, ProtoError> {
let len = u32::decode(bytes)?;
let Some(value) = len.next.get(..len.value as usize) else {
return Err(Error::Incomplete(Some(len.value as usize - len.next.len())));
return Err(ProtoError::Incomplete(Some(
len.value as usize - len.next.len(),
)));
};

let Some(next) = len.next.get(len.value as usize..) else {
return Err(Error::Unreachable("unable to extract rest after slice"));
return Err(ProtoError::Unreachable(
"unable to extract rest after slice",
));
};

Ok(Decoded { value, next })
Expand All @@ -173,7 +177,7 @@ impl Encode for [u8] {
}

impl Decode<'_> for bool {
fn decode(bytes: &[u8]) -> Result<Decoded<'_, Self>, Error> {
fn decode(bytes: &[u8]) -> Result<Decoded<'_, Self>, ProtoError> {
<[u8; 1]>::decode(bytes).map(|decoded| Decoded {
value: decoded.value[0] != 0,
next: decoded.next,
Expand All @@ -188,7 +192,7 @@ impl Encode for bool {
}

impl Decode<'_> for u32 {
fn decode(bytes: &[u8]) -> Result<Decoded<'_, Self>, Error> {
fn decode(bytes: &[u8]) -> Result<Decoded<'_, Self>, ProtoError> {
<[u8; 4]>::decode(bytes).map(|decoded| Decoded {
value: Self::from_be_bytes(decoded.value),
next: decoded.next,
Expand All @@ -203,54 +207,56 @@ impl Encode for u32 {
}

impl<'a, const N: usize> Decode<'a> for [u8; N] {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, Error> {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, ProtoError> {
let Some(inner) = bytes.get(..N) else {
return Err(Error::Incomplete(Some(N - bytes.len())));
return Err(ProtoError::Incomplete(Some(N - bytes.len())));
};

let Some(next) = bytes.get(N..) else {
return Err(Error::Unreachable(
return Err(ProtoError::Unreachable(
"unable to extract rest after fixed-length slice",
));
};

let Ok(value) = <[u8; N]>::try_from(inner) else {
return Err(Error::Unreachable("fixed-length slice converts to array"));
return Err(ProtoError::Unreachable(
"fixed-length slice converts to array",
));
};

Ok(Decoded { value, next })
}
}

impl<'a> Decode<'a> for u8 {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, Error> {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, ProtoError> {
let Some(&inner) = bytes.first() else {
return Err(Error::Incomplete(Some(1)));
return Err(ProtoError::Incomplete(Some(1)));
};

let Some(next) = bytes.get(1..) else {
return Err(Error::Unreachable("unable to extract rest after u8"));
return Err(ProtoError::Unreachable("unable to extract rest after u8"));
};

Ok(Decoded { value: inner, next })
}
}

pub(crate) enum Completion<T> {
pub enum Completion<T> {
Complete(T),
Incomplete(Option<usize>),
}

pub(crate) trait Encode: fmt::Debug + Send + Sync {
pub trait Encode: fmt::Debug + Send + Sync {
fn encode(&self, buf: &mut Vec<u8>);
}

pub(crate) trait Decode<'a>: Sized {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, Error>;
pub trait Decode<'a>: Sized {
fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, ProtoError>;
}

#[derive(Debug)]
pub(crate) struct Decoded<'a, T> {
pub(crate) value: T,
pub(crate) next: &'a [u8],
pub struct Decoded<'a, T> {
pub value: T,
pub next: &'a [u8],
}
Loading