use std::{borrow::Cow, fmt::Debug, mem, str::Utf8Error};
use zenoh_buffers::{
buffer::{Buffer, SplitBuffer},
reader::{HasReader, Reader},
ZBuf, ZBufReader, ZSlice, ZSliceBuffer,
};
use zenoh_protocol::zenoh::ext::AttachmentType;
#[repr(transparent)]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct OptionZBytes(Option<ZBytes>);
impl<T> From<T> for OptionZBytes
where
T: Into<ZBytes>,
{
fn from(value: T) -> Self {
Self(Some(value.into()))
}
}
impl<T> From<Option<T>> for OptionZBytes
where
T: Into<ZBytes>,
{
fn from(mut value: Option<T>) -> Self {
match value.take() {
Some(v) => Self(Some(v.into())),
None => Self(None),
}
}
}
impl<T> From<&Option<T>> for OptionZBytes
where
for<'a> &'a T: Into<ZBytes>,
{
fn from(value: &Option<T>) -> Self {
match value.as_ref() {
Some(v) => Self(Some(v.into())),
None => Self(None),
}
}
}
impl From<OptionZBytes> for Option<ZBytes> {
fn from(value: OptionZBytes) -> Self {
value.0
}
}
#[repr(transparent)]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ZBytes(ZBuf);
impl ZBytes {
pub const fn new() -> Self {
Self(ZBuf::empty())
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn to_bytes(&self) -> Cow<'_, [u8]> {
self.0.contiguous()
}
pub fn try_to_string(&self) -> Result<Cow<'_, str>, Utf8Error> {
Ok(match self.to_bytes() {
Cow::Borrowed(s) => std::str::from_utf8(s)?.into(),
Cow::Owned(v) => String::from_utf8(v).map_err(|err| err.utf8_error())?.into(),
})
}
pub fn reader(&self) -> ZBytesReader<'_> {
ZBytesReader(self.0.reader())
}
pub fn from_reader<R>(mut reader: R) -> Result<Self, std::io::Error>
where
R: std::io::Read,
{
let mut buf: Vec<u8> = vec![];
reader.read_to_end(&mut buf)?;
Ok(buf.into())
}
pub fn writer() -> ZBytesWriter {
ZBytesWriter {
zbuf: ZBuf::empty(),
vec: Vec::new(),
}
}
pub fn slices(&self) -> ZBytesSliceIterator<'_> {
ZBytesSliceIterator(self.0.slices())
}
}
#[cfg(all(feature = "unstable", feature = "shared-memory"))]
const _: () = {
use zenoh_shm::{api::buffer::zshm::zshm, ShmBufInner};
impl ZBytes {
pub fn as_shm(&self) -> Option<&zshm> {
let mut zslices = self.0.zslices();
let buf = zslices.next()?.downcast_ref::<ShmBufInner>();
buf.map(Into::into).filter(|_| zslices.next().is_none())
}
pub fn as_shm_mut(&mut self) -> Option<&mut zshm> {
let mut zslices = self.0.zslices_mut();
let buf = unsafe { zslices.next()?.downcast_mut::<ShmBufInner>() };
buf.map(Into::into).filter(|_| zslices.next().is_none())
}
}
};
#[repr(transparent)]
#[derive(Debug)]
pub struct ZBytesReader<'a>(ZBufReader<'a>);
impl ZBytesReader<'_> {
pub fn remaining(&self) -> usize {
self.0.remaining()
}
pub fn is_empty(&self) -> bool {
self.remaining() == 0
}
}
impl std::io::Read for ZBytesReader<'_> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
std::io::Read::read(&mut self.0, buf)
}
}
impl std::io::Seek for ZBytesReader<'_> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
std::io::Seek::seek(&mut self.0, pos)
}
}
#[derive(Debug)]
pub struct ZBytesWriter {
zbuf: ZBuf,
vec: Vec<u8>,
}
impl ZBytesWriter {
pub fn append(&mut self, zbytes: ZBytes) {
if !self.vec.is_empty() {
self.zbuf.push_zslice(mem::take(&mut self.vec).into());
}
for zslice in zbytes.0.into_zslices() {
self.zbuf.push_zslice(zslice);
}
}
pub fn finish(mut self) -> ZBytes {
if !self.vec.is_empty() {
self.zbuf.push_zslice(self.vec.into());
}
ZBytes(self.zbuf)
}
}
impl From<ZBytesWriter> for ZBytes {
fn from(value: ZBytesWriter) -> Self {
value.finish()
}
}
impl std::io::Write for ZBytesWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
std::io::Write::write(&mut self.vec, buf)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[derive(Debug)]
pub struct ZBytesSliceIterator<'a>(ZBytesSliceIteratorInner<'a>);
type ZBytesSliceIteratorInner<'a> =
std::iter::Map<core::slice::Iter<'a, ZSlice>, fn(&'a ZSlice) -> &'a [u8]>;
impl<'a> Iterator for ZBytesSliceIterator<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl From<ZBuf> for ZBytes {
fn from(value: ZBuf) -> Self {
Self(value)
}
}
impl From<ZBytes> for ZBuf {
fn from(value: ZBytes) -> Self {
value.0
}
}
impl<const N: usize> From<[u8; N]> for ZBytes {
fn from(value: [u8; N]) -> Self {
Self(value.into())
}
}
impl<const N: usize> From<&[u8; N]> for ZBytes {
fn from(value: &[u8; N]) -> Self {
value.to_vec().into()
}
}
impl From<Vec<u8>> for ZBytes {
fn from(value: Vec<u8>) -> Self {
Self(value.into())
}
}
impl From<&Vec<u8>> for ZBytes {
fn from(value: &Vec<u8>) -> Self {
value.clone().into()
}
}
impl From<&[u8]> for ZBytes {
fn from(value: &[u8]) -> Self {
value.to_vec().into()
}
}
impl From<Cow<'_, [u8]>> for ZBytes {
fn from(value: Cow<'_, [u8]>) -> Self {
value.into_owned().into()
}
}
impl From<&Cow<'_, [u8]>> for ZBytes {
fn from(value: &Cow<'_, [u8]>) -> Self {
value.clone().into()
}
}
impl From<String> for ZBytes {
fn from(value: String) -> Self {
value.into_bytes().into()
}
}
impl From<&String> for ZBytes {
fn from(value: &String) -> Self {
value.clone().into()
}
}
impl From<&str> for ZBytes {
fn from(value: &str) -> Self {
value.as_bytes().into()
}
}
impl From<Cow<'_, str>> for ZBytes {
fn from(value: Cow<'_, str>) -> Self {
value.into_owned().into()
}
}
impl From<&Cow<'_, str>> for ZBytes {
fn from(value: &Cow<'_, str>) -> Self {
value.clone().into()
}
}
#[repr(transparent)]
#[derive(Debug)]
struct BytesWrap(bytes::Bytes);
impl ZSliceBuffer for BytesWrap {
fn as_slice(&self) -> &[u8] {
&self.0
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
impl From<bytes::Bytes> for ZBytes {
fn from(value: bytes::Bytes) -> Self {
Self(BytesWrap(value).into())
}
}
#[cfg(all(feature = "unstable", feature = "shared-memory"))]
const _: () = {
use zenoh_shm::api::buffer::{typed::Typed, zshm::ZShm, zshmmut::ZShmMut};
impl From<ZShm> for ZBytes {
fn from(value: ZShm) -> Self {
Self(ZSlice::from(value).into())
}
}
impl From<ZShmMut> for ZBytes {
fn from(value: ZShmMut) -> Self {
Self(ZSlice::from(value).into())
}
}
impl<T, Buf: Into<ZBytes>> From<Typed<T, Buf>> for ZBytes {
fn from(value: Typed<T, Buf>) -> Self {
Typed::into_inner(value).into()
}
}
};
impl<const ID: u8> From<ZBytes> for AttachmentType<ID> {
fn from(this: ZBytes) -> Self {
AttachmentType {
buffer: this.into(),
}
}
}
impl<const ID: u8> From<AttachmentType<ID>> for ZBytes {
fn from(this: AttachmentType<ID>) -> Self {
this.buffer.into()
}
}