Skip to content

Commit ba33bc9

Browse files
killme2008youknowone
authored andcommitted
Impl read, read_byte and readline methods
1 parent d96b165 commit ba33bc9

File tree

1 file changed

+107
-3
lines changed

1 file changed

+107
-3
lines changed

stdlib/src/mmap.rs

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ pub(crate) use mmap::make_module;
55
mod 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

Comments
 (0)