11#[ cfg( feature = "allocator_api" ) ]
22use std:: alloc:: Allocator ;
3+ use std:: { io, io:: ErrorKind } ;
34
45use compio_buf:: { BufResult , IntoInner , IoBuf , IoBufMut , IoVectoredBufMut , t_alloc} ;
56
@@ -141,6 +142,31 @@ macro_rules! loop_read_to_end {
141142 } } ;
142143}
143144
145+ #[ inline]
146+ fn after_read_to_string ( res : io:: Result < usize > , buf : Vec < u8 > ) -> BufResult < usize , String > {
147+ match res {
148+ Err ( err) => {
149+ // we have to clear the read bytes if it is not valid utf8 bytes
150+ let buf = String :: from_utf8 ( buf) . unwrap_or_else ( |err| {
151+ let mut buf = err. into_bytes ( ) ;
152+ buf. clear ( ) ;
153+
154+ // Safety: the buffer is empty
155+ unsafe { String :: from_utf8_unchecked ( buf) }
156+ } ) ;
157+
158+ BufResult ( Err ( err) , buf)
159+ }
160+ Ok ( n) => match String :: from_utf8 ( buf) {
161+ Err ( err) => BufResult (
162+ Err ( std:: io:: Error :: new ( ErrorKind :: InvalidData , err) ) ,
163+ String :: new ( ) ,
164+ ) ,
165+ Ok ( data) => BufResult ( Ok ( n) , data) ,
166+ } ,
167+ }
168+ }
169+
144170/// Implemented as an extension trait, adding utility methods to all
145171/// [`AsyncRead`] types. Callers will tend to import this trait instead of
146172/// [`AsyncRead`].
@@ -161,6 +187,12 @@ pub trait AsyncReadExt: AsyncRead {
161187 loop_read_exact ! ( buf, buf. buf_capacity( ) , read, loop self . read( buf. slice( read..) ) ) ;
162188 }
163189
190+ /// Read all bytes as [`String`] until underlying reader reaches `EOF`.
191+ async fn read_to_string ( & mut self , buf : String ) -> BufResult < usize , String > {
192+ let BufResult ( res, buf) = self . read_to_end ( buf. into_bytes ( ) ) . await ;
193+ after_read_to_string ( res, buf)
194+ }
195+
164196 /// Read all bytes until underlying reader reaches `EOF`.
165197 async fn read_to_end < #[ cfg( feature = "allocator_api" ) ] A : Allocator + ' static > (
166198 & mut self ,
@@ -238,6 +270,13 @@ pub trait AsyncReadAtExt: AsyncReadAt {
238270 ) ;
239271 }
240272
273+ /// Read all bytes as [`String`] until EOF in this source, placing them into
274+ /// `buffer`.
275+ async fn read_to_string_at ( & mut self , buf : String , pos : u64 ) -> BufResult < usize , String > {
276+ let BufResult ( res, buf) = self . read_to_end_at ( buf. into_bytes ( ) , pos) . await ;
277+ after_read_to_string ( res, buf)
278+ }
279+
241280 /// Read all bytes until EOF in this source, placing them into `buffer`.
242281 ///
243282 /// All bytes read from this source will be appended to the specified buffer
0 commit comments