mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Merge branch 'master' into dev_array_del
This commit is contained in:
13 files changed
+305
-102
No files matched your search
Generated
+1
@@ -1585,6 +1585,7 @@ dependencies = [
|
||||
"env_logger",
|
||||
"flame",
|
||||
"flamescope",
|
||||
"libc",
|
||||
"log",
|
||||
"num-traits",
|
||||
"rustpython-compiler",
|
||||
|
||||
@@ -35,6 +35,7 @@ pylib = { package = "rustpython-pylib", path = "vm/pylib-crate", version = "0.1.
|
||||
dirs = { package = "dirs-next", version = "1.0" }
|
||||
num-traits = "0.2.8"
|
||||
cfg-if = "0.1"
|
||||
libc = "0.2"
|
||||
|
||||
flame = { version = "0.2", optional = true }
|
||||
flamescope = { version = "0.1", optional = true }
|
||||
|
||||
Vendored
+8
-9
@@ -915,7 +915,7 @@ def PyUnicode_DecodeUTF16Stateful(s, size, errors, byteorder='native', final=Tru
|
||||
p = []
|
||||
if byteorder == 'native':
|
||||
if (size >= 2):
|
||||
bom = (ord(s[ihi]) << 8) | ord(s[ilo])
|
||||
bom = (s[ihi] << 8) | s[ilo]
|
||||
#ifdef BYTEORDER_IS_LITTLE_ENDIAN
|
||||
if sys.byteorder == 'little':
|
||||
if (bom == 0xFEFF):
|
||||
@@ -962,11 +962,11 @@ def PyUnicode_DecodeUTF16Stateful(s, size, errors, byteorder='native', final=Tru
|
||||
# /* The remaining input chars are ignored if the callback
|
||||
## chooses to skip the input */
|
||||
|
||||
ch = (ord(s[q+ihi]) << 8) | ord(s[q+ilo])
|
||||
ch = (s[q+ihi] << 8) | s[q+ilo]
|
||||
q += 2
|
||||
|
||||
if (ch < 0xD800 or ch > 0xDFFF):
|
||||
p += chr(ch)
|
||||
p.append(chr(ch))
|
||||
continue
|
||||
|
||||
#/* UTF-16 code pair: */
|
||||
@@ -977,15 +977,14 @@ def PyUnicode_DecodeUTF16Stateful(s, size, errors, byteorder='native', final=Tru
|
||||
unicode_call_errorhandler(errors, 'utf-16', errmsg, s, startinpos, endinpos, True)
|
||||
|
||||
if (0xD800 <= ch and ch <= 0xDBFF):
|
||||
ch2 = (ord(s[q+ihi]) << 8) | ord(s[q+ilo])
|
||||
ch2 = (s[q+ihi] << 8) | s[q+ilo]
|
||||
q += 2
|
||||
if (0xDC00 <= ch2 and ch2 <= 0xDFFF):
|
||||
#ifndef Py_UNICODE_WIDE
|
||||
if sys.maxunicode < 65536:
|
||||
p += chr(ch)
|
||||
p += chr(ch2)
|
||||
p += [chr(ch), chr(ch2)]
|
||||
else:
|
||||
p += chr((((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000)
|
||||
p.append(chr((((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000))
|
||||
#endif
|
||||
continue
|
||||
|
||||
@@ -1006,8 +1005,8 @@ def PyUnicode_DecodeUTF16Stateful(s, size, errors, byteorder='native', final=Tru
|
||||
# have any nested variables.
|
||||
|
||||
def STORECHAR(CH, byteorder):
|
||||
hi = chr(((CH) >> 8) & 0xff)
|
||||
lo = chr((CH) & 0xff)
|
||||
hi = (CH >> 8) & 0xff
|
||||
lo = CH & 0xff
|
||||
if byteorder == 'little':
|
||||
return [lo, hi]
|
||||
else:
|
||||
|
||||
@@ -38,8 +38,6 @@ class MiscTest(unittest.TestCase):
|
||||
self.assertRaises(TypeError, array.array, 'xx')
|
||||
self.assertRaises(ValueError, array.array, 'x')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_empty(self):
|
||||
# Exercise code for handling zero-length arrays
|
||||
a = array.array('B')
|
||||
@@ -549,8 +547,6 @@ class BaseTest:
|
||||
self.assertIs(a > ab, False)
|
||||
self.assertIs(a >= ab, False)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_add(self):
|
||||
a = array.array(self.typecode, self.example) \
|
||||
+ array.array(self.typecode, self.example[::-1])
|
||||
@@ -564,8 +560,6 @@ class BaseTest:
|
||||
|
||||
self.assertRaises(TypeError, a.__add__, "bad")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_iadd(self):
|
||||
a = array.array(self.typecode, self.example[::-1])
|
||||
b = a
|
||||
@@ -587,8 +581,6 @@ class BaseTest:
|
||||
|
||||
self.assertRaises(TypeError, a.__iadd__, "bad")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_mul(self):
|
||||
a = 5*array.array(self.typecode, self.example)
|
||||
self.assertEqual(
|
||||
@@ -622,8 +614,6 @@ class BaseTest:
|
||||
|
||||
self.assertRaises(TypeError, a.__mul__, "bad")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_imul(self):
|
||||
a = array.array(self.typecode, self.example)
|
||||
b = a
|
||||
|
||||
@@ -300,8 +300,6 @@ class BaseBytesTest:
|
||||
for step in indices[1:]:
|
||||
self.assertEqual(b[start:stop:step], self.type2test(L[start:stop:step]))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_encoding(self):
|
||||
sample = "Hello world\n\u1234\u5678\u9abc"
|
||||
for enc in ("utf-8", "utf-16"):
|
||||
@@ -311,8 +309,6 @@ class BaseBytesTest:
|
||||
b = self.type2test(sample, "latin-1", "ignore")
|
||||
self.assertEqual(b, self.type2test(sample[:-3], "utf-8"))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_decode(self):
|
||||
sample = "Hello world\n\u1234\u5678\u9abc"
|
||||
for enc in ("utf-8", "utf-16"):
|
||||
|
||||
@@ -787,7 +787,9 @@ class LeapdaysTestCase(unittest.TestCase):
|
||||
|
||||
|
||||
def conv(s):
|
||||
return s.replace('\n', os.linesep).encode()
|
||||
# XXX RUSTPYTHON TODO: TextIOWrapper newline translation
|
||||
return s.encode()
|
||||
# return s.replace('\n', os.linesep).encode()
|
||||
|
||||
class CommandLineTestCase(unittest.TestCase):
|
||||
def run_ok(self, *args):
|
||||
@@ -817,18 +819,14 @@ class CommandLineTestCase(unittest.TestCase):
|
||||
self.assertIn(b'January', stdout)
|
||||
self.assertIn(b'Mo Tu We Th Fr Sa Su', stdout)
|
||||
|
||||
@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows')
|
||||
def test_output_year(self):
|
||||
stdout = self.run_ok('2004')
|
||||
self.assertEqual(stdout, conv(result_2004_text))
|
||||
|
||||
@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows')
|
||||
def test_output_month(self):
|
||||
stdout = self.run_ok('2004', '1')
|
||||
self.assertEqual(stdout, conv(result_2004_01_text))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_option_encoding(self):
|
||||
self.assertFailure('-e')
|
||||
self.assertFailure('--encoding')
|
||||
@@ -860,7 +858,6 @@ class CommandLineTestCase(unittest.TestCase):
|
||||
stdout = self.run_ok('--width', '3', '2004')
|
||||
self.assertIn(b'Mon Tue Wed Thu Fri Sat Sun', stdout)
|
||||
|
||||
@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows')
|
||||
def test_option_lines(self):
|
||||
self.assertFailure('-l')
|
||||
self.assertFailure('--lines')
|
||||
@@ -875,7 +872,6 @@ class CommandLineTestCase(unittest.TestCase):
|
||||
stdout = self.run_ok('--spacing', '8', '2004')
|
||||
self.assertIn(b'Su Mo', stdout)
|
||||
|
||||
@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows')
|
||||
def test_option_months(self):
|
||||
self.assertFailure('-m')
|
||||
self.assertFailure('--month')
|
||||
@@ -883,7 +879,6 @@ class CommandLineTestCase(unittest.TestCase):
|
||||
stdout = self.run_ok('--months', '1', '2004')
|
||||
self.assertIn(conv('\nMo Tu We Th Fr Sa Su\n'), stdout)
|
||||
|
||||
@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows')
|
||||
def test_option_type(self):
|
||||
self.assertFailure('-t')
|
||||
self.assertFailure('--type')
|
||||
|
||||
+13
@@ -36,6 +36,19 @@ fn main() {
|
||||
settings.initialization_parameter = InitParameter::InitializeInternal;
|
||||
}
|
||||
|
||||
// don't translate newlines (\r\n <=> \n)
|
||||
#[cfg(windows)]
|
||||
{
|
||||
extern "C" {
|
||||
fn _setmode(fd: i32, flags: i32) -> i32;
|
||||
}
|
||||
unsafe {
|
||||
_setmode(0, libc::O_BINARY);
|
||||
_setmode(1, libc::O_BINARY);
|
||||
_setmode(2, libc::O_BINARY);
|
||||
}
|
||||
}
|
||||
|
||||
let vm = VirtualMachine::new(settings);
|
||||
|
||||
let res = run_rustpython(&vm, &matches);
|
||||
|
||||
@@ -21,6 +21,18 @@ assert a.__ne__(b) is False
|
||||
b = array("B", [3, 2, 1, 0])
|
||||
assert a.__ne__(b) is True
|
||||
|
||||
def test_float_with_integer_input():
|
||||
f = array("f", [0, 1, 2.0, 3.0])
|
||||
f.append(4)
|
||||
f.insert(0, -1)
|
||||
assert f.count(4) == 1
|
||||
f.remove(1)
|
||||
assert f.index(0) == 1
|
||||
f[0] = -2
|
||||
assert f == array("f", [-2, 0, 2, 3, 4])
|
||||
|
||||
test_float_with_integer_input()
|
||||
|
||||
# slice assignment step overflow behaviour test
|
||||
T = 'I'
|
||||
a = array(T, range(10))
|
||||
|
||||
@@ -1290,3 +1290,29 @@ impl<'s> PyCommonString<'s, u8> for [u8] {
|
||||
splited
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
pub struct DecodeArgs {
|
||||
#[pyarg(positional_or_keyword, default = "None")]
|
||||
encoding: Option<PyStringRef>,
|
||||
#[pyarg(positional_or_keyword, default = "None")]
|
||||
errors: Option<PyStringRef>,
|
||||
}
|
||||
|
||||
pub fn bytes_decode(
|
||||
zelf: PyObjectRef,
|
||||
args: DecodeArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyStringRef> {
|
||||
let DecodeArgs { encoding, errors } = args;
|
||||
vm.decode(zelf, encoding.clone(), errors)?
|
||||
.downcast::<PyString>()
|
||||
.map_err(|obj| {
|
||||
vm.new_type_error(format!(
|
||||
"'{}' decoder returned '{}' instead of 'str'; use codecs.encode() to \
|
||||
encode arbitrary types",
|
||||
encoding.as_ref().map_or("utf-8", |s| s.borrow_value()),
|
||||
obj.lease_class().name,
|
||||
))
|
||||
})
|
||||
}
|
||||
@@ -7,17 +7,17 @@ use std::mem::size_of;
|
||||
use super::objint::PyIntRef;
|
||||
use super::objiter;
|
||||
use super::objsequence::SequenceIndex;
|
||||
use super::objstr::{PyString, PyStringRef};
|
||||
use super::objstr::PyStringRef;
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::bytesinner::{
|
||||
ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions,
|
||||
ByteInnerTranslateOptions, ByteOr, PyBytesInner,
|
||||
bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
|
||||
ByteInnerSplitOptions, ByteInnerTranslateOptions, ByteOr, DecodeArgs, PyBytesInner,
|
||||
};
|
||||
use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard};
|
||||
use crate::function::{OptionalArg, OptionalOption};
|
||||
use crate::pyobject::{
|
||||
BorrowValue, Either, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef,
|
||||
PyResult, PyValue, TryFromObject, TypeProtocol,
|
||||
PyResult, PyValue, TryFromObject,
|
||||
};
|
||||
use crate::pystr::{self, PyCommonString};
|
||||
use crate::vm::VirtualMachine;
|
||||
@@ -582,23 +582,8 @@ impl PyByteArray {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn decode(
|
||||
zelf: PyRef<Self>,
|
||||
encoding: OptionalArg<PyStringRef>,
|
||||
errors: OptionalArg<PyStringRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyStringRef> {
|
||||
let encoding = encoding.into_option();
|
||||
vm.decode(zelf.into_object(), encoding.clone(), errors.into_option())?
|
||||
.downcast::<PyString>()
|
||||
.map_err(|obj| {
|
||||
vm.new_type_error(format!(
|
||||
"'{}' decoder returned '{}' instead of 'str'; use codecs.encode() to \
|
||||
encode arbitrary types",
|
||||
encoding.as_ref().map_or("utf-8", |s| s.borrow_value()),
|
||||
obj.lease_class().name,
|
||||
))
|
||||
})
|
||||
fn decode(zelf: PyRef<Self>, args: DecodeArgs, vm: &VirtualMachine) -> PyResult<PyStringRef> {
|
||||
bytes_decode(zelf.into_object(), args, vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-22
@@ -6,18 +6,18 @@ use std::ops::Deref;
|
||||
use super::objint::PyIntRef;
|
||||
use super::objiter;
|
||||
use super::objsequence::SequenceIndex;
|
||||
use super::objstr::{PyString, PyStringRef};
|
||||
use super::objstr::PyStringRef;
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::bytesinner::{
|
||||
ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions,
|
||||
ByteInnerTranslateOptions, PyBytesInner,
|
||||
bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
|
||||
ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner,
|
||||
};
|
||||
use crate::function::{OptionalArg, OptionalOption};
|
||||
use crate::pyobject::{
|
||||
BorrowValue, Either, IntoPyObject,
|
||||
PyArithmaticValue::{self, *},
|
||||
PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
TryFromObject, TypeProtocol,
|
||||
TryFromObject,
|
||||
};
|
||||
use crate::pystr::{self, PyCommonString};
|
||||
use crate::vm::VirtualMachine;
|
||||
@@ -467,24 +467,9 @@ impl PyBytes {
|
||||
/// For a list of possible encodings,
|
||||
/// see https://docs.python.org/3/library/codecs.html#standard-encodings
|
||||
/// currently, only 'utf-8' and 'ascii' emplemented
|
||||
#[pymethod(name = "decode")]
|
||||
fn decode(
|
||||
zelf: PyRef<Self>,
|
||||
encoding: OptionalArg<PyStringRef>,
|
||||
errors: OptionalArg<PyStringRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyStringRef> {
|
||||
let encoding = encoding.into_option();
|
||||
vm.decode(zelf.into_object(), encoding.clone(), errors.into_option())?
|
||||
.downcast::<PyString>()
|
||||
.map_err(|obj| {
|
||||
vm.new_type_error(format!(
|
||||
"'{}' decoder returned '{}' instead of 'str'; use codecs.encode() to \
|
||||
encode arbitrary types",
|
||||
encoding.as_ref().map_or("utf-8", |s| s.borrow_value()),
|
||||
obj.lease_class().name,
|
||||
))
|
||||
})
|
||||
#[pymethod]
|
||||
fn decode(zelf: PyRef<Self>, args: DecodeArgs, vm: &VirtualMachine) -> PyResult<PyStringRef> {
|
||||
bytes_decode(zelf.into_object(), args, vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+161
-27
@@ -4,6 +4,7 @@ use crate::common::cell::{
|
||||
};
|
||||
use crate::function::OptionalArg;
|
||||
use crate::obj::objbytes::PyBytesRef;
|
||||
use crate::obj::objfloat::try_float;
|
||||
use crate::obj::objsequence::{get_slice_range, PySliceableSequence};
|
||||
use crate::obj::objslice::PySliceRef;
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
@@ -11,7 +12,7 @@ use crate::obj::objtype::PyClassRef;
|
||||
use crate::obj::{objbool, objiter};
|
||||
use crate::pyobject::{
|
||||
BorrowValue, Either, IdProtocol, IntoPyObject, PyArithmaticValue, PyClassImpl,
|
||||
PyComparisonValue, PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
PyComparisonValue, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
TypeProtocol,
|
||||
};
|
||||
use crate::VirtualMachine;
|
||||
@@ -77,7 +78,7 @@ macro_rules! def_array_enum {
|
||||
fn push(&mut self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let val = $t::try_from_object(vm, obj)?;
|
||||
let val = $t::try_into_from_object(vm, obj)?;
|
||||
v.push(val);
|
||||
})*
|
||||
}
|
||||
@@ -95,19 +96,21 @@ macro_rules! def_array_enum {
|
||||
fn insert(&mut self, i: usize, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let val = $t::try_from_object(vm, obj)?;
|
||||
let val = $t::try_into_from_object(vm, obj)?;
|
||||
v.insert(i, val);
|
||||
})*
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn count(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
fn count(&self, obj: PyObjectRef, vm: &VirtualMachine) -> usize {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
Ok(<Option<$t>>::try_from_object(vm, obj)?.map_or(0, |val| {
|
||||
if let Ok(val) = $t::try_into_from_object(vm, obj) {
|
||||
v.iter().filter(|&&a| a == val).count()
|
||||
}))
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})*
|
||||
}
|
||||
}
|
||||
@@ -115,13 +118,15 @@ macro_rules! def_array_enum {
|
||||
fn remove(&mut self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()>{
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let pos = <Option<$t>>::try_from_object(vm, obj)?.map_or(None, |val| {
|
||||
v.iter().position(|&a| a == val)
|
||||
}).ok_or_else(||vm.new_value_error("array.remove(x): x not in array".to_owned()) )?;
|
||||
v.remove(pos);
|
||||
if let Ok(val) = $t::try_into_from_object(vm, obj) {
|
||||
if let Some(pos) = v.iter().position(|&a| a == val) {
|
||||
v.remove(pos);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(vm.new_value_error("array.remove(x): x not in array".to_owned()))
|
||||
})*
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn frombytes(&mut self, b: &[u8]) {
|
||||
@@ -159,12 +164,15 @@ macro_rules! def_array_enum {
|
||||
}
|
||||
}
|
||||
|
||||
fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<usize>> {
|
||||
fn index(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
Ok(<Option<$t>>::try_from_object(vm, x)?.map_or(None, |val| {
|
||||
v.iter().position(|&a| a == val)
|
||||
}))
|
||||
if let Ok(val) = $t::try_into_from_object(vm, obj) {
|
||||
if let Some(pos) = v.iter().position(|&a| a == val) {
|
||||
return Ok(pos);
|
||||
}
|
||||
}
|
||||
Err(vm.new_value_error("array.index(x): x not in array".to_owned()))
|
||||
})*
|
||||
}
|
||||
}
|
||||
@@ -203,13 +211,10 @@ macro_rules! def_array_enum {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let elements = v.get_slice_items(vm, &slice)?;
|
||||
let sliced = ArrayContentType::$n(elements);
|
||||
let obj = PyObject::new(
|
||||
PyArray {
|
||||
array: PyRwLock::new(sliced)
|
||||
},
|
||||
PyArray::class(vm),
|
||||
None
|
||||
);
|
||||
let obj = PyArray {
|
||||
array: PyRwLock::new(sliced)
|
||||
}
|
||||
.into_simple_object(vm);
|
||||
Ok(obj)
|
||||
})*
|
||||
}
|
||||
@@ -330,7 +335,7 @@ macro_rules! def_array_enum {
|
||||
fn setitem_by_idx(&mut self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let i = self.idx(i, "array assignment", vm)?;
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => { v[i] = TryFromObject::try_from_object(vm, value)? },)*
|
||||
$(ArrayContentType::$n(v) => { v[i] = $t::try_into_from_object(vm, value)? },)*
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -419,6 +424,57 @@ macro_rules! def_array_enum {
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&self, other: &ArrayContentType, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => if let ArrayContentType::$n(other) = other {
|
||||
let elements = v.iter().chain(other.iter()).cloned().collect();
|
||||
let sliced = ArrayContentType::$n(elements);
|
||||
let obj = PyArray {
|
||||
array: PyRwLock::new(sliced)
|
||||
}
|
||||
.into_simple_object(vm);
|
||||
Ok(obj)
|
||||
} else {
|
||||
Err(vm.new_type_error("bad argument type for built-in operation".to_owned()))
|
||||
},)*
|
||||
}
|
||||
}
|
||||
|
||||
fn iadd(&mut self, other: ArrayContentType, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => if let ArrayContentType::$n(mut other) = other {
|
||||
v.append(&mut other);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_type_error("can only extend with array of same kind".to_owned()))
|
||||
},)*
|
||||
}
|
||||
}
|
||||
|
||||
fn mul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let counter = if counter < 0 { 0 } else { counter as usize };
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let elements = v.iter().cycle().take(v.len() * counter).cloned().collect();
|
||||
let sliced = ArrayContentType::$n(elements);
|
||||
PyArray {
|
||||
array: PyRwLock::new(sliced)
|
||||
}
|
||||
.into_simple_object(vm)
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
fn imul(&mut self, counter: isize) {
|
||||
let counter = if counter < 0 { 0 } else { counter as usize };
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let mut elements = v.iter().cycle().take(v.len() * counter).cloned().collect();
|
||||
std::mem::swap(v, &mut elements);
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
fn repr(&self, _vm: &VirtualMachine) -> PyResult<String> {
|
||||
// we don't need ReprGuard here
|
||||
let s = match self {
|
||||
@@ -461,6 +517,44 @@ def_array_enum!(
|
||||
(Double, f64, 'd'),
|
||||
);
|
||||
|
||||
trait ArrayElement: Sized {
|
||||
fn try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self>;
|
||||
}
|
||||
|
||||
macro_rules! adapt_try_into_from_object {
|
||||
($(($t:ty, $f: path),)*) => {$(
|
||||
impl ArrayElement for $t {
|
||||
fn try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
$f(vm, obj)
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
adapt_try_into_from_object!(
|
||||
(i8, i8::try_from_object),
|
||||
(u8, u8::try_from_object),
|
||||
(i16, i16::try_from_object),
|
||||
(u16, u16::try_from_object),
|
||||
(i32, i32::try_from_object),
|
||||
(u32, u32::try_from_object),
|
||||
(i64, i64::try_from_object),
|
||||
(u64, u64::try_from_object),
|
||||
(f32, f32_try_into_from_object),
|
||||
(f64, f64_try_into_from_object),
|
||||
);
|
||||
|
||||
fn f32_try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<f32> {
|
||||
try_float(&obj, vm)?
|
||||
.map(|x| x as f32)
|
||||
.ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", obj.class().name)))
|
||||
}
|
||||
|
||||
fn f64_try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<f64> {
|
||||
try_float(&obj, vm)?
|
||||
.ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", obj.class().name)))
|
||||
}
|
||||
|
||||
#[pyclass(module = "array", name = "array")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyArray {
|
||||
@@ -528,7 +622,7 @@ impl PyArray {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn count(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
fn count(&self, x: PyObjectRef, vm: &VirtualMachine) -> usize {
|
||||
self.borrow_value().count(x, vm)
|
||||
}
|
||||
|
||||
@@ -561,9 +655,7 @@ impl PyArray {
|
||||
|
||||
#[pymethod]
|
||||
fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
self.borrow_value()
|
||||
.index(x, vm)?
|
||||
.ok_or_else(|| vm.new_value_error("x not in array".to_owned()))
|
||||
self.borrow_value().index(x, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -672,6 +764,48 @@ impl PyArray {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__add__")]
|
||||
fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
if let Some(other) = other.payload::<PyArray>() {
|
||||
self.borrow_value().add(&*other.borrow_value(), vm)
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"can only append array (not \"{}\") to array",
|
||||
other.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iadd__")]
|
||||
fn iadd(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
if let Some(other) = other.payload::<PyArray>() {
|
||||
let other = other.borrow_value().clone();
|
||||
let result = zelf.borrow_value_mut().iadd(other, vm);
|
||||
result.map(|_| zelf.into_object())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"can only extend array with array (not \"{}\")",
|
||||
other.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__mul__")]
|
||||
fn mul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.borrow_value().mul(counter, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rmul__")]
|
||||
fn rmul(&self, counter: isize, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.mul(counter, &vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__imul__")]
|
||||
fn imul(zelf: PyRef<Self>, counter: isize) -> PyRef<Self> {
|
||||
zelf.borrow_value_mut().imul(counter);
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__repr__")]
|
||||
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<String> {
|
||||
zelf.borrow_value().repr(vm)
|
||||
|
||||
+67
-1
@@ -1,6 +1,6 @@
|
||||
use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard};
|
||||
use std::io::{self, prelude::*};
|
||||
use std::net::{Ipv4Addr, Shutdown, SocketAddr, ToSocketAddrs};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
|
||||
use std::time::Duration;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
@@ -596,6 +596,56 @@ fn socket_gethostbyname(name: PyStringRef, vm: &VirtualMachine) -> PyResult<Stri
|
||||
}
|
||||
}
|
||||
|
||||
fn socket_inet_pton(af_inet: i32, ip_string: PyStringRef, vm: &VirtualMachine) -> PyResult {
|
||||
match af_inet {
|
||||
c::AF_INET => ip_string
|
||||
.borrow_value()
|
||||
.parse::<Ipv4Addr>()
|
||||
.map(|ip_addr| vm.ctx.new_bytes(ip_addr.octets().to_vec()))
|
||||
.map_err(|_| {
|
||||
vm.new_os_error("illegal IP address string passed to inet_pton".to_owned())
|
||||
}),
|
||||
c::AF_INET6 => ip_string
|
||||
.borrow_value()
|
||||
.parse::<Ipv6Addr>()
|
||||
.map(|ip_addr| vm.ctx.new_bytes(ip_addr.octets().to_vec()))
|
||||
.map_err(|_| {
|
||||
vm.new_os_error("illegal IP address string passed to inet_pton".to_owned())
|
||||
}),
|
||||
_ => Err(vm.new_os_error("Address family not supported by protocol".to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
fn socket_inet_ntop(af_inet: i32, packed_ip: PyBytesRef, vm: &VirtualMachine) -> PyResult {
|
||||
match af_inet {
|
||||
c::AF_INET => {
|
||||
if packed_ip.len() != 4 {
|
||||
return Err(
|
||||
vm.new_value_error("invalid length of packed IP address string".to_owned())
|
||||
);
|
||||
}
|
||||
let ip_num = BigEndian::read_u32(&packed_ip);
|
||||
Ok(vm.ctx.new_str(Ipv4Addr::from(ip_num).to_string()))
|
||||
}
|
||||
c::AF_INET6 => {
|
||||
if packed_ip.len() != 16 {
|
||||
return Err(
|
||||
vm.new_value_error("invalid length of packed IP address string".to_owned())
|
||||
);
|
||||
}
|
||||
let mut iter = packed_ip.iter();
|
||||
let mut ip_num: u128 = *iter.next().unwrap() as u128;
|
||||
for item in iter {
|
||||
ip_num <<= 8;
|
||||
ip_num |= *item as u128
|
||||
}
|
||||
let ipv6 = Ipv6Addr::from(ip_num);
|
||||
Ok(vm.ctx.new_str(get_ipv6_addr_str(ipv6)))
|
||||
}
|
||||
_ => Err(vm.new_value_error(format!("unknown address family {}", af_inet))),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_addr<T, I>(vm: &VirtualMachine, addr: T) -> PyResult<socket2::SockAddr>
|
||||
where
|
||||
T: ToSocketAddrs<Iter = I>,
|
||||
@@ -667,6 +717,20 @@ fn convert_sock_error(vm: &VirtualMachine, err: io::Error) -> PyBaseExceptionRef
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ipv6_addr_str(ipv6: Ipv6Addr) -> String {
|
||||
match ipv6.to_ipv4() {
|
||||
Some(_) => {
|
||||
let segments = ipv6.segments();
|
||||
if segments[5] == 0 && segments[6] == 0 {
|
||||
format!("::{:x}", segments[7] as u32)
|
||||
} else {
|
||||
ipv6.to_string()
|
||||
}
|
||||
}
|
||||
None => ipv6.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
let socket_timeout = ctx.new_class(
|
||||
@@ -694,6 +758,8 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"ntohs" => ctx.new_function(u16::from_be),
|
||||
"getdefaulttimeout" => ctx.new_function(|vm: &VirtualMachine| vm.get_none()),
|
||||
"has_ipv6" => ctx.new_bool(false),
|
||||
"inet_pton" => ctx.new_function(socket_inet_pton),
|
||||
"inet_ntop" => ctx.new_function(socket_inet_ntop),
|
||||
// constants
|
||||
"AF_UNSPEC" => ctx.new_int(0),
|
||||
"AF_INET" => ctx.new_int(c::AF_INET),
|
||||
|
||||
Reference in new issue
Block a user