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)
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()