scylla_cql/deserialize/frame_slice.rs
1use bytes::Bytes;
2
3use crate::frame::frame_errors::LowLevelDeserializationError;
4use crate::frame::types;
5
6/// A reference to a part of the frame.
7//
8// # Design justification
9//
10// ## Why we need a borrowed type
11//
12// The reason why we need to store a borrowed slice is that we want a lifetime that is longer than one obtained
13// when coercing Bytes to a slice in the body of a function. That is, we want to allow deserializing types
14// that borrow from the frame, which resides in QueryResult.
15// Consider a function with the signature:
16//
17// fn fun(b: Bytes) { ... }
18//
19// This function cannot return a type that borrows from the frame, because any slice created from `b`
20// inside `fun` cannot escape `fun`.
21// Conversely, if a function has signature:
22//
23// fn fun(s: &'frame [u8]) { ... }
24//
25// then it can happily return types with lifetime 'frame.
26//
27// ## Why we need the full frame
28//
29// We don't. We only need to be able to return Bytes encompassing our subslice. However, the design choice
30// was made to only store a reference to the original Bytes object residing in QueryResult, so that we avoid
31// cloning Bytes when performing subslicing on FrameSlice. We delay the Bytes cloning, normally a moderately
32// expensive operation involving cloning an Arc, up until it is really needed.
33//
34// ## Why not different design
35//
36// - why not a &'frame [u8] only? Because we want to enable deserializing types containing owned Bytes, too.
37// - why not a Bytes only? Because we need to propagate the 'frame lifetime.
38// - why not a &'frame Bytes only? Because we want to somehow represent subslices, and subslicing
39// &'frame Bytes return Bytes, not &'frame Bytes.
40#[derive(Clone, Copy, Debug)]
41pub struct FrameSlice<'frame> {
42 // The actual subslice represented by this FrameSlice.
43 frame_subslice: &'frame [u8],
44
45 // Reference to the original Bytes object that this FrameSlice is derived
46 // from. It is used to convert the `mem` slice into a fully blown Bytes
47 // object via Bytes::slice_ref method.
48 original_frame: &'frame Bytes,
49}
50
51static EMPTY_BYTES: Bytes = Bytes::new();
52
53impl<'frame> FrameSlice<'frame> {
54 /// Creates a new FrameSlice from a reference of a Bytes object.
55 ///
56 /// This method is exposed to allow writing deserialization tests
57 /// for custom types.
58 #[inline]
59 pub fn new(frame: &'frame Bytes) -> Self {
60 Self {
61 frame_subslice: frame,
62 original_frame: frame,
63 }
64 }
65
66 /// Creates an empty FrameSlice.
67 #[inline]
68 pub fn new_empty() -> Self {
69 Self {
70 frame_subslice: &EMPTY_BYTES,
71 original_frame: &EMPTY_BYTES,
72 }
73 }
74
75 /// Creates a new FrameSlice from a reference to a slice.
76 ///
77 /// This method creates a not-fully-valid FrameSlice that does not hold
78 /// the valid original frame Bytes. Thus, it is intended to be used in
79 /// legacy code that does not operate on Bytes, but rather on borrowed slice only.
80 /// For correctness in an unlikely case that someone calls `to_bytes()` on such
81 /// a deficient slice, a special treatment is added there that copies
82 /// the slice into a new-allocation-based Bytes.
83 /// This is pub(crate) for the above reason.
84 #[inline]
85 pub(crate) fn new_borrowed(frame_subslice: &'frame [u8]) -> Self {
86 Self {
87 frame_subslice,
88 original_frame: &EMPTY_BYTES,
89 }
90 }
91
92 /// Returns `true` if the slice has length of 0.
93 #[inline]
94 pub fn is_empty(&self) -> bool {
95 self.frame_subslice.is_empty()
96 }
97
98 /// Returns the subslice.
99 #[inline]
100 pub fn as_slice(&self) -> &'frame [u8] {
101 self.frame_subslice
102 }
103
104 /// Returns a mutable reference to the subslice.
105 #[inline]
106 pub fn as_slice_mut(&mut self) -> &mut &'frame [u8] {
107 &mut self.frame_subslice
108 }
109
110 /// Returns a reference to the Bytes object which encompasses the whole frame slice.
111 ///
112 /// The Bytes object will usually be larger than the slice returned by
113 /// [FrameSlice::as_slice]. If you wish to obtain a new Bytes object that
114 /// points only to the subslice represented by the FrameSlice object,
115 /// see [FrameSlice::to_bytes].
116 #[inline]
117 pub fn as_original_frame_bytes(&self) -> &'frame Bytes {
118 self.original_frame
119 }
120
121 /// Returns a new Bytes object which is a subslice of the original Bytes
122 /// frame slice object.
123 #[inline]
124 pub fn to_bytes(&self) -> Bytes {
125 if self.original_frame.is_empty() {
126 // For the borrowed, deficient version of FrameSlice - the one created with
127 // FrameSlice::new_borrowed to work properly in case someone calls
128 // FrameSlice::to_bytes on it (even though it's not intended for the borrowed version),
129 // the special case is introduced that creates new Bytes by copying the slice into
130 // a new allocation. Note that it's something unexpected to be ever done.
131 return Bytes::copy_from_slice(self.as_slice());
132 }
133
134 self.original_frame.slice_ref(self.frame_subslice)
135 }
136
137 /// Reads and consumes a `[bytes]` item from the beginning of the frame,
138 /// returning a subslice that encompasses that item.
139 ///
140 /// If the operation fails then the slice remains unchanged.
141 #[inline]
142 pub fn read_cql_bytes(
143 &mut self,
144 ) -> Result<Option<FrameSlice<'frame>>, LowLevelDeserializationError> {
145 // We copy the slice reference, not to mutate the FrameSlice in case of an error.
146 let mut slice = self.frame_subslice;
147
148 let cql_bytes = types::read_bytes_opt(&mut slice)?;
149
150 // `read_bytes_opt` hasn't failed, so now we must update the FrameSlice.
151 self.frame_subslice = slice;
152
153 Ok(cql_bytes.map(|slice| Self {
154 frame_subslice: slice,
155 original_frame: self.original_frame,
156 }))
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use bytes::Bytes;
163
164 use super::super::tests::{serialize_cells, CELL1, CELL2};
165 use super::FrameSlice;
166
167 #[test]
168 fn test_cql_bytes_consumption() {
169 let frame = serialize_cells([Some(CELL1), None, Some(CELL2)]);
170 let mut slice = FrameSlice::new(&frame);
171 assert!(!slice.is_empty());
172
173 assert_eq!(
174 slice.read_cql_bytes().unwrap().map(|s| s.as_slice()),
175 Some(CELL1)
176 );
177 assert!(!slice.is_empty());
178 assert!(slice.read_cql_bytes().unwrap().is_none());
179 assert!(!slice.is_empty());
180 assert_eq!(
181 slice.read_cql_bytes().unwrap().map(|s| s.as_slice()),
182 Some(CELL2)
183 );
184 assert!(slice.is_empty());
185 slice.read_cql_bytes().unwrap_err();
186 assert!(slice.is_empty());
187 }
188
189 #[test]
190 fn test_cql_bytes_owned() {
191 let frame = serialize_cells([Some(CELL1), Some(CELL2)]);
192 let mut slice = FrameSlice::new(&frame);
193
194 let subslice1 = slice.read_cql_bytes().unwrap().unwrap();
195 let subslice2 = slice.read_cql_bytes().unwrap().unwrap();
196
197 assert_eq!(subslice1.as_slice(), CELL1);
198 assert_eq!(subslice2.as_slice(), CELL2);
199
200 assert_eq!(
201 subslice1.as_original_frame_bytes() as *const Bytes,
202 &frame as *const Bytes
203 );
204 assert_eq!(
205 subslice2.as_original_frame_bytes() as *const Bytes,
206 &frame as *const Bytes
207 );
208
209 let subslice1_bytes = subslice1.to_bytes();
210 let subslice2_bytes = subslice2.to_bytes();
211
212 assert_eq!(subslice1.as_slice(), subslice1_bytes.as_ref());
213 assert_eq!(subslice2.as_slice(), subslice2_bytes.as_ref());
214 }
215}