| // Copyright 2024 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::{Handle, HandleInfo, ObjectType, Rights}; |
| |
| /// A buffer for _receiving_ messages from a channel. |
| /// |
| /// A `MessageBuf` is essentially a byte buffer and a vector of |
| /// handles, but move semantics for "taking" handles requires special handling. |
| /// |
| /// Note that for sending messages to a channel, the caller manages the buffers, |
| /// using a plain byte slice and `Vec<Handle>`. |
| #[derive(Debug, Default)] |
| pub struct MessageBuf { |
| pub(super) bytes: Vec<u8>, |
| pub(super) handles: Vec<Handle>, |
| } |
| |
| impl MessageBuf { |
| /// Create a new, empty, message buffer. |
| pub fn new() -> Self { |
| Default::default() |
| } |
| |
| /// Create a new non-empty message buffer. |
| pub fn new_with(v: Vec<u8>, h: Vec<Handle>) -> Self { |
| Self { bytes: v, handles: h } |
| } |
| |
| /// Splits apart the message buf into a vector of bytes and a vector of handles. |
| pub fn split_mut(&mut self) -> (&mut Vec<u8>, &mut Vec<Handle>) { |
| (&mut self.bytes, &mut self.handles) |
| } |
| |
| /// Splits apart the message buf into a vector of bytes and a vector of handles. |
| pub fn split(self) -> (Vec<u8>, Vec<Handle>) { |
| (self.bytes, self.handles) |
| } |
| |
| /// Ensure that the buffer has the capacity to hold at least `n_bytes` bytes. |
| pub fn ensure_capacity_bytes(&mut self, n_bytes: usize) { |
| ensure_capacity(&mut self.bytes, n_bytes); |
| } |
| |
| /// Ensure that the buffer has the capacity to hold at least `n_handles` handles. |
| pub fn ensure_capacity_handles(&mut self, n_handles: usize) { |
| ensure_capacity(&mut self.handles, n_handles); |
| } |
| |
| /// Ensure that at least n_bytes bytes are initialized (0 fill). |
| pub fn ensure_initialized_bytes(&mut self, n_bytes: usize) { |
| if n_bytes <= self.bytes.len() { |
| return; |
| } |
| self.bytes.resize(n_bytes, 0); |
| } |
| |
| /// Ensure that the allocation for the message's bytes is as small as possible. |
| pub fn shrink_bytes_to_fit(&mut self) { |
| self.bytes.shrink_to_fit(); |
| } |
| |
| /// Get a reference to the bytes of the message buffer, as a `&[u8]` slice. |
| pub fn bytes(&self) -> &[u8] { |
| self.bytes.as_slice() |
| } |
| |
| /// The number of handles in the message buffer. Note this counts the number |
| /// available when the message was received; `take_handle` does not affect |
| /// the count. |
| pub fn n_handles(&self) -> usize { |
| self.handles.len() |
| } |
| |
| /// Take the handle at the specified index from the message buffer. If the |
| /// method is called again with the same index, it will return `None`, as |
| /// will happen if the index exceeds the number of handles available. |
| pub fn take_handle(&mut self, index: usize) -> Option<Handle> { |
| self.handles.get_mut(index).and_then(|handle| { |
| if handle.is_invalid() { |
| None |
| } else { |
| Some(std::mem::replace(handle, Handle::invalid())) |
| } |
| }) |
| } |
| |
| /// Clear the bytes and handles contained in the buf. This will drop any |
| /// contained handles, resulting in their resources being freed. |
| pub fn clear(&mut self) { |
| self.bytes.clear(); |
| self.handles.clear(); |
| } |
| } |
| |
| /// A buffer for _receiving_ messages from a channel. |
| /// |
| /// This differs from `MessageBuf` in that it holds `HandleInfo` with |
| /// extended handle information. |
| /// |
| /// A `MessageBufEtc` is essentially a byte buffer and a vector of handle |
| /// infos, but move semantics for "taking" handles requires special handling. |
| /// |
| /// Note that for sending messages to a channel, the caller manages the buffers, |
| /// using a plain byte slice and `Vec<HandleDisposition>`. |
| #[derive(Debug, Default)] |
| pub struct MessageBufEtc { |
| pub(super) bytes: Vec<u8>, |
| pub(super) handle_infos: Vec<HandleInfo>, |
| } |
| |
| impl MessageBufEtc { |
| /// Create a new, empty, message buffer. |
| pub fn new() -> Self { |
| Default::default() |
| } |
| |
| /// Create a new non-empty message buffer. |
| pub fn new_with(v: Vec<u8>, h: Vec<HandleInfo>) -> Self { |
| Self { bytes: v, handle_infos: h } |
| } |
| |
| /// Splits apart the message buf into a vector of bytes and a vector of handle infos. |
| pub fn split_mut(&mut self) -> (&mut Vec<u8>, &mut Vec<HandleInfo>) { |
| (&mut self.bytes, &mut self.handle_infos) |
| } |
| |
| /// Splits apart the message buf into a vector of bytes and a vector of handle infos. |
| pub fn split(self) -> (Vec<u8>, Vec<HandleInfo>) { |
| (self.bytes, self.handle_infos) |
| } |
| |
| /// Ensure that the buffer has the capacity to hold at least `n_bytes` bytes. |
| pub fn ensure_capacity_bytes(&mut self, n_bytes: usize) { |
| ensure_capacity(&mut self.bytes, n_bytes); |
| } |
| |
| /// Ensure that the buffer has the capacity to hold at least `n_handles` handle infos. |
| pub fn ensure_capacity_handle_infos(&mut self, n_handle_infos: usize) { |
| ensure_capacity(&mut self.handle_infos, n_handle_infos); |
| } |
| |
| /// Ensure that at least n_bytes bytes are initialized (0 fill). |
| pub fn ensure_initialized_bytes(&mut self, n_bytes: usize) { |
| if n_bytes <= self.bytes.len() { |
| return; |
| } |
| self.bytes.resize(n_bytes, 0); |
| } |
| |
| /// Ensure that the allocation for the message's bytes is as small as possible. |
| pub fn shrink_bytes_to_fit(&mut self) { |
| self.bytes.shrink_to_fit(); |
| } |
| |
| /// Get a reference to the bytes of the message buffer, as a `&[u8]` slice. |
| pub fn bytes(&self) -> &[u8] { |
| self.bytes.as_slice() |
| } |
| |
| /// The number of handles in the message buffer. Note this counts the number |
| /// available when the message was received; `take_handle` does not affect |
| /// the count. |
| pub fn n_handle_infos(&self) -> usize { |
| self.handle_infos.len() |
| } |
| |
| /// Take the handle at the specified index from the message buffer. If the |
| /// method is called again with the same index, it will return `None`, as |
| /// will happen if the index exceeds the number of handles available. |
| pub fn take_handle_info(&mut self, index: usize) -> Option<HandleInfo> { |
| self.handle_infos.get_mut(index).and_then(|handle_info| { |
| if handle_info.handle.is_invalid() { |
| None |
| } else { |
| Some(std::mem::replace( |
| handle_info, |
| HandleInfo { |
| handle: Handle::invalid(), |
| object_type: ObjectType::NONE, |
| rights: Rights::NONE, |
| _unused: 0, |
| }, |
| )) |
| } |
| }) |
| } |
| |
| /// Clear the bytes and handles contained in the buf. This will drop any |
| /// contained handles, resulting in their resources being freed. |
| pub fn clear(&mut self) { |
| self.bytes.clear(); |
| self.handle_infos.clear(); |
| } |
| } |
| |
| pub(crate) fn ensure_capacity<T>(vec: &mut Vec<T>, size: usize) { |
| let len = vec.len(); |
| if size > len { |
| vec.reserve(size - len); |
| } |
| } |