exocore_core/framing/
compound.rs

1use std::io;
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use bytes::Bytes;
5
6use super::{check_from_size, check_into_size, Error, FrameBuilder, FrameReader};
7
8/// Frame that wraps 2 underlying frame into a single frame (like a tuple)
9pub 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
68/// Compound frame builder
69pub 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}