-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prototype a new Buffer
trait.
#1290
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use rustix::io::read; | ||
use rustix::stdio::stdin; | ||
|
||
fn main() { | ||
let buf = Vec::new(); | ||
let _x: Vec<u8> = read(stdin(), buf).unwrap(); | ||
|
||
let mut buf = Vec::new(); | ||
let _x: usize = read(stdin(), &mut buf).unwrap(); | ||
|
||
let mut buf = [0, 0, 0]; | ||
let _x: usize = read(stdin(), &mut buf).unwrap(); | ||
|
||
// Why doesn't this work? This is reduced from src/fs/inotify.rs line 177. | ||
struct Wrapper<'a>(&'a mut [u8]); | ||
impl<'a> Wrapper<'a> { | ||
fn read(&mut self) { | ||
let _x: usize = read(stdin(), self.0).unwrap(); | ||
} | ||
} | ||
let mut buf = Vec::new(); | ||
let mut wrapper = Wrapper(&mut buf); | ||
wrapper.read(); | ||
|
||
// Why does this get two error messages? | ||
let mut buf = [0, 0, 0]; | ||
let _x = read(stdin(), buf).unwrap(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Presumably because they're both valid. There's a hint assuming the type is an array and then the message that lists out all the valid types you can use. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,128 @@ | |
|
||
#![allow(unsafe_code)] | ||
|
||
#[cfg(feature = "alloc")] | ||
use alloc::vec::Vec; | ||
use core::mem::MaybeUninit; | ||
use core::slice; | ||
|
||
/// A memory buffer that may be uninitialized. | ||
pub trait Buffer<T> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how much it's worth discussing the implementation yet, but there are a few concerns:
|
||
/// The result of the process operation. | ||
type Result; | ||
|
||
/// Convert this buffer into a maybe-unitiailized view. | ||
fn as_maybe_uninitialized(&mut self) -> &mut [MaybeUninit<T>]; | ||
|
||
/// Convert a finished buffer pointer into its result. | ||
/// | ||
/// # Safety | ||
/// | ||
/// At least `len` bytes of the buffer must now be initialized. | ||
unsafe fn finish(self, len: usize) -> Self::Result; | ||
} | ||
|
||
/// Implements [`Buffer`] around the a slice of bytes. | ||
/// | ||
/// `Result` is a `usize` indicating how many bytes were written. | ||
impl<T> Buffer<T> for &mut [T] { | ||
type Result = usize; | ||
|
||
#[inline] | ||
fn as_maybe_uninitialized(&mut self) -> &mut [MaybeUninit<T>] { | ||
// SAFETY: This just casts away the knowledge that the elements are | ||
// initialized. | ||
unsafe { core::mem::transmute::<&mut [T], &mut [MaybeUninit<T>]>(self) } | ||
} | ||
|
||
#[inline] | ||
unsafe fn finish(self, len: usize) -> Self::Result { | ||
len | ||
} | ||
} | ||
|
||
/// Implements [`Buffer`] around the a slice of bytes. | ||
/// | ||
/// `Result` is a `usize` indicating how many bytes were written. | ||
impl<T, const N: usize> Buffer<T> for &mut [T; N] { | ||
type Result = usize; | ||
|
||
#[inline] | ||
fn as_maybe_uninitialized(&mut self) -> &mut [MaybeUninit<T>] { | ||
// SAFETY: This just casts away the knowledge that the elements are | ||
// initialized. | ||
unsafe { core::mem::transmute::<&mut [T], &mut [MaybeUninit<T>]>(*self) } | ||
} | ||
|
||
#[inline] | ||
unsafe fn finish(self, len: usize) -> Self::Result { | ||
len | ||
} | ||
} | ||
|
||
/// Implements [`Buffer`] around the a slice of bytes. | ||
/// | ||
/// `Result` is a `usize` indicating how many bytes were written. | ||
impl<T> Buffer<T> for &mut Vec<T> { | ||
type Result = usize; | ||
|
||
#[inline] | ||
fn as_maybe_uninitialized(&mut self) -> &mut [MaybeUninit<T>] { | ||
// SAFETY: This just casts away the knowledge that the elements are | ||
// initialized. | ||
unsafe { core::mem::transmute::<&mut [T], &mut [MaybeUninit<T>]>(self) } | ||
} | ||
|
||
#[inline] | ||
unsafe fn finish(self, len: usize) -> Self::Result { | ||
len | ||
} | ||
} | ||
|
||
/// Implements [`Buffer`] around the a slice of uninitialized bytes. | ||
/// | ||
/// `Result` is a pair of slices giving the initialized and uninitialized | ||
/// subslices after the new data is written. | ||
impl<'a, T> Buffer<T> for &'a mut [MaybeUninit<T>] { | ||
type Result = (&'a mut [T], &'a mut [MaybeUninit<T>]); | ||
|
||
#[inline] | ||
fn as_maybe_uninitialized(&mut self) -> &mut [MaybeUninit<T>] { | ||
self | ||
} | ||
|
||
#[inline] | ||
unsafe fn finish(self, len: usize) -> Self::Result { | ||
let (init, uninit) = self.split_at_mut(len); | ||
|
||
// SAFETY: The user asserts that the slice is now initialized. | ||
let init = slice::from_raw_parts_mut(init.as_mut_ptr().cast::<T>(), init.len()); | ||
|
||
(init, uninit) | ||
} | ||
} | ||
|
||
/// Implements [`Buffer`] around the `Vec` type. | ||
/// | ||
/// This implementation fills the buffer, overwriting any previous data, with | ||
/// the new data data and sets the length. | ||
#[cfg(feature = "alloc")] | ||
impl<T> Buffer<T> for Vec<T> { | ||
type Result = Vec<T>; | ||
|
||
#[inline] | ||
fn as_maybe_uninitialized(&mut self) -> &mut [MaybeUninit<T>] { | ||
self.clear(); | ||
self.spare_capacity_mut() | ||
} | ||
|
||
#[inline] | ||
unsafe fn finish(mut self, len: usize) -> Self::Result { | ||
self.set_len(len); | ||
self | ||
} | ||
} | ||
|
||
/// Split an uninitialized byte slice into initialized and uninitialized parts. | ||
/// | ||
/// # Safety | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,14 +40,16 @@ | |
//! # } | ||
|
||
#![allow(unused_qualifications)] | ||
#![allow(dead_code)] // FIXME | ||
#![allow(unused_imports)] // FIXME | ||
|
||
use super::inotify; | ||
pub use crate::backend::fs::inotify::{CreateFlags, ReadFlags, WatchFlags}; | ||
use crate::backend::fs::syscalls; | ||
use crate::fd::{AsFd, OwnedFd}; | ||
use crate::ffi::CStr; | ||
use crate::io; | ||
use crate::io::{read_uninit, Errno}; | ||
use crate::io::{read, Errno}; | ||
use core::mem::{align_of, size_of, MaybeUninit}; | ||
use linux_raw_sys::general::inotify_event; | ||
|
||
|
@@ -174,14 +176,17 @@ impl<'buf, Fd: AsFd> Reader<'buf, Fd> { | |
#[allow(clippy::should_implement_trait)] | ||
pub fn next(&mut self) -> io::Result<InotifyEvent<'_>> { | ||
if self.is_buffer_empty() { | ||
match read_uninit(self.fd.as_fd(), self.buf).map(|(init, _)| init.len()) { | ||
todo!("FIXME: see \"Why doesn't this work?\" in examples/new_read.rs"); | ||
/* | ||
match read(self.fd.as_fd(), self.buf).map(|(init, _)| init.len()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
Ok(0) => return Err(Errno::INVAL), | ||
Ok(bytes_read) => { | ||
self.initialized = bytes_read; | ||
self.offset = 0; | ||
} | ||
Err(e) => return Err(e), | ||
} | ||
*/ | ||
} | ||
|
||
let ptr = self.buf[self.offset..].as_ptr(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is due to rust-lang/rust#35919. You need to reborrow manually:
&mut *self.0
.One option is to make the Buffer trait impl owned types so the
read
method borrows it. Unfortunately I believe this requires rust 1.65. Also it seems kinda ugly so maybe not worth it.