#[repr(C)]
pub struct ForeignBytes {
pub(crate) len: i32,
pub(crate) data: *const u8,
}
impl ForeignBytes {
pub unsafe fn from_raw_parts(data: *const u8, len: i32) -> Self {
Self { len, data }
}
pub fn as_slice(&self) -> &[u8] {
if self.data.is_null() {
assert!(self.len == 0, "null ForeignBytes had non-zero length");
&[]
} else {
unsafe { std::slice::from_raw_parts(self.data, self.len()) }
}
}
pub fn len(&self) -> usize {
self.len
.try_into()
.expect("bytes length negative or overflowed")
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl std::borrow::Borrow<[u8]> for ForeignBytes {
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
unsafe impl<UT> crate::Lift<UT> for ForeignBytes {
type FfiType = ForeignBytes;
fn try_lift(v: Self::FfiType) -> crate::Result<Self> {
Ok(v)
}
fn try_read(_buf: &mut &[u8]) -> crate::Result<Self> {
anyhow::bail!("ForeignBytes cannot be read from a RustBuffer")
}
}
impl<UT> crate::TypeId<UT> for ForeignBytes {
const TYPE_ID_META: crate::MetadataBuffer =
crate::MetadataBuffer::from_code(crate::metadata::codes::TYPE_VEC)
.concat(<u8 as crate::TypeId<UT>>::TYPE_ID_META);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_foreignbytes_access() {
let v = [1u8, 2, 3];
let fbuf = unsafe { ForeignBytes::from_raw_parts(v.as_ptr(), 3) };
assert_eq!(fbuf.len(), 3);
assert_eq!(fbuf.as_slice(), &[1u8, 2, 3]);
}
#[test]
fn test_foreignbytes_empty() {
let v = Vec::<u8>::new();
let fbuf = unsafe { ForeignBytes::from_raw_parts(v.as_ptr(), 0) };
assert_eq!(fbuf.len(), 0);
assert_eq!(fbuf.as_slice(), &[0u8; 0]);
}
#[test]
fn test_foreignbytes_null_means_empty() {
let fbuf = unsafe { ForeignBytes::from_raw_parts(std::ptr::null_mut(), 0) };
assert_eq!(fbuf.as_slice(), &[0u8; 0]);
}
#[test]
#[should_panic]
fn test_foreignbytes_null_must_have_zero_length() {
let fbuf = unsafe { ForeignBytes::from_raw_parts(std::ptr::null_mut(), 12) };
fbuf.as_slice();
}
#[test]
#[should_panic]
fn test_foreignbytes_provided_len_must_be_non_negative() {
let v = [0u8, 1, 2];
let fbuf = unsafe { ForeignBytes::from_raw_parts(v.as_ptr(), -1) };
fbuf.as_slice();
}
#[test]
fn test_foreignbytes_borrow_as_slice() {
use std::borrow::Borrow;
let v = [10u8, 20, 30];
let fbuf = unsafe { ForeignBytes::from_raw_parts(v.as_ptr(), 3) };
let borrowed: &[u8] = Borrow::<[u8]>::borrow(&fbuf);
assert_eq!(borrowed, &[10u8, 20, 30]);
}
#[test]
fn test_foreignbytes_lift() {
use crate::{Lift, UniFfiTag};
let v = [1u8, 2, 3];
let fbuf = unsafe { ForeignBytes::from_raw_parts(v.as_ptr(), 3) };
let lifted: ForeignBytes = <ForeignBytes as Lift<UniFfiTag>>::try_lift(fbuf).unwrap();
assert_eq!(lifted.as_slice(), &[1u8, 2, 3]);
}
}