I fixed my problem. I was using the field offset instead of the field index.
Here is what I'm doing. I'm using a macro, but I think it's quite efficient to do all the stuff I have to do, in a safe way :)
---------------------------------------------
/* Utility header file */
typedef std::list<capnp::StructSchema::Field> FieldList;
typedef std::list<capnp::StructSchema::Field>::const_iterator FieldListConstIterator;
#define UTIL_CONCAT3(a, b, c) UTIL_CONCAT2(UTIL_CONCAT2(a, b), c)
#define UTIL_CONCAT2(a, b) UTIL_CONCAT2_(a, b)
#define UTIL_CONCAT2_(a, b) a##b
#define UTIL_FIELD_HAS(reader, field) UTIL_CONCAT2(reader.has, field())
#define UTIL_FIELD_READER(reader, field) UTIL_CONCAT2(reader.get, field())
#define UTIL_FIELD_INDEX(reader, field) UTIL_CONCAT3(reader.get, field, FieldIndex())
#define UTIL_SET_COND(fct, reader, field, fieldList, ...) \
({ \
bool success = true; \
if (UTIL_FIELD_HAS(reader, field)) \
{ \
success = Util::pushBackFieldList(fieldList, reader, UTIL_FIELD_INDEX(reader, field)); \
if (success) \
{ \
success = fct(UTIL_FIELD_READER(reader, field), fieldList, ##__VA_ARGS__); \
Util::popBackFieldList(fieldList); \
} \
} \
success \
})
---------------------------------------------
/* Utility source file */
void Util::pushBackFieldList(FieldList &fieldList, const DynamicStruct::Reader &reader, uint16_t fieldIndex)
{
StructSchema::Field field;
if (getField(reader, fieldIndex, field))
{
fieldList.push_back(field);
return true;
}
else
{
return false;
}
}
void Util::popBackFieldList(FieldList &fieldList)
{
KJ_ASSERT(fieldList.size() > 0);
if (fieldList.size() > 0)
fieldList.pop_back();
}
void Util::getField(const DynamicStruct::Reader &reader, uint16_t fieldIndex, StructSchema::Field &field)
{
auto schema = reader.getSchema();
auto fields = schema.getFields();
KJ_ASSERT(fieldIndex < fields.size());
if (fieldIndex < fields.size())
{
field = fields[fieldIndex];
return true;
}
else
{
return false;
}
}
---------------------------------------------
/* Configuration source file */
bool setConfig(const Config::Reader &reader)
{
FieldList fieldList;
bool success = UTIL_SET_COND(setDate, reader, Date, fieldList);
/* ... */
return success;
}
---------------------------------------------
In setDate, if an error is detected, I'm able to get the error path using the fieldList. So, I would be able to report it at higher level, and the JSON client would receive something like this:
{
"code": 1,
"dataPath": "/config/date/hour"
}
Also, I'm able to add an event in a log using this same path (e.g. /config/date/hour 22).