exocore_core/framing/
compound.rs1use std::io;
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use bytes::Bytes;
5
6use super::{check_from_size, check_into_size, Error, FrameBuilder, FrameReader};
7
8pub struct CompoundFrame<I: FrameReader> {
10 inner: I,
11 offset_right: usize,
12}
13
14impl<I: FrameReader> CompoundFrame<I> {
15 pub fn new(inner: I) -> Result<CompoundFrame<I>, Error> {
16 let exposed_data = inner.exposed_data();
17 check_from_size(4, exposed_data)?;
18
19 let offset_right =
20 (&exposed_data[exposed_data.len() - 4..]).read_u32::<LittleEndian>()? as usize;
21 Ok(CompoundFrame {
22 inner,
23 offset_right,
24 })
25 }
26
27 pub fn reader_left(&self) -> CompoundSideReader<I> {
28 CompoundSideReader {
29 frame: self,
30 left: true,
31 }
32 }
33
34 pub fn reader_right(&self) -> CompoundSideReader<I> {
35 CompoundSideReader {
36 frame: self,
37 left: false,
38 }
39 }
40}
41
42pub struct CompoundSideReader<'p, I: FrameReader> {
43 frame: &'p CompoundFrame<I>,
44 left: bool,
45}
46
47impl<'p, I: FrameReader> FrameReader for CompoundSideReader<'p, I> {
48 type OwnedType = Bytes;
49
50 fn exposed_data(&self) -> &[u8] {
51 let exposed_data = self.frame.inner.exposed_data();
52 if self.left {
53 &exposed_data[..self.frame.offset_right]
54 } else {
55 &exposed_data[self.frame.offset_right..exposed_data.len() - 4]
56 }
57 }
58
59 fn whole_data(&self) -> &[u8] {
60 self.frame.inner.whole_data()
61 }
62
63 fn to_owned_frame(&self) -> Self::OwnedType {
64 self.exposed_data().to_vec().into()
65 }
66}
67
68pub struct CompoundFrameBuilder<A: FrameBuilder, B: FrameBuilder> {
70 left: A,
71 right: B,
72}
73
74impl<A: FrameBuilder, B: FrameBuilder> CompoundFrameBuilder<A, B> {
75 pub fn new(left: A, right: B) -> CompoundFrameBuilder<A, B> {
76 CompoundFrameBuilder { left, right }
77 }
78
79 pub fn inner(&mut self) -> &mut A {
80 &mut self.left
81 }
82}
83
84impl<A: FrameBuilder, B: FrameBuilder> FrameBuilder for CompoundFrameBuilder<A, B> {
85 type OwnedFrameType = CompoundFrame<Bytes>;
86
87 fn write_to<W: io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
88 let left_size = self.left.write_to(writer)?;
89 let right_size = self.right.write_to(writer)?;
90 writer.write_u32::<LittleEndian>(left_size as u32)?;
91
92 Ok(left_size + right_size + 4)
93 }
94
95 fn write_into(&self, into: &mut [u8]) -> Result<usize, Error> {
96 let left_size = self.left.write_into(into)?;
97 let right_size = self.right.write_into(&mut into[left_size..])?;
98
99 check_into_size(left_size + right_size + 4, into)?;
100 (&mut into[left_size + right_size..]).write_u32::<LittleEndian>(left_size as u32)?;
101
102 Ok(left_size + right_size + 4)
103 }
104
105 fn expected_size(&self) -> Option<usize> {
106 self.left.expected_size().and_then(|left_size| {
107 self.right
108 .expected_size()
109 .map(|right_size| left_size + right_size + 4)
110 })
111 }
112
113 fn as_owned_frame(&self) -> Self::OwnedFrameType {
114 CompoundFrame::new(self.as_bytes()).expect("Couldn't read just-created frame")
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use crate::framing::assert_builder_equals;
122
123 #[test]
124 fn can_build_and_read() -> anyhow::Result<()> {
125 let left = Bytes::from(vec![1; 10]);
126 let right = Bytes::from(vec![2; 15]);
127
128 let builder = CompoundFrameBuilder::new(left, right);
129 assert_builder_equals(&builder)?;
130
131 let mut buffer = Vec::new();
132 builder.write_to(&mut buffer)?;
133 let buffer = Bytes::from(buffer);
134
135 let frame = CompoundFrame::new(buffer)?;
136 assert_eq!(vec![1; 10], frame.reader_left().exposed_data());
137 assert_eq!(vec![2; 15], frame.reader_right().exposed_data());
138
139 Ok(())
140 }
141
142 #[test]
143 fn can_build_to_owned() -> anyhow::Result<()> {
144 let left = Bytes::from(vec![1; 10]);
145 let right = Bytes::from(vec![2; 15]);
146
147 let builder = CompoundFrameBuilder::new(left, right);
148 assert_builder_equals(&builder)?;
149
150 let frame = builder.as_owned_frame();
151 assert_eq!(vec![1; 10], frame.reader_left().exposed_data());
152 assert_eq!(vec![2; 15], frame.reader_right().exposed_data());
153
154 Ok(())
155 }
156}