Skip to content

Commit fbf7a97

Browse files
authored
Merge pull request RustPython#1894 from RustPython/coolreader18/zlib-decompressobj
Add zlib.decompressobj()
2 parents 5b52bb8 + 130840c commit fbf7a97

File tree

3 files changed

+310
-34
lines changed

3 files changed

+310
-34
lines changed

vm/src/stdlib/io.rs

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
*/
44
use std::cell::{RefCell, RefMut};
55
use std::fs;
6-
use std::io::prelude::*;
7-
use std::io::Cursor;
8-
use std::io::SeekFrom;
6+
use std::io::{self, prelude::*, Cursor, SeekFrom};
97

108
use num_traits::ToPrimitive;
119

10+
use crate::exceptions::PyBaseExceptionRef;
1211
use crate::function::{OptionalArg, OptionalOption, PyFuncArgs};
1312
use crate::obj::objbool;
1413
use crate::obj::objbytearray::PyByteArray;
@@ -26,9 +25,31 @@ use crate::vm::VirtualMachine;
2625
fn byte_count(bytes: OptionalOption<i64>) -> i64 {
2726
bytes.flat_option().unwrap_or(-1 as i64)
2827
}
28+
fn os_err(vm: &VirtualMachine, err: io::Error) -> PyBaseExceptionRef {
29+
#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
30+
{
31+
super::os::convert_io_error(vm, err)
32+
}
33+
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
34+
{
35+
vm.new_os_error(err.to_string())
36+
}
37+
}
2938

3039
const DEFAULT_BUFFER_SIZE: usize = 8 * 1024;
3140

