objtype::class_*_attr into PyClassRef methods

This commit is contained in:
Jeong YunWon
2020-01-27 13:45:46 +09:00
parent ad2d82c66f
commit b2ba6b2013
7 changed files with 84 additions and 86 deletions

View File

@@ -1,7 +1,7 @@
use super::objdict::PyDictRef;
use super::objiter;
use super::objstr::PyStringRef;
use super::objtype::{self, PyClassRef};
use super::objtype::PyClassRef;
use crate::function::OptionalArg;
use crate::pyobject::{
ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
@@ -48,7 +48,7 @@ impl PyMappingProxy {
let opt = match &self.mapping {
MappingProxyInner::Class(class) => {
let key = PyStringRef::try_from_object(vm, key)?;
objtype::class_get_attr(&class, key.as_str())
class.get_attr(key.as_str())
}
MappingProxyInner::Dict(obj) => obj.get_item(&key, vm).ok(),
};
@@ -75,7 +75,7 @@ impl PyMappingProxy {
match &self.mapping {
MappingProxyInner::Class(class) => {
let key = PyStringRef::try_from_object(vm, key)?;
Ok(vm.new_bool(objtype::class_has_attr(&class, key.as_str())))
Ok(vm.new_bool(class.has_attr(key.as_str())))
}
MappingProxyInner::Dict(obj) => vm._membership(obj.clone(), key),
}

View File

@@ -1,6 +1,6 @@
use super::objproperty::PyPropertyRef;
use super::objstr::PyStringRef;
use super::objtype::{class_get_attr, class_has_attr, PyClassRef};
use super::objtype::PyClassRef;
use crate::pyobject::{
IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
@@ -79,10 +79,10 @@ impl PyNone {
}
}
if let Some(attr) = class_get_attr(&cls, name.as_str()) {
if let Some(attr) = cls.get_attr(name.as_str()) {
let attr_class = attr.class();
if class_has_attr(&attr_class, "__set__") {
if let Some(get_func) = class_get_attr(&attr_class, "__get__") {
if attr_class.has_attr("__set__") {
if let Some(get_func) = attr_class.get_attr("__get__") {
return call_descriptor(
attr,
get_func,
@@ -98,14 +98,14 @@ impl PyNone {
// if let Some(obj_attr) = zelf.as_object().get_attr(name.as_str()) {
// Ok(obj_attr)
// } else
if let Some(attr) = class_get_attr(&cls, name.as_str()) {
if let Some(attr) = cls.get_attr(name.as_str()) {
let attr_class = attr.class();
if let Some(get_func) = class_get_attr(&attr_class, "__get__") {
if let Some(get_func) = attr_class.get_attr("__get__") {
call_descriptor(attr, get_func, zelf.into_object(), cls.into_object(), vm)
} else {
Ok(attr)
}
} else if let Some(getter) = class_get_attr(&cls, "__getattr__") {
} else if let Some(getter) = cls.get_attr("__getattr__") {
vm.invoke(&getter, vec![zelf.into_object(), name.into_object()])
} else {
Err(vm.new_attribute_error(format!("{} has no attribute '{}'", zelf.as_object(), name)))

View File

@@ -86,8 +86,8 @@ pub(crate) fn object_setattr(
vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value);
let cls = obj.class();
if let Some(attr) = objtype::class_get_attr(&cls, attr_name.as_str()) {
if let Some(descriptor) = objtype::class_get_attr(&attr.class(), "__set__") {
if let Some(attr) = cls.get_attr(attr_name.as_str()) {
if let Some(descriptor) = attr.class().get_attr("__set__") {
return vm
.invoke(&descriptor, vec![attr, obj.clone(), value])
.map(|_| ());
@@ -109,8 +109,8 @@ pub(crate) fn object_setattr(
fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
let cls = obj.class();
if let Some(attr) = objtype::class_get_attr(&cls, attr_name.as_str()) {
if let Some(descriptor) = objtype::class_get_attr(&attr.class(), "__delete__") {
if let Some(attr) = cls.get_attr(attr_name.as_str()) {
if let Some(descriptor) = attr.class().get_attr("__delete__") {
return vm.invoke(&descriptor, vec![attr, obj.clone()]).map(|_| ());
}
}
@@ -140,7 +140,7 @@ fn object_subclasshook(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult {
}
pub fn object_dir(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyList> {
let attributes: PyAttributes = objtype::get_attributes(obj.class());
let attributes: PyAttributes = obj.class().get_attributes();
let dict = PyDictRef::from_attributes(attributes, vm)?;
@@ -262,9 +262,8 @@ fn object_reduce(obj: PyObjectRef, proto: OptionalArg<usize>, vm: &VirtualMachin
fn object_reduce_ex(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
let cls = obj.class();
if let Some(reduce) = objtype::class_get_attr(&cls, "__reduce__") {
let object_reduce =
objtype::class_get_attr(&vm.ctx.types.object_type, "__reduce__").unwrap();
if let Some(reduce) = cls.get_attr("__reduce__") {
let object_reduce = vm.ctx.types.object_type.get_attr("__reduce__").unwrap();
if !reduce.is(&object_reduce) {
return vm.invoke(&reduce, vec![]);
}

View File

@@ -1,5 +1,5 @@
use super::objint::PyInt;
use super::objtype::{class_has_attr, PyClassRef};
use super::objtype::PyClassRef;
use crate::function::{OptionalArg, PyFuncArgs};
use crate::pyobject::{
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryIntoRef,
@@ -327,7 +327,7 @@ fn to_index_value(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Option<Big
Ok(Some(val.as_bigint().clone()))
} else {
let cls = obj.class();
if class_has_attr(&cls, "__index__") {
if cls.has_attr("__index__") {
let index_result = vm.call_method(obj, "__index__", vec![])?;
if let Some(val) = index_result.payload::<PyInt>() {
Ok(Some(val.as_bigint().clone()))

View File

@@ -98,7 +98,7 @@ impl PyClassRef {
#[pymethod(magic)]
fn dir(self, vm: &VirtualMachine) -> PyList {
let attributes = get_attributes(self);
let attributes = self.get_attributes();
let attributes: Vec<PyObjectRef> = attributes
.keys()
.map(|k| vm.ctx.new_str(k.to_string()))
@@ -156,10 +156,10 @@ impl PyClassRef {
vm_trace!("type.__getattribute__({:?}, {:?})", self, name);
let mcl = self.class();
if let Some(attr) = class_get_attr(&mcl, &name) {
if let Some(attr) = mcl.get_attr(&name) {
let attr_class = attr.class();
if class_has_attr(&attr_class, "__set__") {
if let Some(ref descriptor) = class_get_attr(&attr_class, "__get__") {
if attr_class.has_attr("__set__") {
if let Some(ref descriptor) = attr_class.get_attr("__get__") {
return vm.invoke(
descriptor,
vec![attr, self.into_object(), mcl.into_object()],
@@ -168,18 +168,18 @@ impl PyClassRef {
}
}
if let Some(attr) = class_get_attr(&self, &name) {
if let Some(attr) = self.get_attr(&name) {
let attr_class = attr.class();
if let Some(ref descriptor) = class_get_attr(&attr_class, "__get__") {
if let Some(ref descriptor) = attr_class.get_attr("__get__") {
return vm.invoke(descriptor, vec![attr, vm.get_none(), self.into_object()]);
}
}
if let Some(cls_attr) = class_get_attr(&self, &name) {
if let Some(cls_attr) = self.get_attr(&name) {
Ok(cls_attr)
} else if let Some(attr) = class_get_attr(&mcl, &name) {
} else if let Some(attr) = mcl.get_attr(&name) {
vm.call_get_descriptor(attr, self.into_object())
} else if let Some(ref getter) = class_get_attr(&self, "__getattr__") {
} else if let Some(ref getter) = self.get_attr("__getattr__") {
vm.invoke(getter, vec![mcl.into_object(), name_ref.into_object()])
} else {
Err(vm.new_attribute_error(format!("{} has no attribute '{}'", self, name)))
@@ -193,8 +193,8 @@ impl PyClassRef {
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
if let Some(attr) = class_get_attr(&self.class(), attr_name.as_str()) {
if let Some(ref descriptor) = class_get_attr(&attr.class(), "__set__") {
if let Some(attr) = self.class().get_attr(attr_name.as_str()) {
if let Some(ref descriptor) = attr.class().get_attr("__set__") {
vm.invoke(descriptor, vec![attr, self.into_object(), value])?;
return Ok(());
}
@@ -208,15 +208,15 @@ impl PyClassRef {
#[pymethod(magic)]
fn delattr(self, attr_name: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
if let Some(attr) = class_get_attr(&self.class(), attr_name.as_str()) {
if let Some(ref descriptor) = class_get_attr(&attr.class(), "__delete__") {
if let Some(attr) = self.class().get_attr(attr_name.as_str()) {
if let Some(ref descriptor) = attr.class().get_attr("__delete__") {
return vm
.invoke(descriptor, vec![attr, self.into_object()])
.map(|_| ());
}
}
if class_get_attr(&self, attr_name.as_str()).is_some() {
if self.get_attr(attr_name.as_str()).is_some() {
self.attributes.borrow_mut().remove(attr_name.as_str());
Ok(())
} else {
@@ -397,48 +397,48 @@ fn type_dict_setter(
))
}
/// This is the internal get_attr implementation for fast lookup on a class.
pub fn class_get_attr(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
flame_guard!(format!("class_get_attr({:?})", attr_name));
impl PyClassRef {
/// This is the internal get_attr implementation for fast lookup on a class.
pub fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
flame_guard!(format!("class_get_attr({:?})", attr_name));
class
.attributes
.borrow()
.get(attr_name)
.cloned()
.or_else(|| class_get_super_attr(class, attr_name))
}
pub fn class_get_super_attr(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
class
.mro
.iter()
.find_map(|class| class.attributes.borrow().get(attr_name).cloned())
}
// This is the internal has_attr implementation for fast lookup on a class.
pub fn class_has_attr(class: &PyClassRef, attr_name: &str) -> bool {
class.attributes.borrow().contains_key(attr_name)
|| class
.mro
.iter()
.any(|c| c.attributes.borrow().contains_key(attr_name))
}
pub fn get_attributes(cls: PyClassRef) -> PyAttributes {
// Gather all members here:
let mut attributes = PyAttributes::new();
let mut base_classes: Vec<&PyClassRef> = cls.iter_mro().collect();
base_classes.reverse();
for bc in base_classes {
for (name, value) in bc.attributes.borrow().iter() {
attributes.insert(name.to_string(), value.clone());
}
self.attributes
.borrow()
.get(attr_name)
.cloned()
.or_else(|| self.get_super_attr(attr_name))
}
attributes
pub fn get_super_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
self.mro
.iter()
.find_map(|class| class.attributes.borrow().get(attr_name).cloned())
}
// This is the internal has_attr implementation for fast lookup on a class.
pub fn has_attr(&self, attr_name: &str) -> bool {
self.attributes.borrow().contains_key(attr_name)
|| self
.mro
.iter()
.any(|c| c.attributes.borrow().contains_key(attr_name))
}
pub fn get_attributes(self) -> PyAttributes {
// Gather all members here:
let mut attributes = PyAttributes::new();
let mut base_classes: Vec<&PyClassRef> = self.iter_mro().collect();
base_classes.reverse();
for bc in base_classes {
for (name, value) in bc.attributes.borrow().iter() {
attributes.insert(name.to_string(), value.clone());
}
}
attributes
}
}
fn take_next_base(mut bases: Vec<Vec<PyClassRef>>) -> Option<(PyClassRef, Vec<Vec<PyClassRef>>)> {

View File

@@ -777,7 +777,7 @@ impl PyItertoolsTee {
) -> PyResult<PyRef<PyTuple>> {
let n = n.unwrap_or(2);
let copyable = if objtype::class_has_attr(&iterable.class(), "__copy__") {
let copyable = if iterable.class().has_attr("__copy__") {
vm.call_method(&iterable, "__copy__", PyFuncArgs::from(vec![]))?
} else {
PyItertoolsTee::from_iter(iterable, vm)?

View File

@@ -624,7 +624,7 @@ impl VirtualMachine {
if let Some(descr_get) = slots.borrow().descr_get.as_ref() {
let cls = obj.class();
descr_get(self, vec![attr, obj.clone(), cls.into_object()].into())
} else if let Some(ref descriptor) = objtype::class_get_attr(&attr_class, "__get__") {
} else if let Some(ref descriptor) = attr_class.get_attr("__get__") {
let cls = obj.class();
self.invoke(descriptor, vec![attr, obj.clone(), cls.into_object()])
} else {
@@ -640,7 +640,7 @@ impl VirtualMachine {
// This is only used in the vm for magic methods, which use a greatly simplified attribute lookup.
let cls = obj.class();
match objtype::class_get_attr(&cls, method_name) {
match cls.get_attr(method_name) {
Some(func) => {
vm_trace!(
"vm.call_method {:?} {:?} {:?} -> {:?}",
@@ -666,7 +666,7 @@ impl VirtualMachine {
let result = slot_call(self, args);
self.trace_event(TraceEvent::Return)?;
result
} else if objtype::class_has_attr(&class, "__call__") {
} else if class.has_attr("__call__") {
let result = self.call_method(&callable, "__call__", args);
result
} else {
@@ -781,7 +781,7 @@ impl VirtualMachine {
F: FnOnce() -> String,
{
let cls = obj.class();
match objtype::class_get_attr(&cls, method_name) {
match cls.get_attr(method_name) {
Some(method) => self.call_get_descriptor(method, obj.clone()),
None => Err(self.new_type_error(err_msg())),
}
@@ -790,7 +790,7 @@ impl VirtualMachine {
/// May return exception, if `__get__` descriptor raises one
pub fn get_method(&self, obj: PyObjectRef, method_name: &str) -> Option<PyResult> {
let cls = obj.class();
let method = objtype::class_get_attr(&cls, method_name)?;
let method = cls.get_attr(method_name)?;
Some(self.call_get_descriptor(method, obj.clone()))
}
@@ -851,10 +851,10 @@ impl VirtualMachine {
let name = name_str.as_str();
let cls = obj.class();
if let Some(attr) = objtype::class_get_attr(&cls, &name) {
if let Some(attr) = cls.get_attr(&name) {
let attr_class = attr.class();
if objtype::class_has_attr(&attr_class, "__set__") {
if let Some(descriptor) = objtype::class_get_attr(&attr_class, "__get__") {
if attr_class.has_attr("__set__") {
if let Some(descriptor) = attr_class.get_attr("__get__") {
return self
.invoke(&descriptor, vec![attr, obj, cls.into_object()])
.map(Some);
@@ -870,9 +870,9 @@ impl VirtualMachine {
if let Some(obj_attr) = attr {
Ok(Some(obj_attr))
} else if let Some(attr) = objtype::class_get_attr(&cls, &name) {
} else if let Some(attr) = cls.get_attr(&name) {
self.call_get_descriptor(attr, obj).map(Some)
} else if let Some(getter) = objtype::class_get_attr(&cls, "__getattr__") {
} else if let Some(getter) = cls.get_attr("__getattr__") {
self.invoke(&getter, vec![obj, name_str.into_object()])
.map(Some)
} else {
@@ -881,8 +881,7 @@ impl VirtualMachine {
}
pub fn is_callable(&self, obj: &PyObjectRef) -> bool {
obj.class().slots.borrow().call.is_some()
|| objtype::class_has_attr(&obj.class(), "__call__")
obj.class().slots.borrow().call.is_some() || obj.class().has_attr("__call__")
}
#[inline]