I'm having trouble defining a nanopb message that has a nested type whose type is the message itself.
syntax = "proto2";
import "nanopb.proto";
option (nanopb_fileopt).max_size = 20;
message myMessage {
optional string string1 = 1;
optional string string2 = 2;
optional string string3 = 3;
}
generated code:
typedef struct _myMessage {
bool has_string1;
char string1[20];
bool has_string2;
char string2[20];
bool has_string3;
char string3[20];
/* @@protoc_insertion_point(struct:myMessage) */
} myMessage;
syntax = "proto2";
import "nanopb.proto";
option (nanopb_fileopt).max_size = 20;
message myMessage {
optional string string1 = 1;
optional string string2 = 2;
optional string string3 = 3;
optional myMessage submessage = 4;
}
errors:
$ python3 generate_c_files.py test/aaa.proto
Today is a good day to code
Traceback (most recent call last):
File ".../generator/nanopb_generator.py", line 1850, in <module>
main_cli()
File ".../generator/nanopb_generator.py", line 1746, in main_cli
results = process_file(filename, None, options)
File ".../generator/nanopb_generator.py", line 1704, in process_file
headerdata = ''.join(f.generate_header(includes, headerbasename, options))
File ".../generator/nanopb_generator.py", line 1338, in generate_header
msize = msg.encoded_size(self.dependencies)
File ".../generator/nanopb_generator.py", line 1068, in encoded_size
fsize = field.encoded_size(dependencies)
File ".../generator/nanopb_generator.py", line 670, in encoded_size
encsize = submsg.encoded_size(dependencies)
File ".../generator/nanopb_generator.py", line 1068, in encoded_size
fsize = field.encoded_size(dependencies)
File ".../generator/nanopb_generator.py", line 670, in encoded_size
encsize = submsg.encoded_size(dependencies)
...
File ".../generator/nanopb_generator.py", line 1068, in encoded_size
fsize = field.encoded_size(dependencies)
File ".../generator/nanopb_generator.py", line 670, in encoded_size
encsize = submsg.encoded_size(dependencies)
File ".../generator/nanopb_generator.py", line 1068, in encoded_size
fsize = field.encoded_size(dependencies)
File ".../generator/nanopb_generator.py", line 706, in encoded_size
encsize = EncodedSize(self.enc_size)
File ".../generator/nanopb_generator.py", line 160, in __init__
elif isinstance(value, strtypes + (Names,)):
RecursionError: maximum recursion depth exceeded in __instancecheck__
It's not possible to statically allocate space for an unbounded recursive structure. You need to either use dynamic allocation or callbacks. This can be accomplished using the type
option set to either FT_CALLBACK
or FT_POINTER
:
message myMessage {
optional string string1 = 1;
optional string string2 = 2;
optional string string3 = 3;
optional myMessage submessage = 4 [(nanopb).type = FT_CALLBACK];
}
Starting with version 0.4.8, the FT_CALLBACK
option will be automatically applied if the generator detects a recursive message. With earlier versions it has to be added manually, in either the .proto
file or in a separate .options
file.
To use a callback, you need to define a field callback function that will pass the data between your custom storage structure and the protobuf wire format.
With dynamic allocation, the structure will contain the pointer struct myMessage*
, which points to the nested message or NULL
at the end of recursion. For encoding you can use any kind of allocation for the messages. For decoding, pb_realloc()
is used, which by default uses libc heap, but can be overridden to use e.g. custom arena allocator.