Skip to content

Commit

Permalink
Make submessages pointers for field presence check and to support rec…
Browse files Browse the repository at this point in the history
…ursive messages.
  • Loading branch information
eerimoq committed Jul 31, 2020
1 parent ee7af41 commit 4e2b410
Show file tree
Hide file tree
Showing 11 changed files with 1,416 additions and 27 deletions.
10 changes: 0 additions & 10 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,8 @@ The C source code is designed with the following in mind:

Known limitations:

- Recursive messages are not supported.

- Submessage presence detection isn't implemented.

- ``char`` must be 8 bits.

Support for recursive messages and submessage presence detection has
been implemented on the branch
``submessage-presence-and-recursive-messages``. However, it makes the
generated code slightly harder to use, so it has not been merged to
the master branch yet.

Memory management
-----------------

Expand Down
20 changes: 20 additions & 0 deletions lib/include/pbtools.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,12 @@ int pbtools_message_decode(struct pbtools_message_base_t *self_p,
size_t size,
pbtools_message_decode_inner_t message_decode_inner);

int pbtools_sub_message_alloc(
struct pbtools_message_base_t **message_pp,
struct pbtools_heap_t *heap_p,
size_t sub_message_size,
pbtools_message_init_t message_init);

int pbtools_alloc_repeated(
struct pbtools_repeated_message_t *repeated_p,
int length,
Expand Down Expand Up @@ -684,6 +690,12 @@ void pbtools_encoder_sub_message_encode(
struct pbtools_message_base_t *message_p,
pbtools_message_encode_inner_t encode_inner);

void pbtools_encoder_sub_message_pointer_encode(
struct pbtools_encoder_t *self_p,
int field_number,
struct pbtools_message_base_t *message_p,
pbtools_message_encode_inner_t encode_inner);

void pbtools_encoder_sub_message_encode_always(
struct pbtools_encoder_t *self_p,
int field_number,
Expand All @@ -696,6 +708,14 @@ void pbtools_decoder_sub_message_decode(
struct pbtools_message_base_t *message_p,
pbtools_message_decode_inner_t decode_inner);

void pbtools_decoder_sub_message_pointer_decode(
struct pbtools_decoder_t *self_p,
int wire_type,
struct pbtools_message_base_t **message_pp,
size_t sub_message_size,
pbtools_message_init_t message_init,
pbtools_message_decode_inner_t decode_inner);

const char *pbtools_error_code_to_string(int code);

void pbtools_repeated_info_init(struct pbtools_repeated_info_t *self_p,
Expand Down
61 changes: 61 additions & 0 deletions lib/src/pbtools.c
Original file line number Diff line number Diff line change
Expand Up @@ -2360,6 +2360,26 @@ int pbtools_message_decode(
return (decoder_get_result(&decoder));
}

int pbtools_sub_message_alloc(
struct pbtools_message_base_t **message_pp,
struct pbtools_heap_t *heap_p,
size_t sub_message_size,
pbtools_message_init_t message_init)
{
struct pbtools_message_base_t *message_p;

message_p = heap_alloc(heap_p, sub_message_size, alignof(*message_p));

if (message_p == NULL) {
return (-1);
}

message_init(message_p, heap_p);
*message_pp = message_p;

return (0);
}

int pbtools_alloc_repeated(
struct pbtools_repeated_message_t *repeated_p,
int length,
Expand Down Expand Up @@ -2506,6 +2526,23 @@ void pbtools_encoder_sub_message_encode(
(uint64_t)(pos - self_p->pos));
}

void pbtools_encoder_sub_message_pointer_encode(
struct pbtools_encoder_t *self_p,
int field_number,
struct pbtools_message_base_t *message_p,
pbtools_message_encode_inner_t encode_inner)
{
int pos;

if (message_p != NULL) {
pos = self_p->pos;
encode_inner(self_p, message_p);
encoder_write_length_delimited(self_p,
field_number,
(uint64_t)(pos - self_p->pos));
}
}

void pbtools_encoder_sub_message_encode_always(
struct pbtools_encoder_t *self_p,
int field_number,
Expand Down Expand Up @@ -2537,6 +2574,30 @@ void pbtools_decoder_sub_message_decode(
decoder_seek(self_p, decoder_get_result(&decoder));
}

void pbtools_decoder_sub_message_pointer_decode(
struct pbtools_decoder_t *self_p,
int wire_type,
struct pbtools_message_base_t **message_pp,
size_t sub_message_size,
pbtools_message_init_t message_init,
pbtools_message_decode_inner_t decode_inner)
{
struct pbtools_message_base_t *message_p;

message_p = decoder_heap_alloc(
self_p,
sub_message_size,
alignof(*message_p));

if (message_p == NULL) {
return;
}

message_init(message_p, self_p->heap_p);
pbtools_decoder_sub_message_decode(self_p, wire_type, message_p, decode_inner);
*message_pp = message_p;
}

void pbtools_repeated_info_init(struct pbtools_repeated_info_t *self_p,
int tag)
{
Expand Down
119 changes: 106 additions & 13 deletions pbtools/c_source/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@
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,
Expand Down Expand Up @@ -264,6 +269,14 @@
(pbtools_message_encode_inner_t){field.full_type_snake_case}_encode_inner);
'''

ENCODE_SUB_MESSAGE_MEMBER_POINTER_FMT = '''\
pbtools_encoder_sub_message_pointer_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});
Expand Down Expand Up @@ -388,6 +401,18 @@
break;
'''

DECODE_SUB_MESSAGE_MEMBER_POINTER_FMT = '''\
case {field.field_number}:
pbtools_decoder_sub_message_pointer_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(\
Expand Down Expand Up @@ -513,6 +538,18 @@
}}
'''

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,
Expand Down Expand Up @@ -592,13 +629,14 @@

class Generator:

def __init__(self, namespace, parsed, header_name):
def __init__(self, namespace, parsed, header_name, sub_message_pointers):
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.sub_message_pointers = sub_message_pointers

@property
def messages(self):
Expand Down Expand Up @@ -627,7 +665,11 @@ def generate_struct_member_fmt(self, type, name_snake_case, type_kind):
elif type_kind == 'enum':
type = f'enum {type}_e '
elif type_kind == 'message':
type = f'struct {type}_t '
if self.sub_message_pointers:
type = f'struct {type}_t *'
name_snake_case = f'{name_snake_case}_p'
else:
type = f'struct {type}_t '
else:
type += ' '

Expand Down Expand Up @@ -773,9 +815,20 @@ def generate_declarations(self):
return '\n'.join(declarations)

def generate_message_declarations(self, message, declarations, public):
for field in message.repeated_fields:
declarations.append(
REPEATED_DECLARATION_FMT.format(message=message, field=field))
if self.sub_message_pointers:
for field in message.fields:
if field.repeated:
declarations.append(
REPEATED_DECLARATION_FMT.format(message=message, field=field))
elif field.type_kind == 'message' and self.sub_message_pointers:
declarations.append(
SUB_MESSAGE_ALLOC_DECLARATION_FMT.format(message=message,
field=field))
else:
for field in message.repeated_fields:
declarations.append(
REPEATED_DECLARATION_FMT.format(message=message, field=field))


for sub_message in message.messages:
self.generate_message_declarations(sub_message,
Expand Down Expand Up @@ -827,7 +880,10 @@ def generate_message_encode_body(self, message):
else:
fmt = ENCODE_REPEATED_MESSAGE_MEMBER_FMT
elif field.type_kind == 'message':
fmt = ENCODE_SUB_MESSAGE_MEMBER_FMT
if self.sub_message_pointers:
fmt = ENCODE_SUB_MESSAGE_MEMBER_POINTER_FMT
else:
fmt = ENCODE_SUB_MESSAGE_MEMBER_FMT
else:
fmt = ENCODE_ENUM_FMT

Expand Down Expand Up @@ -867,7 +923,10 @@ def generate_message_decode_body(self, message):
elif field.type_kind == 'scalar-value-type':
fmt = DECODE_MEMBER_FMT
elif field.type_kind == 'message':
fmt = DECODE_SUB_MESSAGE_MEMBER_FMT
if self.sub_message_pointers:
fmt = DECODE_SUB_MESSAGE_MEMBER_POINTER_FMT
else:
fmt = DECODE_SUB_MESSAGE_MEMBER_FMT
else:
fmt = DECODE_ENUM_FMT

Expand Down Expand Up @@ -895,8 +954,11 @@ def generate_message_members_init(self, message):
elif field.type_kind == 'scalar-value-type':
member = f' self_p->{name} = 0;'
elif field.type_kind == 'message':
member = (f' {field.full_type_snake_case}_init(&self_p->{name}, '
f'heap_p);')
if self.sub_message_pointers:
member = f' self_p->{name}_p = NULL;'
else:
member = (f' {field.full_type_snake_case}_init(&self_p->{name}, '
f'heap_p);')
else:
member = f' self_p->{name} = 0;'

Expand Down Expand Up @@ -924,6 +986,25 @@ def generate_repeated_definitions(self, 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

if not self.sub_message_pointers:
continue

allocs.append(
SUB_MESSAGE_ALLOC_DEFINITION_FMT.format(message=message,
field=field))

return '\n'.join(allocs)

def generate_repeated_finalizers(self, message):
finalizers = []

Expand Down Expand Up @@ -1085,6 +1166,11 @@ def generate_message_definitions(self,
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:
Expand Down Expand Up @@ -1123,15 +1209,19 @@ def generate(self):
return header, source


def generate(namespace, parsed, header_name):
def generate(namespace, parsed, header_name, sub_message_pointers):
"""Generate C source code from given parsed proto-file.
"""

return Generator(namespace, parsed, header_name).generate()
return Generator(namespace, parsed, header_name, sub_message_pointers).generate()


def generate_files(import_path, output_directory, infiles):
def generate_files(import_path,
output_directory,
namespace,
sub_message_pointers,
infiles):
"""Generate C source code from proto-file(s).
"""
Expand All @@ -1141,10 +1231,13 @@ def generate_files(import_path, output_directory, infiles):
basename = os.path.basename(filename)
name = camel_to_snake_case(os.path.splitext(basename)[0])

if namespace:
name = f'{namespace}_{name}'

filename_h = f'{name}.h'
filename_c = f'{name}.c'

header, source = generate(name, parsed, filename_h)
header, source = generate(name, parsed, filename_h, sub_message_pointers)
filename_h = os.path.join(output_directory, filename_h)
filename_c = os.path.join(output_directory, filename_c)

Expand Down

0 comments on commit 4e2b410

Please sign in to comment.