Exemple #1
0
def simple_serializer_generator(msg_context, spec, start, end, serialize): #primitives that can be handled with struct
    """
    Generator (de)serialization code for multiple fields from spec

    :param spec: :class:`genmsg.MsgSpec`
    :param start: first field to serialize, ``int``
    :param end: last field to serialize, ``int``
    """
    # optimize member var access
    if end - start > 1 and _serial_context.endswith('.'):
        yield '_x = '+_serial_context[:-1]
        vars_ = '_x.' + (', _x.').join(spec.names[start:end])
    else:
        vars_ = _serial_context + (', '+_serial_context).join(spec.names[start:end])

    pattern = compute_struct_pattern(spec.types[start:end])
    if serialize:
        yield pack(pattern, vars_)
    else:
        yield "start = end"
        yield "end += %s"%struct.calcsize('<%s'%reduce_pattern(pattern))
        yield unpack('(%s,)'%vars_, pattern, 'str[start:end]')

        # convert uint8 to bool. this doesn't add much value as Python
        # equality test on a field will return that True == 1, but I
        # want to be consistent with bool
        bool_vars = [(f, t) for f, t in zip(spec.names[start:end], spec.types[start:end]) if t == 'bool']
        for f, t in bool_vars:
            #TODO: could optimize this as well
            var = _serial_context+f
            yield "%s = bool(%s)"%(var, var)
Exemple #2
0
def array_serializer_generator(msg_context, package, type_, name, serialize, is_numpy):
    """
    Generator for array types

    :raises: :exc:`MsgGenerationException` If array spec is invalid
    """
    base_type, is_array, array_len = genmsg.msgs.parse_type(type_)
    if not is_array:
        raise MsgGenerationException("Invalid array spec: %s"%type_)
    var_length = array_len is None

    # handle fixed-size byte arrays could be slightly more efficient
    # as we recalculated the length in the generated code.
    if base_type in ['char', 'uint8']: #treat unsigned int8 arrays as string type
        for y in string_serializer_generator(package, type_, name, serialize):
            yield y
        return

    var = _serial_context+name
    # yield length serialization, if necessary
    if var_length:
        for y in len_serializer_generator(var, False, serialize):
            yield y #serialize array length
        length = None
    else:
        length = array_len

    #optimization for simple arrays
    if is_simple(base_type):
        if var_length:
            pattern = compute_struct_pattern([base_type])
            yield "pattern = '<%%s%s'%%length"%pattern
            if serialize:
                if is_numpy:
                    yield pack_numpy(var)
                else:
                    yield pack2('pattern', "*"+var)
            else:
                yield "start = end"
                yield "end += struct.calcsize(pattern)"
                if is_numpy:
                    dtype = NUMPY_DTYPE[base_type]
                    yield unpack_numpy(var, 'length', dtype, 'str[start:end]')
                else:
                    yield unpack2(var, 'pattern', 'str[start:end]')
        else:
            pattern = "%s%s"%(length, compute_struct_pattern([base_type]))
            if serialize:
                if is_numpy:
                    yield pack_numpy(var)
                else:
                    yield pack(pattern, "*"+var)
            else:
                yield "start = end"
                yield "end += %s"%struct.calcsize('<%s'%pattern)
                if is_numpy:
                    dtype = NUMPY_DTYPE[base_type]
                    yield unpack_numpy(var, length, dtype, 'str[start:end]')
                else:
                    yield unpack(var, pattern, 'str[start:end]')
        if not serialize and base_type == 'bool':
            # convert uint8 to bool
            if base_type == 'bool':
                yield "%s = map(bool, %s)"%(var, var)

    else:
        #generic recursive serializer
        #NOTE: this is functionally equivalent to the is_registered branch of complex_serializer_generator

        # choose a unique temporary variable for iterating
        loop_var = 'val%s'%len(_context_stack)

        # compute the variable context and factory to use
        if base_type == 'string':
            push_context('')
            factory = string_serializer_generator(package, base_type, loop_var, serialize)
        else:
            push_context('%s.'%loop_var)
            factory = serializer_generator(msg_context, get_registered_ex(msg_context, base_type), serialize, is_numpy)

        if serialize:
            yield 'for %s in %s:'%(loop_var, var)
        else:
            yield '%s = []'%var
            if var_length:
                yield 'for i in range(0, length):'
            else:
                yield 'for i in range(0, %s):'%length
            if base_type != 'string':
                yield INDENT + '%s = %s'%(loop_var, compute_constructor(msg_context, package, base_type))
        for y in factory:
            yield INDENT + y
        if not serialize:
            yield INDENT + '%s.append(%s)'%(var, loop_var)
        pop_context()
Exemple #3
0
def string_serializer_generator(package, type_, name, serialize):
    """
    Generator for string types. similar to arrays, but with more
    efficient call to struct.pack.

    :param name: spec field name, ``str``
    :param serialize: if ``True``, generate code for
      serialization. Other, generate code for deserialization, ``bool``
    """
    # don't optimize in deserialization case as assignment doesn't
    # work
    if _serial_context and serialize:
        # optimize as string serialization accesses field twice
        yield "_x = %s%s"%(_serial_context, name)
        var = "_x"
    else:
        var = _serial_context+name

    # the length generator is a noop if serialize is True as we
    # optimize the serialization call.
    base_type, is_array, array_len = genmsg.msgs.parse_type(type_)
    # - don't serialize length for fixed-length arrays of bytes
    if base_type not in ['uint8', 'char'] or array_len is None:
        for y in len_serializer_generator(var, True, serialize):
            yield y #serialize string length

    if serialize:
        #serialize length and string together

        #check to see if its a uint8/byte type, in which case we need to convert to string before serializing
        base_type, is_array, array_len = genmsg.msgs.parse_type(type_)
        if base_type in ['uint8', 'char']:
            yield "# - if encoded as a list instead, serialize as bytes instead of string"
            if array_len is None:
                yield "if type(%s) in [list, tuple]:"%var
                yield INDENT+pack2("'<I%sB'%length", "length, *%s"%var)
                yield "else:"
                yield INDENT+pack2("'<I%ss'%length", "length, %s"%var)
            else:
                yield "if type(%s) in [list, tuple]:"%var
                yield INDENT+pack('%sB'%array_len, "*%s"%var)
                yield "else:"
                yield INDENT+pack('%ss'%array_len, var)
        else:
            # FIXME: for py3k, this needs to be w/ encode(), but this interferes with actual byte data
            yield "if python3 or type(%s) == unicode:"%(var)
            yield INDENT+"%s = %s.encode('utf-8')"%(var,var) #For unicode-strings in Python2, encode using utf-8
            yield INDENT+"length = len(%s)"%(var) # Update the length after utf-8 conversion

            yield "if python3:"
            yield INDENT+pack2("'<I%sB'%length", "length, *%s"%var)
            yield "else:"
            yield INDENT+pack2("'<I%ss'%length", "length, %s"%var)
    else:
        yield "start = end"
        if array_len is not None:
            yield "end += %s" % array_len
            yield "%s = str[start:end]" % var
        else:
            yield "end += length"
            if base_type in ['uint8', 'char']:
                yield "%s = str[start:end]" % (var)
            else:
                yield "if python3:"
                yield INDENT+"%s = str[start:end].decode('utf-8')" % (var) #If messages are python3-decode back to unicode
                yield "else:"
                yield INDENT+"%s = str[start:end]" % (var)