Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 11 additions & 18 deletions crates/stdlib/src/binascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

pub(super) use decl::crc32;
pub(crate) use decl::module_def;

use rustpython_common::wtf8::Wtf8Buf;
use rustpython_vm::{VirtualMachine, builtins::PyBaseExceptionRef, convert::ToPyException};

const PAD: u8 = 61u8;
Expand All @@ -16,6 +18,7 @@ mod decl {
convert::ToPyException,
function::{ArgAsciiBuffer, ArgBytesLike, OptionalArg},
};

use base64::Engine;
use itertools::Itertools;

Expand All @@ -33,7 +36,7 @@ mod decl {
vm.ctx.new_exception_type("binascii", "Incomplete", None)
}

fn hex_nibble(n: u8) -> u8 {
const fn hex_nibble(n: u8) -> u8 {
match n {
0..=9 => b'0' + n,
10..=15 => b'a' + (n - 10),
Expand Down Expand Up @@ -174,21 +177,15 @@ mod decl {
fn unhexlify(data: ArgAsciiBuffer, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
data.with_ref(|hex_bytes| {
if hex_bytes.len() % 2 != 0 {
return Err(super::new_binascii_error(
"Odd-length string".to_owned(),
vm,
));
return Err(super::new_binascii_error("Odd-length string", vm));
}

let mut unhex = Vec::<u8>::with_capacity(hex_bytes.len() / 2);
for (n1, n2) in hex_bytes.iter().tuples() {
if let (Some(n1), Some(n2)) = (unhex_nibble(*n1), unhex_nibble(*n2)) {
unhex.push((n1 << 4) | n2);
} else {
return Err(super::new_binascii_error(
"Non-hexadecimal digit found".to_owned(),
vm,
));
return Err(super::new_binascii_error("Non-hexadecimal digit found", vm));
}
}

Expand Down Expand Up @@ -264,10 +261,10 @@ mod decl {

#[pyfunction]
fn a2b_base64(args: A2bBase64Args, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
#[rustfmt::skip]
// Converts between ASCII and base-64 characters. The index of a given number yields the
// number in ASCII while the value of said index yields the number in base-64. For example
// "=" is 61 in ASCII but 0 (since it's the pad character) in base-64, so BASE64_TABLE[61] == 0
#[rustfmt::skip]
const BASE64_TABLE: [i8; 256] = [
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
Expand Down Expand Up @@ -398,7 +395,7 @@ mod decl {
if [b'\r', b'\n'].contains(c) {
return Ok(0);
}
return Err(super::new_binascii_error("Illegal char".to_owned(), vm));
return Err(super::new_binascii_error("Illegal char", vm));
}
Ok((*c - b' ') & 0x3f)
}
Expand Down Expand Up @@ -757,8 +754,7 @@ mod decl {

// Allocate the buffer
let mut res = Vec::<u8>::with_capacity(length);
let trailing_garbage_error =
|| Err(super::new_binascii_error("Trailing garbage".to_owned(), vm));
let trailing_garbage_error = || Err(super::new_binascii_error("Trailing garbage", vm));

for chunk in b.get(1..).unwrap_or_default().chunks(4) {
let (char_a, char_b, char_c, char_d) = {
Expand Down Expand Up @@ -823,10 +819,7 @@ mod decl {
data.with_ref(|b| {
let length = b.len();
if length > 45 {
return Err(super::new_binascii_error(
"At most 45 bytes at once".to_owned(),
vm,
));
return Err(super::new_binascii_error("At most 45 bytes at once", vm));
}
let mut res = Vec::<u8>::with_capacity(2 + length.div_ceil(3) * 4);
res.push(uu_b2a(length as u8, backtick));
Expand All @@ -850,7 +843,7 @@ mod decl {

struct Base64DecodeError(base64::DecodeError);

fn new_binascii_error(msg: String, vm: &VirtualMachine) -> PyBaseExceptionRef {
fn new_binascii_error<T: Into<Wtf8Buf>>(msg: T, vm: &VirtualMachine) -> PyBaseExceptionRef {
vm.new_exception_msg(decl::error_type(vm), msg.into())
}

Expand Down
9 changes: 4 additions & 5 deletions crates/stdlib/src/unicodedata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,10 @@ mod unicodedata {

#[pymethod]
fn decomposition(&self, character: PyStrRef, vm: &VirtualMachine) -> PyResult<String> {
let ch = match self.extract_char(character, vm)?.and_then(|c| c.to_char()) {
Some(ch) => ch,
None => return Ok(String::new()),
let Some(ch) = self.extract_char(character, vm)?.and_then(|c| c.to_char()) else {
return Ok(String::new());
};
let chars: Vec<char> = ch.decomposition_map().collect();
let chars = ch.decomposition_map().collect::<Vec<char>>();
// If decomposition maps to just the character itself, there's no decomposition
if chars.len() == 1 && chars[0] == ch {
return Ok(String::new());
Expand Down Expand Up @@ -356,7 +355,7 @@ mod unicodedata {
}
}

fn decomposition_type_tag(dt: DecompositionType) -> &'static str {
const fn decomposition_type_tag(dt: DecompositionType) -> &'static str {
match dt {
DecompositionType::Canonical => "canonical",
DecompositionType::Compat => "compat",
Expand Down
3 changes: 3 additions & 0 deletions crates/vm/src/builtins/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,7 @@ impl Iterator for DictIntoIter {
(l, Some(l))
}
}

impl ExactSizeIterator for DictIntoIter {
fn len(&self) -> usize {
self.dict.entries.len_from_entry_index(self.position)
Expand Down Expand Up @@ -886,6 +887,7 @@ impl Iterator for DictIter<'_> {
(l, Some(l))
}
}

impl ExactSizeIterator for DictIter<'_> {
fn len(&self) -> usize {
self.dict.entries.len_from_entry_index(self.position)
Expand Down Expand Up @@ -1266,6 +1268,7 @@ trait ViewSetOps: DictView {
}

impl ViewSetOps for PyDictKeys {}

#[pyclass(
flags(DISALLOW_INSTANTIATION),
with(
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/builtins/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ impl AsSequence for PyList {
}
.map_err(|e| {
if e.class().is(vm.ctx.exceptions.index_error) {
vm.new_index_error("list assignment index out of range".to_owned())
vm.new_index_error("list assignment index out of range")
} else {
e
}
Expand Down
9 changes: 8 additions & 1 deletion crates/vm/src/stdlib/_collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ mod _collections {
})
} else {
Err(vm.new_type_error(format!(
"can only concatenate deque (not \"{}\") to deque",
r#"can only concatenate deque (not "{}") to deque"#,
other.class().name()
)))
}
Expand Down Expand Up @@ -503,11 +503,13 @@ mod _collections {
.concat(other, vm)
.map(|x| x.into_ref(&vm.ctx).into())
}),

repeat: atomic_func!(|seq, n, vm| {
PyDeque::sequence_downcast(seq)
.__mul__(n, vm)
.map(|x| x.into_ref(&vm.ctx).into())
}),

item: atomic_func!(|seq, i, vm| PyDeque::sequence_downcast(seq).__getitem__(i, vm)),
ass_item: atomic_func!(|seq, i, value, vm| {
let zelf = PyDeque::sequence_downcast(seq);
Expand All @@ -517,14 +519,17 @@ mod _collections {
zelf.__delitem__(i, vm)
}
}),

contains: atomic_func!(
|seq, needle, vm| PyDeque::sequence_downcast(seq)._contains(needle, vm)
),

inplace_concat: atomic_func!(|seq, other, vm| {
let zelf = PyDeque::sequence_downcast(seq);
zelf._extend(other, vm)?;
Ok(zelf.to_owned().into())
}),

inplace_repeat: atomic_func!(|seq, n, vm| {
let zelf = PyDeque::sequence_downcast(seq);
PyDeque::__imul__(zelf.to_owned(), n, vm).map(|x| x.into())
Expand All @@ -545,6 +550,7 @@ mod _collections {
if let Some(res) = op.identical_optimization(zelf, other) {
return Ok(res.into());
}

let other = class_or_notimplemented!(Self, other);
let lhs = zelf.borrow_deque();
let rhs = other.borrow_deque();
Expand Down Expand Up @@ -573,6 +579,7 @@ mod _collections {
if zelf.__len__() == 0 {
return Ok(vm.ctx.new_str(format!("{class_name}([{closing_part})")));
}

if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
Ok(vm.ctx.new_str(collection_repr(
Some(&class_name),
Expand Down
Loading
Loading