exocore_core/framing/
mod.rs

1use std::io;
2
3pub mod capnp;
4pub mod compound;
5pub mod error;
6pub mod multihash;
7pub mod padded;
8pub mod sized;
9
10use bytes::{Buf, Bytes};
11pub use error::Error;
12pub use padded::{PaddedFrame, PaddedFrameBuilder};
13pub use sized::{IteratedSizedSliceFrame, SizedFrame, SizedFrameBuilder, SizedFrameSliceIterator};
14
15pub use self::{
16    capnp::{CapnpFrame, CapnpFrameBuilder, TypedCapnpFrame},
17    multihash::{MultihashFrame, MultihashFrameBuilder},
18};
19
20/// Represents a frame that either wrap another frame or bytes (vec or slice).
21///
22/// The hierarchy of a FrameReader instances are the opposite of the persisted
23/// hierarchy. Ex:
24///     Stored: SizedFrame( MultihashFrame( Data ) )
25///     Runtime: Data ( MultiHash ( SizedFrame ) )
26///
27/// The reason for this reversal is that the inner most frame doesn't know how
28/// to extract the bytes from the whole frame. Therefor, the wrapping frame
29/// "exposes" the bytes to the inner most frames at runtime.
30pub trait FrameReader {
31    type OwnedType: FrameReader;
32
33    /// Data exposed by this frame to inner frame.
34    /// Ex: sized frame will expose the sized data without encoded size numbers
35    fn exposed_data(&self) -> &[u8];
36
37    /// Data of the whole frame, not just the exposed data.
38    fn whole_data(&self) -> &[u8];
39
40    /// Size of the whole data of the frame.
41    #[inline]
42    fn whole_data_size(&self) -> usize {
43        self.whole_data().len()
44    }
45
46    /// Converts the frame to a owned version (without lifetime)
47    fn to_owned_frame(&self) -> Self::OwnedType;
48
49    /// Copy the frame into the given writer
50    fn copy_to<W: io::Write>(&self, writer: &mut W) -> Result<(), Error> {
51        writer.write_all(self.whole_data())?;
52        Ok(())
53    }
54
55    /// Copy the frame into the given slice
56    fn copy_into(&self, into: &mut [u8]) -> Result<usize, Error> {
57        let whole_data = self.whole_data();
58        check_into_size(whole_data.len(), into)?;
59        into[0..whole_data.len()].copy_from_slice(whole_data);
60        Ok(whole_data.len())
61    }
62}
63
64impl<B: Buf> FrameReader for B {
65    type OwnedType = Bytes;
66
67    fn exposed_data(&self) -> &[u8] {
68        self.chunk()
69    }
70
71    fn whole_data(&self) -> &[u8] {
72        self.chunk()
73    }
74
75    fn to_owned_frame(&self) -> Self::OwnedType {
76        self.chunk().to_vec().into()
77    }
78}
79
80/// A frame builder can wrap another frame (or just data), and can be wrapped
81/// into another frame. The runtime hierarchy is the same as persisted.
82///
83/// Ex:
84///     Stored: SizedFrame(MultihashFrame(Data))
85///     Runtime: SizedFrameBuilder(MultihashFrameBuilder(Data))
86pub trait FrameBuilder {
87    type OwnedFrameType;
88
89    /// Write the frame to the given writer
90    fn write_to<W: io::Write>(&self, writer: &mut W) -> Result<usize, Error>;
91
92    /// Write the frame into the given bytes slice
93    fn write_into(&self, into: &mut [u8]) -> Result<usize, Error>;
94
95    /// Expected size of the frame (in bytes). Optional since some kind of
96    /// frames have an unknown size until they are serialized (ex: capnp)
97    fn expected_size(&self) -> Option<usize>;
98
99    /// Creates a owned version of this frame, which is usually a FrameReader
100    /// implementation
101    fn as_owned_frame(&self) -> Self::OwnedFrameType;
102
103    /// Writes the frame into a in-memory buffer and returns it.
104    fn as_bytes(&self) -> Bytes {
105        let mut buffer = Vec::new();
106        self.write_to(&mut buffer)
107            .expect("Couldn't write frame into in-memory vec");
108        buffer.into()
109    }
110}
111
112/// Implementation of FrameBuilder for a byte array allow wrapping the content
113/// of the array into another frame
114impl<B: Buf> FrameBuilder for B {
115    type OwnedFrameType = Bytes;
116
117    fn write_to<W: io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
118        writer.write_all(self.chunk())?;
119        Ok(self.remaining())
120    }
121
122    fn write_into(&self, into: &mut [u8]) -> Result<usize, Error> {
123        check_into_size(self.remaining(), into)?;
124        into[0..self.remaining()].copy_from_slice(self.chunk());
125        Ok(self.remaining())
126    }
127
128    fn expected_size(&self) -> Option<usize> {
129        Some(self.remaining())
130    }
131
132    fn as_owned_frame(&self) -> Self::OwnedFrameType {
133        self.chunk().to_vec().into()
134    }
135}
136
137/// Asserts that the destination array is big enough for the needed size
138fn check_into_size(needed: usize, into: &[u8]) -> Result<(), Error> {
139    if into.len() < needed {
140        Err(Error::DestinationTooSmall(needed, into.len()))
141    } else {
142        Ok(())
143    }
144}
145
146/// Asserts that the source array contains at least the needed size
147fn check_from_size(needed: usize, from: &[u8]) -> Result<(), Error> {
148    if from.len() < needed {
149        Err(Error::SourceTooSmall(needed, from.len()))
150    } else {
151        Ok(())
152    }
153}
154
155/// Asserts that the given offset can be subtracted from an offset
156fn check_offset_subtract(offset: usize, sub_offset: usize) -> Result<(), Error> {
157    if sub_offset > offset {
158        Err(Error::OffsetSubtract(offset, sub_offset))
159    } else {
160        Ok(())
161    }
162}
163
164#[cfg(test)]
165fn assert_builder_equals<B: FrameBuilder>(frame_builder: &B) -> anyhow::Result<()> {
166    let mut buffer1 = Vec::new();
167    frame_builder.write_to(&mut buffer1)?;
168
169    assert_ne!(0, buffer1.len());
170
171    let mut buffer2 = vec![0; 500];
172    let size = frame_builder.write_into(&mut buffer2)?;
173    assert_eq!(&buffer1[..], &buffer2[..size]);
174
175    assert_eq!(frame_builder.as_bytes(), buffer1);
176
177    if let Some(expected_size) = frame_builder.expected_size() {
178        assert_eq!(expected_size, buffer1.len());
179    }
180
181    Ok(())
182}