Skip to content

Commit 810ef7d

Browse files
committed
Add bytearray object
1 parent a6f64ee commit 810ef7d

File tree

9 files changed

+161
-38
lines changed

9 files changed

+161
-38
lines changed

tests/snippets/whats_left_to_implement.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -858,12 +858,11 @@
858858
not_implemented.append(("bool", method))
859859

860860
for method in bytearray_expected_methods:
861-
# TODO: uncomment this when bytearray is implemented
862-
# try:
863-
# if not hasattr(bytearray(), method):
864-
# not_implemented.append(("bytearray", method))
865-
# except NameError:
866-
not_implemented.append(("bytearray", method))
861+
try:
862+
if not hasattr(bytearray(), method):
863+
not_implemented.append(("bytearray", method))
864+
except NameError:
865+
not_implemented.append(("bytearray", method))
867866

868867
for method in bytes_expected_methods:
869868
try:

vm/src/builtins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ fn builtin_bin(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
9696
}
9797

9898
// builtin_breakpoint
99-
// builtin_bytearray
10099
// builtin_callable
101100

102101
fn builtin_chr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -531,6 +530,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
531530
dict.insert(String::from("any"), ctx.new_rustfunc(builtin_any));
532531
dict.insert(String::from("bin"), ctx.new_rustfunc(builtin_bin));
533532
dict.insert(String::from("bool"), ctx.bool_type());
533+
dict.insert(String::from("bytearray"), ctx.bytearray_type());
534534
dict.insert(String::from("bytes"), ctx.bytes_type());
535535
dict.insert(String::from("chr"), ctx.new_rustfunc(builtin_chr));
536536
dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile));

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! This package contains the python basic/builtin types
22
33
pub mod objbool;
4+
pub mod objbytearray;
45
pub mod objbytes;
56
pub mod objcomplex;
67
pub mod objdict;

vm/src/obj/objbytearray.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//! Implementation of the python bytearray object.
2+
3+
use super::super::pyobject::{
4+
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
5+
TypeProtocol,
6+
};
7+
use super::super::vm::VirtualMachine;
8+
use super::objbytes::get_value;
9+
use super::objint;
10+
use super::objtype;
11+
use num_traits::ToPrimitive;
12+
// Binary data support
13+
14+
/// Fill bytearray class methods dictionary.
15+
pub fn init(context: &PyContext) {
16+
let ref bytearray_type = context.bytearray_type;
17+
bytearray_type.set_attr("__eq__", context.new_rustfunc(bytearray_eq));
18+
bytearray_type.set_attr("__new__", context.new_rustfunc(bytearray_new));
19+
bytearray_type.set_attr("__repr__", context.new_rustfunc(bytearray_repr));
20+
}
21+
22+
fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
23+
arg_check!(
24+
vm,
25+
args,
26+
required = [(cls, None)],
27+
optional = [(val_option, None)]
28+
);
29+
if !objtype::issubclass(cls, &vm.ctx.bytearray_type()) {
30+
return Err(vm.new_type_error(format!("{:?} is not a subtype of bytearray", cls)));
31+
}
32+
33+
// Create bytes data:
34+
let value = if let Some(ival) = val_option {
35+
let elements = vm.extract_elements(ival)?;
36+
let mut data_bytes = vec![];
37+
for elem in elements.iter() {
38+
let v = objint::to_int(vm, elem, 10)?;
39+
data_bytes.push(v.to_u8().unwrap());
40+
}
41+
data_bytes
42+
// return Err(vm.new_type_error("Cannot construct bytes".to_string()));
43+
} else {
44+
vec![]
45+
};
46+
47+
Ok(PyObject::new(
48+
PyObjectKind::Bytes { value: value },
49+
cls.clone(),
50+
))
51+
}
52+
53+
fn bytearray_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
54+
arg_check!(
55+
vm,
56+
args,
57+
required = [(a, Some(vm.ctx.bytearray_type())), (b, None)]
58+
);
59+
60+
let result = if objtype::isinstance(b, &vm.ctx.bytearray_type()) {
61+
get_value(a).to_vec() == get_value(b).to_vec()
62+
} else {
63+
false
64+
};
65+
Ok(vm.ctx.new_bool(result))
66+
}
67+
68+
/*
69+
fn set_value(obj: &PyObjectRef, value: Vec<u8>) {
70+
obj.borrow_mut().kind = PyObjectKind::Bytes { value };
71+
}
72+
*/
73+
74+
fn bytearray_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
75+
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]);
76+
let data = get_value(obj);
77+
let data: Vec<String> = data.iter().map(|b| format!("\\x{:02x}", b)).collect();
78+
let data = data.join("");
79+
Ok(vm.new_str(format!("bytearray(b'{}')", data)))
80+
}

