Skip to content

Commit 6070af3

Browse files
skinnyBatyouknowone
authored andcommitted
Use buffer args for _struct
1 parent 7ff974e commit 6070af3

File tree

2 files changed

+36
-48
lines changed

2 files changed

+36
-48
lines changed

vm/src/builtins/memory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl PyMemoryView {
7474
}
7575

7676
fn parse_format(format: &str, vm: &VirtualMachine) -> PyResult<FormatSpec> {
77-
FormatSpec::parse(format, vm)
77+
FormatSpec::parse(format.as_bytes(), vm)
7878
}
7979

8080
pub fn from_buffer(buffer: PyBuffer, vm: &VirtualMachine) -> PyResult<Self> {

vm/src/stdlib/pystruct.rs

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ pub(crate) mod _struct {
1414
use crate::{
1515
builtins::{float, PyBaseExceptionRef, PyBytesRef, PyStr, PyStrRef, PyTupleRef, PyTypeRef},
1616
common::str::wchar_t,
17-
function::{ArgBytesLike, ArgIntoBool, ArgMemoryBuffer, IntoPyObject, PosArgs},
17+
function::{
18+
ArgAsciiBuffer, ArgBytesLike, ArgIntoBool, ArgMemoryBuffer, IntoPyObject, PosArgs,
19+
},
1820
protocol::PyIterReturn,
1921
slots::{IteratorIterable, SlotConstructor, SlotIterator},
20-
utils::Either,
2122
PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, VirtualMachine,
2223
};
2324
use crossbeam_utils::atomic::AtomicCell;
@@ -211,24 +212,8 @@ pub(crate) mod _struct {
211212
}
212213

213214
impl FormatSpec {
214-
fn decode_and_parse(
215-
vm: &VirtualMachine,
216-
fmt: &Either<PyStrRef, PyBytesRef>,
217-
) -> PyResult<FormatSpec> {
218-
let decoded_fmt = match fmt {
219-
Either::A(string) => string.as_str(),
220-
Either::B(bytes) if bytes.is_ascii() => std::str::from_utf8(bytes).unwrap(),
221-
_ => {
222-
return Err(vm.new_unicode_decode_error(
223-
"Struct format must be a ascii string".to_owned(),
224-
))
225-
}
226-
};
227-
FormatSpec::parse(decoded_fmt, vm)
228-
}
229-
230-
pub fn parse(fmt: &str, vm: &VirtualMachine) -> PyResult<FormatSpec> {
231-
let mut chars = fmt.bytes().peekable();
215+
pub fn parse(fmt: &[u8], vm: &VirtualMachine) -> PyResult<FormatSpec> {
216+
let mut chars = fmt.iter().copied().peekable();
232217

233218
// First determine "@", "<", ">","!" or "="
234219
let endianness = parse_endianness(&mut chars);
@@ -399,10 +384,10 @@ pub(crate) mod _struct {
399384
let mut repeat = 0isize;
400385
while let Some(b'0'..=b'9') = chars.peek() {
401386
if let Some(c) = chars.next() {
402-
let current_digit = (c as char).to_digit(10).unwrap() as isize;
387+
let current_digit = c - b'0';
403388
repeat = repeat
404389
.checked_mul(10)
405-
.and_then(|r| r.checked_add(current_digit))
390+
.and_then(|r| r.checked_add(current_digit as _))
406391
.ok_or_else(|| OVERFLOW_MSG.to_owned())?;
407392
}
408393
}
@@ -486,20 +471,26 @@ pub(crate) mod _struct {
486471
}
487472
buffer_len - (-offset as usize)
488473
} else {
489-
if offset as usize >= buffer_len {
474+
let offset = offset as usize;
475+
let (op, op_action) = if is_pack {
476+
("pack_into", "packing")
477+
} else {
478+
("unpack_from", "unpacking")
479+
};
480+
if offset >= buffer_len {
490481
let msg = format!(
491482
"{op} requires a buffer of at least {required} bytes for {op_action} {needed} \
492483
bytes at offset {offset} (actual buffer size is {buffer_len})",
493-
op = if is_pack { "pack_into" } else { "unpack_from" },
494-
op_action = if is_pack { "packing" } else { "unpacking" },
484+
op = op,
485+
op_action = op_action,
495486
required = needed + offset as usize,
496487
needed = needed,
497488
offset = offset,
498489
buffer_len = buffer_len
499490
);
500491
return Err(new_struct_error(vm, msg));
501492
}
502-
offset as usize
493+
offset
503494
};
504495

505496
if (buffer_len - offset_from_start) < needed {
@@ -717,24 +708,20 @@ pub(crate) mod _struct {
717708
}
718709

719710
#[pyfunction]
720-
fn pack(
721-
fmt: Either<PyStrRef, PyBytesRef>,
722-
args: PosArgs,
723-
vm: &VirtualMachine,
724-
) -> PyResult<Vec<u8>> {
725-
let format_spec = FormatSpec::decode_and_parse(vm, &fmt)?;
711+
fn pack(fmt: ArgAsciiBuffer, args: PosArgs, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
712+
let format_spec = fmt.with_ref(|bytes| FormatSpec::parse(bytes, vm))?;
726713
format_spec.pack(args.into_vec(), vm)
727714
}
728715

729716
#[pyfunction]
730717
fn pack_into(
731-
fmt: Either<PyStrRef, PyBytesRef>,
718+
fmt: ArgAsciiBuffer,
732719
buffer: ArgMemoryBuffer,
733720
offset: isize,
734721
args: PosArgs,
735722
vm: &VirtualMachine,
736723
) -> PyResult<()> {
737-
let format_spec = FormatSpec::decode_and_parse(vm, &fmt)?;
724+
let format_spec = fmt.with_ref(|bytes| FormatSpec::parse(bytes, vm))?;
738725
let offset = get_buffer_offset(buffer.len(), offset, format_spec.size, true, vm)?;
739726
buffer.with_ref(|data| format_spec.pack_into(&mut data[offset..], args.into_vec(), vm))
740727
}
@@ -757,11 +744,11 @@ pub(crate) mod _struct {
757744

758745
#[pyfunction]
759746
fn unpack(
760-
fmt: Either<PyStrRef, PyBytesRef>,
747+
fmt: ArgAsciiBuffer,
761748
buffer: ArgBytesLike,
762749
vm: &VirtualMachine,
763750
) -> PyResult<PyTupleRef> {
764-
let format_spec = FormatSpec::decode_and_parse(vm, &fmt)?;
751+
let format_spec = fmt.with_ref(|bytes| FormatSpec::parse(bytes, vm))?;
765752
buffer.with_ref(|buf| format_spec.unpack(buf, vm))
766753
}
767754

@@ -774,11 +761,11 @@ pub(crate) mod _struct {
774761

775762
#[pyfunction]
776763
fn unpack_from(
777-
fmt: Either<PyStrRef, PyBytesRef>,
764+
fmt: ArgAsciiBuffer,
778765
args: UpdateFromArgs,
779766
vm: &VirtualMachine,
780767
) -> PyResult<PyTupleRef> {
781-
let format_spec = FormatSpec::decode_and_parse(vm, &fmt)?;
768+
let format_spec = fmt.with_ref(|bytes| FormatSpec::parse(bytes, vm))?;
782769
let offset =
783770
get_buffer_offset(args.buffer.len(), args.offset, format_spec.size, false, vm)?;
784771
args.buffer
@@ -849,17 +836,17 @@ pub(crate) mod _struct {
849836

850837
#[pyfunction]
851838
fn iter_unpack(
852-
fmt: Either<PyStrRef, PyBytesRef>,
839+
fmt: ArgAsciiBuffer,
853840
buffer: ArgBytesLike,
854841
vm: &VirtualMachine,
855842
) -> PyResult<UnpackIterator> {
856-
let format_spec = FormatSpec::decode_and_parse(vm, &fmt)?;
843+
let format_spec = fmt.with_ref(|bytes| FormatSpec::parse(bytes, vm))?;
857844
UnpackIterator::new(vm, format_spec, buffer)
858845
}
859846

860847
#[pyfunction]
861-
fn calcsize(fmt: Either<PyStrRef, PyBytesRef>, vm: &VirtualMachine) -> PyResult<usize> {
862-
let format_spec = FormatSpec::decode_and_parse(vm, &fmt)?;
848+
fn calcsize(fmt: ArgAsciiBuffer, vm: &VirtualMachine) -> PyResult<usize> {
849+
let format_spec = fmt.with_ref(|bytes| FormatSpec::parse(bytes, vm))?;
863850
Ok(format_spec.size)
864851
}
865852

@@ -872,14 +859,15 @@ pub(crate) mod _struct {
872859
}
873860

874861
impl SlotConstructor for PyStruct {
875-
type Args = Either<PyStrRef, PyBytesRef>;
862+
type Args = ArgAsciiBuffer;
876863

877864
fn py_new(cls: PyTypeRef, fmt: Self::Args, vm: &VirtualMachine) -> PyResult {
878-
let spec = FormatSpec::decode_and_parse(vm, &fmt)?;
865+
let spec = fmt.with_ref(|bytes| FormatSpec::parse(bytes, vm))?;
879866
let fmt_str = match fmt {
880-
Either::A(s) => s,
881-
Either::B(b) => PyStr::from(std::str::from_utf8(b.as_bytes()).unwrap())
882-
.into_ref_with_type(vm, vm.ctx.types.str_type.clone())?,
867+
ArgAsciiBuffer::String(s) => s,
868+
buffer => buffer
869+
.with_ref(|bytes| PyStr::from(std::str::from_utf8(bytes).unwrap()))
870+
.into_ref(vm),
883871
};
884872
PyStruct { spec, fmt_str }.into_pyresult_with_type(vm, cls)
885873
}

0 commit comments

Comments
 (0)