Skip to content

Commit 929ad30

Browse files
killme2008youknowone
authored andcommitted
Impl seek, write, write_byte methods etc.
1 parent ba33bc9 commit 929ad30

File tree

1 file changed

+155
-2
lines changed

1 file changed

+155
-2
lines changed

stdlib/src/mmap.rs

Lines changed: 155 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ mod mmap {
66
use crate::common::lock::{PyMutex, PyMutexGuard};
77
use crate::vm::{
88
builtins::{PyBytes, PyBytesRef, PyInt, PyIntRef, PyTypeRef},
9-
function::{FuncArgs, OptionalArg},
9+
byte::value_from_object,
10+
function::{ArgBytesLike, FuncArgs, OptionalArg},
1011
sliceable::saturate_index,
1112
types::Constructor,
1213
AsObject, FromArgs, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
@@ -16,7 +17,8 @@ mod mmap {
1617
use memmap2::{Advice, Mmap, MmapMut, MmapOptions};
1718
use nix::unistd;
1819
use std::fs::File;
19-
use std::ops::Deref;
20+
use std::io::Write;
21+
use std::ops::{Deref, DerefMut};
2022
#[cfg(all(unix, not(target_os = "redox")))]
2123
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
2224

@@ -355,6 +357,24 @@ mod mmap {
355357
self.pos.store(self.inner_pos() + step);
356358
}
357359

360+
#[inline]
361+
fn try_writable<R>(
362+
&self,
363+
vm: &VirtualMachine,
364+
f: impl FnOnce(&mut MmapMut) -> R,
365+
) -> PyResult<R> {
366+
if matches!(self.access, AccessMode::Read) {
367+
return Err(
368+
vm.new_type_error("mmap can't modify a readonly memory map.".to_owned())
369+
);
370+
}
371+
372+
match self.check_valid(vm)?.deref_mut().as_mut().unwrap() {
373+
MmapObj::Write(mmap) => Ok(f(mmap)),
374+
_ => unreachable!("already check"),
375+
}
376+
}
377+
358378
fn check_valid(&self, vm: &VirtualMachine) -> PyResult<PyMutexGuard<Option<MmapObj>>> {
359379
let m = self.mmap.lock();
360380

@@ -365,6 +385,24 @@ mod mmap {
365385
Ok(m)
366386
}
367387

388+
/// TODO: impl resize
389+
#[allow(dead_code)]
390+
fn check_resizeable(&self, vm: &VirtualMachine) -> PyResult<()> {
391+
if self.exports.load() > 0 {
392+
return Err(vm.new_buffer_error(
393+
"mmap can't resize with extant buffers exported.".to_owned(),
394+
));
395+
}
396+
397+
if self.access == AccessMode::Write || self.access == AccessMode::Default {
398+
return Ok(());
399+
}
400+
401+
Err(vm.new_type_error(
402+
"mmap can't resize a readonly or copy-on-write memory map.".to_owned(),
403+
))
404+
}
405+
368406
#[pyproperty]
369407
fn closed(&self) -> bool {
370408
self.closed.load()
@@ -521,6 +559,30 @@ mod mmap {
521559
Ok(())
522560
}
523561

562+
#[pymethod(name = "move")]
563+
fn move_(&self, dest: isize, src: isize, cnt: isize, vm: &VirtualMachine) -> PyResult<()> {
564+
let size = self.inner_size();
565+
if dest < 0 || src < 0 || cnt < 0 || size - dest < cnt || size - src < cnt {
566+
return Err(
567+
vm.new_value_error("source, destination, or count out of range".to_owned())
568+
);
569+
}
570+
571+
let dest: usize = dest.try_into().unwrap();
572+
let cnt: usize = cnt.try_into().unwrap();
573+
let dest_end = dest + cnt;
574+
let src: usize = src.try_into().unwrap();
575+
let src_end = src + cnt;
576+
577+
self.try_writable(vm, |mmap| {
578+
let src_buf = mmap[src..src_end].to_vec();
579+
(&mut mmap[dest..dest_end])
580+
.write(&src_buf)
581+
.map_err(|e| vm.new_os_error(e.to_string()))?;
582+
Ok(())
583+
})?
584+
}
585+
524586
#[pymethod]
525587
fn read(&self, n: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
526588
let mut num_bytes = n
@@ -619,6 +681,54 @@ mod mmap {
619681
Ok(result)
620682
}
621683

684+
//TODO: supports resize
685+
#[pymethod]
686+
fn resize(&self, _newsize: PyIntRef, vm: &VirtualMachine) -> PyResult<()> {
687+
self.check_resizeable(vm)?;
688+
Err(vm.new_system_error("mmap: resizing not available--no mremap()".to_owned()))
689+
}
690+
691+
#[pymethod]
692+
fn seek(
693+
&self,
694+
pos: isize,
695+
whence: OptionalArg<libc::c_int>,
696+
vm: &VirtualMachine,
697+
) -> PyResult<()> {
698+
let dist = pos;
699+
700+
let how = whence.unwrap_or(0);
701+
let size = self.inner_size();
702+
703+
let new_pos = match how {
704+
0 => dist, // relative to start
705+
1 => {
706+
// relative to current position
707+
let pos = self.inner_pos();
708+
if isize::MAX - pos < dist {
709+
return Err(vm.new_value_error("seek out of range".to_owned()));
710+
}
711+
pos + dist
712+
}
713+
2 => {
714+
// relative to end
715+
if isize::MAX - size < dist {
716+
return Err(vm.new_value_error("seek out of range".to_owned()));
717+
}
718+
size + dist
719+
}
720+
_ => return Err(vm.new_value_error("unknown seek type".to_owned())),
721+
};
722+
723+
if new_pos > size || new_pos < 0 {
724+
return Err(vm.new_value_error("seek out of range".to_owned()));
725+
}
726+
727+
self.pos.store(new_pos);
728+
729+
Ok(())
730+
}
731+
622732
#[pymethod]
623733
fn size(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
624734
let new_fd = unistd::dup(self.fd).map_err(|e| vm.new_os_error(e.to_string()))?;
@@ -636,6 +746,49 @@ mod mmap {
636746
Ok(self.inner_pos())
637747
}
638748

749+
#[pymethod]
750+
fn write(&self, bytes: ArgBytesLike, vm: &VirtualMachine) -> PyResult<PyIntRef> {
751+
let pos = self.inner_pos();
752+
let size = self.inner_size();
753+
754+
let data = bytes.borrow_buf();
755+
756+
if pos > size || size - pos < data.len() as isize {
757+
return Err(vm.new_value_error("data out of range".to_owned()));
758+
}
759+
760+
let len = self.try_writable(vm, |mmap| {
761+
(&mut mmap[pos as usize..(pos as usize + data.len())])
762+
.write(&data)
763+
.map_err(|e| vm.new_os_error(e.to_string()))?;
764+
Ok(data.len())
765+
})??;
766+
767+
self.advance_pos(len as isize);
768+
769+
Ok(PyInt::from(len).into_ref(vm))
770+
}
771+
772+
#[pymethod]
773+
fn write_byte(&self, byte: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
774+
let b = value_from_object(vm, &byte)?;
775+
776+
let pos = self.inner_pos();
777+
let size = self.inner_size();
778+
779+
if pos >= size {
780+
return Err(vm.new_value_error("write byte out of range".to_owned()));
781+
}
782+
783+
self.try_writable(vm, |mmap| {
784+
mmap[pos as usize] = b;
785+
})?;
786+
787+
self.advance_pos(1);
788+
789+
Ok(())
790+
}
791+
639792
#[pymethod(magic)]
640793
fn enter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
641794
let _m = zelf.check_valid(vm)?;

0 commit comments

Comments
 (0)