Author: Armin Rigo <[email protected]>
Branch:
Changeset: r61168:3d9c73dd0f46
Date: 2013-02-13 11:26 +0100
http://bitbucket.org/pypy/pypy/changeset/3d9c73dd0f46/
Log: Support cffi's "enum-as-int" branch
diff --git a/pypy/module/_cffi_backend/ctypeenum.py
b/pypy/module/_cffi_backend/ctypeenum.py
--- a/pypy/module/_cffi_backend/ctypeenum.py
+++ b/pypy/module/_cffi_backend/ctypeenum.py
@@ -6,23 +6,19 @@
from rpython.rtyper.lltypesystem import rffi
from rpython.rlib.rarithmetic import intmask, r_ulonglong
from rpython.rlib.objectmodel import keepalive_until_here
+from rpython.rlib.objectmodel import specialize
from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUnsigned
from pypy.module._cffi_backend import misc
-class W_CTypeEnum(W_CTypePrimitiveSigned):
- _attrs_ = ['enumerators2values', 'enumvalues2erators']
- _immutable_fields_ = ['enumerators2values', 'enumvalues2erators']
- kind = "enum"
+class _Mixin_Enum(object):
+ _mixin_ = True
- def __init__(self, space, name, enumerators, enumvalues):
- from pypy.module._cffi_backend.newtype import alignment
+ def __init__(self, space, name, size, align, enumerators, enumvalues):
name = "enum " + name
- size = rffi.sizeof(rffi.INT)
- align = alignment(rffi.INT)
- W_CTypePrimitiveSigned.__init__(self, space, size,
- name, len(name), align)
+ self._super.__init__(self, space, size, name, len(name), align)
self.enumerators2values = {} # str -> int
self.enumvalues2erators = {} # int -> str
for i in range(len(enumerators)-1, -1, -1):
@@ -44,55 +40,46 @@
space.setitem(w_dct, space.wrap(enumerator),
space.wrap(enumvalue))
return w_dct
- return W_CTypePrimitiveSigned._fget(self, attrchar)
+ return self._super._fget(self, attrchar)
+
+ def extra_repr(self, cdata):
+ value = self._get_value(cdata)
+ try:
+ s = self.enumvalues2erators[value]
+ except KeyError:
+ return str(value)
+ else:
+ return '%s: %s' % (value, s)
def string(self, cdataobj, maxlen):
- w_result = self.convert_to_object(cdataobj._cdata)
+ value = self._get_value(cdataobj._cdata)
keepalive_until_here(cdataobj)
- return w_result
+ try:
+ s = self.enumvalues2erators[value]
+ except KeyError:
+ s = str(value)
+ return self.space.wrap(s)
- def convert_to_object(self, cdata):
- value = misc.read_raw_long_data(cdata, self.size)
- try:
- enumerator = self.enumvalues2erators[value]
- except KeyError:
- enumerator = '#%d' % (value,)
- return self.space.wrap(enumerator)
- def convert_from_object(self, cdata, w_ob):
- space = self.space
- try:
- return W_CTypePrimitiveSigned.convert_from_object(self, cdata,
- w_ob)
- except OperationError, e:
- if not e.match(space, space.w_TypeError):
- raise
- if space.isinstance_w(w_ob, space.w_basestring):
- value = self.convert_enum_string_to_int(space.str_w(w_ob))
- value = r_ulonglong(value)
- misc.write_raw_integer_data(cdata, value, self.size)
- else:
- raise self._convert_error("str or int", w_ob)
+class W_CTypeEnumSigned(_Mixin_Enum, W_CTypePrimitiveSigned):
+ _attrs_ = ['enumerators2values', 'enumvalues2erators']
+ _immutable_fields_ = ['enumerators2values', 'enumvalues2erators']
+ kind = "enum"
+ _super = W_CTypePrimitiveSigned
- def cast_str(self, w_ob):
- space = self.space
- return self.convert_enum_string_to_int(space.str_w(w_ob))
+ def _get_value(self, cdata):
+ # returns a signed long
+ assert self.value_fits_long
+ return misc.read_raw_long_data(cdata, self.size)
- def cast_unicode(self, w_ob):
- return self.cast_str(w_ob)
- def convert_enum_string_to_int(self, s):
- space = self.space
- if s.startswith('#'):
- try:
- return int(s[1:])
- except ValueError:
- raise OperationError(space.w_ValueError,
- space.wrap("invalid literal after '#'"))
- else:
- try:
- return self.enumerators2values[s]
- except KeyError:
- raise operationerrfmt(space.w_ValueError,
- "'%s' is not an enumerator for %s",
- s, self.name)
+class W_CTypeEnumUnsigned(_Mixin_Enum, W_CTypePrimitiveUnsigned):
+ _attrs_ = ['enumerators2values', 'enumvalues2erators']
+ _immutable_fields_ = ['enumerators2values', 'enumvalues2erators']
+ kind = "enum"
+ _super = W_CTypePrimitiveUnsigned
+
+ def _get_value(self, cdata):
+ # returns an unsigned long
+ assert self.value_fits_ulong
+ return misc.read_raw_ulong_data(cdata, self.size)
diff --git a/pypy/module/_cffi_backend/ctypeprim.py
b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -171,9 +171,7 @@
self.vrangemax = (r_uint(1) << sh) - 1
def int(self, cdata):
- # enums: really call convert_to_object() just below,
- # and not the one overridden in W_CTypeEnum.
- return W_CTypePrimitiveSigned.convert_to_object(self, cdata)
+ return self.convert_to_object(cdata)
def convert_to_object(self, cdata):
if self.value_fits_long:
diff --git a/pypy/module/_cffi_backend/newtype.py
b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -1,7 +1,8 @@
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import unwrap_spec
from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rlib.rarithmetic import ovfcheck, r_uint
+from rpython.rlib.rarithmetic import most_neg_value_of, most_pos_value_of
from rpython.rlib.objectmodel import specialize
from pypy.module._cffi_backend import ctypeobj, ctypeprim, ctypeptr, ctypearray
@@ -271,18 +272,57 @@
raise OperationError(space.w_ValueError,
space.wrap("tuple args must have the same size"))
enumerators = [space.str_w(w) for w in enumerators_w]
- enumvalues = []
+ #
+ smallest_value = 0
+ largest_value = r_uint(0)
+ i = 0
try:
for w in enumvalues_w:
- enumvalues.append(space.c_int_w(w))
+ try:
+ ulvalue = space.uint_w(w)
+ except OperationError, e:
+ if not e.match(space, space.w_ValueError):
+ raise
+ lvalue = space.int_w(w)
+ if lvalue < smallest_value:
+ smallest_value = lvalue
+ else:
+ if ulvalue > largest_value:
+ largest_value = ulvalue
+ i += 1 # 'i' is here for the exception case, see below
except OperationError, e:
if not e.match(space, space.w_OverflowError):
raise
- i = len(enumvalues)
raise operationerrfmt(space.w_OverflowError,
- "enum '%s' declaration for '%s' does not fit an int",
+ "enum '%s' declaration for '%s' does not fit "
+ "a long or unsigned long",
name, enumerators[i])
- ctype = ctypeenum.W_CTypeEnum(space, name, enumerators, enumvalues)
+ #
+ if smallest_value < 0:
+ if (smallest_value >= most_neg_value_of(rffi.INT) and
+ largest_value <= r_uint(most_pos_value_of(rffi.INT))):
+ size = rffi.sizeof(rffi.INT)
+ align = alignment(rffi.INT)
+ elif largest_value <= r_uint(most_pos_value_of(rffi.LONG)):
+ size = rffi.sizeof(rffi.LONG)
+ align = alignment(rffi.LONG)
+ else:
+ raise operationerrfmt(space.w_OverflowError,
+ "enum '%s' values don't all fit into either 'long' "
+ "or 'unsigned long'", name)
+ enumvalues = [space.int_w(w) for w in enumvalues_w]
+ ctype = ctypeenum.W_CTypeEnumSigned(space, name, size, align,
+ enumerators, enumvalues)
+ else:
+ if largest_value <= r_uint(most_pos_value_of(rffi.UINT)):
+ size = rffi.sizeof(rffi.UINT)
+ align = alignment(rffi.UINT)
+ else:
+ size = rffi.sizeof(rffi.ULONG)
+ align = alignment(rffi.ULONG)
+ enumvalues = [space.uint_w(w) for w in enumvalues_w]
+ ctype = ctypeenum.W_CTypeEnumUnsigned(space, name, size, align,
+ enumerators, enumvalues)
return ctype
# ____________________________________________________________
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1314,7 +1314,8 @@
p = newp(BStructPtr, [12])
assert p.a1 == 12
e = py.test.raises(TypeError, newp, BStructPtr, [None])
- assert "an integer is required" in str(e.value)
+ assert ("an integer is required" in str(e.value) or
+ "unsupported operand type for int(): 'NoneType'" in str(e.value)) #PyPy
py.test.raises(TypeError, 'p.a1 = "def"')
if sys.version_info < (3,):
BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,))
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit