protobuf_native/
internal.rs#[cfg(unix)]
use std::ffi::OsStr;
use std::fmt;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::os::raw::{c_char, c_int, c_void};
#[cfg(unix)]
use std::os::unix::prelude::OsStrExt;
use std::path::Path;
use cxx::kind::Trivial;
use cxx::{type_id, ExternType};
use crate::OperationFailedError;
#[cxx::bridge]
mod ffi {
extern "Rust" {
unsafe fn vec_u8_set_len(v: &mut Vec<u8>, new_len: usize);
}
unsafe extern "C++" {
include!("protobuf-native/src/internal.h");
#[namespace = "absl"]
#[cxx_name = "string_view"]
type StringView<'a> = crate::internal::StringView<'a>;
#[namespace = "protobuf_native::internal"]
fn string_view_from_bytes(bytes: &[u8]) -> StringView;
}
}
unsafe fn vec_u8_set_len(v: &mut Vec<u8>, new_len: usize) {
v.set_len(new_len)
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct StringView<'a> {
repr: MaybeUninit<[*const c_void; 2]>,
borrow: PhantomData<&'a [c_char]>,
}
impl<'a> From<&'a str> for StringView<'a> {
fn from(s: &'a str) -> StringView<'a> {
ffi::string_view_from_bytes(s.as_bytes())
}
}
impl<'a> From<ProtobufPath<'a>> for StringView<'a> {
fn from(path: ProtobufPath<'a>) -> StringView<'a> {
ffi::string_view_from_bytes(path.as_bytes())
}
}
unsafe impl<'a> ExternType for StringView<'a> {
type Id = type_id!("absl::string_view");
type Kind = Trivial;
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CInt(pub c_int);
impl CInt {
pub fn to_usize(self) -> Result<usize, OperationFailedError> {
usize::try_from(self.0).map_err(|_| OperationFailedError)
}
pub fn expect_usize(self) -> usize {
match self.to_usize() {
Ok(n) => n,
Err(_) => panic!("C int is not representible as a Rust usize: {}", self.0),
}
}
pub fn try_from<T>(value: T) -> Result<CInt, T::Error>
where
T: TryInto<c_int>,
{
value.try_into().map(CInt)
}
pub fn expect_from<T>(value: T) -> CInt
where
T: TryInto<c_int> + Copy + fmt::Display,
{
match CInt::try_from(value) {
Ok(n) => n,
Err(_) => panic!("value is not representable as a C int: {}", value),
}
}
}
unsafe impl ExternType for CInt {
type Id = type_id!("protobuf_native::internal::CInt");
type Kind = Trivial;
}
#[derive(Debug)]
pub struct CVoid(pub c_void);
unsafe impl ExternType for CVoid {
type Id = type_id!("protobuf_native::internal::CVoid");
type Kind = Trivial;
}
pub struct ReadAdaptor<'a>(pub &'a mut dyn Read);
impl ReadAdaptor<'_> {
pub fn read(&mut self, buf: &mut [u8]) -> isize {
match self.0.read(buf) {
Ok(n) => n.try_into().expect("read bytes do not fit into isize"),
Err(_) => -1,
}
}
}
pub struct WriteAdaptor<'a>(pub &'a mut dyn Write);
impl WriteAdaptor<'_> {
pub fn write(&mut self, buf: &[u8]) -> bool {
self.0.write_all(buf).as_status()
}
}
pub trait ResultExt {
fn as_status(&self) -> bool;
}
impl<T, E> ResultExt for Result<T, E> {
fn as_status(&self) -> bool {
match self {
Ok(_) => true,
Err(_) => false,
}
}
}
pub trait BoolExt {
fn as_result(self) -> Result<(), OperationFailedError>;
}
impl BoolExt for bool {
fn as_result(self) -> Result<(), OperationFailedError> {
match self {
true => Ok(()),
false => Err(OperationFailedError),
}
}
}
#[cfg(unix)]
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ProtobufPath<'a>(&'a Path);
#[cfg(windows)]
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ProtobufPath<'a> {
inner: Vec<u8>,
_phantom: PhantomData<'a>,
}
#[cfg(unix)]
impl<'a> ProtobufPath<'a> {
pub fn as_path(&self) -> impl AsRef<Path> + 'a {
self.0
}
}
#[cfg(unix)]
impl<'a> From<&'a [u8]> for ProtobufPath<'a> {
fn from(p: &'a [u8]) -> ProtobufPath<'a> {
ProtobufPath(Path::new(OsStr::from_bytes(p)))
}
}
#[cfg(unix)]
impl<'a> From<&'a Path> for ProtobufPath<'a> {
fn from(p: &'a Path) -> ProtobufPath<'a> {
ProtobufPath(p)
}
}
#[cfg(unix)]
impl<'a> ProtobufPath<'a> {
pub fn as_bytes(&self) -> &'a [u8] {
self.0.as_os_str().as_bytes()
}
}
#[cfg(windows)]
impl<'a> ProtobufPath<'a> {
pub fn as_path(&self) -> impl AsRef<Path> {
PathBuf::from(String::from_utf8_lossy(self.inner))
}
}
#[cfg(windows)]
impl<'a> From<&'a [u8]> for ProtobufPath<'static> {
fn from(p: &'a [u8]) -> ProtobufPath<'static> {
ProtobufPath {
inner: p.to_vec(),
_phantom: PhantomData,
}
}
}
#[cfg(windows)]
impl<'a> From<Path> for ProtobufPath<'a> {
fn from(p: Path) -> ProtobufPath<'a> {
ProtobufPath {
inner: p.to_string_lossy().into_owned().into_bytes(),
_phantom: PhantomData,
}
}
}
#[cfg(windows)]
impl<'a> ProtobufPath<'a> {
pub fn as_bytes(&self) -> &'a [u8] {
&self.inner
}
}
macro_rules! unsafe_ffi_conversions {
($ty:ty) => {
#[allow(dead_code)]
pub(crate) unsafe fn from_ffi_owned(from: *mut $ty) -> Pin<Box<Self>> {
std::mem::transmute(from)
}
#[allow(dead_code)]
pub(crate) unsafe fn from_ffi_ptr<'_a>(from: *const $ty) -> &'_a Self {
std::mem::transmute(from)
}
#[allow(dead_code)]
pub(crate) fn from_ffi_ref(from: &$ty) -> &Self {
unsafe { std::mem::transmute(from) }
}
#[allow(dead_code)]
pub(crate) unsafe fn from_ffi_mut<'_a>(from: *mut $ty) -> Pin<&'_a mut Self> {
std::mem::transmute(from)
}
#[allow(dead_code)]
pub(crate) fn as_ffi(&self) -> &$ty {
unsafe { std::mem::transmute(self) }
}
#[allow(dead_code)]
pub(crate) fn as_ffi_mut(self: Pin<&mut Self>) -> Pin<&mut $ty> {
unsafe { std::mem::transmute(self) }
}
#[allow(dead_code)]
pub(crate) fn as_ffi_mut_ptr(self: Pin<&mut Self>) -> *mut $ty {
unsafe { std::mem::transmute(self) }
}
#[allow(dead_code)]
pub(crate) unsafe fn as_ffi_mut_ptr_unpinned(&mut self) -> *mut $ty {
std::mem::transmute(self)
}
};
}
pub(crate) use unsafe_ffi_conversions;