add mapping protocol methods to update_slot

Signed-off-by: snowapril <sinjihng@gmail.com>
This commit is contained in:
snowapril committed 2021-10-02 14:43:20 +09:00
1 parent 1fbbdaabe3
commit 6e11b8931c
1 file changed
+50
+50
View File
@@ -4,6 +4,7 @@ use super::{
};
use crate::common::{ascii, lock::PyRwLock};
use crate::{
builtins::dict::PyMapping,
function::{FuncArgs, KwArgs, OptionalArg},
protocol::PyIterReturn,
slots::{self, Callable, PyTypeFlags, PyTypeSlots, SlotGetattro, SlotSetattro},
@@ -12,6 +13,7 @@ use crate::{
PyValue, TryFromObject, TypeProtocol, VirtualMachine,
};
use itertools::Itertools;
use num_traits::ToPrimitive;
use std::collections::HashSet;
use std::fmt;
use std::ops::Deref;
@@ -270,6 +272,54 @@ impl PyType {
};
update_slot!(iternext, func);
}
"__len__" | "__getitem__" | "__setitem__" | "__delitem__" => {
macro_rules! then_some_closure {
($cond:expr, $closure:expr) => {
if $cond {
Some($closure)
} else {
None
}
};
}
let func: slots::MappingFunc = |zelf, _vm| {
Ok(PyMapping {
length: then_some_closure!(zelf.has_class_attr("__len__"), |zelf, vm| {
vm.call_special_method(zelf, "__len__", ()).map(|obj| {
obj.payload_if_subclass::<PyInt>(vm)
.map(|length_obj| {
length_obj.as_bigint().to_usize().ok_or_else(|| {
vm.new_value_error(
"__len__() should return >= 0".to_owned(),
)
})
})
.unwrap()
})?
}),
subscript: then_some_closure!(
zelf.has_class_attr("__getitem__"),
|zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine| {
vm.call_special_method(zelf, "__getitem__", (needle,))
}
),
ass_subscript: then_some_closure!(
zelf.has_class_attr("__setitem__") | zelf.has_class_attr("__delitem__"),
|zelf, needle, value, vm| match value {
Some(value) => vm
.call_special_method(zelf, "__setitem__", (needle, value),)
.map(|_| Ok(()))?,
None => vm
.call_special_method(zelf, "__delitem__", (needle,))
.map(|_| Ok(()))?,
}
),
})
};
update_slot!(as_mapping, func);
// TODO: need to update sequence protocol too
}
_ => {}
}
}