@@ -5,11 +5,12 @@ pub(crate) use mmap::make_module;
55mod mmap {
66 use crate :: common:: lock:: { PyMutex , PyMutexGuard } ;
77 use crate :: vm:: {
8- builtins:: { PyInt , PyIntRef , PyTypeRef } ,
9- function:: FuncArgs ,
8+ builtins:: { PyBytes , PyBytesRef , PyInt , PyIntRef , PyTypeRef } ,
9+ function:: { FuncArgs , OptionalArg } ,
1010 sliceable:: saturate_index,
1111 types:: Constructor ,
12- FromArgs , PyObject , PyPayload , PyRef , PyResult , TryFromBorrowedObject , VirtualMachine ,
12+ AsObject , FromArgs , PyObject , PyObjectRef , PyPayload , PyRef , PyResult ,
13+ TryFromBorrowedObject , VirtualMachine ,
1314 } ;
1415 use crossbeam_utils:: atomic:: AtomicCell ;
1516 use memmap2:: { Advice , Mmap , MmapMut , MmapOptions } ;
@@ -349,6 +350,11 @@ mod mmap {
349350 self . pos . load ( )
350351 }
351352
353+ #[ inline]
354+ fn advance_pos ( & self , step : isize ) {
355+ self . pos . store ( self . inner_pos ( ) + step) ;
356+ }
357+
352358 fn check_valid ( & self , vm : & VirtualMachine ) -> PyResult < PyMutexGuard < Option < MmapObj > > > {
353359 let m = self . mmap . lock ( ) ;
354360
@@ -515,6 +521,104 @@ mod mmap {
515521 Ok ( ( ) )
516522 }
517523
524+ #[ pymethod]
525+ fn read ( & self , n : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < PyBytesRef > {
526+ let mut num_bytes = n
527+ . map ( |obj| {
528+ let name = obj. class ( ) . name ( ) . to_string ( ) ;
529+ obj. try_into_value :: < Option < isize > > ( vm) . map_err ( |_| {
530+ vm. new_type_error ( format ! (
531+ "read argument must be int or None, not {}" ,
532+ name,
533+ ) )
534+ } )
535+ } )
536+ . transpose ( ) ?
537+ . flatten ( )
538+ . unwrap_or ( isize:: MAX ) ;
539+ let mmap = self . check_valid ( vm) ?;
540+ let pos = self . inner_pos ( ) ;
541+
542+ let remaining = if pos < self . inner_size ( ) {
543+ self . inner_size ( ) - pos
544+ } else {
545+ 0
546+ } ;
547+
548+ if num_bytes < 0 || num_bytes > remaining {
549+ num_bytes = remaining;
550+ }
551+
552+ let end_pos = ( pos + num_bytes) as usize ;
553+ let bytes = match mmap. deref ( ) . as_ref ( ) . unwrap ( ) {
554+ MmapObj :: Read ( mmap) => mmap[ pos as usize ..end_pos] . to_vec ( ) ,
555+ MmapObj :: Write ( mmap) => mmap[ pos as usize ..end_pos] . to_vec ( ) ,
556+ } ;
557+
558+ let result = PyBytes :: from ( bytes) . into_ref ( vm) ;
559+
560+ self . advance_pos ( num_bytes) ;
561+
562+ Ok ( result)
563+ }
564+
565+ #[ pymethod]
566+ fn read_byte ( & self , vm : & VirtualMachine ) -> PyResult < PyIntRef > {
567+ let pos = self . inner_pos ( ) ;
568+ if pos >= self . inner_size ( ) {
569+ return Err ( vm. new_value_error ( "read byte out of range" . to_owned ( ) ) ) ;
570+ }
571+
572+ let b = match self . check_valid ( vm) ?. deref ( ) . as_ref ( ) . unwrap ( ) {
573+ MmapObj :: Read ( mmap) => mmap[ pos as usize ] ,
574+ MmapObj :: Write ( mmap) => mmap[ pos as usize ] ,
575+ } ;
576+
577+ self . advance_pos ( 1 ) ;
578+
579+ Ok ( PyInt :: from ( b) . into_ref ( vm) )
580+ }
581+
582+ #[ pymethod]
583+ fn readline ( & self , vm : & VirtualMachine ) -> PyResult < PyBytesRef > {
584+ let pos = self . inner_pos ( ) ;
585+ let mmap = self . check_valid ( vm) ?;
586+
587+ let remaining = if pos < self . inner_size ( ) {
588+ self . inner_size ( ) - pos
589+ } else {
590+ 0
591+ } ;
592+
593+ if remaining == 0 {
594+ return Ok ( PyBytes :: from ( vec ! [ ] ) . into_ref ( vm) ) ;
595+ }
596+
597+ let eof = match mmap. as_ref ( ) . unwrap ( ) {
598+ MmapObj :: Read ( mmap) => & mmap[ pos as usize ..] ,
599+ MmapObj :: Write ( mmap) => & mmap[ pos as usize ..] ,
600+ }
601+ . iter ( )
602+ . position ( |& x| x == b'\n' ) ;
603+
604+ let end_pos = if let Some ( i) = eof {
605+ pos as usize + i + 1
606+ } else {
607+ self . inner_size ( ) as usize
608+ } ;
609+
610+ let bytes = match mmap. deref ( ) . as_ref ( ) . unwrap ( ) {
611+ MmapObj :: Read ( mmap) => mmap[ pos as usize ..end_pos] . to_vec ( ) ,
612+ MmapObj :: Write ( mmap) => mmap[ pos as usize ..end_pos] . to_vec ( ) ,
613+ } ;
614+
615+ let result = PyBytes :: from ( bytes) . into_ref ( vm) ;
616+
617+ self . advance_pos ( end_pos as isize - pos) ;
618+
619+ Ok ( result)
620+ }
621+
518622 #[ pymethod]
519623 fn size ( & self , vm : & VirtualMachine ) -> PyResult < PyIntRef > {
520624 let new_fd = unistd:: dup ( self . fd ) . map_err ( |e| vm. new_os_error ( e. to_string ( ) ) ) ?;
0 commit comments