Skip to main content

imsg_obex/
lib.rs

1//! Sans-IO OBEX packet codec, framing, and client/server state machines.
2
3// Not covered by the workspace's `todo`/`unimplemented`/`panic` denials — scoped here rather
4// than workspace-wide since other crates (e.g. `cli`) still rely on `unreachable!()`.
5#![deny(clippy::unreachable)]
6
7use thiserror::Error;
8use tokio::io::{AsyncRead, AsyncWrite};
9use tokio_util::codec::Framed;
10
11/// OBEX client state machine — encodes requests and processes responses.
12pub mod client;
13/// OBEX length-prefix framing codec for [`tokio_util::codec::Framed`].
14pub mod codec;
15/// OBEX header types; wire tag bytes 0x01–0xCB.
16pub mod headers;
17/// Wire packet representation — opcode, fixed extra-byte section, and header list; plus codec errors.
18pub mod packet;
19/// OBEX server state machine — decodes requests and encodes responses.
20pub mod server;
21
22pub use codec::ObexCodec;
23
24/// OBEX framing errors — invalid length, unexpected EOF, and external transport failures.
25#[derive(Debug, Error)]
26pub enum TransportError {
27    /// OS-level socket error; check `kind()` for connection-refused, permission-denied, etc.
28    #[error("I/O: {0}")]
29    Io(#[from] std::io::Error),
30    /// Declared packet length is below the 3-byte OBEX minimum.
31    #[error("declared packet length {declared} is below the 3-byte OBEX minimum")]
32    InvalidLength {
33        /// The value read from wire bytes 1–2.
34        declared: usize,
35    },
36    /// Stream closed before a complete packet arrived.
37    #[error("unexpected end of stream")]
38    UnexpectedEof,
39    /// External transport driver error (QUIC, TLS, or other); carries the driver error message.
40    #[error("transport driver: {0}")]
41    External(String),
42}
43
44/// OBEX-framed async transport over any [`AsyncRead`] + [`AsyncWrite`] stream.
45///
46/// Yields and accepts complete OBEX packets as [`bytes::Bytes`]. Obtain via
47/// [`wrap`]; use `futures::SinkExt` / `futures::StreamExt` to send and receive.
48pub type ObexTransport<T> = Framed<T, ObexCodec>;
49
50/// Buffers reads until a complete OBEX packet arrives.
51pub fn wrap<T: AsyncRead + AsyncWrite>(inner: T) -> ObexTransport<T> {
52    Framed::new(inner, ObexCodec)
53}