41+
fn seekfrom(vm: &VirtualMachine, offset: PyObjectRef, how: OptionalArg<i32>) -> PyResult<SeekFrom> {
42+
let seek = match how {
43+
OptionalArg::Present(0) | OptionalArg::Missing => {
44+
SeekFrom::Start(u64::try_from_object(vm, offset)?)
45+
}
46+
OptionalArg::Present(1) => SeekFrom::Current(i64::try_from_object(vm, offset)?),
47+
OptionalArg::Present(2) => SeekFrom::End(i64::try_from_object(vm, offset)?),
48+
_ => return Err(vm.new_value_error("invalid value for how".to_owned())),
49+
};
50+
Ok(seek)
51+
}
52+
3253
#[derive(Debug)]
3354
struct BufferedIO {
3455
cursor: Cursor<Vec<u8>>,
@@ -54,11 +75,8 @@ impl BufferedIO {
5475
}
5576

5677
//skip to the jth position
57-
fn seek(&mut self, offset: u64) -> Option<u64> {
58-
match self.cursor.seek(SeekFrom::Start(offset)) {
59-
Ok(_) => Some(offset),
60-
Err(_) => None,
61-
}
78+
fn seek(&mut self, seek: SeekFrom) -> io::Result<u64> {
79+
self.cursor.seek(seek)
6280
}
6381

6482
//Read k bytes from the object and return.
@@ -142,11 +160,15 @@ impl PyStringIORef {
142160
}
143161

144162
//skip to the jth position
145-
fn seek(self, offset: u64, vm: &VirtualMachine) -> PyResult {
146-
match self.buffer(vm)?.seek(offset) {
147-
Some(value) => Ok(vm.ctx.new_int(value)),
148-
None => Err(vm.new_value_error("Error Performing Operation".to_owned())),
149-
}
163+
fn seek(
164+
self,
165+
offset: PyObjectRef,
166+
how: OptionalArg<i32>,
167+
vm: &VirtualMachine,
168+
) -> PyResult<u64> {
169+
self.buffer(vm)?
170+
.seek(seekfrom(vm, offset, how)?)
171+
.map_err(|err| os_err(vm, err))
150172
}
151173

152174
fn seekable(self) -> bool {
@@ -264,11 +286,15 @@ impl PyBytesIORef {
264286
}
265287

266288
//skip to the jth position
267-
fn seek(self, offset: u64, vm: &VirtualMachine) -> PyResult {
268-
match self.buffer(vm)?.seek(offset) {
269-
Some(value) => Ok(vm.ctx.new_int(value)),
270-
None => Err(vm.new_value_error("Error Performing Operation".to_owned())),
271-
}
289+
fn seek(
290+
self,
291+
offset: PyObjectRef,
292+
how: OptionalArg<i32>,
293+
vm: &VirtualMachine,
294+
) -> PyResult<u64> {
295+
self.buffer(vm)?
296+
.seek(seekfrom(vm, offset, how)?)
297+
.map_err(|err| os_err(vm, err))
272298
}
273299

274300
fn seekable(self) -> bool {
@@ -509,6 +535,22 @@ fn buffered_reader_seekable(_self: PyObjectRef) -> bool {
509535
true
510536
}
511537

538+
fn buffered_reader_seek(
539+
instance: PyObjectRef,
540+
offset: PyObjectRef,
541+
how: OptionalArg,
542+
vm: &VirtualMachine,
543+
) -> PyResult {
544+
let raw = vm.get_attribute(instance, "raw")?;
545+
let args: Vec<_> = std::iter::once(offset).chain(how.into_option()).collect();
546+
vm.invoke(&vm.get_attribute(raw, "seek")?, args)
547+
}
548+
549+
fn buffered_reader_tell(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
550+
let raw = vm.get_attribute(instance, "raw")?;
551+
vm.invoke(&vm.get_attribute(raw, "tell")?, vec![])
552+
}
553+
512554
fn buffered_reader_close(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
513555
let raw = vm.get_attribute(instance, "raw")?;
514556
vm.invoke(&vm.get_attribute(raw, "close")?, vec![])?;
@@ -670,6 +712,35 @@ mod fileio {
670712
true
671713
}
672714

715+
fn file_io_seek(
716+
instance: PyObjectRef,
717+
offset: PyObjectRef,
718+
how: OptionalArg<i32>,
719+
vm: &VirtualMachine,
720+
) -> PyResult<u64> {
721+
let mut handle = fio_get_fileno(&instance, vm)?;
722+
723+
let new_pos = handle
724+
.seek(seekfrom(vm, offset, how)?)
725+
.map_err(|e| os::convert_io_error(vm, e))?;
726+
727+
fio_set_fileno(&instance, handle, vm)?;
728+
729+
Ok(new_pos)
730+
}
731+
732+
fn file_io_tell(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<u64> {
733+
let mut handle = fio_get_fileno(&instance, vm)?;
734+
735+
let pos = handle
736+
.seek(SeekFrom::Current(0))
737+
.map_err(|e| os::convert_io_error(vm, e))?;
738+
739+
fio_set_fileno(&instance, handle, vm)?;
740+
741+
Ok(pos)
742+
}
743+
673744
fn file_io_fileno(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
674745
vm.get_attribute(instance, "__fileno")
675746
}
@@ -683,6 +754,8 @@ mod fileio {
683754
"write" => ctx.new_method(file_io_write),
684755
"close" => ctx.new_method(file_io_close),
685756
"seekable" => ctx.new_method(file_io_seekable),
757+
"seek" => ctx.new_method(file_io_seek),
758+
"tell" => ctx.new_method(file_io_tell),
686759
"fileno" => ctx.new_method(file_io_fileno),
687760
})
688761
}
@@ -968,6 +1041,8 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
9681041
"__init__" => ctx.new_method(buffered_io_base_init),
9691042
"read" => ctx.new_method(buffered_reader_read),
9701043
"seekable" => ctx.new_method(buffered_reader_seekable),
1044+
"seek" => ctx.new_method(buffered_reader_seek),
1045+
"tell" => ctx.new_method(buffered_reader_tell),
9711046
"close" => ctx.new_method(buffered_reader_close),
9721047
"fileno" => ctx.new_method(buffered_io_base_fileno),
9731048
});
@@ -1146,10 +1221,10 @@ mod tests {
11461221
let data = vec![1, 2, 3, 4];
11471222
let count: u64 = 2;
11481223
let mut buffered = BufferedIO {
1149-
cursor: Cursor::new(data.clone()),
1224+
cursor: Cursor::new(data),
11501225
};
11511226

1152-
assert_eq!(buffered.seek(count.clone()).unwrap(), count);
1227+
assert_eq!(buffered.seek(SeekFrom::Start(count)).unwrap(), count);
11531228
assert_eq!(buffered.read(count.clone() as i64).unwrap(), vec![3, 4]);
11541229
}
11551230

vm/src/stdlib/pystruct.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -598,9 +598,18 @@ mod _struct {
598598
}
599599

600600
#[pyfunction]
601-
fn unpack(fmt: PyStringRef, buffer: PyBytesRef, vm: &VirtualMachine) -> PyResult<PyTuple> {
602-
let fmt_str = fmt.as_str();
603-
let format_spec = FormatSpec::parse(fmt_str).map_err(|e| new_struct_error(vm, e))?;
601+
fn unpack(
602+
fmt: Either<PyStringRef, PyBytesRef>,
603+
buffer: PyBytesRef,
604+
vm: &VirtualMachine,
605+
) -> PyResult<PyTuple> {
606+
// FIXME: the given fmt must be parsed as ascii string
607+
// https://github.com/RustPython/RustPython/pull/1792#discussion_r387340905
608+
let parsed = match fmt {
609+
Either::A(string) => FormatSpec::parse(string.as_str()),
610+
Either::B(bytes) => FormatSpec::parse(std::str::from_utf8(&bytes).unwrap()),
611+
};
612+
let format_spec = parsed.map_err(|e| new_struct_error(vm, e))?;
604613
format_spec.unpack(buffer.get_value(), vm)
605614
}
606615

0 commit comments

Comments
 (0)