blob: b7a23bddd1c11f88001ad5d60c443ae1aceb42c3 [file] [log] [blame] [edit]
// 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);
}
}