import os
from ..parser import SCALAR_VALUE_TYPES
from ..parser import camel_to_snake_case
from ..parser import parse_file
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
HEADER_FMT = '''\
/**
* The MIT License (MIT)
*
* Copyright (c) 2019 Erik Moqvist
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* This file was generated by pbtools.
*/
#ifndef {include_guard}
#define {include_guard}
#ifdef __cplusplus
extern "C" {{
#endif
#include "pbtools.h"
{includes}\
{types}
{declarations}
/* Internal functions. Do not use! */
{internal_declarations}
#ifdef __cplusplus
}}
#endif
#endif
'''
SOURCE_FMT = '''\
/**
* The MIT License (MIT)
*
* Copyright (c) 2019 Erik Moqvist
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* This file was generated by pbtools.
*/
#include <limits.h>
#include "{header}"
#if CHAR_BIT != 8
# error "Number of bits in a char must be 8."
#endif
{definitions}\
'''
MESSAGE_STRUCT_FMT = '''\
/**
* Message {message.full_name}.
*/
{repeated_struct}
struct {message.full_name_snake_case}_t {{
struct pbtools_message_base_t base;
{members}\
}};
'''
REPEATED_MESSAGE_STRUCT_FMT = '''\
struct {message.full_name_snake_case}_repeated_t {{
int length;
struct {message.full_name_snake_case}_t *items_p;
}};\
'''
ENUM_FMT = '''\
/**
* Enum {full_name}.
*/
enum {name}_e {{
{members}
}};
'''
ENUM_MEMBER_FMT = '''\
{enum.namespace_snake_case}_{field.name_snake_case}_e = {field.field_number}\
'''
ONEOF_FMT = '''\
enum {oneof.full_name_snake_case}_e {oneof.name_snake_case};
union {{
{members}
}};\
'''
MESSAGE_DECLARATION_FMT = '''\
/**
* Encoding and decoding of {message.full_name}.
*/
struct {message.full_name_snake_case}_t *
{message.full_name_snake_case}_new(
void *workspace_p,
size_t size);
int {message.full_name_snake_case}_encode(
struct {message.full_name_snake_case}_t *self_p,
uint8_t *encoded_p,
size_t size);
int {message.full_name_snake_case}_decode(
struct {message.full_name_snake_case}_t *self_p,
const uint8_t *encoded_p,
size_t size);
'''
REPEATED_DECLARATION_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p,
int length);
'''
SUB_MESSAGE_ALLOC_DECLARATION_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p);
'''
MESSAGE_DECLARATIONS_FMT = '''\
void {message.full_name_snake_case}_init(
struct {message.full_name_snake_case}_t *self_p,
struct pbtools_heap_t *heap_p);
void {message.full_name_snake_case}_encode_inner(
struct pbtools_encoder_t *encoder_p,
struct {message.full_name_snake_case}_t *self_p);
void {message.full_name_snake_case}_decode_inner(
struct pbtools_decoder_t *decoder_p,
struct {message.full_name_snake_case}_t *self_p);
void {message.full_name_snake_case}_encode_repeated_inner(
struct pbtools_encoder_t *encoder_p,
int field_number,
struct {message.full_name_snake_case}_repeated_t *repeated_p);
void {message.full_name_snake_case}_decode_repeated_inner(
struct pbtools_decoder_t *decoder_p,
struct pbtools_repeated_info_t *repeated_info_p,
struct {message.full_name_snake_case}_repeated_t *repeated_p);
'''
INIT_ONEOF_FMT = '''\
void {message.full_name_snake_case}_{field.name_snake_case}_init(
struct {message.full_name_snake_case}_t *self_p);
'''
ALLOC_ONEOF_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p);
'''
MESSAGE_DEFINITIONS_FMT = '''\
void {name}_init(
struct {name}_t *self_p,
struct pbtools_heap_t *heap_p)
{{
self_p->base.heap_p = heap_p;
{members_init}
}}
void {name}_encode_inner(
struct pbtools_encoder_t *encoder_p,
struct {name}_t *self_p)
{{
{encode_body}\
}}
void {name}_decode_inner(
struct pbtools_decoder_t *decoder_p,
struct {name}_t *self_p)
{{
{unused_decode}\
int wire_type;
{repeated_infos}
while (pbtools_decoder_available(decoder_p)) {{
switch (pbtools_decoder_read_tag(decoder_p, &wire_type)) {{
{decode_body}
default:
pbtools_decoder_skip_field(decoder_p, wire_type);
break;
}}
}}
{finalizers}\
}}
'''
ENCODE_MEMBER_FMT = '''\
pbtools_encoder_write_{field.full_type_snake_case}(\
encoder_p, {field.field_number}, {ref}self_p->{field.name_snake_case});
'''
ENCODE_OPTIONAL_MEMBER_FMT = '''\
if (self_p->{field.name_snake_case}.is_present) {{
pbtools_encoder_write_{field.full_type_snake_case}_always(\
encoder_p, {field.field_number}, {ref}self_p->{field.name_snake_case}.value);
}}
'''
ENCODE_STRING_MEMBER_FMT = '''\
pbtools_encoder_write_string(\
encoder_p, {field.field_number}, {ref}self_p->{field.name_snake_case}_p);
'''
ENCODE_OPTIONAL_STRING_MEMBER_FMT = '''\
if (self_p->{field.name_snake_case}.is_present) {{
pbtools_encoder_write_string_always(\
encoder_p, {field.field_number}, {ref}self_p->{field.name_snake_case}.value_p);
}}
'''
ENCODE_REPEATED_MEMBER_FMT = '''\
pbtools_encoder_write_repeated_{field.full_type_snake_case}(\
encoder_p, {field.field_number}, &self_p->{field.name_snake_case});
'''
ENCODE_REPEATED_ENUM_FMT = '''\
pbtools_encoder_write_repeated_int32(\
encoder_p, {field.field_number}, &self_p->{field.name_snake_case});
'''
ENCODE_SUB_MESSAGE_MEMBER_FMT = '''\
pbtools_encoder_sub_message_encode(
encoder_p,
{field.field_number},
(struct pbtools_message_base_t *)self_p->{field.name_snake_case}_p,
(pbtools_message_encode_inner_t){field.full_type_snake_case}_encode_inner);
'''
ENCODE_ENUM_FMT = '''\
pbtools_encoder_write_enum(encoder_p, {field.field_number}, \
self_p->{field.name_snake_case});
'''
ENCODE_OPTIONAL_ENUM_FMT = '''\
if (self_p->{field.name_snake_case}.is_present) {{
pbtools_encoder_write_enum_always(encoder_p, {field.field_number}, \
self_p->{field.name_snake_case}.value);
}}
'''
ENCODE_ONEOF_CHOICE_FMT = '''\
case {oneof.full_name_snake_case}_{field.name_snake_case}_e:
pbtools_encoder_write_{field.full_type_snake_case}_always(
encoder_p,
{field.field_number},
{ref}self_p->{field.name_snake_case});
break;
'''
ENCODE_ONEOF_STRING_MEMBER_FMT = '''\
case {oneof.full_name_snake_case}_{field.name_snake_case}_e:
pbtools_encoder_write_string_always(
encoder_p,
{field.field_number},
{ref}self_p->{field.name_snake_case}_p);
break;
'''
ENCODE_ONEOF_SUB_MESSAGE_MEMBER_FMT = '''\
case {oneof.full_name_snake_case}_{field.name_snake_case}_e:
pbtools_encoder_sub_message_encode_always(
encoder_p,
{field.field_number},
&self_p->{field.name_snake_case}_p->base,
(pbtools_message_encode_inner_t){field.full_type_snake_case}_encode_inner);
break;
'''
ENCODE_ONEOF_ENUM_FMT = '''\
case {oneof.full_name_snake_case}_{field.name_snake_case}_e:
pbtools_encoder_write_enum_always(
encoder_p,
{field.field_number},
self_p->{field.name_snake_case});
break;
'''
ENCODE_REPEATED_MESSAGE_MEMBER_FMT = '''\
{field.full_type_snake_case}_encode_repeated_inner(
encoder_p,
{field.field_number},
&self_p->{field.name_snake_case});
'''
ENCODE_ONEOF_FMT = '''\
switch (self_p->{oneof.name_snake_case}) {{
{choices}
default:
break;
}}
'''
DECODE_MEMBER_FMT = '''\
case {field.field_number}:
self_p->{field.name_snake_case} = \
pbtools_decoder_read_{field.full_type_snake_case}(decoder_p, wire_type);
break;
'''
DECODE_OPTIONAL_MEMBER_FMT = '''\
case {field.field_number}:
self_p->{field.name_snake_case}.is_present = true;
self_p->{field.name_snake_case}.value = \
pbtools_decoder_read_{field.full_type_snake_case}(decoder_p, wire_type);
break;
'''
DECODE_MEMBER_BYTES_FMT = '''\
case {field.field_number}:
pbtools_decoder_read_bytes(\
decoder_p, wire_type, &self_p->{field.name_snake_case});
break;
'''
DECODE_OPTIONAL_MEMBER_BYTES_FMT = '''\
case {field.field_number}:
self_p->{field.name_snake_case}.is_present = true;
pbtools_decoder_read_bytes(\
decoder_p, wire_type, &self_p->{field.name_snake_case}.value);
break;
'''
DECODE_MEMBER_STRING_FMT = '''\
case {field.field_number}:
pbtools_decoder_read_string(\
decoder_p, wire_type, &self_p->{field.name_snake_case}_p);
break;
'''
DECODE_OPTIONAL_MEMBER_STRING_FMT = '''\
case {field.field_number}:
self_p->{field.name_snake_case}.is_present = true;
pbtools_decoder_read_string(\
decoder_p, wire_type, &self_p->{field.name_snake_case}.value_p);
break;
'''
DECODE_REPEATED_SCALAR_VALUE_FMT = '''\
case {field.field_number}:
pbtools_repeated_info_decode_{field.type}(
&repeated_info_{field.name_snake_case},
decoder_p,
wire_type);
break;
'''
DECODE_REPEATED_ENUM_FMT = '''\
case {field.field_number}:
pbtools_repeated_info_decode_int32(
&repeated_info_{field.name_snake_case},
decoder_p,
wire_type);
break;
'''
DECODE_REPEATED_FIELD_FMT = '''\
case {field.field_number}:
pbtools_repeated_info_decode(&repeated_info_{field.name_snake_case},
decoder_p,
wire_type);
break;
'''
DECODE_SUB_MESSAGE_MEMBER_FMT = '''\
case {field.field_number}:
pbtools_decoder_sub_message_decode(
decoder_p,
wire_type,
(struct pbtools_message_base_t **)&self_p->{field.name_snake_case}_p,
sizeof(struct {field.full_type_snake_case}_t),
(pbtools_message_init_t){field.full_type_snake_case}_init,
(pbtools_message_decode_inner_t){field.full_type_snake_case}_decode_inner);
break;
'''
DECODE_ENUM_FMT = '''\
case {field.field_number}:
self_p->{field.name_snake_case} = pbtools_decoder_read_enum(\
decoder_p, wire_type);
break;
'''
DECODE_OPTIONAL_ENUM_FMT = '''\
case {field.field_number}:
self_p->{field.name_snake_case}.is_present = true;
self_p->{field.name_snake_case}.value = pbtools_decoder_read_enum(\
decoder_p, wire_type);
break;
'''
DECODE_ONEOF_FMT = '''\
case {field.field_number}:
{message.full_name_snake_case}_{field.name_snake_case}_decode(
decoder_p,
wire_type,
self_p);
break;
'''
DECODE_ONEOF_MEMBER_BYTES_FMT = '''\
pbtools_decoder_read_bytes(decoder_p,
wire_type,
&self_p->{field.name_snake_case});
'''
DECODE_ONEOF_MEMBER_STRING_FMT = '''\
pbtools_decoder_read_string(decoder_p,
wire_type,
&self_p->{field.name_snake_case}_p);
'''
DECODE_ONEOF_MEMBER_FMT = '''\
self_p->{field.name_snake_case} = \
pbtools_decoder_read_{field.full_type_snake_case}(
decoder_p,
wire_type);
'''
DECODE_ONEOF_ENUM_FMT = '''\
self_p->{field.name_snake_case} = pbtools_decoder_read_enum(
decoder_p,
wire_type);
'''
INIT_ONEOF_FIELD_FMT = '''\
void {message.full_name_snake_case}_{field.name_snake_case}_init(
struct {message.full_name_snake_case}_t *self_p)
{{
self_p->{oneof.name_snake_case} = \
{oneof.full_name_snake_case}_{field.name_snake_case}_e;
{init}
}}
'''
ALLOC_ONEOF_FIELD_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p)
{{
self_p->{oneof.name_snake_case} = \
{oneof.full_name_snake_case}_{field.name_snake_case}_e;
return (pbtools_sub_message_alloc(
(struct pbtools_message_base_t **)&self_p->{field.name_snake_case}_p,
self_p->base.heap_p,
sizeof(struct {field.full_type_snake_case}_t),
(pbtools_message_init_t){field.full_type_snake_case}_init));
}}
'''
DECODE_ONEOF_FIELD_FMT = '''\
static void {message.full_name_snake_case}_{field.name_snake_case}_decode(
struct pbtools_decoder_t *decoder_p,
int wire_type,
struct {message.full_name_snake_case}_t *self_p)
{{
{message.full_name_snake_case}_{field.name_snake_case}_init(self_p);
{decode}\
}}
'''
DECODE_ONEOF_SUB_MESSAGE_FIELD_FMT = '''\
static void {message.full_name_snake_case}_{field.name_snake_case}_decode(
struct pbtools_decoder_t *decoder_p,
int wire_type,
struct {message.full_name_snake_case}_t *self_p)
{{
self_p->{oneof.name_snake_case} = \
{oneof.full_name_snake_case}_{field.name_snake_case}_e;
pbtools_decoder_sub_message_decode(
decoder_p,
wire_type,
(struct pbtools_message_base_t **)&self_p->{field.name_snake_case}_p,
sizeof(struct {field.full_type_snake_case}_t),
(pbtools_message_init_t){field.full_type_snake_case}_init,
(pbtools_message_decode_inner_t){field.full_type_snake_case}_decode_inner);
}}
'''
MESSAGE_DEFINITION_FMT = '''\
struct {message.full_name_snake_case}_t *
{message.full_name_snake_case}_new(
void *workspace_p,
size_t size)
{{
return (pbtools_message_new(
workspace_p,
size,
sizeof(struct {message.full_name_snake_case}_t),
(pbtools_message_init_t){message.full_name_snake_case}_init));
}}
int {message.full_name_snake_case}_encode(
struct {message.full_name_snake_case}_t *self_p,
uint8_t *encoded_p,
size_t size)
{{
return (pbtools_message_encode(
&self_p->base,
encoded_p,
size,
(pbtools_message_encode_inner_t)\
{message.full_name_snake_case}_encode_inner));
}}
int {message.full_name_snake_case}_decode(
struct {message.full_name_snake_case}_t *self_p,
const uint8_t *encoded_p,
size_t size)
{{
return (pbtools_message_decode(
&self_p->base,
encoded_p,
size,
(pbtools_message_decode_inner_t)\
{message.full_name_snake_case}_decode_inner));
}}
'''
REPEATED_DEFINITION_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p,
int length)
{{
return (pbtools_alloc_repeated_{field.full_type_snake_case}(
&self_p->base,
length,
&self_p->{field.name_snake_case}));
}}
'''
SUB_MESSAGE_ALLOC_DEFINITION_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p)
{{
return (pbtools_sub_message_alloc(
(struct pbtools_message_base_t **)&self_p->{field.name_snake_case}_p,
self_p->base.heap_p,
sizeof(struct {field.full_type_snake_case}_t),
(pbtools_message_init_t){field.full_type_snake_case}_init));
}}
'''
REPEATED_ENUM_DEFINITION_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p,
int length)
{{
return (pbtools_alloc_repeated_int32(
&self_p->base,
length,
&self_p->{field.name_snake_case}));
}}
'''
REPEATED_MESSAGE_DEFINITION_ALLOC_FMT = '''\
int {message.full_name_snake_case}_{field.name_snake_case}_alloc(
struct {message.full_name_snake_case}_t *self_p,
int length)
{{
return (pbtools_alloc_repeated(
(struct pbtools_repeated_message_t *)&self_p->{field.name_snake_case},
length,
self_p->base.heap_p,
sizeof(struct {field.full_type_snake_case}_t),
(pbtools_message_init_t){field.full_type_snake_case}_init));
}}
'''
REPEATED_MESSAGE_DEFINITION_FMT = '''\
void {message.full_name_snake_case}_encode_repeated_inner(
struct pbtools_encoder_t *encoder_p,
int field_number,
struct {message.full_name_snake_case}_repeated_t *repeated_p)
{{
pbtools_encode_repeated_inner(
encoder_p,
field_number,
(struct pbtools_repeated_message_t *)repeated_p,
sizeof(struct {message.full_name_snake_case}_t),
(pbtools_message_encode_inner_t){message.full_name_snake_case}_encode_inner);
}}
void {message.full_name_snake_case}_decode_repeated_inner(
struct pbtools_decoder_t *decoder_p,
struct pbtools_repeated_info_t *repeated_info_p,
struct {message.full_name_snake_case}_repeated_t *repeated_p)
{{
pbtools_decode_repeated_inner(
decoder_p,
repeated_info_p,
(struct pbtools_repeated_message_t *)repeated_p,
sizeof(struct {message.full_name_snake_case}_t),
(pbtools_message_init_t){message.full_name_snake_case}_init,
(pbtools_message_decode_inner_t){message.full_name_snake_case}_decode_inner);
}}
'''
REPEATED_FINALIZER_FMT = '''\
pbtools_decoder_decode_repeated_{field.full_type_snake_case}(
decoder_p,
&repeated_info_{field.name_snake_case},
&self_p->{field.name_snake_case});\
'''
REPEATED_ENUM_FINALIZER_FMT = '''\
pbtools_decoder_decode_repeated_int32(
decoder_p,
&repeated_info_{field.name_snake_case},
&self_p->{field.name_snake_case});\
'''
REPEATED_MESSAGE_FINALIZER_FMT = '''\
{field.full_type_snake_case}_decode_repeated_inner(
decoder_p,
&repeated_info_{field.name_snake_case},
&self_p->{field.name_snake_case});\
'''
OPTIONAL_STRUCT_MEMBER_FMT = '''\
struct {{
bool is_present;
{type}{value_name_snake_case};
}} {name_snake_case};\
'''
class Options:
def __init__(self, enums_upper_case=False):
self.enums_upper_case = enums_upper_case
class Generator:
def __init__(self, namespace, parsed, header_name, options):
if parsed.package is not None:
namespace = camel_to_snake_case(parsed.package)
self.namespace = namespace
self.parsed = parsed
self.header_name = header_name
self.enums_upper_case = options.enums_upper_case
@property
def messages(self):
return self.parsed.messages
@property
def package(self):
return self.parsed.package
def generate_struct_member_fmt(self, type, name_snake_case, type_kind):
if type in ['int32', 'int64', 'uint32', 'uint64']:
type = f'{type}_t '
elif type in ['sint32', 'sint64']:
type = f'{type[1:]}_t '
elif type in ['fixed32', 'fixed64']:
type = f'uint{type[5:]}_t '
elif type in ['sfixed32', 'sfixed64']:
type = f'int{type[6:]}_t '
elif type in ['float', 'double', 'bool']:
type = f'{type} '
elif type == 'bytes':
type = f'struct pbtools_bytes_t '
elif type == 'string':
type = f'char *'
name_snake_case = f'{name_snake_case}_p'
elif type_kind == 'enum':
type = f'enum {type}_e '
elif type_kind == 'message':
type = f'struct {type}_t *'
name_snake_case = f'{name_snake_case}_p'
else:
type += ' '
return f' {type}{name_snake_case};'
def generate_optional_struct_member_fmt(self, type, name_snake_case, type_kind):
value_name_snake_case = 'value'
if type in ['int32', 'int64', 'uint32', 'uint64']:
type = f'{type}_t '
elif type in ['sint32', 'sint64']:
type = f'{type[1:]}_t '
elif type in ['fixed32', 'fixed64']:
type = f'uint{type[5:]}_t '
elif type in ['sfixed32', 'sfixed64']:
type = f'int{type[6:]}_t '
elif type in ['float', 'double', 'bool']:
type = f'{type} '
elif type == 'bytes':
type = f'struct pbtools_bytes_t '
elif type == 'string':
type = f'char *'
value_name_snake_case = f'{value_name_snake_case}_p'
elif type_kind == 'enum':
type = f'enum {type}_e '
else:
raise Exception('Only scalar value types may be optional.')
return OPTIONAL_STRUCT_MEMBER_FMT.format(
type=type,
name_snake_case=name_snake_case,
value_name_snake_case=value_name_snake_case)
def generate_repeated_struct_member_fmt(self,
type,
name_snake_case,
type_kind):
if type in SCALAR_VALUE_TYPES:
if type in ['sint32', 'sint64']:
type = type[1:]
elif type in ['fixed32', 'fixed64']:
type = f'uint{type[5:]}'
elif type in ['sfixed32', 'sfixed64']:
type = f'int{type[6:]}'
type = f'struct pbtools_repeated_{type}_t'
elif type_kind == 'enum':
type = 'struct pbtools_repeated_int32_t'
else:
type = f'struct {type}_repeated_t'
return f' {type} {name_snake_case};'
def generate_struct_members(self, message):
members = []
for field in message.fields:
if field.repeated:
member = self.generate_repeated_struct_member_fmt(
field.full_type_snake_case,
field.name_snake_case,
field.type_kind)
elif field.optional:
member = self.generate_optional_struct_member_fmt(
field.full_type_snake_case,
field.name_snake_case,
field.type_kind)
else:
member = self.generate_struct_member_fmt(
field.full_type_snake_case,
field.name_snake_case,
field.type_kind)
members.append(member)
for oneof in message.oneofs:
members.append(
ONEOF_FMT.format(oneof=oneof,
members=self.generate_oneof_members(oneof)))
members = '\n'.join(members)
if members:
members += '\n'
return members
def generate_repeated_struct(self, message):
return REPEATED_MESSAGE_STRUCT_FMT.format(message=message)
def generate_enum_members(self, enum):
lines = []
for field in enum.fields:
line = ENUM_MEMBER_FMT.format(enum=enum, field=field)
if self.enums_upper_case:
line = line.upper()
lines.append(line)
return ',\n'.join(lines)
def generate_enum_type(self, enum):
return [
ENUM_FMT.format(full_name=enum.full_name,
name=enum.full_name_snake_case,
members=self.generate_enum_members(enum))
]
def generate_oneof_members(self, oneof):
members = []
for field in oneof.fields:
member = self.generate_struct_member_fmt(
field.full_type_snake_case,
field.name_snake_case,
field.type_kind)
members.append(f' {member}')
return '\n'.join(members)
def generate_oneof_choices(self, oneof):
members = [
f' {oneof.full_name_snake_case}_none_e = 0'
]
for i, field in enumerate(oneof.fields, 1):
members.append(
f' {oneof.full_name_snake_case}_{field.name_snake_case}_e = {i}')
return ENUM_FMT.format(full_name=oneof.full_name,
name=f'{oneof.full_name_snake_case}',
members=',\n'.join(members))
def generate_oneof_type(self, oneof):
types = [self.generate_oneof_choices(oneof)]
return ['\n'.join(types)]
def generate_message_types(self, message):
types = []
for enum in message.enums:
types += self.generate_enum_type(enum)
for sub_message in message.messages:
types += self.generate_message_types(sub_message)
for oneof in message.oneofs:
types += self.generate_oneof_type(oneof)
types += [
MESSAGE_STRUCT_FMT.format(
message=message,
repeated_struct=self.generate_repeated_struct(message),
members=self.generate_struct_members(message))
]
return types
def generate_types(self):
types = []
for enum in self.parsed.enums:
types += self.generate_enum_type(enum)
for message in self.messages:
types += self.generate_message_types(message)
return '\n'.join(types)
def generate_declarations(self):
declarations = []
for message in self.messages:
self.generate_message_declarations(message, declarations, True)
return '\n'.join(declarations)
def generate_message_declarations(self, message, declarations, public):
for field in message.fields:
if field.repeated:
declarations.append(
REPEATED_DECLARATION_FMT.format(message=message, field=field))
elif field.type_kind == 'message':
declarations.append(
SUB_MESSAGE_ALLOC_DECLARATION_FMT.format(message=message,
field=field))
for sub_message in message.messages:
self.generate_message_declarations(sub_message,
declarations,
public=False)
for oneof in message.oneofs:
for field in oneof.fields:
if field.type_kind == 'message':
declarations.append(
ALLOC_ONEOF_FMT.format(oneof=oneof,
message=message,
field=field))
else:
declarations.append(
INIT_ONEOF_FMT.format(oneof=oneof,
message=message,
field=field))
if public:
declarations.append(
MESSAGE_DECLARATION_FMT.format(message=message))
def generate_internal_declarations(self):
declarations = []
for message in self.messages:
self.generate_internal_message_declarations(message,
declarations)
return '\n'.join(declarations)
def generate_internal_message_declarations(self, message, declarations):
declarations.append(MESSAGE_DECLARATIONS_FMT.format(message=message))
for sub_message in message.messages:
self.generate_internal_message_declarations(sub_message,
declarations)
def generate_message_encode_body(self, message):
members = []
for field in reversed(message.fields):
if field.type_kind == 'scalar-value-type':
if field.repeated:
fmt = ENCODE_REPEATED_MEMBER_FMT
elif field.type == 'string':
if field.optional:
fmt = ENCODE_OPTIONAL_STRING_MEMBER_FMT
else:
fmt = ENCODE_STRING_MEMBER_FMT
else:
if field.optional:
fmt = ENCODE_OPTIONAL_MEMBER_FMT
else:
fmt = ENCODE_MEMBER_FMT
else:
if field.repeated:
if field.type_kind == 'enum':
fmt = ENCODE_REPEATED_ENUM_FMT
else:
fmt = ENCODE_REPEATED_MESSAGE_MEMBER_FMT
elif field.type_kind == 'message':
fmt = ENCODE_SUB_MESSAGE_MEMBER_FMT
else:
if field.optional:
fmt = ENCODE_OPTIONAL_ENUM_FMT
else:
fmt = ENCODE_ENUM_FMT
member = fmt.format(field=field,
ref='&' if field.type == 'bytes' else '')
members.append(member)
for oneof in message.oneofs:
self.generate_oneof_encode_definitions(message, oneof, members)
if not members:
members = [
' (void)encoder_p;\n'
' (void)self_p;\n'
]
return ''.join(members)
def generate_message_decode_body(self, message):
members = []
for field in message.fields:
if field.repeated:
if field.type_kind == 'scalar-value-type':
fmt = DECODE_REPEATED_SCALAR_VALUE_FMT
elif field.type_kind == 'enum':
fmt = DECODE_REPEATED_ENUM_FMT
else:
fmt = DECODE_REPEATED_FIELD_FMT
elif field.type == 'bytes':
if field.optional:
fmt = DECODE_OPTIONAL_MEMBER_BYTES_FMT
else:
fmt = DECODE_MEMBER_BYTES_FMT
elif field.type == 'string':
if field.optional:
fmt = DECODE_OPTIONAL_MEMBER_STRING_FMT
else:
fmt = DECODE_MEMBER_STRING_FMT
elif field.type_kind == 'scalar-value-type':
if field.optional:
fmt = DECODE_OPTIONAL_MEMBER_FMT
else:
fmt = DECODE_MEMBER_FMT
elif field.type_kind == 'message':
fmt = DECODE_SUB_MESSAGE_MEMBER_FMT
else:
if field.optional:
fmt = DECODE_OPTIONAL_ENUM_FMT
else:
fmt = DECODE_ENUM_FMT
members.append(fmt.format(field=field))
for oneof in message.oneofs:
for field in oneof.fields:
members.append(
DECODE_ONEOF_FMT.format(message=message,
oneof=oneof,
field=field))
return '\n'.join(members)
def generate_message_members_init(self, message):
members = []
for field in message.fields:
name = field.name_snake_case
if field.repeated:
member = f' self_p->{name}.length = 0;'
elif field.optional:
member = f' self_p->{name}.is_present = false;'
elif field.type == 'bytes':
member = f' pbtools_bytes_init(&self_p->{name});'
elif field.type == 'string':
member = f' self_p->{name}_p = "";'
elif field.type_kind == 'scalar-value-type':
member = f' self_p->{name} = 0;'
elif field.type_kind == 'message':
member = f' self_p->{name}_p = NULL;'
else:
member = f' self_p->{name} = 0;'
members.append(member)
for oneof in message.oneofs:
members.append(f' self_p->{oneof.name_snake_case} = 0;')
return '\n'.join(members)
def generate_repeated_definitions(self, message):
members = []
for field in message.repeated_fields:
if field.type_kind == 'scalar-value-type':
fmt = REPEATED_DEFINITION_FMT
elif field.type_kind == 'enum':
fmt = REPEATED_ENUM_DEFINITION_FMT
else:
fmt = REPEATED_MESSAGE_DEFINITION_ALLOC_FMT
members.append(fmt.format(message=message, field=field))
members.append(REPEATED_MESSAGE_DEFINITION_FMT.format(message=message))
return '\n'.join(members)
def generate_sub_message_definitions(self, message):
allocs = []
for field in message.fields:
if field.repeated:
continue
if field.type_kind != 'message':
continue
allocs.append(
SUB_MESSAGE_ALLOC_DEFINITION_FMT.format(message=message,
field=field))
return '\n'.join(allocs)
def generate_repeated_finalizers(self, message):
finalizers = []
for field in message.repeated_fields:
if field.type_kind == 'scalar-value-type':
fmt = REPEATED_FINALIZER_FMT
elif field.type_kind == 'enum':
fmt = REPEATED_ENUM_FINALIZER_FMT
else:
fmt = REPEATED_MESSAGE_FINALIZER_FMT
finalizers.append(fmt.format(field=field))
if finalizers:
finalizers = [''] + finalizers + ['']
return '\n'.join(finalizers)
def generate_repeated_infos(self, message):
variables = []
inits = []
for field in message.repeated_fields:
variables.append(
f' struct pbtools_repeated_info_t '
f'repeated_info_{field.name_snake_case};')
inits.append(
f' pbtools_repeated_info_init('
f'&repeated_info_{field.name_snake_case}, '
f'{field.field_number});')
if inits:
inits = [''] + inits + ['']
return '\n'.join(variables + inits)
def generate_definitions(self):
declarations = []
definitions = []
for message in self.messages:
self.generate_message_definitions(message,
declarations,
definitions,
public=True)
return '\n'.join(declarations + definitions)
def generate_oneof_init_and_alloc_definitions(self,
message,
oneof,
definitions):
for field in oneof.fields:
name = field.name_snake_case
if field.type_kind == 'message':
definitions.append(
ALLOC_ONEOF_FIELD_FMT.format(message=message,
oneof=oneof,
field=field))
else:
if field.type == 'bytes':
init = (f' pbtools_bytes_init('
f'&self_p->{name});')
elif field.type == 'string':
init = f' self_p->{name}_p = "";'
elif field.type_kind == 'scalar-value-type':
init = f' self_p->{name} = 0;'
elif field.type_kind == 'message':
raise
init = ALLOC_ONEOF_FIELD_FMT.format()
else:
init = f' self_p->{name} = 0;'
definitions.append(
INIT_ONEOF_FIELD_FMT.format(message=message,
oneof=oneof,
field=field,
init=init))
def generate_oneof_encode_definitions(self, message, oneof, definitions):
choices = []
for field in oneof.fields:
if field.type_kind == 'scalar-value-type':
if field.type == 'string':
fmt = ENCODE_ONEOF_STRING_MEMBER_FMT
else:
fmt = ENCODE_ONEOF_CHOICE_FMT
else:
if field.type_kind == 'message':
fmt = ENCODE_ONEOF_SUB_MESSAGE_MEMBER_FMT
else:
fmt = ENCODE_ONEOF_ENUM_FMT
choice = fmt.format(oneof=oneof,
field=field,
ref='&' if field.type == 'bytes' else '')
choices.append(choice)
definitions.append(
ENCODE_ONEOF_FMT.format(oneof=oneof, choices='\n'.join(choices)))
def generate_oneof_decode_definitions(self,
message,
oneof,
definitions):
for field in oneof.fields:
if field.type_kind == 'message':
definitions.append(
DECODE_ONEOF_SUB_MESSAGE_FIELD_FMT.format(message=message,
oneof=oneof,
field=field))
else:
if field.type == 'bytes':
fmt = DECODE_ONEOF_MEMBER_BYTES_FMT
elif field.type == 'string':
fmt = DECODE_ONEOF_MEMBER_STRING_FMT
elif field.type_kind == 'scalar-value-type':
fmt = DECODE_ONEOF_MEMBER_FMT
else:
fmt = DECODE_ONEOF_ENUM_FMT
definitions.append(
DECODE_ONEOF_FIELD_FMT.format(message=message,
oneof=oneof,
field=field,
decode=fmt.format(oneof=oneof,
field=field)))
def generate_oneof_definitions(self,
message,
oneof,
definitions):
self.generate_oneof_init_and_alloc_definitions(message, oneof, definitions)
self.generate_oneof_decode_definitions(message, oneof, definitions)
def generate_message_definitions(self,
message,
declarations,
definitions,
public):
for oneof in message.oneofs:
self.generate_oneof_definitions(message, oneof, definitions)
for sub_message in message.messages:
self.generate_message_definitions(sub_message,
declarations,
definitions,
public=False)
decode_body = self.generate_message_decode_body(message)
if decode_body:
unused_decode = ''
else:
unused_decode = ' (void)self_p;\n\n'
definitions.append(
MESSAGE_DEFINITIONS_FMT.format(
name=message.full_name_snake_case,
encode_body=self.generate_message_encode_body(message),
decode_body=decode_body,
unused_decode=unused_decode,
repeated_infos=self.generate_repeated_infos(message),
members_init=self.generate_message_members_init(message),
finalizers=self.generate_repeated_finalizers(message)))
sub_messages = self.generate_sub_message_definitions(message)
if sub_messages:
definitions.append(sub_messages)
repeated = self.generate_repeated_definitions(message)
if repeated:
definitions.append(repeated)
if public:
definitions.append(MESSAGE_DEFINITION_FMT.format(message=message))
def generate_includes(self):
includes = []
for imported in self.parsed.imports:
name = camel_to_snake_case(os.path.splitext(imported.path)[0])
includes.append(f'#include "{name}.h"')
includes = '\n'.join(includes)
if includes:
includes += '\n'
return includes
def generate_include_guard(self):
return f'{os.path.splitext(self.header_name)[0].upper()}_H'
def generate(self):
header = HEADER_FMT.format(
include_guard=self.generate_include_guard(),
includes=self.generate_includes(),
types=self.generate_types(),
declarations=self.generate_declarations(),
internal_declarations=self.generate_internal_declarations())
source = SOURCE_FMT.format(header=self.header_name,
definitions=self.generate_definitions())
return header, source
def generate(namespace, parsed, header_name, options):
"""Generate C source code from given parsed proto-file.
"""
return Generator(namespace, parsed, header_name, options).generate()
[docs]def generate_files(infiles,
import_paths=None,
output_directory='.',
options=None):
"""Generate C source code from proto-file(s).
"""
if options is None:
options = Options()
os.makedirs(output_directory, exist_ok=True)
for filename in infiles:
parsed = parse_file(filename, import_paths)
basename = os.path.basename(filename)
name = camel_to_snake_case(os.path.splitext(basename)[0])
filename_h = f'{name}.h'
filename_c = f'{name}.c'
header, source = generate(name, parsed, filename_h, options)
filename_h = os.path.join(output_directory, filename_h)
filename_c = os.path.join(output_directory, filename_c)
with open(filename_h, 'w') as fout:
fout.write(header)
with open(filename_c, 'w') as fout:
fout.write(source)