Hello again, Adam,

If I understand you correctly, the key would be to obtain the 
mutable-message (by name) for the child from the parent as I descend the 
tree.

It think that would work!
Thank you very much for your light, I'm a newbie to protobuf and this 
demystifies part of it. I'll see if I can get that working
Thanks again

On Tuesday, 22 June 2021 at 14:49:20 UTC-4 [email protected] wrote:

> Here's how you could set that nested field in your example (this code is 
> untested so may not work exactly, but should be pretty close):
>
> const FieldDescriptor* health_report_field = 
> parent.GetDescriptor()->FindFieldByName("healthreport");
> Message* health_report = parent.GetReflection()->MutableMessage(&parent, 
> health_report_field);
> const FieldDescriptor* os_field = 
> health_report->GetDescriptor()->FieldFieldByName("os");
> Message* os = 
> health_report->GetReflection()->MutableMessage(health_report, os_field);
> const FieldDescriptor* version_field = 
> os->GetDescriptor()->FindFieldByName("version");
> os->GetReflection()->SetEnumValue(os, version_field, 3);
>
> On Tue, Jun 22, 2021 at 11:34 AM J G <[email protected]> wrote:
>
>> Hi Adam,
>>
>> OK, but would I need to know the fields in the message ahead of time? 
>> That is what I am trying to avoid.
>> The paths of the nested messages are in a table, such as
>>
>> "healthreport/os/version", 3
>>
>> So the healthreport variable is allocated, and it contains a component 
>> called os, which itself contains a field called version.
>>
>> So I am trying to write a generic enum function, that can descend the 
>> parent, and guided by the path info, can resolve the value that needs to be 
>> stored there, but if I am to traverse the entire tree manually, how does 
>> the reflection API help?
>> On Tuesday, 22 June 2021 at 14:21:59 UTC-4 [email protected] wrote:
>>
>>> I think the reason this is getting tricky is because you're trying to 
>>> traverse the descriptors first and then look at the message tree afterward. 
>>> I would expect it to be much easier if you traverse the message and look at 
>>> the descriptors at the same time.
>>>
>>> On Tue, Jun 22, 2021 at 10:58 AM J G <[email protected]> wrote:
>>>
>>>> Hi Adam,
>>>>
>>>> That works for the first iteration, but I descend the tree like so: 
>>>>
>>>> bool enumpb( const char * pszpath, ENUMPROTOPROC f, const 
>>>> google::protobuf::Descriptor * d, uintptr_t param ) {
>>>>
>>>>     std::string path = pszpath;
>>>>
>>>>     for ( int i = 0; i < d->field_count(); i++ ) {
>>>>
>>>>         auto field = d->field( i );
>>>>
>>>>         std::string localpath = pszpath;
>>>>
>>>>         if ( 0 != strcmp( "component", field->name().c_str() ) ) {
>>>>
>>>>             localpath.append( field->name() );
>>>>
>>>>         }
>>>>
>>>>         if ( ( ! localpath.empty() ) && ( '/' != localpath.back() ) ) {
>>>>
>>>>             if ( f && ! f( field, localpath.c_str(), param ) ) {
>>>>
>>>>                 return false;
>>>>
>>>>             }
>>>>
>>>>         }
>>>>
>>>>         auto mt = field->message_type();
>>>>
>>>>         if ( ! mt ) {
>>>>
>>>>             continue;
>>>>
>>>>         } else if ( 0 != strcmp( d->full_name().c_str(), 
>>>> mt->full_name().c_str() ) ) {
>>>>
>>>>             std::string localpath2 = localpath;
>>>>
>>>>             if ( ( ! localpath.empty() ) && ( '/' != localpath.back() ) 
>>>> ) {
>>>>
>>>>                 localpath2.append( "/" );
>>>>
>>>>             }
>>>>
>>>>             if ( ! enumpb( hp, report, localpath2.c_str(), f, mt, param 
>>>> ) ) {
>>>>
>>>>                 return false;
>>>>
>>>>             }
>>>>
>>>>         } else {
>>>>
>>>> //            printf( "Skipping circular %s" EOL, 
>>>> d->full_name().c_str() );
>>>>
>>>>         }
>>>>
>>>>     }
>>>>
>>>>     return true;
>>>>
>>>> }
>>>>
>>>> So I start the traversal like this:
>>>>
>>>> auto d = report->GetDescriptor();
>>>>
>>>> enumpb( "", f, d, param );
>>>>
>>>> And it goes down the variable, visiting each leaf and nested child 
>>>> variable, but I can't address each nested child directly that way, can I?
>>>> The mt variable does hold the descriptor for each nested variable at 
>>>> some point, but I don't know how I'd derive the variable's instance from 
>>>> it.
>>>>
>>>> On Tuesday, 22 June 2021 at 13:47:15 UTC-4 [email protected] wrote:
>>>>
>>>>> I think the easiest thing would be that wherever you're now storing a 
>>>>> google::protobuf::FieldDescriptor*, you can also store a 
>>>>> google::protobuf::Message* pointing to the parent message.
>>>>>
>>>>> On Tue, Jun 22, 2021 at 10:41 AM J G <[email protected]> wrote:
>>>>>
>>>>>> Hi Adam,
>>>>>>
>>>>>> Yes, the HealthReport variable is the parent, and it contains a 
>>>>>> HardwareComponent variable, but I am enumerating the from the parent, 
>>>>>> meaning I am trying to not hard-code the structure of the contained 
>>>>>> items.
>>>>>>
>>>>>> So how would I obtain a pointer to the message for each leaf without 
>>>>>> hard-coding the member names in there?
>>>>>>
>>>>>> I am able to figure out what value I want to set in each leaf by a 
>>>>>> map I have that uses the field's path to match it to the value I want to 
>>>>>> store.
>>>>>>
>>>>>> On Tuesday, 22 June 2021 at 13:33:11 UTC-4 [email protected] wrote:
>>>>>>
>>>>>>> So is it correct that HealthReport is the top-level message type and 
>>>>>>> HardwareComponent is nested somewhere within that? I think what you're 
>>>>>>> trying to do is doable, but when you call reflection->SetString(), you 
>>>>>>> have 
>>>>>>> to pass the immediate parent message containing the field, not the 
>>>>>>> top-level message. You don't need to save the descriptor for each leaf, 
>>>>>>> but 
>>>>>>> you do need to save a pointer to the message containing each leaf.
>>>>>>>
>>>>>>> On Tue, Jun 22, 2021 at 10:17 AM J G <[email protected]> wrote:
>>>>>>>
>>>>>>>> Hi again Adam, and thank you for taking the time to help me.
>>>>>>>>
>>>>>>>> Maybe I haven't explained what I am trying to do properly.
>>>>>>>>
>>>>>>>> I have a protobuf variable, which itself is composed of more nested 
>>>>>>>> variables.
>>>>>>>>
>>>>>>>> I am enumerating the fields of the variable.
>>>>>>>>
>>>>>>>> Where the item is a leaf, the field is a simple c-like type (int, 
>>>>>>>> bool, string, etc)
>>>>>>>>
>>>>>>>> Where the item itself has fields, it is an agglomerate type and it 
>>>>>>>> is descended recursively.
>>>>>>>>
>>>>>>>> My aim is to set each leaf programmatically.
>>>>>>>>
>>>>>>>> So as I traverse the arborescance, I am collecting the field 
>>>>>>>> definitions for the leafs.
>>>>>>>>
>>>>>>>> So later, I am addressing the variable again, but trying to set one 
>>>>>>>> of its leafs by the field definition I saved. Do I also have to save 
>>>>>>>> the 
>>>>>>>> descriptor for each leaf?
>>>>>>>>
>>>>>>>> Can what I want to do be done?
>>>>>>>>
>>>>>>>>
>>>>>>>> On Tuesday, 22 June 2021 at 11:52:00 UTC-4 [email protected] 
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> It looks to me like r->report points to a vafmsg.HealthReport but 
>>>>>>>>> the field descriptor refers to a field in another message 
>>>>>>>>> (vafmsg.HardwareComponent).
>>>>>>>>>
>>>>>>>>> On Tue, Jun 22, 2021 at 7:42 AM J G <[email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hello Adam,
>>>>>>>>>>
>>>>>>>>>> OK, I understand, so I've tried this, but I get an error.
>>>>>>>>>>
>>>>>>>>>> void my_set_value( class healthreport * r, const char * 
>>>>>>>>>> defaultvalue, const google::protobuf::FieldDescriptor * descriptor ) 
>>>>>>>>>> {
>>>>>>>>>>
>>>>>>>>>>     auto reflection = r->report->GetReflection();
>>>>>>>>>>
>>>>>>>>>>     switch( descriptor->type() ) {
>>>>>>>>>>         case google::protobuf::FieldDescriptor::TYPE_STRING: {
>>>>>>>>>>
>>>>>>>>>>                 printf( "REQUESTED TYPE: STRING" EOL );
>>>>>>>>>>                 std::string s = defaultvalue;
>>>>>>>>>>                 reflection->SetString( r->report, descriptor, s );
>>>>>>>>>>
>>>>>>>>>>             }
>>>>>>>>>>             break;
>>>>>>>>>>
>>>>>>>>>>         default:
>>>>>>>>>>
>>>>>>>>>>             printf( "REQUESTED TYPE %d NOT HANDLED" EOL, 
>>>>>>>>>> descriptor->type() );
>>>>>>>>>>             break;
>>>>>>>>>>
>>>>>>>>>>     }
>>>>>>>>>>
>>>>>>>>>> }
>>>>>>>>>> Running the above produces the following output:
>>>>>>>>>>
>>>>>>>>>> REQUESTED TYPE: STRING
>>>>>>>>>> [libprotobuf FATAL 
>>>>>>>>>> /var/tmp/portage/dev-libs/protobuf-3.15.8/work/protobuf-3.15.8/src/google/protobuf/generated_message_reflection.cc:111]
>>>>>>>>>>  
>>>>>>>>>> Protocol Buffer reflection usage error:
>>>>>>>>>>   Method      : google::protobuf::Reflection::SetString
>>>>>>>>>>   Message type: vafmsg.HealthReport
>>>>>>>>>>   Field       : vafmsg.HardwareComponent.hardware_interface
>>>>>>>>>>   Problem     : Field does not match message type.
>>>>>>>>>> terminate called after throwing an instance of 
>>>>>>>>>> 'google::protobuf::FatalException'
>>>>>>>>>>   what():  Protocol Buffer reflection usage error:
>>>>>>>>>>   Method      : google::protobuf::Reflection::SetString
>>>>>>>>>>   Message type: vafmsg.HealthReport
>>>>>>>>>>   Field       : vafmsg.HardwareComponent.hardware_interface
>>>>>>>>>>   Problem     : Field does not match message type.
>>>>>>>>>>
>>>>>>>>>> Here is the proto definition of the variable triggering the 
>>>>>>>>>> exception:
>>>>>>>>>>
>>>>>>>>>> message HardwareComponent { 
>>>>>>>>>>     optional Component component = 1;
>>>>>>>>>>     repeated DiscreteValue temp = 2;
>>>>>>>>>>     optional string hardware_interface = 3;
>>>>>>>>>>     optional uint32 remaining_life = 4;
>>>>>>>>>>     optional uint32 total_hours = 5;
>>>>>>>>>>     optional EnergyInfo energy = 6;
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> So the type really IS string, yet an exception is triggered...
>>>>>>>>>>
>>>>>>>>>> What am I doing wrong?
>>>>>>>>>>
>>>>>>>>>> On Friday, 18 June 2021 at 17:56:57 UTC-4 [email protected] 
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>> Each descriptor describes part of the schema (e.g. a message 
>>>>>>>>>>> type, enum type, etc.) but is unrelated to any particular instance 
>>>>>>>>>>> of it. 
>>>>>>>>>>> As a result, if you have a descriptor by itself then you can't 
>>>>>>>>>>> really 
>>>>>>>>>>> modify anything because you separately need an instance of the 
>>>>>>>>>>> thing you 
>>>>>>>>>>> want to modify. The way to programmatically modify a message is to 
>>>>>>>>>>> use the 
>>>>>>>>>>> Reflection 
>>>>>>>>>>> <https://github.com/protocolbuffers/protobuf/blob/9d9d8ee18dedfb18371031cd299d1d282ddf707f/src/google/protobuf/message.h#L452>
>>>>>>>>>>>  
>>>>>>>>>>> API. You can use Reflection::ListFields() to get a list of all the 
>>>>>>>>>>> fields 
>>>>>>>>>>> that are set on the message and then there are Reflection::Get* and 
>>>>>>>>>>> Reflection::Set* methods to get and set particular fields.
>>>>>>>>>>>
>>>>>>>>>>> On Fri, Jun 18, 2021 at 9:11 AM J G <[email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> I've got some code that lets me recursively walk a protobuf 
>>>>>>>>>>>> variable.
>>>>>>>>>>>>
>>>>>>>>>>>> That part works, I can enumerate the characteristics of a 
>>>>>>>>>>>> variable, but the pointers/references returned by the API are 
>>>>>>>>>>>> const.
>>>>>>>>>>>>
>>>>>>>>>>>> My question is: From a variable's Descriptor or 
>>>>>>>>>>>> FieldDescriptor, is it possible to get a non-const 
>>>>>>>>>>>> pointer/reference to the 
>>>>>>>>>>>> field to be able to modify it?
>>>>>>>>>>>>
>>>>>>>>>>>> Here's my (simplified) code so far:
>>>>>>>>>>>>
>>>>>>>>>>>> void enumpb(  const google::protobuf::Descriptor * d ) {
>>>>>>>>>>>>
>>>>>>>>>>>>     for ( int i = 0; i < d->field_count(); i++ ) {
>>>>>>>>>>>>
>>>>>>>>>>>>         auto field = d->field( i );
>>>>>>>>>>>>
>>>>>>>>>>>>         // Modify variable code here
>>>>>>>>>>>>         [...]
>>>>>>>>>>>>
>>>>>>>>>>>>         auto mt = field->message_type();
>>>>>>>>>>>>         if ( ! mt ) {
>>>>>>>>>>>>             continue;
>>>>>>>>>>>>         } else if ( 0 != strcmp( d->full_name().c_str(), 
>>>>>>>>>>>> mt->full_name().c_str() ) ) {
>>>>>>>>>>>>
>>>>>>>>>>>>             enumpb( mt ) ;
>>>>>>>>>>>>
>>>>>>>>>>>>         }
>>>>>>>>>>>>
>>>>>>>>>>>>     }
>>>>>>>>>>>>
>>>>>>>>>>>>     return true;
>>>>>>>>>>>>
>>>>>>>>>>>> }
>>>>>>>>>>>>
>>>>>>>>>>>> -- 
>>>>>>>>>>>> You received this message because you are subscribed to the 
>>>>>>>>>>>> Google Groups "Protocol Buffers" group.
>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from 
>>>>>>>>>>>> it, send an email to [email protected].
>>>>>>>>>>>> To view this discussion on the web visit 
>>>>>>>>>>>> https://groups.google.com/d/msgid/protobuf/dcf6bb53-24ce-4404-ab71-0fe3a94adc40n%40googlegroups.com
>>>>>>>>>>>>  
>>>>>>>>>>>> <https://groups.google.com/d/msgid/protobuf/dcf6bb53-24ce-4404-ab71-0fe3a94adc40n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>>>>>> .
>>>>>>>>>>>>
>>>>>>>>>>> -- 
>>>>>>>>>> You received this message because you are subscribed to the 
>>>>>>>>>> Google Groups "Protocol Buffers" group.
>>>>>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>>>>>> send an email to [email protected].
>>>>>>>>>>
>>>>>>>>> To view this discussion on the web visit 
>>>>>>>>>> https://groups.google.com/d/msgid/protobuf/7ef6e77e-8635-4b16-b570-b80f75d207d9n%40googlegroups.com
>>>>>>>>>>  
>>>>>>>>>> <https://groups.google.com/d/msgid/protobuf/7ef6e77e-8635-4b16-b570-b80f75d207d9n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>>>> .
>>>>>>>>>>
>>>>>>>>> -- 
>>>>>>>> You received this message because you are subscribed to the Google 
>>>>>>>> Groups "Protocol Buffers" group.
>>>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>>>> send an email to [email protected].
>>>>>>>>
>>>>>>> To view this discussion on the web visit 
>>>>>>>> https://groups.google.com/d/msgid/protobuf/39fd7a89-426a-453d-9482-4cb3e3658da0n%40googlegroups.com
>>>>>>>>  
>>>>>>>> <https://groups.google.com/d/msgid/protobuf/39fd7a89-426a-453d-9482-4cb3e3658da0n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>> .
>>>>>>>>
>>>>>>> -- 
>>>>>> You received this message because you are subscribed to the Google 
>>>>>> Groups "Protocol Buffers" group.
>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>> send an email to [email protected].
>>>>>>
>>>>> To view this discussion on the web visit 
>>>>>> https://groups.google.com/d/msgid/protobuf/764459e6-6f37-42aa-869c-0f8405aa13c6n%40googlegroups.com
>>>>>>  
>>>>>> <https://groups.google.com/d/msgid/protobuf/764459e6-6f37-42aa-869c-0f8405aa13c6n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>> .
>>>>>>
>>>>> -- 
>>>> You received this message because you are subscribed to the Google 
>>>> Groups "Protocol Buffers" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>> an email to [email protected].
>>>>
>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/protobuf/3d9ed924-341b-43cf-8359-c91a93d1916dn%40googlegroups.com
>>>>  
>>>> <https://groups.google.com/d/msgid/protobuf/3d9ed924-341b-43cf-8359-c91a93d1916dn%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Protocol Buffers" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected].
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/protobuf/9c617cbc-f632-46a3-a1ac-c95c7fe6d2e2n%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/protobuf/9c617cbc-f632-46a3-a1ac-c95c7fe6d2e2n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/protobuf/66ae16c1-fc14-407f-b0d4-ab18d695d9d3n%40googlegroups.com.

Reply via email to