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/CADqAXr5tTGP-oaGLt8P84m%3Dn%2BwQLGZwJknefh7akQ2f-GjkTmg%40mail.gmail.com.
