use std::io::{self, Read, Write};
use std::marker::{PhantomData, PhantomPinned};
use std::mem::{self, MaybeUninit};
use std::pin::Pin;
use std::slice;
use crate::internal::{unsafe_ffi_conversions, BoolExt, CInt, CVoid, ReadAdaptor, WriteAdaptor};
use crate::OperationFailedError;
#[cxx::bridge(namespace = "protobuf_native::io")]
pub(crate) mod ffi {
extern "Rust" {
type ReadAdaptor<'a>;
fn read(self: &mut ReadAdaptor<'_>, buf: &mut [u8]) -> isize;
type WriteAdaptor<'a>;
fn write(self: &mut WriteAdaptor<'_>, buf: &[u8]) -> bool;
}
unsafe extern "C++" {
include!("protobuf-native/src/internal.h");
include!("protobuf-native/src/io.h");
#[namespace = "protobuf_native::internal"]
type CVoid = crate::internal::CVoid;
#[namespace = "protobuf_native::internal"]
type CInt = crate::internal::CInt;
#[namespace = "google::protobuf::io"]
type ZeroCopyInputStream;
unsafe fn DeleteZeroCopyInputStream(stream: *mut ZeroCopyInputStream);
unsafe fn Next(
self: Pin<&mut ZeroCopyInputStream>,
data: *mut *const CVoid,
size: *mut CInt,
) -> bool;
fn BackUp(self: Pin<&mut ZeroCopyInputStream>, count: CInt);
fn Skip(self: Pin<&mut ZeroCopyInputStream>, count: CInt) -> bool;
fn ByteCount(self: &ZeroCopyInputStream) -> i64;
type ReaderStream;
fn NewReaderStream(adaptor: Box<ReadAdaptor<'_>>) -> *mut ReaderStream;
unsafe fn DeleteReaderStream(stream: *mut ReaderStream);
#[namespace = "google::protobuf::io"]
type ArrayInputStream;
unsafe fn NewArrayInputStream(data: *const u8, size: CInt) -> *mut ArrayInputStream;
unsafe fn DeleteArrayInputStream(stream: *mut ArrayInputStream);
#[namespace = "google::protobuf::io"]
type ZeroCopyOutputStream;
unsafe fn Next(
self: Pin<&mut ZeroCopyOutputStream>,
data: *mut *mut CVoid,
size: *mut CInt,
) -> bool;
fn BackUp(self: Pin<&mut ZeroCopyOutputStream>, count: CInt);
fn ByteCount(self: &ZeroCopyOutputStream) -> i64;
type WriterStream;
fn NewWriterStream(adaptor: Box<WriteAdaptor<'_>>) -> *mut WriterStream;
unsafe fn DeleteWriterStream(stream: *mut WriterStream);
#[namespace = "google::protobuf::io"]
type ArrayOutputStream;
unsafe fn NewArrayOutputStream(data: *mut u8, size: CInt) -> *mut ArrayOutputStream;
unsafe fn DeleteArrayOutputStream(stream: *mut ArrayOutputStream);
type VecOutputStream;
fn NewVecOutputStream(target: &mut Vec<u8>) -> *mut VecOutputStream;
unsafe fn DeleteVecOutputStream(stream: *mut VecOutputStream);
#[namespace = "google::protobuf::io"]
type CodedInputStream;
unsafe fn NewCodedInputStream(ptr: *mut ZeroCopyInputStream) -> *mut CodedInputStream;
unsafe fn DeleteCodedInputStream(stream: *mut CodedInputStream);
fn IsFlat(self: &CodedInputStream) -> bool;
unsafe fn ReadRaw(self: Pin<&mut CodedInputStream>, buffer: *mut CVoid, size: CInt)
-> bool;
unsafe fn ReadVarint32(self: Pin<&mut CodedInputStream>, value: *mut u32) -> bool;
unsafe fn ReadVarint64(self: Pin<&mut CodedInputStream>, value: *mut u64) -> bool;
fn ReadTag(self: Pin<&mut CodedInputStream>) -> u32;
fn ReadTagNoLastTag(self: Pin<&mut CodedInputStream>) -> u32;
fn LastTagWas(self: Pin<&mut CodedInputStream>, expected: u32) -> bool;
fn ConsumedEntireMessage(self: Pin<&mut CodedInputStream>) -> bool;
fn CurrentPosition(self: &CodedInputStream) -> CInt;
#[namespace = "google::protobuf::io"]
type CodedOutputStream;
unsafe fn DeleteCodedOutputStream(stream: *mut CodedOutputStream);
}
impl UniquePtr<ZeroCopyOutputStream> {}
impl UniquePtr<CodedOutputStream> {}
}
pub trait ZeroCopyInputStream: zero_copy_input_stream::Sealed {
fn next(self: Pin<&mut Self>) -> Result<&[u8], OperationFailedError> {
let mut data = MaybeUninit::uninit();
let mut size = MaybeUninit::uninit();
unsafe {
self.upcast_mut()
.Next(data.as_mut_ptr(), size.as_mut_ptr())
.as_result()?;
let data = data.assume_init() as *const u8;
let size = size.assume_init().to_usize()?;
Ok(slice::from_raw_parts(data, size))
}
}
fn back_up(self: Pin<&mut Self>, count: usize) {
let count = CInt::try_from(count).expect("count did not fit in a C int");
self.upcast_mut().BackUp(count)
}
fn skip(self: Pin<&mut Self>, count: usize) -> Result<(), OperationFailedError> {
let count = CInt::try_from(count).map_err(|_| OperationFailedError)?;
self.upcast_mut().Skip(count).as_result()
}
fn byte_count(&self) -> i64 {
self.upcast().ByteCount()
}
}
mod zero_copy_input_stream {
use std::pin::Pin;
use crate::io::ffi;
pub trait Sealed {
fn upcast(&self) -> &ffi::ZeroCopyInputStream;
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyInputStream>;
unsafe fn upcast_mut_ptr(self: Pin<&mut Self>) -> *mut ffi::ZeroCopyInputStream {
self.upcast_mut().get_unchecked_mut() as *mut _
}
}
}
pub struct ReaderStream<'a> {
_opaque: PhantomPinned,
_lifetime: PhantomData<&'a ()>,
}
impl<'a> Drop for ReaderStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteReaderStream(self.as_ffi_mut_ptr_unpinned()) }
}
}
impl<'a> ReaderStream<'a> {
pub fn new(reader: &'a mut dyn Read) -> Pin<Box<ReaderStream<'a>>> {
let stream = ffi::NewReaderStream(Box::new(ReadAdaptor(reader)));
unsafe { Self::from_ffi_owned(stream) }
}
unsafe_ffi_conversions!(ffi::ReaderStream);
}
impl<'a> ZeroCopyInputStream for ReaderStream<'a> {}
impl<'a> zero_copy_input_stream::Sealed for ReaderStream<'a> {
fn upcast(&self) -> &ffi::ZeroCopyInputStream {
unsafe { mem::transmute(self) }
}
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyInputStream> {
unsafe { mem::transmute(self) }
}
}
pub struct SliceInputStream<'a> {
_opaque: PhantomPinned,
_lifetime: PhantomData<&'a ()>,
}
impl<'a> Drop for SliceInputStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteArrayInputStream(self.as_ffi_mut_ptr_unpinned()) }
}
}
impl<'a> SliceInputStream<'a> {
pub fn new(slice: &[u8]) -> Pin<Box<SliceInputStream<'a>>> {
let size = CInt::expect_from(slice.len());
let stream = unsafe { ffi::NewArrayInputStream(slice.as_ptr(), size) };
unsafe { Self::from_ffi_owned(stream) }
}
unsafe_ffi_conversions!(ffi::ArrayInputStream);
}
impl<'a> ZeroCopyInputStream for SliceInputStream<'a> {}
impl<'a> zero_copy_input_stream::Sealed for SliceInputStream<'a> {
fn upcast(&self) -> &ffi::ZeroCopyInputStream {
unsafe { mem::transmute(self) }
}
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyInputStream> {
unsafe { mem::transmute(self) }
}
}
pub struct DynZeroCopyInputStream<'a> {
_opaque: PhantomPinned,
lifetime_: PhantomData<&'a ()>,
}
impl<'a> Drop for DynZeroCopyInputStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteZeroCopyInputStream(self.as_ffi_mut_ptr_unpinned()) }
}
}
impl<'a> DynZeroCopyInputStream<'a> {
unsafe_ffi_conversions!(ffi::ZeroCopyInputStream);
}
impl ZeroCopyInputStream for DynZeroCopyInputStream<'_> {}
impl zero_copy_input_stream::Sealed for DynZeroCopyInputStream<'_> {
fn upcast(&self) -> &ffi::ZeroCopyInputStream {
unsafe { mem::transmute(self) }
}
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyInputStream> {
unsafe { mem::transmute(self) }
}
}
pub trait ZeroCopyOutputStream: zero_copy_output_stream::Sealed {
unsafe fn next(self: Pin<&mut Self>) -> Result<&mut [MaybeUninit<u8>], OperationFailedError> {
let mut data = MaybeUninit::uninit();
let mut size = MaybeUninit::uninit();
self.upcast_mut()
.Next(data.as_mut_ptr(), size.as_mut_ptr())
.as_result()?;
let data = data.assume_init() as *mut MaybeUninit<u8>;
let size = size.assume_init().to_usize()?;
Ok(slice::from_raw_parts_mut(data, size))
}
fn back_up(self: Pin<&mut Self>, count: usize) {
let count = CInt::try_from(count).expect("count did not fit in a C int");
self.upcast_mut().BackUp(count)
}
fn byte_count(&self) -> i64 {
self.upcast().ByteCount()
}
}
mod zero_copy_output_stream {
use std::pin::Pin;
use crate::io::ffi;
pub trait Sealed {
fn upcast(&self) -> &ffi::ZeroCopyOutputStream;
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyOutputStream>;
unsafe fn upcast_mut_ptr(self: Pin<&mut Self>) -> *mut ffi::ZeroCopyOutputStream {
self.upcast_mut().get_unchecked_mut() as *mut _
}
}
}
pub struct WriterStream<'a> {
_opaque: PhantomPinned,
_lifetime: PhantomData<&'a mut ()>,
}
impl<'a> WriterStream<'a> {
pub fn new(writer: &'a mut dyn Write) -> Pin<Box<WriterStream<'a>>> {
let stream = ffi::NewWriterStream(Box::new(WriteAdaptor(writer)));
unsafe { Self::from_ffi_owned(stream) }
}
unsafe_ffi_conversions!(ffi::WriterStream);
}
impl<'a> Drop for WriterStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteWriterStream(self.as_ffi_mut_ptr_unpinned()) }
}
}
impl<'a> ZeroCopyOutputStream for WriterStream<'a> {}
impl<'a> zero_copy_output_stream::Sealed for WriterStream<'a> {
fn upcast(&self) -> &ffi::ZeroCopyOutputStream {
unsafe { mem::transmute(self) }
}
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyOutputStream> {
unsafe { mem::transmute(self) }
}
}
pub struct SliceOutputStream<'a> {
_opaque: PhantomPinned,
_lifetime: PhantomData<&'a ()>,
}
impl<'a> SliceOutputStream<'a> {
pub fn new(slice: &mut [u8]) -> Pin<Box<SliceOutputStream<'a>>> {
let size = CInt::expect_from(slice.len());
let stream = unsafe { ffi::NewArrayOutputStream(slice.as_mut_ptr(), size) };
unsafe { Self::from_ffi_owned(stream) }
}
unsafe_ffi_conversions!(ffi::ArrayOutputStream);
}
impl<'a> Drop for SliceOutputStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteArrayOutputStream(self.as_ffi_mut_ptr_unpinned()) }
}
}
impl<'a> ZeroCopyOutputStream for SliceOutputStream<'a> {}
impl<'a> zero_copy_output_stream::Sealed for SliceOutputStream<'a> {
fn upcast(&self) -> &ffi::ZeroCopyOutputStream {
unsafe { mem::transmute(self) }
}
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyOutputStream> {
unsafe { mem::transmute(self) }
}
}
pub struct VecOutputStream<'a> {
_opaque: PhantomPinned,
_lifetime: PhantomData<&'a ()>,
}
impl<'a> VecOutputStream<'a> {
pub fn new(vec: &mut Vec<u8>) -> Pin<Box<VecOutputStream<'a>>> {
let stream = ffi::NewVecOutputStream(vec);
unsafe { Self::from_ffi_owned(stream) }
}
unsafe_ffi_conversions!(ffi::VecOutputStream);
}
impl<'a> Drop for VecOutputStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteVecOutputStream(self.as_ffi_mut_ptr_unpinned()) }
}
}
impl<'a> ZeroCopyOutputStream for VecOutputStream<'a> {}
impl<'a> zero_copy_output_stream::Sealed for VecOutputStream<'a> {
fn upcast(&self) -> &ffi::ZeroCopyOutputStream {
unsafe { mem::transmute(self) }
}
fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::ZeroCopyOutputStream> {
unsafe { mem::transmute(self) }
}
}
pub struct CodedInputStream<'a> {
_opaque: PhantomPinned,
_lifetime: PhantomData<&'a ()>,
}
impl<'a> Drop for CodedInputStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteCodedInputStream(self.as_ffi_mut_ptr_unpinned()) }
}
}
impl<'a> CodedInputStream<'a> {
pub fn new(input: Pin<&'a mut dyn ZeroCopyInputStream>) -> Pin<Box<CodedInputStream<'a>>> {
let stream = unsafe { ffi::NewCodedInputStream(input.upcast_mut_ptr()) };
unsafe { Self::from_ffi_owned(stream) }
}
pub fn is_flat(&self) -> bool {
self.as_ffi().IsFlat()
}
pub fn read_varint32(self: Pin<&mut Self>) -> Result<u32, OperationFailedError> {
let mut value = MaybeUninit::uninit();
unsafe {
match self.as_ffi_mut().ReadVarint32(value.as_mut_ptr()) {
true => Ok(value.assume_init()),
false => Err(OperationFailedError),
}
}
}
pub fn read_varint64(self: Pin<&mut Self>) -> Result<u64, OperationFailedError> {
let mut value = MaybeUninit::uninit();
unsafe {
match self.as_ffi_mut().ReadVarint64(value.as_mut_ptr()) {
true => Ok(value.assume_init()),
false => Err(OperationFailedError),
}
}
}
pub fn read_tag(self: Pin<&mut Self>) -> Result<u32, OperationFailedError> {
match self.as_ffi_mut().ReadTag() {
0 => Err(OperationFailedError), tag => Ok(tag),
}
}
pub fn read_tag_no_last_tag(self: Pin<&mut Self>) -> Result<u32, OperationFailedError> {
match self.as_ffi_mut().ReadTag() {
0 => Err(OperationFailedError), tag => Ok(tag),
}
}
pub fn last_tag_was(self: Pin<&mut Self>, expected: u32) -> bool {
self.as_ffi_mut().LastTagWas(expected)
}
pub fn consumed_entire_message(self: Pin<&mut Self>) -> bool {
self.as_ffi_mut().ConsumedEntireMessage()
}
pub fn current_position(&self) -> usize {
self.as_ffi()
.CurrentPosition()
.to_usize()
.expect("stream position not representable as usize")
}
unsafe_ffi_conversions!(ffi::CodedInputStream);
}
impl<'a> Read for Pin<&mut CodedInputStream<'a>> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
let start = self.current_position();
let data = buf.as_mut_ptr() as *mut CVoid;
let size = CInt::try_from(buf.len()).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"buffer exceeds size of a C int",
)
})?;
unsafe { self.as_mut().as_ffi_mut().ReadRaw(data, size) };
let end = self.current_position();
Ok(end - start)
}
}
pub struct CodedOutputStream<'a> {
_opaque: PhantomPinned,
_lifetime: PhantomData<&'a ()>,
}
impl<'a> CodedOutputStream<'a> {
unsafe_ffi_conversions!(ffi::CodedOutputStream);
}
impl<'a> Drop for CodedOutputStream<'a> {
fn drop(&mut self) {
unsafe { ffi::DeleteCodedOutputStream(self.as_ffi_mut_ptr_unpinned()) }
}
}