1//! Generic connection-related types and definitions.
2//!
3//! This module contains the `Connection` trait and related definitions. The code in this module is
4//! used by each concrete implementation of the X11 protocol.
5
6use std::borrow::Cow;
7use std::convert::{TryFrom, TryInto};
8use std::io::IoSlice;
9
10use x11rb_protocol::x11_utils::{ReplyFDsRequest, ReplyRequest, VoidRequest};
11
12use crate::cookie::{Cookie, CookieWithFds, VoidCookie};
13use crate::errors::{ConnectionError, ParseError, ReplyError, ReplyOrIdError};
14use crate::protocol::xproto::Setup;
15use crate::protocol::Event;
16use crate::utils::RawFdContainer;
17use crate::x11_utils::{ExtensionInformation, TryParse, TryParseFd, X11Error};
18
19pub use x11rb_protocol::{DiscardMode, RawEventAndSeqNumber, SequenceNumber};
20
21// Used to avoid too-complex types.
22/// A combination of a buffer and a list of file descriptors.
23pub type BufWithFds<B> = (B, Vec<RawFdContainer>);
24/// An event and its sequence number.
25pub type EventAndSeqNumber = (Event, SequenceNumber);
26/// A buffer that is logically continuous, but presented in a number of pieces.
27pub type PiecewiseBuf<'a> = Vec<Cow<'a, [u8]>>;
28
29/// Either a raw reply or a raw error response to an X11 request.
30#[derive(Debug)]
31pub enum ReplyOrError<R, E = R>
32where
33 R: std::fmt::Debug,
34 E: AsRef<[u8]> + std::fmt::Debug,
35{
36 /// The reply to an X11 request.
37 Reply(R),
38
39 /// An error caused by an X11 request.
40 Error(E),
41}
42
43/// A connection to an X11 server for sending requests.
44///
45/// This trait only contains functions that are used by other parts of this library. This means
46/// that users of this library will most likely not need these functions, unless they want to
47/// implement their own X11 connection.
48pub trait RequestConnection {
49 /// Type used as buffer to store raw replies or events before
50 /// they are parsed.
51 type Buf: AsRef<[u8]> + std::fmt::Debug + Send + Sync + 'static;
52
53 /// Send a request with a reply to the server.
54 ///
55 /// The `bufs` parameter describes the raw bytes that should be sent. The returned cookie
56 /// allows to get the response.
57 ///
58 /// The `fds` parameter contains a list of file descriptors that should be sent with the
59 /// request. Ownership of these FDs is transferred to the connection. This means that the
60 /// connection will close the FDs after they were sent.
61 ///
62 /// Users of this library will most likely not want to use this function directly. Instead, the
63 /// generated code will take the supplied arguments, construct byte buffers, and call this
64 /// method.
65 ///
66 /// The provided buffers must contain at least a single element and the first buffer must have
67 /// at least four bytes. The length field must be set correctly, unless the request is larger
68 /// than 2^18 bytes, because in this case, the length field would overflow. The connection
69 /// automatically uses the BIG-REQUESTS extension for such large requests.
70 ///
71 /// In any case, the request may not be larger than the server's maximum request length.
72 fn send_request_with_reply<R>(
73 &self,
74 bufs: &[IoSlice<'_>],
75 fds: Vec<RawFdContainer>,
76 ) -> Result<Cookie<'_, Self, R>, ConnectionError>
77 where
78 R: TryParse;
79
80 /// Send a request with a reply to the server.
81 ///
82 /// This function is a wrapper around [`RequestConnection::send_request_with_reply`]. This
83 /// function gets a [`ReplyRequest`] as its argument to specify the request to send.
84 fn send_trait_request_with_reply<R>(
85 &self,
86 request: R,
87 ) -> Result<Cookie<'_, Self, <R as ReplyRequest>::Reply>, ConnectionError>
88 where
89 R: ReplyRequest,
90 {
91 let opcode = match R::EXTENSION_NAME {
92 None => 0,
93 Some(extension) => {
94 self.extension_information(extension)?
95 .ok_or(ConnectionError::UnsupportedExtension)?
96 .major_opcode
97 }
98 };
99 let (buf, fds) = request.serialize(opcode);
100 self.send_request_with_reply(&[IoSlice::new(&buf)], fds)
101 }
102
103 /// Send a request with a reply containing file descriptors to the server.
104 ///
105 /// The `bufs` parameter describes the raw bytes that should be sent. The returned cookie
106 /// allows to get the response.
107 ///
108 /// The `fds` parameter contains a list of file descriptors that should be sent with the
109 /// request. Ownership of these FDs is transferred to the connection. This means that the
110 /// connection will close the FDs after they were sent.
111 ///
112 /// Users of this library will most likely not want to use this function directly. Instead, the
113 /// generated code will take the supplied arguments, construct byte buffers, and call this
114 /// method.
115 ///
116 /// The provided buffers must contain at least a single element and the first buffer must have
117 /// at least four bytes. The length field must be set correctly, unless the request is larger
118 /// than 2^18 bytes, because in this case, the length field would overflow. The connection
119 /// automatically uses the BIG-REQUESTS extension for such large requests.
120 ///
121 /// In any case, the request may not be larger than the server's maximum request length.
122 fn send_request_with_reply_with_fds<R>(
123 &self,
124 bufs: &[IoSlice<'_>],
125 fds: Vec<RawFdContainer>,
126 ) -> Result<CookieWithFds<'_, Self, R>, ConnectionError>
127 where
128 R: TryParseFd;
129
130 /// Send a request with a reply containing file descriptors to the server.
131 ///
132 /// This function is a wrapper around [`RequestConnection::send_request_with_reply_with_fds`].
133 /// This function gets a [`ReplyFDsRequest`] as its argument to specify the request to send.
134 fn send_trait_request_with_reply_with_fds<R>(
135 &self,
136 request: R,
137 ) -> Result<CookieWithFds<'_, Self, R::Reply>, ConnectionError>
138 where
139 R: ReplyFDsRequest,
140 {
141 let opcode = match R::EXTENSION_NAME {
142 None => 0,
143 Some(extension) => {
144 self.extension_information(extension)?
145 .ok_or(ConnectionError::UnsupportedExtension)?
146 .major_opcode
147 }
148 };
149 let (buf, fds) = request.serialize(opcode);
150 self.send_request_with_reply_with_fds(&[IoSlice::new(&buf)], fds)
151 }
152
153 /// Send a request without a reply to the server.
154 ///
155 /// The `bufs` parameter describes the raw bytes that should be sent. The sequence number of
156 /// the request is returned, but most likely not useful to users.
157 ///
158 /// The `fds` parameter contains a list of file descriptors that should be sent with the
159 /// request. Ownership of these FDs is transferred to the connection. This means that the
160 /// connection will close the FDs after they were sent.
161 ///
162 /// Users of this library will most likely not want to use this function directly. Instead, the
163 /// generated code will take the supplied arguments, construct byte buffers, and call this
164 /// method.
165 ///
166 /// The provided buffers must contain at least a single element and the first buffer must have
167 /// at least four bytes. The length field must be set correctly, unless the request is larger
168 /// than 2^18 bytes, because in this case, the length field would overflow. The connection
169 /// automatically uses the BIG-REQUESTS extension for such large requests.
170 ///
171 /// In any case, the request may not be larger than the server's maximum request length.
172 fn send_request_without_reply(
173 &self,
174 bufs: &[IoSlice<'_>],
175 fds: Vec<RawFdContainer>,
176 ) -> Result<VoidCookie<'_, Self>, ConnectionError>;
177
178 /// Send a request without a reply to the server.
179 ///
180 /// This function is a wrapper around [`RequestConnection::send_request_without_reply`]. This
181 /// function gets a [`VoidRequest`] as its argument to specify the request to send.
182 fn send_trait_request_without_reply<R>(
183 &self,
184 request: R,
185 ) -> Result<VoidCookie<'_, Self>, ConnectionError>
186 where
187 R: VoidRequest,
188 {
189 let opcode = match R::EXTENSION_NAME {
190 None => 0,
191 Some(extension) => {
192 self.extension_information(extension)?
193 .ok_or(ConnectionError::UnsupportedExtension)?
194 .major_opcode
195 }
196 };
197 let (buf, fds) = request.serialize(opcode);
198 self.send_request_without_reply(&[IoSlice::new(&buf)], fds)
199 }
200
201 /// A reply to an error should be discarded.
202 ///
203 /// This method is automatically called by the `Drop` implementation on `Cookie` so that any
204 /// replies that are received later can be ignored.
205 ///
206 /// Users of this library will most likely not want to use this function directly.
207 fn discard_reply(&self, sequence: SequenceNumber, kind: RequestKind, mode: DiscardMode);
208
209 /// Prefetches information about an extension.
210 ///
211 /// If the information of a extension is not cached yet, this function sends a
212 /// `QueryExtension` request, but it does not wait for the reply.
213 ///
214 /// You can use `extension_information()` to get the reply of such request.
215 ///
216 /// Using this function can help to reduce round-trip latency, but you can use
217 /// `extension_information()` directly without calling this function first.
218 fn prefetch_extension_information(
219 &self,
220 extension_name: &'static str,
221 ) -> Result<(), ConnectionError>;
222
223 /// Get information about an extension.
224 ///
225 /// To send a request for some extension, information about the extension (major opcode,
226 /// first event code and first error code) is necessary. This function provides this
227 /// information.
228 ///
229 /// The returned object is guaranteed to have a non-zero `present` field. Extensions that are
230 /// not present are instead returned as `None`.
231 fn extension_information(
232 &self,
233 extension_name: &'static str,
234 ) -> Result<Option<ExtensionInformation>, ConnectionError>;
235
236 /// Wait for the reply to a request.
237 ///
238 /// The given sequence number identifies the request for which replies are expected. If the X11
239 /// server answered the request with an error, that error is returned as an `Err`.
240 ///
241 /// Users of this library will most likely not want to use this function directly.
242 fn wait_for_reply_or_error(&self, sequence: SequenceNumber) -> Result<Self::Buf, ReplyError> {
243 match self.wait_for_reply_or_raw_error(sequence)? {
244 ReplyOrError::Reply(reply) => Ok(reply),
245 ReplyOrError::Error(error) => {
246 Err(ReplyError::X11Error(self.parse_error(error.as_ref())?))
247 }
248 }
249 }
250
251 /// Wait for the reply to a request.
252 ///
253 /// The given sequence number identifies the request for which replies are expected. If the X11
254 /// server answered the request with an error, that error is returned as an `Err`.
255 ///
256 /// Users of this library will most likely not want to use this function directly.
257 fn wait_for_reply_or_raw_error(
258 &self,
259 sequence: SequenceNumber,
260 ) -> Result<ReplyOrError<Self::Buf>, ConnectionError>;
261
262 /// Wait for the reply to a request.
263 ///
264 /// The given sequence number identifies the request for which replies are expected. If the X11
265 /// server answered the request with an error, this function returns `None` and the error is
266 /// instead returned by `wait_for_event()` or `poll_for_event()`.
267 ///
268 /// Users of this library will most likely not want to use this function directly.
269 fn wait_for_reply(
270 &self,
271 sequence: SequenceNumber,
272 ) -> Result<Option<Self::Buf>, ConnectionError>;
273
274 /// Wait for the reply to a request that has FDs.
275 ///
276 /// The given sequence number identifies the request for which replies are expected.
277 ///
278 /// Users of this library will most likely not want to use this function directly.
279 fn wait_for_reply_with_fds(
280 &self,
281 sequence: SequenceNumber,
282 ) -> Result<BufWithFds<Self::Buf>, ReplyError> {
283 match self.wait_for_reply_with_fds_raw(sequence)? {
284 ReplyOrError::Reply(reply) => Ok(reply),
285 ReplyOrError::Error(error) => {
286 Err(ReplyError::X11Error(self.parse_error(error.as_ref())?))
287 }
288 }
289 }
290
291 /// Wait for the reply to a request that has FDs.
292 ///
293 /// The given sequence number identifies the request for which replies are expected.
294 ///
295 /// Users of this library will most likely not want to use this function directly.
296 fn wait_for_reply_with_fds_raw(
297 &self,
298 sequence: SequenceNumber,
299 ) -> Result<ReplyOrError<BufWithFds<Self::Buf>, Self::Buf>, ConnectionError>;
300
301 /// Check whether a request that does not have a reply caused an X11 error.
302 ///
303 /// The given sequence number identifies the request for which the check should be performed.
304 ///
305 /// Users of this library will most likely not want to use this function directly.
306 fn check_for_error(&self, sequence: SequenceNumber) -> Result<(), ReplyError> {
307 match self.check_for_raw_error(sequence)? {
308 Some(err) => Err(self.parse_error(err.as_ref())?.into()),
309 None => Ok(()),
310 }
311 }
312
313 /// Check whether a request that does not have a reply caused an X11 error.
314 ///
315 /// The given sequence number identifies the request for which the check should be performed.
316 ///
317 /// Users of this library will most likely not want to use this function directly.
318 fn check_for_raw_error(
319 &self,
320 sequence: SequenceNumber,
321 ) -> Result<Option<Self::Buf>, ConnectionError>;
322
323 /// Prefetches the maximum request length.
324 ///
325 /// If the maximum request length is not cached yet, this function sends a `BigRequests::Enable`
326 /// request, but it does not wait for the reply.
327 ///
328 /// You can use `maximum_request_bytes()` to get the result of this request.
329 ///
330 /// Using this function can help to reduce round-trip latency, but you can use
331 /// `maximum_request_bytes()` directly without calling this function first.
332 ///
333 /// Since this uses the `BigRequests` extension, the information about that extension needs to
334 /// available. Otherwise, this has to wait for the reply when calling
335 /// `extension_information()`.
336 ///
337 /// To prefetch the necessary information, you can do the following:
338 /// ```no_run
339 /// use x11rb::connection::RequestConnection;
340 /// use x11rb::errors::ConnectionError;
341 /// use x11rb::protocol::bigreq;
342 /// # fn do_it(conn: impl RequestConnection) -> Result<(), ConnectionError> {
343 /// // conn is a RequestConnection
344 /// conn.prefetch_extension_information(bigreq::X11_EXTENSION_NAME)?;
345 /// # Ok(())
346 /// # }
347 /// ```
348 fn prefetch_maximum_request_bytes(&self);
349
350 /// The maximum number of bytes that the X11 server accepts in a request.
351 fn maximum_request_bytes(&self) -> usize;
352
353 /// Parse a generic error.
354 fn parse_error(&self, error: &[u8]) -> Result<X11Error, ParseError>;
355
356 /// Parse a generic event.
357 fn parse_event(&self, event: &[u8]) -> Result<Event, ParseError>;
358}
359
360/// A connection to an X11 server.
361pub trait Connection: RequestConnection {
362 /// Wait for a new event from the X11 server.
363 fn wait_for_event(&self) -> Result<Event, ConnectionError> {
364 Ok(self.wait_for_event_with_sequence()?.0)
365 }
366
367 /// Wait for a new raw/unparsed event from the X11 server.
368 fn wait_for_raw_event(&self) -> Result<Self::Buf, ConnectionError> {
369 Ok(self.wait_for_raw_event_with_sequence()?.0)
370 }
371
372 /// Wait for a new event from the X11 server.
373 fn wait_for_event_with_sequence(&self) -> Result<EventAndSeqNumber, ConnectionError> {
374 let (event, seq) = self.wait_for_raw_event_with_sequence()?;
375 let event = self.parse_event(event.as_ref())?;
376 Ok((event, seq))
377 }
378
379 /// Wait for a new raw/unparsed event from the X11 server.
380 fn wait_for_raw_event_with_sequence(
381 &self,
382 ) -> Result<RawEventAndSeqNumber<Self::Buf>, ConnectionError>;
383
384 /// Poll for a new event from the X11 server.
385 fn poll_for_event(&self) -> Result<Option<Event>, ConnectionError> {
386 Ok(self.poll_for_event_with_sequence()?.map(|r| r.0))
387 }
388
389 /// Poll for a new raw/unparsed event from the X11 server.
390 fn poll_for_raw_event(&self) -> Result<Option<Self::Buf>, ConnectionError> {
391 Ok(self.poll_for_raw_event_with_sequence()?.map(|r| r.0))
392 }
393
394 /// Poll for a new event from the X11 server.
395 fn poll_for_event_with_sequence(&self) -> Result<Option<EventAndSeqNumber>, ConnectionError> {
396 Ok(match self.poll_for_raw_event_with_sequence()? {
397 Some((event, seq)) => Some((self.parse_event(event.as_ref())?, seq)),
398 None => None,
399 })
400 }
401
402 /// Poll for a new unparsed/raw event from the X11 server.
403 fn poll_for_raw_event_with_sequence(
404 &self,
405 ) -> Result<Option<RawEventAndSeqNumber<Self::Buf>>, ConnectionError>;
406
407 /// Send all pending requests to the server.
408 ///
409 /// Implementations of this trait may buffer requests for batched sending. When this method is
410 /// called, all pending requests are sent.
411 ///
412 /// You do not have to call this method before `wait_for_reply()`. If the request you want to
413 /// wait for was not yet sent, it will be sent by `wait_for_reply()`.
414 fn flush(&self) -> Result<(), ConnectionError>;
415
416 /// Get the setup information sent by the X11 server.
417 ///
418 /// The setup information contains X11 server, for example the window id of the root window.
419 fn setup(&self) -> &Setup;
420
421 /// Generate a new X11 identifier.
422 ///
423 /// This method can, for example, be used for creating a new window. First, this method is
424 /// called to generate an identifier. Next, `xproto::create_window` can be called to
425 /// actually create the window.
426 fn generate_id(&self) -> Result<u32, ReplyOrIdError>;
427}
428
429/// Does a request have a response?
430#[derive(Debug, Copy, Clone, PartialEq, Eq)]
431pub enum RequestKind {
432 /// The request has no response, i.e. its type is "void".
433 IsVoid,
434 /// The request has a response.
435 HasResponse,
436}
437
438/// Check the request length and use BIG-REQUESTS if necessary.
439///
440/// Users of this library will most likely not want to use this function directly.
441///
442/// This function is used by implementations of `RequestConnection` for sending requests. It
443/// examines the given request buffers and checks that the length field is set correctly.
444///
445/// If the request has more than 2^18 bytes, this function handles using the BIG-REQUESTS
446/// extension. The request is rewritten to include the correct length field. For this case, the
447/// `storage` parameter is needed. This function uses it to store the necessary buffers.
448///
449/// When using this function, it is recommended to allocate the `storage` parameter with
450/// `Default::default()`.
451///
452/// Example usage:
453/// ```
454/// use std::io::IoSlice;
455/// use x11rb::connection::{BufWithFds, RequestConnection, compute_length_field};
456/// use x11rb::cookie::{Cookie, CookieWithFds, VoidCookie};
457/// use x11rb::errors::{ParseError, ConnectionError};
458/// use x11rb::utils::RawFdContainer;
459/// use x11rb::x11_utils::{ExtensionInformation, TryParse, TryParseFd};
460/// use x11rb_protocol::SequenceNumber;
461/// # use x11rb::connection::ReplyOrError;
462///
463/// struct MyConnection();
464///
465/// impl RequestConnection for MyConnection {
466/// type Buf = Vec<u8>;
467///
468/// // [snip, other functions here]
469/// # fn discard_reply(&self, sequence: SequenceNumber,
470/// # kind: x11rb::connection::RequestKind,
471/// # mode: x11rb_protocol::DiscardMode) {
472/// # unimplemented!()
473/// # }
474/// # fn prefetch_extension_information(
475/// # &self,
476/// # extension_name: &'static str,
477/// # ) -> Result<(), ConnectionError> {
478/// # unimplemented!()
479/// # }
480/// # fn extension_information(&self, ext: &'static str)
481/// # -> Result<Option<ExtensionInformation>, ConnectionError> {
482/// # unimplemented!()
483/// # }
484/// # fn wait_for_reply_or_raw_error(&self, sequence: SequenceNumber)
485/// # -> Result<ReplyOrError<Vec<u8>>, ConnectionError> {
486/// # unimplemented!()
487/// # }
488/// # fn wait_for_reply(&self, sequence: SequenceNumber)
489/// # -> Result<Option<Vec<u8>>, x11rb::errors::ConnectionError> {
490/// # unimplemented!()
491/// # }
492/// # fn wait_for_reply_with_fds_raw(&self, sequence: SequenceNumber)
493/// # -> Result<ReplyOrError<BufWithFds<Vec<u8>>, Vec<u8>>, ConnectionError> {
494/// # unimplemented!()
495/// # }
496/// # fn check_for_raw_error(&self, sequence: SequenceNumber)
497/// # ->Result<Option<Vec<u8>>, ConnectionError> {
498/// # unimplemented!()
499/// # }
500/// # fn maximum_request_bytes(&self) -> usize {
501/// # unimplemented!()
502/// # }
503/// # fn prefetch_maximum_request_bytes(&self) {
504/// # unimplemented!()
505/// # }
506/// # fn parse_error(&self, _error: &[u8]) -> Result<x11rb::x11_utils::X11Error, ParseError> {
507/// # unimplemented!()
508/// # }
509/// # fn parse_event(&self, _event: &[u8]) -> Result<x11rb::protocol::Event, ParseError> {
510/// # unimplemented!()
511/// # }
512///
513/// fn send_request_with_reply<R>(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>)
514/// -> Result<Cookie<Self, R>, ConnectionError>
515/// where R: TryParse {
516/// Ok(Cookie::new(self, self.send_request(bufs, fds, true, false)?))
517/// }
518///
519/// fn send_request_with_reply_with_fds<R>(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>)
520/// -> Result<CookieWithFds<Self, R>, ConnectionError>
521/// where R: TryParseFd {
522/// Ok(CookieWithFds::new(self, self.send_request(bufs, fds, true, true)?))
523/// }
524///
525/// fn send_request_without_reply(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>)
526/// -> Result<VoidCookie<Self>, ConnectionError> {
527/// Ok(VoidCookie::new(self, self.send_request(bufs, fds, false, false)?))
528/// }
529/// }
530///
531/// impl MyConnection {
532/// fn send_request(&self, bufs: &[IoSlice], fds: Vec<RawFdContainer>,
533/// has_reply: bool, reply_has_fds: bool)
534/// -> Result<SequenceNumber, ConnectionError>
535/// {
536/// let mut storage = Default::default();
537/// let bufs = compute_length_field(self, bufs, &mut storage)?;
538/// unimplemented!("Now send bufs and fds to the X11 server");
539/// }
540/// }
541/// ```
542pub fn compute_length_field<'b>(
543 conn: &impl RequestConnection,
544 request_buffers: &'b [IoSlice<'b>],
545 storage: &'b mut (Vec<IoSlice<'b>>, [u8; 8]),
546) -> Result<&'b [IoSlice<'b>], ConnectionError> {
547 // Compute the total length of the request
548 let length: usize = request_buffers.iter().map(|buf| buf.len()).sum();
549 assert_eq!(
550 length % 4,
551 0,
552 "The length of X11 requests must be a multiple of 4, got {}",
553 length
554 );
555 let wire_length = length / 4;
556
557 let first_buf = &request_buffers[0];
558
559 // If the length fits into an u16, just return the request as-is
560 if let Ok(wire_length) = u16::try_from(wire_length) {
561 // Check that the request contains the correct length field
562 let length_field = u16::from_ne_bytes([first_buf[2], first_buf[3]]);
563 assert_eq!(
564 wire_length, length_field,
565 "Length field contains incorrect value"
566 );
567 return Ok(request_buffers);
568 }
569
570 // Check that the total length is not too large
571 if length > conn.maximum_request_bytes() {
572 return Err(ConnectionError::MaximumRequestLengthExceeded);
573 }
574
575 // Okay, we need to use big requests (thus four extra bytes, "+1" below)
576 let wire_length: u32 = wire_length
577 .checked_add(1)
578 .ok_or(ConnectionError::MaximumRequestLengthExceeded)?
579 .try_into()
580 .expect("X11 request larger than 2^34 bytes?!?");
581 let wire_length = wire_length.to_ne_bytes();
582
583 // Now construct the new IoSlices
584
585 // Replacement for the first four bytes of the request
586 storage.1.copy_from_slice(&[
587 // First part of the request
588 first_buf[0],
589 first_buf[1],
590 // length field zero indicates big requests
591 0,
592 0,
593 // New bytes: extended length
594 wire_length[0],
595 wire_length[1],
596 wire_length[2],
597 wire_length[3],
598 ]);
599 storage.0.push(IoSlice::new(&storage.1));
600
601 // The remaining part of the first buffer of the request
602 storage.0.push(IoSlice::new(&first_buf[4..]));
603
604 // and the rest of the request
605 storage.0.extend(
606 request_buffers[1..]
607 .iter()
608 .map(std::ops::Deref::deref)
609 .map(IoSlice::new),
610 );
611
612 Ok(&storage.0[..])
613}
614