compio_io/framed/mod.rs
1//! Framed I/O operations.
2//!
3//! This module provides functionality for encoding and decoding frames
4//! for network protocols and other stream-based communication.
5
6use std::marker::PhantomData;
7
8use futures_util::FutureExt;
9
10use crate::{AsyncRead, buffer::Buffer, framed::codec::Decoder, util::Splittable};
11
12pub mod codec;
13pub mod frame;
14
15mod read;
16mod write;
17
18/// A framed encoder/decoder that handles both [`Sink`] for writing frames and
19/// [`Stream`] for reading frames.
20///
21/// It uses a [`codec`] to encode/decode messages into frames (`T -> Vec<u8>`)
22/// and a [`Framer`] to define how frames are laid out in buffer (`&mut [u8] ->
23/// &mut [u8]`).
24pub struct Framed<R, W, C, F, In, Out> {
25 read_state: read::State<R>,
26 write_state: write::State<W>,
27 codec: C,
28 framer: F,
29 types: PhantomData<(In, Out)>,
30}
31
32/// [`Framed`] with same In ([`Sink`]) and Out ([`Stream::Item`]) type
33pub type SymmetricFramed<R, W, C, F, Item> = Framed<R, W, C, F, Item, Item>;
34
35impl<R, W, C, F, In, Out> Framed<R, W, C, F, In, Out> {
36 /// Change the reader of the `Framed` object.
37 pub fn with_reader<Io>(self, reader: Io) -> Framed<Io, W, C, F, In, Out> {
38 Framed {
39 read_state: read::State::new(reader, Buffer::with_capacity(64)),
40 write_state: self.write_state,
41 codec: self.codec,
42 framer: self.framer,
43 types: PhantomData,
44 }
45 }
46
47 /// Change the writer of the `Framed` object.
48 pub fn with_writer<Io>(self, writer: Io) -> Framed<R, Io, C, F, In, Out> {
49 Framed {
50 read_state: self.read_state,
51 write_state: write::State::new(writer, Vec::new()),
52 codec: self.codec,
53 framer: self.framer,
54 types: PhantomData,
55 }
56 }
57
58 /// Change the codec of the `Framed` object.
59 ///
60 /// This is useful when you have a duplex I/O type, e.g., a
61 /// `compio::net::TcpStream` or `compio::fs::File`, and you want
62 /// [`Framed`] to implement both [`Sink`](futures_util::Sink) and
63 /// [`Stream`](futures_util::Stream).
64 ///
65 /// Some types like the ones mentioned above are multiplexed by nature, so
66 /// they implement the [`Splittable`] trait by themselves. For other types,
67 /// you may want to wrap them in [`Split`] or [`UnsyncSplit`] first, which
68 /// uses lock or `RefCell` under the hood.
69 ///
70 /// [`Split`]: crate::util::split::Split
71 /// [`UnsyncSplit`]: crate::util::split::UnsyncSplit
72 pub fn with_duplex<Io: Splittable>(
73 self,
74 io: Io,
75 ) -> Framed<Io::ReadHalf, Io::WriteHalf, C, F, In, Out> {
76 let (read_half, write_half) = io.split();
77
78 Framed {
79 read_state: read::State::new(read_half, Buffer::with_capacity(64)),
80 write_state: write::State::new(write_half, Vec::new()),
81 codec: self.codec,
82 framer: self.framer,
83 types: PhantomData,
84 }
85 }
86}
87
88impl<C, F> Framed<(), (), C, F, (), ()> {
89 /// Creates a new `Framed` with the given I/O object, codec, framer and a
90 /// different input and output type.
91 pub fn new<In, Out>(codec: C, framer: F) -> Framed<(), (), C, F, In, Out> {
92 Framed {
93 read_state: read::State::empty(),
94 write_state: write::State::empty(),
95 codec,
96 framer,
97 types: PhantomData,
98 }
99 }
100
101 /// Creates a new `Framed` with the given I/O object, codec, and framer with
102 /// the same input and output type.
103 pub fn symmetric<T>(codec: C, framer: F) -> Framed<(), (), C, F, T, T> {
104 Framed {
105 read_state: read::State::empty(),
106 write_state: write::State::empty(),
107 codec,
108 framer,
109 types: PhantomData,
110 }
111 }
112}