Indigo
Indigo

Reputation: 962

Repeated submessage fields always decodes to zero

I have a somewhat deeply nested .proto. Message is a union, Update is a member of that union (ignoring the others for the sake of this question), Update contains a repeated Config (added just once for simplicity), Config contains actual data (ints here for simplicity).

    message Message {
    
        message Config {
            int64 job = 1;
            int64 job2 = 2;
        }
    
        message Update {
            repeated Config jobs = 1;
        }
    
        oneof message {
            Update update = 1;
        }
    
    }

Right now I'm just trying to encode and decode (useless, but just to get it working). It seems to encode/decode okay, doesn't throw any errors. But whatever I put in as data to my job and job2, it always spits back a zero on the other end.

    void main(void)
    {
        /* This is the buffer where we will store our message. */
        uint8_t buffer[128];
        size_t message_length;
        bool status;
    
        /* Encode our message */
        {
            /* Create a stream that will write to our buffer. */
            pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
    
            /* Fill in the message */
            Message_Config my_job_config_struct =
            {
                .job = 345,
                .job2 = 988,
            };
    
            /* Configure it as a union, add the encode func for the repeated field encoding */
            Message message = {
                .which_message = Message_update_tag,
                .my_message.update = {
                    .jobs = {
                        .arg = &my_job_config_struct,
                        .funcs.encode = &encode_Config,
                    },
                }
            };
    
            /* Now we are ready to encode the message! */
            status = pb_encode(&ostream, Message_fields, &message);
            message_length = ostream.bytes_written;
    
            /* Then just check for any errors.. */
            if (!status)
            {
                printf("\nEncoding failed: %s\n", PB_GET_ERROR(&ostream));
                return 1;
            }
        }
        printf("~~~~~~~~~~~~~~~~Done Encoding");
    
        /* Now we could transmit the message over network, store it in a file or
         * wrap it to a pigeon's leg.
         */
    
        /* But because we are lazy, we will just decode it immediately. */
    
        {
            /* Create a stream that reads from the buffer. */
            pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
    
            /* Find out the union type */
            const pb_msgdesc_t *type = decode_Update_type(&istream);
    
            /* Now we are ready to decode the message. */
            if (type == Message_ConfigUpdate_fields)
            {
                Message_ConfigUpdate msg = Message_ConfigUpdate_init_zero;
                msg.jobs.funcs.decode = &decode_Config;
                status = decode_Update_contents(&istream, Message_ConfigUpdate_fields, &msg);
            }
            else
            {
                LOG_ERR("Sad :( no type match");
            }
    
            /* Check for errors... */
            if (!status)
            {
                LOG_ERR("Decoding failed: %s\n", PB_GET_ERROR(&istream));
                return 1;
            }
        }
    
        return 0;
    }
    
    
    bool encode_Config(pb_ostream_t *stream, const pb_field_t *field, void *const *arg)
    {
        /* Cast the args back to config type */
        struct Message_Config *update_submessage =
            (struct Message_Config *)(*arg);
    
        if (!pb_encode_tag_for_field(stream, field))
        {
            return false;
        }
    
        /* Encode the struct as a submessage */
        /* If we were repeating this field we'd loop here and encode multiple times */
        bool ret = pb_encode_submessage(stream,
            Message_Config_fields, &update_submessage);
    
        return ret;
    }
    
    const pb_msgdesc_t* decode_Update_type(pb_istream_t *stream)
    {
        pb_wire_type_t wire_type;
        uint32_t tag;
        bool eof;
    
        while (pb_decode_tag(stream, &wire_type, &tag, &eof))
        {
            if (wire_type == PB_WT_STRING)
            {
                pb_field_iter_t iter;
                if (pb_field_iter_begin(&iter, Message_fields, NULL) &&
                    pb_field_iter_find(&iter, tag))
                {
                    /* Found our field. */
                    return iter.submsg_desc;
                }
            }
            
            /* Wasn't our field.. */
            pb_skip_field(stream, wire_type);
        }
        
        return NULL;
    }
    
    bool decode_Update_contents(pb_istream_t *stream, const pb_msgdesc_t *messagetype, void *dest_struct)
    {
        bool status = true;
        pb_istream_t substream;
        if (!pb_make_string_substream(stream, &substream))
            {return false;}
    
        /* messagetype = Message_ConfigUpdate_fields, dest_struct = type Message_ConfigUpdate*/
        status &= pb_decode(&substream, messagetype, dest_struct);
    
        pb_close_string_substream(stream, &substream);
        return status;
    }
    
    bool decode_Config(pb_istream_t *stream, const pb_field_t *field, void **arg)
    {
        Message_Config config_struct = Message_Config_init_zero;
    
        bool ret = pb_decode(&stream, Message_Config_fields, &config_struct);
        printf("job: %i", config_struct.job);
        printf("job2: %i", config_struct.job2);
    
        return ret;
    }

Based on what I put into the ints in this example, I expect them to print out with job = 345, job2 = 988, but this is the actual output I get

00> I: ~~~~~~~~~~~~~~~~Done Encoding
00> I: job: 0
00> I: job2: 0

I've tried making the field not repeated and changing the encode/decode calls accordingly, and the ints pass through just fine. There seems to be something wrong with either my encoding or my decoding of the repeated submessage and I haven't been able to narrow it down. Any hints from a second pair eyes would be greatly appreciated.

Upvotes: 1

Views: 140

Answers (0)

Related Questions