Merge branch 'master' of https://github.com/RustPython/RustPython into cryptomods

This commit is contained in:
Windel Bouwman committed 2019-06-29 16:46:00 +02:00
commit df31abea98
24 files changed
+429 -185

No files matched your search

+2
View File
@@ -111,6 +111,8 @@ matrix:
- target
script:
- tests/.travis-runner.sh
# Only do code coverage on master via a cron job.
if: branch = master AND type = cron
env:
- TRAVIS_RUST_VERSION=nightly
- REGULAR_TEST=false
+32 -8
View File
@@ -52,6 +52,10 @@ assert ('d', 3) == next(it)
with assertRaises(StopIteration):
next(it)
with assertRaises(KeyError) as cm:
del x[10]
assert cm.exception.args[0] == 10
# Iterating a dictionary is just its keys:
assert ['a', 'b', 'd'] == list(x)
@@ -95,9 +99,6 @@ x[7] = 7
x[2] = 2
x[(5, 6)] = 5
with assertRaises(KeyError):
x["not here"]
with assertRaises(TypeError):
x[[]] # Unhashable type.
@@ -167,19 +168,42 @@ assert y == {'a': 2, 'b': 12, 'c': 19, 'd': -1}
y.update(y)
assert y == {'a': 2, 'b': 12, 'c': 19, 'd': -1} # hasn't changed
# KeyError has object that used as key as an .args[0]
with assertRaises(KeyError) as cm:
x['not here']
assert cm.exception.args[0] == "not here"
with assertRaises(KeyError) as cm:
x.pop('not here')
assert cm.exception.args[0] == "not here"
with assertRaises(KeyError) as cm:
x[10]
assert cm.exception.args[0] == 10
with assertRaises(KeyError) as cm:
x.pop(10)
assert cm.exception.args[0] == 10
class MyClass: pass
obj = MyClass()
with assertRaises(KeyError) as cm:
x[obj]
assert cm.exception.args[0] == obj
with assertRaises(KeyError) as cm:
x.pop(obj)
assert cm.exception.args[0] == obj
x = {1: 'a', '1': None}
assert x.pop(1) == 'a'
assert x.pop('1') is None
assert x == {}
with assertRaises(KeyError):
x.pop("not here")
x = {1: 'a'}
assert (1, 'a') == x.popitem()
with assertRaises(KeyError):
x.popitem()
assert x == {}
with assertRaises(KeyError) as cm:
x.popitem()
assert cm.exception.args == ('popitem(): dictionary is empty',)
x = {'a': 4}
assert 4 == x.setdefault('a', 0)
+4 -2
View File
@@ -9,8 +9,10 @@ class A(dict):
assert A.__dict__['a'] == A.a
with assertRaises(KeyError):
A.__dict__['not_here']
with assertRaises(KeyError) as cm:
A.__dict__['not here']
assert cm.exception.args[0] == "not here"
assert 'b' in A.__dict__
assert 'c' not in A.__dict__
+6
View File
@@ -0,0 +1,6 @@
obj = b"abcde"
a = memoryview(obj)
assert a.obj == obj
assert a[2:3] == b"c"
+7
View File
@@ -1,4 +1,5 @@
from io import BufferedReader, FileIO
import os
fi = FileIO('README.md')
bb = BufferedReader(fi)
@@ -14,3 +15,9 @@ with FileIO('README.md') as fio:
assert len(result) <= 8*1024
assert len(result) >= 0
assert isinstance(result, bytes)
fd = os.open('README.md', os.O_RDONLY)
with FileIO(fd) as fio:
res2 = fio.read()
assert res == res2
+1 -1
View File
@@ -244,7 +244,7 @@ with TestWithTempDir() as tmpdir:
with TestWithTempCurrentDir():
os.chdir(tmpdir)
assert os.getcwd() == tmpdir
assert os.getcwd() == os.path.realpath(tmpdir)
os.path.exists(FILE_NAME)
# supports
+2
View File
@@ -14,6 +14,8 @@ assert isinstance(sys.implementation.cache_tag, str)
assert sys.getfilesystemencoding() == 'utf-8'
assert sys.getfilesystemencodeerrors().startswith('surrogate')
assert sys.byteorder == "little" or sys.byteorder == "big"
assert isinstance(sys.flags, tuple)
assert type(sys.flags).__name__ == "flags"
assert type(sys.flags.optimize) is int
+14
View File
@@ -8,3 +8,17 @@ v1, v2 = struct.unpack('IH', data)
assert v1 == 14
assert v2 == 12
data = struct.pack('<IH', 14, 12)
assert data == bytes([14, 0, 0, 0, 12, 0])
v1, v2 = struct.unpack('<IH', data)
assert v1 == 14
assert v2 == 12
data = struct.pack('>IH', 14, 12)
assert data == bytes([0, 0, 0, 14, 0, 12])
v1, v2 = struct.unpack('>IH', data)
assert v1 == 14
assert v2 == 12
+3
View File
@@ -23,6 +23,7 @@ def assert_raises(exc_type, expr, msg=None):
class assertRaises:
def __init__(self, expected):
self.expected = expected
self.exception = None
def __enter__(self):
return self
@@ -33,6 +34,8 @@ class assertRaises:
assert False, failmsg
if not issubclass(exc_type, self.expected):
return False
self.exception = exc_val
return True
+1 -1
View File
@@ -9,7 +9,7 @@ assert y[0] == 1
assert x + y == (1, 2, 1)
assert x * 3 == (1, 2, 1, 2, 1, 2)
# assert 3 * x == (1, 2, 1, 2, 1, 2)
assert 3 * x == (1, 2, 1, 2, 1, 2)
assert x * 0 == ()
assert x * -1 == () # integers less than zero treated as 0
+2 -4
View File
@@ -129,8 +129,7 @@ impl<T: Clone> Dict<T> {
if self.delete_if_exists(vm, key)? {
Ok(())
} else {
let key_repr = vm.to_pystr(key)?;
Err(vm.new_key_error(format!("Key not found: {}", key_repr)))
Err(vm.new_key_error(key.clone()))
}
}
@@ -247,8 +246,7 @@ impl<T: Clone> Dict<T> {
self.unchecked_delete(index);
Ok(value)
} else {
let key_repr = vm.to_pystr(key)?;
Err(vm.new_key_error(format!("Key not found: {}", key_repr)))
Err(vm.new_key_error(key.clone()))
}
}
+3 -2
View File
@@ -210,7 +210,7 @@ impl PyDictRef {
let method = method_or_err?;
return vm.invoke(method, vec![key]);
}
Err(vm.new_key_error(format!("Key not found: {}", vm.to_pystr(&key)?)))
Err(vm.new_key_error(key.clone()))
}
fn get(
@@ -266,7 +266,8 @@ impl PyDictRef {
if let Some((key, value)) = entries.pop_front() {
Ok(vm.ctx.new_tuple(vec![key, value]))
} else {
Err(vm.new_key_error("popitem(): dictionary is empty".to_string()))
let err_msg = vm.new_str("popitem(): dictionary is empty".to_string());
Err(vm.new_key_error(err_msg))
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ impl PyMappingProxy {
if let Some(value) = objtype::class_get_attr(&self.class, key.as_str()) {
return Ok(value);
}
Err(vm.new_key_error(format!("Key not found: {}", key)))
Err(vm.new_key_error(key.into_object()))
}
#[pymethod(name = "__contains__")]
+5
View File
@@ -33,6 +33,11 @@ impl PyMemoryView {
fn obj(&self, __vm: &VirtualMachine) -> PyObjectRef {
self.obj_ref.clone()
}
#[pymethod(name = "__getitem__")]
fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
vm.call_method(&self.obj_ref, "__getitem__", vec![needle])
}
}
impl PyValue for PyMemoryView {
+2 -1
View File
@@ -269,7 +269,8 @@ impl PySetInner {
if let Some((key, _)) = self.content.pop_front() {
Ok(key)
} else {
Err(vm.new_key_error("pop from an empty set".to_string()))
let err_msg = vm.new_str("pop from an empty set".to_string());
Err(vm.new_key_error(err_msg))
}
}
+1 -1
View File
@@ -1335,7 +1335,7 @@ fn perform_format(
let result = match arguments.get_optional_kwarg(&keyword) {
Some(argument) => call_object_format(vm, argument.clone(), &format_spec)?,
None => {
return Err(vm.new_key_error(format!("'{}'", keyword)));
return Err(vm.new_key_error(vm.new_str(keyword.to_string())));
}
};
get_value(&result)
+6
View File
@@ -168,6 +168,11 @@ impl PyTupleRef {
vm.ctx.new_tuple(new_elements)
}
fn rmul(self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
let new_elements = seq_mul(&self.elements, counter);
vm.ctx.new_tuple(new_elements)
}
fn getitem(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
get_item(vm, self.as_object(), &self.elements, needle.clone())
}
@@ -263,6 +268,7 @@ If the argument is a tuple, the return value is the same object.";
"__len__" => context.new_rustfunc(PyTupleRef::len),
"__new__" => context.new_rustfunc(tuple_new),
"__mul__" => context.new_rustfunc(PyTupleRef::mul),
"__rmul__" => context.new_rustfunc(PyTupleRef::rmul),
"__repr__" => context.new_rustfunc(PyTupleRef::repr),
"count" => context.new_rustfunc(PyTupleRef::count),
"__lt__" => context.new_rustfunc(PyTupleRef::lt),
+5
View File
@@ -77,6 +77,10 @@ fn imp_is_frozen_package(_name: PyStringRef, _vm: &VirtualMachine) -> bool {
false
}
fn imp_fix_co_filename(_code: PyObjectRef, _path: PyStringRef, _vm: &VirtualMachine) {
// TODO:
}
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
let module = py_module!(vm, "_imp", {
@@ -91,6 +95,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"get_frozen_object" => ctx.new_rustfunc(imp_get_frozen_object),
"init_frozen" => ctx.new_rustfunc(imp_init_frozen),
"is_frozen_package" => ctx.new_rustfunc(imp_is_frozen_package),
"_fix_co_filename" => ctx.new_rustfunc(imp_fix_co_filename),
});
module
+60 -61
View File
@@ -2,9 +2,7 @@
* I/O core tools.
*/
use std::cell::RefCell;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Cursor;
use std::io::SeekFrom;
@@ -18,9 +16,12 @@ use crate::function::{OptionalArg, PyFuncArgs};
use crate::import;
use crate::obj::objbytearray::PyByteArray;
use crate::obj::objbytes;
use crate::obj::objbytes::PyBytes;
use crate::obj::objint;
use crate::obj::objstr;
use crate::obj::objtype;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::TypeProtocol;
use crate::pyobject::{BufferProtocol, PyObjectRef, PyRef, PyResult, PyValue};
use crate::vm::VirtualMachine;
@@ -284,16 +285,19 @@ fn buffered_reader_read(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
}
fn compute_c_flag(mode: &str) -> u32 {
let flags = match mode {
"w" => os::FileCreationFlags::O_WRONLY | os::FileCreationFlags::O_CREAT,
"x" => {
os::FileCreationFlags::O_WRONLY
| os::FileCreationFlags::O_CREAT
| os::FileCreationFlags::O_EXCL
}
"a" => os::FileCreationFlags::O_APPEND,
"+" => os::FileCreationFlags::O_RDWR,
_ => os::FileCreationFlags::O_RDONLY,
let flags = match mode.chars().next() {
Some(mode) => match mode {
'w' => os::FileCreationFlags::O_WRONLY | os::FileCreationFlags::O_CREAT,
'x' => {
os::FileCreationFlags::O_WRONLY
| os::FileCreationFlags::O_CREAT
| os::FileCreationFlags::O_EXCL
}
'a' => os::FileCreationFlags::O_APPEND,
'+' => os::FileCreationFlags::O_RDWR,
_ => os::FileCreationFlags::O_RDONLY,
},
None => os::FileCreationFlags::O_RDONLY,
};
flags.bits()
}
@@ -302,47 +306,43 @@ fn file_io_init(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(file_io, None), (name, Some(vm.ctx.str_type()))],
required = [(file_io, None), (name, None)],
optional = [(mode, Some(vm.ctx.str_type()))]
);
let rust_mode = mode.map_or("r".to_string(), objstr::get_value);
let file_no = if objtype::isinstance(&name, &vm.ctx.str_type()) {
let rust_mode = mode.map_or("r".to_string(), objstr::get_value);
let args = vec![
name.clone(),
vm.ctx
.new_int(compute_c_flag(&rust_mode).to_bigint().unwrap()),
];
os::os_open(vm, PyFuncArgs::new(args, vec![]))?
} else if objtype::isinstance(&name, &vm.ctx.int_type()) {
name.clone()
} else {
return Err(vm.new_type_error("name parameter must be string or int".to_string()));
};
match compute_c_flag(&rust_mode).to_bigint() {
Some(os_mode) => {
let args = vec![name.clone(), vm.ctx.new_int(os_mode)];
let file_no = os::os_open(vm, PyFuncArgs::new(args, vec![]))?;
vm.set_attr(file_io, "name", name.clone())?;
vm.set_attr(file_io, "fileno", file_no)?;
vm.set_attr(file_io, "closefd", vm.new_bool(false))?;
vm.set_attr(file_io, "closed", vm.new_bool(false))?;
Ok(vm.get_none())
}
None => Err(vm.new_type_error(format!("invalid mode {}", rust_mode))),
}
vm.set_attr(file_io, "name", name.clone())?;
vm.set_attr(file_io, "fileno", file_no)?;
vm.set_attr(file_io, "closefd", vm.new_bool(false))?;
vm.set_attr(file_io, "closed", vm.new_bool(false))?;
Ok(vm.get_none())
}
fn file_io_read(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(file_io, None)]);
let py_name = vm.get_attribute(file_io.clone(), "name")?;
let f = match File::open(objstr::get_value(&py_name)) {
Ok(v) => Ok(v),
Err(_) => Err(vm.new_type_error("Error opening file".to_string())),
};
let buffer = match f {
Ok(v) => Ok(BufReader::new(v)),
Err(_) => Err(vm.new_type_error("Error reading from file".to_string())),
};
let file_no = vm.get_attribute(file_io.clone(), "fileno")?;
let raw_fd = objint::get_value(&file_no).to_i64().unwrap();
let mut handle = os::rust_file(raw_fd);
let mut bytes = vec![];
if let Ok(mut buff) = buffer {
match buff.read_to_end(&mut bytes) {
Ok(_) => {}
Err(_) => return Err(vm.new_value_error("Error reading from Buffer".to_string())),
}
match handle.read_to_end(&mut bytes) {
Ok(_) => {}
Err(_) => return Err(vm.new_value_error("Error reading from Buffer".to_string())),
}
Ok(vm.ctx.new_bytes(bytes))
@@ -385,11 +385,7 @@ fn file_io_readinto(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
}
fn file_io_write(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(file_io, None), (obj, Some(vm.ctx.bytes_type()))]
);
arg_check!(vm, args, required = [(file_io, None), (obj, None)]);
let file_no = vm.get_attribute(file_io.clone(), "fileno")?;
let raw_fd = objint::get_value(&file_no).to_i64().unwrap();
@@ -399,22 +395,25 @@ fn file_io_write(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
//to support windows - i.e. raw file_handles
let mut handle = os::rust_file(raw_fd);
match obj.payload::<PyByteArray>() {
Some(bytes) => {
let value_mut = &mut bytes.inner.borrow_mut().elements;
match handle.write(&value_mut[..]) {
Ok(len) => {
//reset raw fd on the FileIO object
let updated = os::raw_file_number(handle);
vm.set_attr(file_io, "fileno", vm.ctx.new_int(updated))?;
let bytes = match_class!(obj.clone(),
i @ PyBytes => Ok(i.get_value().to_vec()),
j @ PyByteArray => Ok(j.inner.borrow().elements.to_vec()),
obj => Err(vm.new_type_error(format!(
"a bytes-like object is required, not {}",
obj.class()
)))
);
//return number of bytes written
Ok(vm.ctx.new_int(len))
}
Err(_) => Err(vm.new_value_error("Error Writing Bytes to Handle".to_string())),
}
match handle.write(&bytes?) {
Ok(len) => {
//reset raw fd on the FileIO object
let updated = os::raw_file_number(handle);
vm.set_attr(file_io, "fileno", vm.ctx.new_int(updated))?;
//return number of bytes written
Ok(vm.ctx.new_int(len))
}
None => Err(vm.new_value_error("Expected Bytes Object".to_string())),
Err(_) => Err(vm.new_value_error("Error Writing Bytes to Handle".to_string())),
}
}
+12
View File
@@ -605,6 +605,17 @@ fn os_stat(path: PyStringRef, vm: &VirtualMachine) -> PyResult {
unimplemented!();
}
fn os_lstat(path: PyStringRef, dir_fd: DirFd, vm: &VirtualMachine) -> PyResult<StatResult> {
os_stat(
path,
dir_fd,
FollowSymlinks {
follow_symlinks: false,
},
vm,
)
}
#[cfg(unix)]
fn os_symlink(
src: PyStringRef,
@@ -788,6 +799,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"ScandirIter" => scandir_iter,
"DirEntry" => dir_entry,
"stat_result" => stat_result,
"lstat" => ctx.new_rustfunc(os_lstat),
"getcwd" => ctx.new_rustfunc(os_getcwd),
"chdir" => ctx.new_rustfunc(os_chdir),
"fspath" => ctx.new_rustfunc(os_fspath),
+2 -2
View File
@@ -48,7 +48,7 @@ fn pwd_getpwnam(name: PyStringRef, vm: &VirtualMachine) -> PyResult<Passwd> {
Ok(Some(passwd)) => Ok(passwd),
_ => {
let name_repr = vm.to_repr(name.as_object())?;
let message = format!("getpwnam(): name not found: {}", name_repr);
let message = vm.new_str(format!("getpwnam(): name not found: {}", name_repr));
Err(vm.new_key_error(message))
}
}
@@ -58,7 +58,7 @@ fn pwd_getpwuid(uid: u32, vm: &VirtualMachine) -> PyResult<Passwd> {
match Passwd::from_uid(uid) {
Some(passwd) => Ok(passwd),
_ => {
let message = format!("getpwuid(): uid not found: {}", uid);
let message = vm.new_str(format!("getpwuid(): uid not found: {}", uid));
Err(vm.new_key_error(message))
}
}
+238 -91
View File
@@ -1,6 +1,8 @@
/*
* Python struct module.
*
* Docs: https://docs.python.org/3/library/struct.html
*
* renamed to pystruct since struct is a rust keyword.
*
* Use this rust module to do byte packing:
@@ -8,8 +10,9 @@
*/
use std::io::{Cursor, Read, Write};
use std::iter::Peekable;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use byteorder::{ReadBytesExt, WriteBytesExt};
use num_bigint::BigInt;
use num_traits::ToPrimitive;
@@ -19,28 +22,86 @@ use crate::pyobject::{PyObjectRef, PyResult};
use crate::VirtualMachine;
#[derive(Debug)]
struct FormatCode {
code: char,
repeat: i32,
struct FormatSpec {
endianness: Endianness,
codes: Vec<FormatCode>,
}
fn parse_format_string(fmt: String) -> Vec<FormatCode> {
#[derive(Debug)]
enum Endianness {
Native,
Little,
Big,
Network,
}
#[derive(Debug)]
struct FormatCode {
code: char,
}
fn parse_format_string(fmt: String) -> Result<FormatSpec, String> {
let mut chars = fmt.chars().peekable();
// First determine "<", ">","!" or "="
// TODO
let endianness = parse_endiannes(&mut chars);
// Now, analyze struct string furter:
let codes = parse_format_codes(&mut chars)?;
Ok(FormatSpec { endianness, codes })
}
/// Parse endianness
/// See also: https://docs.python.org/3/library/struct.html?highlight=struct#byte-order-size-and-alignment
fn parse_endiannes<I>(chars: &mut Peekable<I>) -> Endianness
where
I: Sized,
I: Iterator<Item = char>,
{
match chars.peek() {
Some('@') => {
chars.next().unwrap();
Endianness::Native
}
Some('=') => {
chars.next().unwrap();
Endianness::Native
}
Some('<') => {
chars.next().unwrap();
Endianness::Little
}
Some('>') => {
chars.next().unwrap();
Endianness::Big
}
Some('!') => {
chars.next().unwrap();
Endianness::Network
}
_ => Endianness::Native,
}
}
fn parse_format_codes<I>(chars: &mut Peekable<I>) -> Result<Vec<FormatCode>, String>
where
I: Sized,
I: Iterator<Item = char>,
{
let mut codes = vec![];
for c in fmt.chars() {
for c in chars {
match c {
'b' | 'B' | 'h' | 'H' | 'i' | 'I' | 'q' | 'Q' | 'f' | 'd' => {
codes.push(FormatCode { code: c, repeat: 1 })
'b' | 'B' | 'h' | 'H' | 'i' | 'I' | 'l' | 'L' | 'q' | 'Q' | 'f' | 'd' => {
codes.push(FormatCode { code: c })
}
c => {
panic!("Illegal format code {:?}", c);
return Err(format!("Illegal format code {:?}", c));
}
}
}
codes
Ok(codes)
}
fn get_int(vm: &VirtualMachine, arg: &PyObjectRef) -> PyResult<BigInt> {
@@ -69,60 +130,112 @@ fn pack_bool(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResu
}
}
fn pack_i16(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
fn pack_i16<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_int(vm, arg)?.to_i16().unwrap();
data.write_i16::<LittleEndian>(v).unwrap();
data.write_i16::<Endianness>(v).unwrap();
Ok(())
}
fn pack_u16(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
fn pack_u16<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_int(vm, arg)?.to_u16().unwrap();
data.write_u16::<LittleEndian>(v).unwrap();
data.write_u16::<Endianness>(v).unwrap();
Ok(())
}
fn pack_i32(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
fn pack_i32<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_int(vm, arg)?.to_i32().unwrap();
data.write_i32::<LittleEndian>(v).unwrap();
data.write_i32::<Endianness>(v).unwrap();
Ok(())
}
fn pack_u32(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
fn pack_u32<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_int(vm, arg)?.to_u32().unwrap();
data.write_u32::<LittleEndian>(v).unwrap();
data.write_u32::<Endianness>(v).unwrap();
Ok(())
}
fn pack_i64(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
fn pack_i64<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_int(vm, arg)?.to_i64().unwrap();
data.write_i64::<LittleEndian>(v).unwrap();
data.write_i64::<Endianness>(v).unwrap();
Ok(())
}
fn pack_u64(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
fn pack_u64<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_int(vm, arg)?.to_u64().unwrap();
data.write_u64::<LittleEndian>(v).unwrap();
data.write_u64::<Endianness>(v).unwrap();
Ok(())
}
fn pack_f32(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
fn pack_f32<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_float(vm, arg)? as f32;
data.write_f32::<Endianness>(v).unwrap();
Ok(())
}
fn pack_f64<Endianness>(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
let v = get_float(vm, arg)?;
data.write_f64::<Endianness>(v).unwrap();
Ok(())
}
fn get_float(vm: &VirtualMachine, arg: &PyObjectRef) -> PyResult<f64> {
if objtype::isinstance(&arg, &vm.ctx.float_type()) {
let v = objfloat::get_value(arg) as f32;
data.write_f32::<LittleEndian>(v).unwrap();
Ok(())
Ok(objfloat::get_value(arg))
} else {
Err(vm.new_type_error("Expected float".to_string()))
}
}
fn pack_f64(vm: &VirtualMachine, arg: &PyObjectRef, data: &mut Write) -> PyResult<()> {
if objtype::isinstance(&arg, &vm.ctx.float_type()) {
let v = objfloat::get_value(arg) as f64;
data.write_f64::<LittleEndian>(v).unwrap();
Ok(())
} else {
Err(vm.new_type_error("Expected float".to_string()))
fn pack_item<Endianness>(
vm: &VirtualMachine,
code: &FormatCode,
arg: &PyObjectRef,
data: &mut Write,
) -> PyResult<()>
where
Endianness: byteorder::ByteOrder,
{
match code.code {
'b' => pack_i8(vm, arg, data)?,
'B' => pack_u8(vm, arg, data)?,
'?' => pack_bool(vm, arg, data)?,
'h' => pack_i16::<Endianness>(vm, arg, data)?,
'H' => pack_u16::<Endianness>(vm, arg, data)?,
'i' | 'l' => pack_i32::<Endianness>(vm, arg, data)?,
'I' | 'L' => pack_u32::<Endianness>(vm, arg, data)?,
'q' => pack_i64::<Endianness>(vm, arg, data)?,
'Q' => pack_u64::<Endianness>(vm, arg, data)?,
'f' => pack_f32::<Endianness>(vm, arg, data)?,
'd' => pack_f64::<Endianness>(vm, arg, data)?,
c => {
panic!("Unsupported format code {:?}", c);
}
}
Ok(())
}
fn struct_pack(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -136,30 +249,26 @@ fn struct_pack(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
if objtype::isinstance(&fmt_arg, &vm.ctx.str_type()) {
let fmt_str = objstr::get_value(&fmt_arg);
let codes = parse_format_string(fmt_str);
let format_spec = parse_format_string(fmt_str).map_err(|e| vm.new_value_error(e))?;;
if codes.len() + 1 == args.args.len() {
if format_spec.codes.len() + 1 == args.args.len() {
// Create data vector:
let mut data = Vec::<u8>::new();
// Loop over all opcodes:
for (code, arg) in codes.iter().zip(args.args.iter().skip(1)) {
for (code, arg) in format_spec.codes.iter().zip(args.args.iter().skip(1)) {
debug!("code: {:?}", code);
match code.code {
'b' => pack_i8(vm, arg, &mut data)?,
'B' => pack_u8(vm, arg, &mut data)?,
'?' => pack_bool(vm, arg, &mut data)?,
'h' => pack_i16(vm, arg, &mut data)?,
'H' => pack_u16(vm, arg, &mut data)?,
'i' => pack_i32(vm, arg, &mut data)?,
'I' => pack_u32(vm, arg, &mut data)?,
'l' => pack_i32(vm, arg, &mut data)?,
'L' => pack_u32(vm, arg, &mut data)?,
'q' => pack_i64(vm, arg, &mut data)?,
'Q' => pack_u64(vm, arg, &mut data)?,
'f' => pack_f32(vm, arg, &mut data)?,
'd' => pack_f64(vm, arg, &mut data)?,
c => {
panic!("Unsupported format code {:?}", c);
match format_spec.endianness {
Endianness::Little => {
pack_item::<byteorder::LittleEndian>(vm, code, arg, &mut data)?
}
Endianness::Big => {
pack_item::<byteorder::BigEndian>(vm, code, arg, &mut data)?
}
Endianness::Network => {
pack_item::<byteorder::NetworkEndian>(vm, code, arg, &mut data)?
}
Endianness::Native => {
pack_item::<byteorder::NativeEndian>(vm, code, arg, &mut data)?
}
}
}
@@ -168,7 +277,7 @@ fn struct_pack(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
} else {
Err(vm.new_type_error(format!(
"Expected {} arguments (got: {})",
codes.len() + 1,
format_spec.codes.len() + 1,
args.args.len()
)))
}
@@ -199,57 +308,81 @@ fn unpack_bool(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
}
}
fn unpack_i16(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_i16::<LittleEndian>() {
fn unpack_i16<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_i16::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_int(v)),
}
}
fn unpack_u16(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_u16::<LittleEndian>() {
fn unpack_u16<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_u16::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_int(v)),
}
}
fn unpack_i32(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_i32::<LittleEndian>() {
fn unpack_i32<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_i32::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_int(v)),
}
}
fn unpack_u32(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_u32::<LittleEndian>() {
fn unpack_u32<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_u32::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_int(v)),
}
}
fn unpack_i64(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_i64::<LittleEndian>() {
fn unpack_i64<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_i64::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_int(v)),
}
}
fn unpack_u64(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_u64::<LittleEndian>() {
fn unpack_u64<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_u64::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_int(v)),
}
}
fn unpack_f32(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_f32::<LittleEndian>() {
fn unpack_f32<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_f32::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_float(f64::from(v))),
}
}
fn unpack_f64(vm: &VirtualMachine, rdr: &mut Read) -> PyResult {
match rdr.read_f64::<LittleEndian>() {
fn unpack_f64<Endianness>(vm: &VirtualMachine, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match rdr.read_f64::<Endianness>() {
Err(err) => panic!("Error in reading {:?}", err),
Ok(v) => Ok(vm.ctx.new_float(v)),
}
@@ -267,41 +400,55 @@ fn struct_unpack(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
let fmt_str = objstr::get_value(&fmt);
let codes = parse_format_string(fmt_str);
let format_spec = parse_format_string(fmt_str).map_err(|e| vm.new_value_error(e))?;
let data = objbytes::get_value(buffer).to_vec();
let mut rdr = Cursor::new(data);
let mut items = vec![];
for code in codes {
for code in format_spec.codes {
debug!("unpack code: {:?}", code);
match code.code {
'b' => items.push(unpack_i8(vm, &mut rdr)?),
'B' => items.push(unpack_u8(vm, &mut rdr)?),
'?' => items.push(unpack_bool(vm, &mut rdr)?),
'h' => items.push(unpack_i16(vm, &mut rdr)?),
'H' => items.push(unpack_u16(vm, &mut rdr)?),
'i' => items.push(unpack_i32(vm, &mut rdr)?),
'I' => items.push(unpack_u32(vm, &mut rdr)?),
'l' => items.push(unpack_i32(vm, &mut rdr)?),
'L' => items.push(unpack_u32(vm, &mut rdr)?),
'q' => items.push(unpack_i64(vm, &mut rdr)?),
'Q' => items.push(unpack_u64(vm, &mut rdr)?),
'f' => items.push(unpack_f32(vm, &mut rdr)?),
'd' => items.push(unpack_f64(vm, &mut rdr)?),
c => {
panic!("Unsupported format code {:?}", c);
}
}
let item = match format_spec.endianness {
Endianness::Little => unpack_code::<byteorder::LittleEndian>(vm, &code, &mut rdr)?,
Endianness::Big => unpack_code::<byteorder::BigEndian>(vm, &code, &mut rdr)?,
Endianness::Network => unpack_code::<byteorder::NetworkEndian>(vm, &code, &mut rdr)?,
Endianness::Native => unpack_code::<byteorder::NativeEndian>(vm, &code, &mut rdr)?,
};
items.push(item);
}
Ok(vm.ctx.new_tuple(items))
}
fn unpack_code<Endianness>(vm: &VirtualMachine, code: &FormatCode, rdr: &mut Read) -> PyResult
where
Endianness: byteorder::ByteOrder,
{
match code.code {
'b' => unpack_i8(vm, rdr),
'B' => unpack_u8(vm, rdr),
'?' => unpack_bool(vm, rdr),
'h' => unpack_i16::<Endianness>(vm, rdr),
'H' => unpack_u16::<Endianness>(vm, rdr),
'i' | 'l' => unpack_i32::<Endianness>(vm, rdr),
'I' | 'L' => unpack_u32::<Endianness>(vm, rdr),
'q' => unpack_i64::<Endianness>(vm, rdr),
'Q' => unpack_u64::<Endianness>(vm, rdr),
'f' => unpack_f32::<Endianness>(vm, rdr),
'd' => unpack_f64::<Endianness>(vm, rdr),
c => {
panic!("Unsupported format code {:?}", c);
}
}
}
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
let struct_error = ctx.new_class("struct.error", ctx.object());
py_module!(vm, "struct", {
"pack" => ctx.new_rustfunc(struct_pack),
"unpack" => ctx.new_rustfunc(struct_unpack)
"unpack" => ctx.new_rustfunc(struct_unpack),
"error" => struct_error,
})
}
+10
View File
@@ -151,6 +151,15 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR
"unknown".to_string()
};
// https://doc.rust-lang.org/reference/conditional-compilation.html#target_endian
let bytorder = if cfg!(target_endian = "little") {
"little".to_string()
} else if cfg!(target_endian = "big") {
"big".to_string()
} else {
"unknown".to_string()
};
let sys_doc = "This module provides access to some objects used or maintained by the
interpreter and to functions that interact strongly with the interpreter.
@@ -229,6 +238,7 @@ settrace() -- set the global debug tracing function
"__name__" => ctx.new_str(String::from("sys")),
"argv" => argv(ctx),
"builtin_module_names" => ctx.new_tuple(module_names.iter().map(|v| v.into_pyobject(vm).unwrap()).collect()),
"byteorder" => ctx.new_str(bytorder),
"flags" => flags,
"getrefcount" => ctx.new_rustfunc(sys_getrefcount),
"getsizeof" => ctx.new_rustfunc(sys_getsizeof),
+10 -10
View File
@@ -167,20 +167,20 @@ impl VirtualMachine {
self.ctx.new_bool(b)
}
pub fn new_empty_exception(&self, exc_type: PyClassRef) -> PyResult {
fn new_exception_obj(&self, exc_type: PyClassRef, args: Vec<PyObjectRef>) -> PyResult {
// TODO: add repr of args into logging?
info!("New exception created: {}", exc_type.name);
let args = PyFuncArgs::default();
self.invoke(exc_type.into_object(), args)
}
pub fn new_empty_exception(&self, exc_type: PyClassRef) -> PyResult {
self.new_exception_obj(exc_type, vec![])
}
/// Create Python instance of `exc_type` with message as first element of `args` tuple
pub fn new_exception(&self, exc_type: PyClassRef, msg: String) -> PyObjectRef {
// TODO: exc_type may be user-defined exception, so we should return PyResult
// TODO: maybe there is a clearer way to create an instance:
info!("New exception created: {}('{}')", exc_type.name, msg);
let pymsg = self.new_str(msg);
let args: Vec<PyObjectRef> = vec![pymsg];
self.invoke(exc_type.into_object(), args).unwrap()
let pystr_msg = self.new_str(msg);
self.new_exception_obj(exc_type, vec![pystr_msg]).unwrap()
}
pub fn new_attribute_error(&self, msg: String) -> PyObjectRef {
@@ -224,9 +224,9 @@ impl VirtualMachine {
self.new_exception(value_error, msg)
}
pub fn new_key_error(&self, msg: String) -> PyObjectRef {
pub fn new_key_error(&self, obj: PyObjectRef) -> PyObjectRef {
let key_error = self.ctx.exceptions.key_error.clone();
self.new_exception(key_error, msg)
self.new_exception_obj(key_error, vec![obj]).unwrap()
}
pub fn new_index_error(&self, msg: String) -> PyObjectRef {