From 110f3573508a3ac61fb200c5bbdc24886c75aa68 Mon Sep 17 00:00:00 2001
From: Jan Moringen <jmoringe@techfak.uni-bielefeld.de>
Date: Fri, 5 Apr 2013 16:40:06 +0200
Subject: [PATCH] Fix dynamic converter selection for numeric types

refs #487

TODO explain

* rsb/__init__.py: TODO
* rsb/converter.py: TODO
---
 rsb/__init__.py  |    3 ++-
 rsb/converter.py |   40 ++++++++++++++++++++++++++--------------
 2 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/rsb/__init__.py b/rsb/__init__.py
index 2fabeb5..a75aa2b 100644
--- a/rsb/__init__.py
+++ b/rsb/__init__.py
@@ -188,13 +188,14 @@ class ParticipantConfig (object):
                 # Try to add converters form global map
                 globalMap = rsb.converter.getGlobalConverterMap(wireType)
                 for ((wireSchema, dataType), converter) in globalMap.getConverters().items():
+                    priority = globalMap.getPriority(converter)
                     # Converter can be added if converterOptions does not
                     # contain a disambiguation that gives precedence to a
                     # different converter. map may still raise an
                     # exception in case of ambiguity.
                     if not wireSchema in converterOptions \
                             or dataType.__name__ == converterOptions[wireSchema]:
-                        self.__converters.addConverter(converter)
+                        self.__converters.addConverter(converter, priority = priority)
             else:
                 # If the converter has already been created and configured.
                 self.__converters = converter_
diff --git a/rsb/converter.py b/rsb/converter.py
index 75a1f82..1b80d94 100644
--- a/rsb/converter.py
+++ b/rsb/converter.py
@@ -155,16 +155,21 @@ class ConverterMap(ConverterSelectionStrategy):
     def __init__(self, wireType):
         self._wireType = wireType
         self._converters = {}
+        self._priorities = {}
 
     def getWireType(self):
         return self._wireType
 
-    def addConverter(self, converter, replaceExisting=False):
+    def addConverter(self, converter, replaceExisting=False, priority = 0):
         key = (converter.getWireSchema(), converter.getDataType())
         if key in self._converters and not replaceExisting:
             raise RuntimeError("There already is a converter with wire-schema `%s' and data-type `%s'"
                                % key)
         self._converters[key] = converter
+        self._priorities[converter] = priority
+
+    def getPriority(self, converter):
+        return self._priorities[converter]
 
     def _getConverterForWireSchema(self, wireSchema):
         for ((converterWireSchema, ignored), converter) in self._converters.items():
@@ -172,7 +177,9 @@ class ConverterMap(ConverterSelectionStrategy):
                 return converter
 
     def _getConverterForDataType(self, dataType):
-        for ((ignored, converterDataType), converter) in self._converters.items():
+        for ((ignored, converterDataType), converter) \
+                in sorted(self._converters.items(),
+                          key = lambda x: self._priorities[x[1]]):
             if issubclass(dataType, converterDataType):
                 return converter
 
@@ -231,7 +238,7 @@ class UnambiguousConverterMap (ConverterMap):
     def __init__(self, wireType):
         super(UnambiguousConverterMap, self).__init__(wireType)
 
-    def addConverter(self, converter, replaceExisting=False):
+    def addConverter(self, converter, replaceExisting = False, priority = 0 ):
         for (wireSchema, dataType) in self.getConverters().keys():
             if wireSchema == converter.getWireSchema():
                 if dataType == converter.getDataType():
@@ -239,11 +246,14 @@ class UnambiguousConverterMap (ConverterMap):
                 else:
                     raise RuntimeError("Trying to register ambiguous converter with data type `%s' for wire-schema `%s' (present converter is for data type `%s')."
                                        % (converter.getDataType(), wireSchema, dataType))
-        super(UnambiguousConverterMap, self).addConverter(converter, replaceExisting)
+        super(UnambiguousConverterMap, self) \
+            .addConverter(converter,
+                          replaceExisting= replaceExisting,
+                          priority = priority)
 
 __globalConverterMaps = {}
 
-def registerGlobalConverter(converter, replaceExisting=False):
+def registerGlobalConverter(converter, replaceExisting = False, priority = 0):
     """
     Register B{converter} as a globally available converter.
 
@@ -255,7 +265,9 @@ def registerGlobalConverter(converter, replaceExisting=False):
                             an error is raised.
     """
     mapForWireType = getGlobalConverterMap(converter.getWireType())
-    mapForWireType.addConverter(converter, replaceExisting)
+    mapForWireType.addConverter(converter,
+                                replaceExisting = replaceExisting,
+                                priority = priority)
 
 def getGlobalConverterMap(wireType):
     """
@@ -340,8 +352,8 @@ def makeStructBasedConverter(name, dataType, wireSchema, format, size):
 
 makeStructBasedConverter('DoubleConverter', Real,     'double', '<d', 8)
 makeStructBasedConverter('FloatConverter',  Real,     'float',  '<f', 4)
-makeStructBasedConverter('Uint32Converter', Integral, 'uint32', '<I', 4)
-makeStructBasedConverter('Int32Converter',  Integral, 'int32',  '<i', 4)
+makeStructBasedConverter('Uint32Converter', int,      'uint32', '<I', 4)
+makeStructBasedConverter('Int32Converter',  int,      'int32',  '<i', 4)
 makeStructBasedConverter('Uint64Converter', Integral, 'uint64', '<Q', 8)
 makeStructBasedConverter('Int64Converter',  Integral, 'int64',  '<q', 8)
 makeStructBasedConverter('BoolConverter',   bool,     'bool',   '?',  1)
@@ -431,12 +443,12 @@ class ProtocolBufferConverter(Converter):
         return str(self)
 
 registerGlobalConverter(NoneConverter())
-registerGlobalConverter(DoubleConverter())
-registerGlobalConverter(FloatConverter())
-registerGlobalConverter(Uint32Converter())
-registerGlobalConverter(Int32Converter())
-registerGlobalConverter(Uint64Converter())
-registerGlobalConverter(Int64Converter())
+registerGlobalConverter(DoubleConverter(), priority = 6)
+registerGlobalConverter(FloatConverter(),  priority = 5)
+registerGlobalConverter(Uint32Converter(), priority = 1)
+registerGlobalConverter(Int32Converter(),  priority = 2)
+registerGlobalConverter(Uint64Converter(), priority = 3)
+registerGlobalConverter(Int64Converter(),  priority = 4)
 registerGlobalConverter(BoolConverter())
 registerGlobalConverter(StringConverter(wireSchema="utf-8-string", dataType=str, encoding="utf_8"))
 registerGlobalConverter(ByteArrayConverter())
-- 
1.7.10.4

