Merge branch 'master' into dev_array_del

This commit is contained in:
Steve Shi authored and GitHub committed 2020-09-04 10:25:47 +02:00
commit 05b7acc95f
13 files changed
+305 -102

No files matched your search

Generated
+1
View File
@@ -1585,6 +1585,7 @@ dependencies = [
"env_logger",
"flame",
"flamescope",
"libc",
"log",
"num-traits",
"rustpython-compiler",
+1
View File
@@ -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 }
+8 -9
View File
@@ -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:
-10
View File
@@ -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
-4
View File
@@ -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"):
+3 -8
View File
@@ -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
View File
@@ -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);
+12
View File
@@ -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))
+26
View File
@@ -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,
))
})
}
+6 -21
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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),