protoc-gen-validate icon indicating copy to clipboard operation
protoc-gen-validate copied to clipboard

Cpp support

Open manuelnp opened this issue 3 years ago • 0 comments

I have fixed a bunch of compilation errors I found using a pretty large and diverse proto codebase:

1. Using system types as field name: float, double, enum, bool Generated accessors should end with underscore, ie: message.float_() and message.has_float_()

2. camelCase field names: C++ generated code had all casing lowered, ie: a field named productId generates the methods message.productid() and message.has_productid() (notice the upper/lower i on id)

3. Use full qualified classnames for enums: Before this change, two user cases made the validation generated code fail to compile:

  • Enum defined on a different package
  • Several Enums, with the same name, defined in the same file but under different messages

4. Two or more repeated fields with validation rules Having two or more repeated fields with validations rules under the same message fails because the redefinition of cmp and hash structs. I added a CCFuncs function safeClassName which returns an underscored version of the full qualified class name in order to use it as unique identifier. So, instead of this:

struct cmp {
  bool operator() (const std::reference_wrapper<::foo::bar::Baz> lhs, const std::reference_wrapper<::foo::bar::Baz> rhs) const {
    return lhs.get() == rhs.get();
    }
  };

now we get this (notice the brand new full qualified name!):

struct __foo__bar__Baz_cmp {
  bool operator() (const std::reference_wrapper<::foo::bar::Baz> lhs, const std::reference_wrapper<::foo::bar::Baz> rhs) const {
    return lhs.get() == rhs.get();
    }
  };

5. remove const_cast in set of references to avoid copying overhead: Use C-style cast instead on the emplace.

// Save a set of references to avoid copying overhead
std::unordered_set<std::reference_wrapper<::foo::bar::Baz>, ::foo::bar::Baz_hash, ::foo::bar::Baz_cmp> __foo__bar__Baz_Elements_Unique;

for (int i = 0; i < m.elements().size(); i++) {
  const auto& item = m.elements().Get(i);
  (void)item;

  auto p = __foo__bar__Baz_Elements_Unique.emplace((::foo::bar::Baz&)(item));
  if (p.second == false) {
    {
std::ostringstream msg("invalid ");
msg << "BazValidationError" << "." << "Elements";
msg << "[" << i << "]";
msg << ": " << "repeated value must contain unique items";
*err = msg.str();
return false;
    }
  }
// no validation rules for elements[i]
}

When the underlying type of the repeated element is Enum, proto/C++ uses an int instead, so the following statement:

const auto& item = m.elements().Get(i);

Makes item a const int& and the compilation for this fails.

auto p = __foo__bar__Baz_Elements_Unique.emplace(const_cast<::foo::bar::Baz&>(item));

However, using a C-style cast does the trick, Not very happy about it, but gets the work done.

auto p = __foo__bar__Baz_Elements_Unique.emplace((::foo::bar::Baz&)(item));

manuelnp avatar Apr 26 '22 10:04 manuelnp