@@ -62,6 +62,8 @@ pub enum AioCancelStat {
6262#[ repr( C ) ]
6363pub struct AioCb < ' a > {
6464 aiocb : libc:: aiocb ,
65+ /// Tracks whether the buffer pointed to by aiocb.aio_buf is mutable
66+ mutable : bool ,
6567 phantom : PhantomData < & ' a mut [ u8 ] >
6668}
6769
@@ -81,7 +83,7 @@ impl<'a> AioCb<'a> {
8183 a. aio_nbytes = 0 ;
8284 a. aio_buf = null_mut ( ) ;
8385
84- let aiocb = AioCb { aiocb : a, phantom : PhantomData } ;
86+ let aiocb = AioCb { aiocb : a, mutable : false , phantom : PhantomData } ;
8587 aiocb
8688 }
8789
@@ -102,37 +104,39 @@ impl<'a> AioCb<'a> {
102104 let mut a = AioCb :: common_init ( fd, prio, sigev_notify) ;
103105 a. aio_offset = offs;
104106 a. aio_nbytes = buf. len ( ) as size_t ;
107+ // casting an immutable buffer to a mutable pointer looks unsafe, but
108+ // technically its only unsafe to dereference it, not to create it.
105109 a. aio_buf = buf. as_ptr ( ) as * mut c_void ;
106110 a. aio_lio_opcode = opcode as :: c_int ;
107111
108- let aiocb = AioCb { aiocb : a, phantom : PhantomData } ;
112+ let aiocb = AioCb { aiocb : a, mutable : true , phantom : PhantomData } ;
109113 aiocb
110114 }
111115
112116 /// Like `from_mut_slice`, but works on constant slices rather than
113117 /// mutable slices.
114118 ///
115- /// This is technically unsafe, but in practice it's fine
116- /// to use with any aio functions except `aio_read` and `lio_listio` (with
117- /// `opcode` set to `LIO_READ`). This method is useful when writing a const
118- /// buffer with `aio_write`, since from_mut_slice can't work with const
119+ /// An `AioCb` created this way cannot be used with `read`, and its
120+ /// `LioOpcode` cannot be set to `LIO_READ`. This method is useful when writing a
121+ /// const buffer with `aio_write`, since from_mut_slice can't work with const
119122 /// buffers.
120123 // Note: another solution to the problem of writing const buffers would be
121124 // to genericize AioCb for both &mut [u8] and &[u8] buffers. aio_read could
122125 // take the former and aio_write could take the latter. However, then
123126 // lio_listio wouldn't work, because that function needs a slice of AioCb,
124127 // and they must all be the same type. We're basically stuck with using an
125128 // unsafe function, since aio (as designed in C) is an unsafe API.
126- pub unsafe fn from_slice ( fd : RawFd , offs : off_t , buf : & ' a [ u8 ] ,
127- prio : :: c_int , sigev_notify : SigevNotify ,
128- opcode : LioOpcode ) -> AioCb {
129+ pub fn from_slice ( fd : RawFd , offs : off_t , buf : & ' a [ u8 ] ,
130+ prio : :: c_int , sigev_notify : SigevNotify ,
131+ opcode : LioOpcode ) -> AioCb {
129132 let mut a = AioCb :: common_init ( fd, prio, sigev_notify) ;
130133 a. aio_offset = offs;
131134 a. aio_nbytes = buf. len ( ) as size_t ;
132135 a. aio_buf = buf. as_ptr ( ) as * mut c_void ;
136+ assert ! ( opcode != LioOpcode :: LIO_READ , "Can't read into an immutable buffer" ) ;
133137 a. aio_lio_opcode = opcode as :: c_int ;
134138
135- let aiocb = AioCb { aiocb : a, phantom : PhantomData } ;
139+ let aiocb = AioCb { aiocb : a, mutable : false , phantom : PhantomData } ;
136140 aiocb
137141 }
138142
@@ -185,13 +189,15 @@ impl<'a> AioCb<'a> {
185189
186190 /// Asynchronously reads from a file descriptor into a buffer
187191 pub fn read ( & mut self ) -> Result < ( ) > {
192+ assert ! ( self . mutable, "Can't read into an immutable buffer" ) ;
188193 let p: * mut libc:: aiocb = & mut self . aiocb ;
189194 Errno :: result ( unsafe { libc:: aio_read ( p) } ) . map ( drop)
190195 }
191196
192197 /// Retrieve return status of an asynchronous operation. Should only be called
193198 /// once for each `AioCb`, after `aio_error` indicates that it has completed.
194199 /// The result the same as for `read`, `write`, of `fsync`.
200+ // Note: this should be just `return`, but that's a reserved word
195201 pub fn aio_return ( & mut self ) -> Result < isize > {
196202 let p: * mut libc:: aiocb = & mut self . aiocb ;
197203 Errno :: result ( unsafe { libc:: aio_return ( p) } )
0 commit comments