vm/src/obj/objbytes.rs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,52 @@
11
use super::super::pyobject::{
2-
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
2+
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
3+
TypeProtocol,
34
};
45
use super::super::vm::VirtualMachine;
56
use super::objint;
6-
use super::objlist;
77
use super::objtype;
88
use num_traits::ToPrimitive;
9+
use std::cell::Ref;
10+
use std::ops::Deref;
911
// Binary data support
1012

1113
// Fill bytes class methods:
1214
pub fn init(context: &PyContext) {
1315
let ref bytes_type = context.bytes_type;
1416
bytes_type.set_attr("__eq__", context.new_rustfunc(bytes_eq));
15-
bytes_type.set_attr("__init__", context.new_rustfunc(bytes_init));
17+
bytes_type.set_attr("__new__", context.new_rustfunc(bytes_new));
1618
bytes_type.set_attr("__repr__", context.new_rustfunc(bytes_repr));
1719
}
1820

19-
// __init__ (store value into objectkind)
20-
fn bytes_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
21+
fn bytes_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2122
arg_check!(
2223
vm,
2324
args,
24-
required = [(zelf, Some(vm.ctx.bytes_type())), (arg, None)]
25+
required = [(cls, None)],
26+
optional = [(val_option, None)]
2527
);
26-
let val = if objtype::isinstance(arg, &vm.ctx.list_type()) {
28+
if !objtype::issubclass(cls, &vm.ctx.bytes_type()) {
29+
return Err(vm.new_type_error(format!("{:?} is not a subtype of bytes", cls)));
30+
}
31+
32+
// Create bytes data:
33+
let value = if let Some(ival) = val_option {
34+
let elements = vm.extract_elements(ival)?;
2735
let mut data_bytes = vec![];
28-
for elem in objlist::get_elements(arg).iter() {
36+
for elem in elements.iter() {
2937
let v = objint::to_int(vm, elem, 10)?;
3038
data_bytes.push(v.to_u8().unwrap());
3139
}
3240
data_bytes
41+
// return Err(vm.new_type_error("Cannot construct bytes".to_string()));
3342
} else {
34-
return Err(vm.new_type_error("Cannot construct bytes".to_string()));
43+
vec![]
3544
};
36-
set_value(zelf, val);
37-
Ok(vm.get_none())
45+
46+
Ok(PyObject::new(
47+
PyObjectKind::Bytes { value: value },
48+
cls.clone(),
49+
))
3850
}
3951

4052
fn bytes_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -45,29 +57,27 @@ fn bytes_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4557
);
4658

4759
let result = if objtype::isinstance(b, &vm.ctx.bytes_type()) {
48-
get_value(a) == get_value(b)
60+
get_value(a).to_vec() == get_value(b).to_vec()
4961
} else {
5062
false
5163
};
5264
Ok(vm.ctx.new_bool(result))
5365
}
5466

55-
pub fn get_value(obj: &PyObjectRef) -> Vec<u8> {
56-
if let PyObjectKind::Bytes { value } = &obj.borrow().kind {
57-
value.clone()
58-
} else {
59-
panic!("Inner error getting int {:?}", obj);
60-
}
61-
}
62-
63-
fn set_value(obj: &PyObjectRef, value: Vec<u8>) {
64-
obj.borrow_mut().kind = PyObjectKind::Bytes { value };
67+
pub fn get_value<'a>(obj: &'a PyObjectRef) -> impl Deref<Target = Vec<u8>> + 'a {
68+
Ref::map(obj.borrow(), |py_obj| {
69+
if let PyObjectKind::Bytes { ref value } = py_obj.kind {
70+
value
71+
} else {
72+
panic!("Inner error getting int {:?}", obj);
73+
}
74+
})
6575
}
6676

6777
fn bytes_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6878
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytes_type()))]);
6979
let data = get_value(obj);
70-
let data: Vec<String> = data.into_iter().map(|b| format!("\\x{:02x}", b)).collect();
80+
let data: Vec<String> = data.iter().map(|b| format!("\\x{:02x}", b)).collect();
7181
let data = data.join("");
7282
Ok(vm.new_str(format!("b'{}'", data)))
7383
}

vm/src/obj/objlist.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,10 @@ fn list_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6868
return Err(vm.new_type_error(format!("{:?} is not a subtype of list", cls)));
6969
}
7070

