Skip to content
Merged
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
81 changes: 48 additions & 33 deletions crates/stdlib/src/elementtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,17 @@ pub(crate) mod _elementtree {
if obj.downcastable::<PyElement>() {
Ok(())
} else {
Err(vm.new_type_error(format!(
"expected an Element, not \"{}\"",
obj.class().name()
)))
reject_element(obj, vm)
}
}

fn reject_element(obj: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
Err(vm.new_type_error(format!(
"expected an Element, not \"{}\"",
obj.class().name()
)))
}

fn as_element<'a>(obj: &'a PyObject, vm: &VirtualMachine) -> PyResult<&'a Py<PyElement>> {
obj.downcast_ref::<PyElement>().ok_or_else(|| {
vm.new_type_error(format!(
Expand Down Expand Up @@ -984,40 +988,49 @@ pub(crate) mod _elementtree {
let mut recycle: Vec<PyObjectRef> = Vec::new();
match sequence_index(vm, needle)? {
SequenceIndex::Int(i) => {
check_element(&value, vm)?;
let mut inner = self.inner.write();
let pos = inner
.children
.wrap_index(i)
.ok_or_else(|| vm.new_index_error("child assignment index out of range"))?;
let Some(pos) = inner.children.wrap_index(i) else {
drop(inner);
return Err(vm.new_index_error("child assignment index out of range"));
};
if !value.downcastable::<PyElement>() {
drop(inner);
return reject_element(&value, vm);
}
recycle.push(core::mem::replace(&mut inner.children[pos], value));
Ok(())
}
SequenceIndex::Slice(slice) => {
let items: Vec<PyObjectRef> = value.try_to_value(vm)?;
for item in &items {
check_element(item, vm)?;
}
// This check cannot call Python. Delay reporting it until
// after the extended-slice length check.
let invalid = items.iter().find(|item| !item.downcastable::<PyElement>());
let mut inner = self.inner.write();
let (range, step, slice_len) = slice.adjust_indices(inner.children.len());
if step != 1 && slice_len != items.len() {
let new_len = items.len();
drop(inner);
drop(items);
return Err(vm.new_value_error(format!(
"attempt to assign sequence of size {} to extended slice of size {}",
new_len, slice_len
)));
}
if let Some(item) = invalid {
drop(inner);
return reject_element(item, vm);
}
if step == 1 {
recycle.extend(inner.children.splice(range, items));
Ok(())
} else if slice_len == items.len() {
} else {
let iter = crate::vm::sliceable::SaturatedSliceIter::from_adjust_indices(
range, step, slice_len,
);
for (pos, item) in iter.zip(items) {
recycle.push(core::mem::replace(&mut inner.children[pos], item));
}
Ok(())
} else {
Err(vm.new_value_error(format!(
"attempt to assign sequence of size {} to extended slice of size {}",
items.len(),
slice_len
)))
}
Ok(())
}
}
}
Expand Down Expand Up @@ -1232,19 +1245,21 @@ pub(crate) mod _elementtree {
}),
ass_item: atomic_func!(|seq, i, value, vm| {
let zelf = PyElement::sequence_downcast(seq);
let recycle = if let Some(value) = value {
check_element(&value, vm)?;
let recycle = {
let mut inner = zelf.inner.write();
let pos = inner.children.wrap_index(i).ok_or_else(|| {
vm.new_index_error("child assignment index out of range")
})?;
core::mem::replace(&mut inner.children[pos], value)
} else {
let mut inner = zelf.inner.write();
let pos = inner.children.wrap_index(i).ok_or_else(|| {
vm.new_index_error("child assignment index out of range")
})?;
inner.children.remove(pos)
let Some(pos) = inner.children.wrap_index(i) else {
drop(inner);
return Err(vm.new_index_error("child assignment index out of range"));
};
if let Some(value) = value {
if !value.downcastable::<PyElement>() {
drop(inner);
return reject_element(&value, vm);
}
core::mem::replace(&mut inner.children[pos], value)
} else {
inner.children.remove(pos)
}
};
drop(recycle);
Ok(())
Expand Down
Loading