use std::ops::{Deref, DerefMut};
pub type BufResult<T, B> = (std::io::Result<T>, B);
pub unsafe trait IoBufMut: Unpin + 'static {
fn stable_ptr_mut(&mut self) -> *mut u8;
fn bytes_total(&self) -> usize;
unsafe fn set_init(&mut self, n: usize);
}
pub unsafe trait IoBuf: Unpin + 'static {
fn stable_ptr(&self) -> *const u8;
fn bytes_init(&self) -> usize;
}
unsafe impl IoBufMut for Vec<u8> {
fn stable_ptr_mut(&mut self) -> *mut u8 {
self.as_mut_ptr()
}
fn bytes_total(&self) -> usize {
self.capacity()
}
unsafe fn set_init(&mut self, n: usize) {
unsafe { self.set_len(n) }
}
}
unsafe impl IoBuf for Vec<u8> {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
}
unsafe impl IoBuf for Box<[u8]> {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
}
unsafe impl IoBufMut for Box<[u8]> {
fn stable_ptr_mut(&mut self) -> *mut u8 {
self.as_mut_ptr()
}
fn bytes_total(&self) -> usize {
self.len()
}
unsafe fn set_init(&mut self, _n: usize) {}
}
unsafe impl<const N: usize> IoBuf for [u8; N] {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
N
}
}
unsafe impl<const N: usize> IoBufMut for [u8; N] {
fn stable_ptr_mut(&mut self) -> *mut u8 {
self.as_mut_ptr()
}
fn bytes_total(&self) -> usize {
N
}
unsafe fn set_init(&mut self, _n: usize) {}
}
unsafe impl IoBuf for String {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
}
unsafe impl IoBuf for &'static [u8] {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
}
unsafe impl IoBuf for &'static str {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
}
pub struct Slice<B> {
buf: B,
begin: usize,
end: usize,
}
impl<B: IoBufMut> Slice<B> {
pub fn new(buf: B, begin: usize, end: usize) -> Self {
assert!(
begin <= end && end <= buf.bytes_total(),
"Slice range {begin}..{end} out of bounds for buffer capacity {}",
buf.bytes_total()
);
Self { buf, begin, end }
}
pub fn into_inner(self) -> B {
self.buf
}
pub fn begin(&self) -> usize {
self.begin
}
pub fn end(&self) -> usize {
self.end
}
}
impl<B: IoBuf + IoBufMut> Deref for Slice<B> {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(self.buf.stable_ptr().add(self.begin), self.end - self.begin)
}
}
}
impl<B: IoBuf + IoBufMut> DerefMut for Slice<B> {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
std::slice::from_raw_parts_mut(
self.buf.stable_ptr_mut().add(self.begin),
self.end - self.begin,
)
}
}
}
unsafe impl<B: IoBufMut> IoBufMut for Slice<B> {
fn stable_ptr_mut(&mut self) -> *mut u8 {
unsafe { self.buf.stable_ptr_mut().add(self.begin) }
}
fn bytes_total(&self) -> usize {
self.end - self.begin
}
unsafe fn set_init(&mut self, n: usize) {
assert!(
self.begin + n <= self.end,
"Slice::set_init({n}) exceeds slice end {} (begin={})",
self.end,
self.begin
);
unsafe { self.buf.set_init(self.begin + n) }
}
}
unsafe impl<B: IoBuf> IoBuf for Slice<B> {
fn stable_ptr(&self) -> *const u8 {
unsafe { self.buf.stable_ptr().add(self.begin) }
}
fn bytes_init(&self) -> usize {
self.end - self.begin
}
}
pub trait IoBufMutExt: IoBufMut + Sized {
fn slice(self, range: impl std::ops::RangeBounds<usize>) -> Slice<Self> {
use std::ops::Bound::*;
let begin = match range.start_bound() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end_bound() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => self.bytes_total(),
};
Slice::new(self, begin, end)
}
}
impl<B: IoBufMut> IoBufMutExt for B {}
pub struct IoSlice<B> {
buf: B,
begin: usize,
end: usize,
}
impl<B: IoBuf> IoSlice<B> {
pub fn new(buf: B, begin: usize, end: usize) -> Self {
assert!(
begin <= end && end <= buf.bytes_init(),
"IoSlice range {begin}..{end} out of bounds for initialized length {}",
buf.bytes_init()
);
Self { buf, begin, end }
}
pub fn into_inner(self) -> B {
self.buf
}
}
unsafe impl<B: IoBuf> IoBuf for IoSlice<B> {
fn stable_ptr(&self) -> *const u8 {
unsafe { self.buf.stable_ptr().add(self.begin) }
}
fn bytes_init(&self) -> usize {
self.end - self.begin
}
}