71-
let elements = match iterable {
72-
None => vec![],
73-
Some(iterable) => {
74-
let iterator = objiter::get_iter(vm, iterable)?;
75-
objiter::get_all(vm, &iterator)?
76-
}
71+
let elements = if let Some(iterable) = iterable {
72+
vm.extract_elements(iterable)?
73+
} else {
74+
vec![]
7775
};
7876

7977
Ok(PyObject::new(

vm/src/obj/objtuple.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::super::pyobject::{
2-
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
2+
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
3+
TypeProtocol,
34
};
45
use super::super::vm::VirtualMachine;
56
use super::objbool;
@@ -55,6 +56,30 @@ fn tuple_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5556
Ok(vm.context().new_int(elements.len().to_bigint().unwrap()))
5657
}
5758

59+
fn tuple_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
60+
arg_check!(
61+
vm,
62+
args,
63+
required = [(cls, None)],
64+
optional = [(iterable, None)]
65+
);
66+
67+
if !objtype::issubclass(cls, &vm.ctx.tuple_type()) {
68+
return Err(vm.new_type_error(format!("{:?} is not a subtype of tuple", cls)));
69+
}
70+
71+
let elements = if let Some(iterable) = iterable {
72+
vm.extract_elements(iterable)?
73+
} else {
74+
vec![]
75+
};
76+
77+
Ok(PyObject::new(
78+
PyObjectKind::Tuple { elements: elements },
79+
cls.clone(),
80+
))
81+
}
82+
5883
fn tuple_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5984
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.tuple_type()))]);
6085

@@ -120,5 +145,6 @@ pub fn init(context: &PyContext) {
120145
tuple_type.set_attr("__getitem__", context.new_rustfunc(tuple_getitem));
121146
tuple_type.set_attr("__hash__", context.new_rustfunc(tuple_hash));
122147
tuple_type.set_attr("__len__", context.new_rustfunc(tuple_len));
148+
tuple_type.set_attr("__new__", context.new_rustfunc(tuple_new));
123149
tuple_type.set_attr("__repr__", context.new_rustfunc(tuple_repr));
124150
}

vm/src/pyobject.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::bytecode;
22
use super::exceptions;
33
use super::frame::Frame;
44
use super::obj::objbool;
5+
use super::obj::objbytearray;
56
use super::obj::objbytes;
67
use super::obj::objcomplex;
78
use super::obj::objdict;
@@ -63,6 +64,7 @@ pub struct PyContext {
6364
pub float_type: PyObjectRef,
6465
pub complex_type: PyObjectRef,
6566
pub bytes_type: PyObjectRef,
67+
pub bytearray_type: PyObjectRef,
6668
pub bool_type: PyObjectRef,
6769
pub true_value: PyObjectRef,
6870
pub false_value: PyObjectRef,
@@ -137,6 +139,7 @@ impl PyContext {
137139
let float_type = create_type("float", &type_type, &object_type, &dict_type);
138140
let complex_type = create_type("complex", &type_type, &object_type, &dict_type);
139141
let bytes_type = create_type("bytes", &type_type, &object_type, &dict_type);
142+
let bytearray_type = create_type("bytearray", &type_type, &object_type, &dict_type);
140143
let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type);
141144
let iter_type = create_type("iter", &type_type, &object_type, &dict_type);
142145
let bool_type = create_type("bool", &type_type, &int_type, &dict_type);
@@ -162,6 +165,7 @@ impl PyContext {
162165
float_type: float_type,
163166
complex_type: complex_type,
164167
bytes_type: bytes_type,
168+
bytearray_type: bytearray_type,
165169
list_type: list_type,
166170
set_type: set_type,
167171
bool_type: bool_type,
@@ -193,6 +197,7 @@ impl PyContext {
193197
objfloat::init(&context);
194198
objcomplex::init(&context);
195199
objbytes::init(&context);
200+
objbytearray::init(&context);
196201
objstr::init(&context);
197202
objtuple::init(&context);
198203
objiter::init(&context);
@@ -217,6 +222,10 @@ impl PyContext {
217222
self.bytes_type.clone()
218223
}
219224

225+
pub fn bytearray_type(&self) -> PyObjectRef {
226+
self.bytearray_type.clone()
227+
}
228+
220229
pub fn list_type(&self) -> PyObjectRef {
221230
self.list_type.clone()
222231
}

vm/src/stdlib/pystruct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ fn struct_unpack(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
313313
let fmt_str = objstr::get_value(&fmt);
314314

315315
let codes = parse_format_string(fmt_str);
316-
let data = objbytes::get_value(buffer);
316+
let data = objbytes::get_value(buffer).to_vec();
317317
let mut rdr = Cursor::new(data);
318318

319319
let mut items = vec![];

0 commit comments

Comments
 (0)