[pypy-svn] r45780 - in pypy/branch/pypy-more-rtti-inprogress/rlib: . test

arigo at codespeak.net arigo at codespeak.net
Fri Aug 17 09:17:28 CEST 2007


Author: arigo
Date: Fri Aug 17 09:17:27 2007
New Revision: 45780

Added:
   pypy/branch/pypy-more-rtti-inprogress/rlib/rmarshal.py   (contents, props changed)
   pypy/branch/pypy-more-rtti-inprogress/rlib/test/test_rmarshal.py   (contents, props changed)
Log:
Playing with a limited version of marshall/unmarshall for RPython programs.


Added: pypy/branch/pypy-more-rtti-inprogress/rlib/rmarshal.py
==============================================================================
--- (empty file)
+++ pypy/branch/pypy-more-rtti-inprogress/rlib/rmarshal.py	Fri Aug 17 09:17:27 2007
@@ -0,0 +1,157 @@
+"""A way to serialize data in the same format as the 'marshal' module
+but accessible to RPython programs.
+"""
+
+from pypy.annotation import model as annmodel
+from pypy.annotation.signature import annotation
+from pypy.annotation.listdef import ListDef, TooLateForChange
+from pypy.annotation.pairtype import pair, pairtype
+from pypy.rlib.rarithmetic import formatd
+from pypy.rlib.unroll import unrolling_iterable
+
+class CannotMarshal(Exception):
+    pass
+
+def get_marshaller(type):
+    s_obj = annotation(type, None)
+    try:
+        # look for a marshaller in the 'dumpers' dictionary
+        return find_dumper(s_obj)
+    except CannotMarshal:
+        # ask the annotation to produce an appropriate dumper
+        pair(_tag, s_obj).install_marshaller()
+        return find_dumper(s_obj)
+get_marshaller._annspecialcase_ = 'specialize:memo'
+
+def get_unmarshaller(type):
+    xxx
+get_unmarshaller._annspecialcase_ = 'specialize:memo'
+
+# ____________________________________________________________
+#
+# Dumpers and loaders
+
+TYPE_NONE     = 'N'
+TYPE_INT      = 'i'
+TYPE_FLOAT    = 'f'
+#TYPE_LONG     = 'l'
+TYPE_STRING   = 's'
+TYPE_TUPLE    = '('
+TYPE_LIST     = '['
+
+dumpers = []
+s_list_of_chars = ListDef(None, annmodel.SomeChar(),
+                          mutated=True, resized=True)
+
+def add_dumper(s_obj, dumper):
+    dumpers.append((s_obj, dumper))
+    dumper._annenforceargs_ = [s_list_of_chars, s_obj]
+
+def get_dumper_annotation(dumper):
+    return dumper._annenforceargs_[1]
+
+def find_dumper(s_obj):
+    for s_cond, dumper in dumpers:
+        if weakly_contains(s_cond, s_obj):
+            return dumper
+    raise CannotMarshal(s_obj)
+
+def w_long(buf, x):
+    buf.append(chr(x & 0xff))
+    x >>= 8
+    buf.append(chr(x & 0xff))
+    x >>= 8
+    buf.append(chr(x & 0xff))
+    x >>= 8
+    buf.append(chr(x & 0xff))
+w_long._annenforceargs_ = [None, int]
+
+def dump_none(buf, x):
+    buf.append(TYPE_NONE)
+add_dumper(annmodel.s_None, dump_none)
+
+def dump_int(buf, x):
+    buf.append(TYPE_INT)
+    w_long(buf, x)
+add_dumper(annmodel.SomeInteger(), dump_int)
+
+def dump_float(buf, x):
+    buf.append(TYPE_FLOAT)
+    s = formatd("%.17g", x)
+    buf.append(chr(len(s)))
+    buf += s
+add_dumper(annmodel.SomeFloat(), dump_float)
+
+def dump_string_or_none(buf, x):
+    if x is None:
+        dump_none(buf, x)
+    else:
+        buf.append(TYPE_STRING)
+        w_long(buf, len(x))
+        buf += x
+add_dumper(annmodel.SomeString(can_be_None=True), dump_string_or_none)
+
+# ____________________________________________________________
+#
+# Annotations => dumpers and loaders
+
+class MTag(object):
+    """Tag for pairtype(), for the purpose of making the get_marshaller()
+    and get_unmarshaller() methods of SomeObject only locally visible."""
+_tag = MTag()
+
+def weakly_contains(s_bigger, s_smaller):
+    # a special version of s_bigger.contains(s_smaller).  Warning, to
+    # support ListDefs properly, this works by trying to produce a side-effect
+    # on s_bigger.  It relies on the fact that s_bigger was created with
+    # an expression like 'annotation([s_item])' which returns a ListDef with
+    # no bookkeeper, on which side-effects are not allowed.
+    try:
+        s_union = annmodel.unionof(s_bigger, s_smaller)
+        return s_bigger.contains(s_union)
+    except (annmodel.UnionError, TooLateForChange):
+        return False
+
+
+class __extend__(pairtype(MTag, annmodel.SomeObject)):
+
+    def install_marshaller((tag, s_obj)):
+        raise CannotMarshal(s_obj)
+
+
+class __extend__(pairtype(MTag, annmodel.SomeList)):
+
+    def install_marshaller((tag, s_list)):
+        def dump_list_or_none(buf, x):
+            if x is None:
+                dump_none(buf, x)
+            else:
+                buf.append(TYPE_LIST)
+                w_long(buf, len(x))
+                for item in x:
+                    itemdumper(buf, item)
+
+        itemdumper = get_marshaller(s_list.listdef.listitem.s_value)
+        if s_list.listdef.listitem.dont_change_any_more:
+            s_general_list = s_list
+        else:
+            s_item = get_dumper_annotation(itemdumper)
+            s_general_list = annotation([s_item])
+        add_dumper(s_general_list, dump_list_or_none)
+
+
+class __extend__(pairtype(MTag, annmodel.SomeTuple)):
+
+    def install_marshaller((tag, s_tuple)):
+        def dump_tuple(buf, x):
+            buf.append(TYPE_TUPLE)
+            w_long(buf, len(x))
+            for i, itemdumper in unroll_item_dumpers:
+                itemdumper(buf, x[i])
+
+        itemdumpers = [get_marshaller(s_item) for s_item in s_tuple.items]
+        unroll_item_dumpers = unrolling_iterable(enumerate(itemdumpers))
+        dumper_annotations = [get_dumper_annotation(itemdumper)
+                              for itemdumper in itemdumpers]
+        s_general_tuple = annmodel.SomeTuple(dumper_annotations)
+        add_dumper(s_general_tuple, dump_tuple)

Added: pypy/branch/pypy-more-rtti-inprogress/rlib/test/test_rmarshal.py
==============================================================================
--- (empty file)
+++ pypy/branch/pypy-more-rtti-inprogress/rlib/test/test_rmarshal.py	Fri Aug 17 09:17:27 2007
@@ -0,0 +1,25 @@
+import marshal
+from pypy.rlib.rmarshal import *
+
+
+def test_marshaller():
+    buf = []
+    get_marshaller(int)(buf, 5)
+    assert marshal.loads(''.join(buf)) == 5
+
+    buf = []
+    get_marshaller(float)(buf, 3.25)
+    assert marshal.loads(''.join(buf)) == 3.25
+
+    buf = []
+    get_marshaller(str)(buf, "hello, world")
+    assert marshal.loads(''.join(buf)) == "hello, world"
+
+    buf = []
+    get_marshaller([int])(buf, [2, 5, -7])
+    assert marshal.loads(''.join(buf)) == [2, 5, -7]
+
+    buf = []
+    get_marshaller((int, float, (str, ())))(buf, (7, -1.5, ("foo", ())))
+    assert marshal.loads(''.join(buf)) == (7, -1.5, ("foo", ()))
+



More information about the Pypy-commit mailing list