13d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler/*
23d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * Copyright (C) 2016 The Android Open Source Project
33d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler *
43d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * Licensed under the Apache License, Version 2.0 (the "License");
53d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * you may not use this file except in compliance with the License.
63d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * You may obtain a copy of the License at
73d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler *
83d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler *      http://www.apache.org/licenses/LICENSE-2.0
93d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler *
103d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * Unless required by applicable law or agreed to in writing, software
113d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * distributed under the License is distributed on an "AS IS" BASIS,
123d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * See the License for the specific language governing permissions and
143d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * limitations under the License.
153d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler */
163d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
173d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// This file implements a simple protobuf encoder and decoder. The high-level
183d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// idea is to use C++ structs as data containers corresponding to protobuf
193d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// messages. A descriptor must be provided for a struct via a
203d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |nvram::DescriptorForType| specialization that declares the protobuf fields
213d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// to encode and decode.
223d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * Encoding works by going through the declared fields, and encode the
233d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    corresponding struct members in protobuf wire format.
243d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * Decoding scans through the binary encoded message. It looks at the wire
253d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    tag decoded form the message to recover the field number as well as
263d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    the protobuf wire type (i.e. kind of encoding). The field number is then
273d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    used to locate the struct field declaration so the appropriate decoding
283d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    logic for the corresponding struct member can be invoked.
293d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * The main dispatch point that ties member types to decoding and encoding
303d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    logic is the |nvram::proto::detail::Codec| template. The idea is that
313d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    |Codec<Type>| provides encoding and decoding logic for |Type|.
323d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
333d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// The API for encoding and decoding is straightforward. Consider the following
343d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Employee struct and its descriptor:
353d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// type:
363d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
373d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   struct Employee {
383d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//     uint32_t id;
393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//     std::string name;
403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//     std::vector<uint32_t> reports;
413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   };
423d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   template <>
443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   struct DescriptorForType<Employee> {
453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//     static constexpr auto kFields =
463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//         MakeFieldList(MakeField(1, &Employee::id),
473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//                       MakeField(2, &Employee::name),
483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//                       MakeField(3, &Employee::reports));
493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   };
503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Encoding is simple:
523d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   Employee employee;
543d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   uint8_t buffer[SIZE];
553d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   nvram::OutputStream stream(buffer, sizeof(buffer));
563d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   if (!nvram::proto::Encode(employee, &stream)) {
573d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//     // Handle encoding failure.
583d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   }
593d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
603d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Note that |nvram::proto::GetSize()| can be used to determine a sufficient
613d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// buffer size.
623d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
633d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Decoding is similar:
643d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
653d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   Employee employee;
663d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   nvram::InputStreamBuffer stream(buffer_start, buffer_size);
673d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   if (!nvram::proto::Decode(&employee, &stream)) {
683d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//     // Handle decoding failure.
693d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//   }
703d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
713d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Note that this file is not meant as a header to be included by all code that
723d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// needs to encode or decode messages. Rather, this header should only be
733d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// included by a .cpp file which can then instantiate the
743d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |nvram::proto::Encode()| and |nvram::proto::Decode()| templates to obtain
753d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// encoders and decoders for the relevant message types. This approach results
763d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// in decode and encode logic getting compiled in only one translation unit,
773d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// which other code can link against.
783d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
79a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#ifndef NVRAM_MESSAGES_PROTO_HPP_
80a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#define NVRAM_MESSAGES_PROTO_HPP_
813d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
823d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerextern "C" {
833d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler#include <stdint.h>
843d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}
853d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
86a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/blob.h>
87a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/compiler.h>
88a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/io.h>
89a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/message_codec.h>
90a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/optional.h>
91a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/struct.h>
92a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/tagged_union.h>
93a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/type_traits.h>
94a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/vector.h>
953d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
963d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslernamespace nvram {
973d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslernamespace proto {
983d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
993d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslernamespace detail {
1003d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1013d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// A class template that performs encoding and decoding of a protobuf message
1023d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// field of the C++ type |Type|. The base template is left undefined here,
1033d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// specific implementations for relevant |Type|s are provided by template
1043d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// specializations. Each specialization needs to provide the following members:
1053d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * |static constexpr WireType kWireType| indicates the wire type used for
1063d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    encoded field data.
1073d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * |static bool Encode(const Type& object, ProtoWriter* writer)| writes the
1083d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    encoded form of |object| to |writer|.
1093d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * |static bool Decode(Type& object, ProtoReader* reader)| decodes a field
1103d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//    from |reader| and places recovered data in |object|.
1113d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
1123d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |Codec| specializations are provided below for commonly-used types such as
1133d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// integral and enum types, as well as structs with corresponding descriptors.
1143d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Additional specializations can be added as needed.
1153d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Type, typename Enable = void>
1163d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct Codec {
1173d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // The assert below fails unconditionally, but must depend on the |Type|
1183d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // parameter so it only triggers at instantiation time. If this assert fires,
1193d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // then you are attempting to encode or decode a struct that contains a field
1203d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // of a C++ type for which there exists no code that implements encoding and
1213d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // decoding for that type. To add encoding/decoding support for a type, you
1223d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // can provide a Codec specialization.
1233d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static_assert(sizeof(Type) == 0,
1243d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                "A Codec specialization must be provided for types "
1253d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                "that are to be used with the protobuf encoder.");
1263d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
1273d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1283d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslernamespace {
1293d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1303d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Codec specific message field encoding function. Note that this is marked
1313d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// noinline to prevent the compiler from inlining |Codec::Encode| for every
1323d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// occurrence of a field of type |Type|.
1333d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Codec, typename Type>
13486e84547d37d7d32a5444756f839e11d81c9fc2dMattias NisslerNVRAM_NOINLINE bool EncodeField(const Type& value, ProtoWriter* writer) {
1353d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  return Codec::Encode(value, writer);
1363d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}
1373d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1383d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Codec specific message field decoding function. Note that this is marked
1393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// noinline to prevent the compiler from inlining |Codec::Decode| for every
1403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// occurrence of a field of type |Type|.
1413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Codec, typename Type>
14286e84547d37d7d32a5444756f839e11d81c9fc2dMattias NisslerNVRAM_NOINLINE bool DecodeField(Type& value, ProtoReader* reader) {
1433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  return Codec::Decode(value, reader);
1443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}
1453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}  // namespace
1473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |Codec| specialization for Blob.
1493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <>
1503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct Codec<Blob> {
1513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr WireType kWireType = WireType::kLengthDelimited;
1523d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Encode(const Blob& blob, ProtoWriter* writer) {
1543d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return writer->WriteLengthDelimited(blob.data(), blob.size());
1553d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
1563d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1573d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Decode(Blob& blob, ProtoReader* reader) {
1583d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return blob.Resize(reader->field_size()) &&
1593d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler           reader->ReadLengthDelimited(blob.data(), blob.size());
1603d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
1613d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
1623d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1633d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// A helper to test whether a given |Type| should be handled by the Varint
1643d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |Codec| specialization. The |Type| needs to allow conversion from and to
1653d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |uint64_t|. This checks for static_cast conversion behavior instead of
1663d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// implicit conversion in order to also match scoped enums.
1673d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Type>
1683d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct IsVarintCompatible {
1693d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  template <typename From, typename To>
1703d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  struct IsCastConvertible {
1713d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    template <typename T>
1723d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    static decltype(static_cast<T>(declval<From>()), true_type()) test(int);
1733d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1743d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    template <typename T>
1753d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    static false_type test(...);
1763d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1773d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    static constexpr bool value = decltype(test<To>(0))::value;
1783d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  };
1793d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1803d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr bool value = IsCastConvertible<Type, uint64_t>::value &&
1813d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                                IsCastConvertible<uint64_t, Type>::value;
1823d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
1833d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1843d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |Codec| specialization for varint-encoded numeric fields.
1853d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Type>
1863d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct Codec<Type, typename enable_if<IsVarintCompatible<Type>::value>::Type> {
1873d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr WireType kWireType = WireType::kVarint;
1883d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1893d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Encode(const Type& value, ProtoWriter* writer) {
1903d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return writer->WriteVarint(static_cast<uint64_t>(value));
1913d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
1923d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
1933d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Decode(Type& value, ProtoReader* reader) {
1943d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    uint64_t raw_value;
1953d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    if (!reader->ReadVarint(&raw_value)) {
1963d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      return false;
1973d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    }
1983d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    value = static_cast<Type>(raw_value);
1993d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return static_cast<uint64_t>(value) == raw_value;
2003d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
2013d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
2023d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2033d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |Codec| specialization for |Vector|.
2043d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename ElementType>
2053d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct Codec<Vector<ElementType>> {
2063d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  using ElementCodec = Codec<ElementType>;
2073d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr WireType kWireType = ElementCodec::kWireType;
2083d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2093d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Encode(const Vector<ElementType>& vector, ProtoWriter* writer) {
2103d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    for (const ElementType& elem : vector) {
2113d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      if (!EncodeField<ElementCodec>(elem, writer)) {
2123d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler        return false;
2133d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      }
2143d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    }
2153d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return true;
2163d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
2173d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2183d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Decode(Vector<ElementType>& vector, ProtoReader* reader) {
2193d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return vector.Resize(vector.size() + 1) &&
2203d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler           DecodeField<ElementCodec>(vector[vector.size() - 1], reader);
2213d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
2223d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
2233d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
22474986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler// |Codec| specialization for |Optional|.
22574986c03b64cc787718412ffeaa110efc3154d22Mattias Nisslertemplate <typename ValueType>
22674986c03b64cc787718412ffeaa110efc3154d22Mattias Nisslerstruct Codec<Optional<ValueType>> {
22774986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler  using ValueCodec = Codec<ValueType>;
22874986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler  static constexpr WireType kWireType = ValueCodec::kWireType;
22974986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler
23074986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler  static bool Encode(const Optional<ValueType>& value, ProtoWriter* writer) {
23174986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler    return !value.valid() || EncodeField<ValueCodec>(value.value(), writer);
23274986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler  }
23374986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler
23474986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler  static bool Decode(Optional<ValueType>& value, ProtoReader* reader) {
23574986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler    return DecodeField<ValueCodec>(value.Activate(), reader);
23674986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler  }
23774986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler};
23874986c03b64cc787718412ffeaa110efc3154d22Mattias Nissler
2393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslernamespace {
2403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |StructDescriptor| provides the |FieldDescriptor| table corresponding to
2423d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |StructType|. The table contains information about each field in the protobuf
2433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// encoding, e.g. field number and wire type.
2443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
2453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// The |IndexSequence| template parameter is present purely for technical
2463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// reasons. It provides a sequence of indices, one for each entry in the field
2473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// declaration list for |StructType|. Having the index available simplifies
2483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// generation of the descriptor table entries.
2493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <
2503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    typename StructType,
2513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    typename IndexSequence = decltype(
2523d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler        make_index_sequence<DescriptorForType<StructType>::kFields.kSize>())>
2533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct StructDescriptor;
2543d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2553d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename StructType, size_t... indices>
2563d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct StructDescriptor<StructType, index_sequence<indices...>> {
2573d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler private:
2583d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr auto kFieldSpecList =
2593d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      DescriptorForType<StructType>::kFields;
2603d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  using FieldSpecs = typename remove_const<decltype(kFieldSpecList)>::Type;
2613d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2623d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // A helper function used to preform a compile-time sanity check on the
2633d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // declared field numbers to ensure that they're positive, unique and in
2643d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // ascending order.
2653d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  template <typename FieldSpecList>
2663d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr bool CheckFieldNumbersAscending(
2673d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      FieldSpecList list,
2683d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      uint32_t previous_field_number) {
2693d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return list.kFieldSpec.kFieldNumber > previous_field_number &&
2703d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler           CheckFieldNumbersAscending(list.kTail, list.kFieldSpec.kFieldNumber);
2713d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
2723d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr bool CheckFieldNumbersAscending(FieldSpecList<>, uint32_t) {
2733d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return true;
2743d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
2753d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2763d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // If this fails, check your struct field declarations for the following:
2773d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  //  * Field numbers must be positive.
2783d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  //  * Field numbers must be unique.
2793d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  //  * Fields must be declared in ascending field number order.
2803d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static_assert(CheckFieldNumbersAscending(kFieldSpecList, 0),
2813d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                "Field numbers must be positive, unique and declared in "
2823d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                "ascending order.");
2833d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
2843d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // Provides the |FieldDescriptor| instance for the field specified by |index|.
2853d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // Note that |index| is *not* the proto field number, but the zero-based index
2863d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // in the field declaration list.
2873d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  template <size_t index>
2883d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  class FieldDescriptorBuilder {
2893d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    static constexpr auto kFieldSpec = kFieldSpecList.template Get<index>();
2903d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    using FieldSpecType = typename remove_const<decltype(kFieldSpec)>::Type;
2913d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    using MemberType = typename FieldSpecType::MemberType;
29286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler
29386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    // Determines the Codec type to use for the field. The default is to use
29486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    // |Codec<MemberType>|, which is appropriate for simple fields declared via
29586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    // |FieldSpec|.
29686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    template <typename FieldSpec>
29786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    struct MemberCodecLookup {
29886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler      using Type = Codec<MemberType>;
29986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    };
30086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler
30186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    // |TaggedUnion| members require a special codec implementation that takes
30286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    // into account the case, so encoding only takes place if the respective
30386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    // union member is active and decoding activates the requested member before
30486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    // decoding data.
30586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    template <typename Struct, typename TagType, typename... Member>
30686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    struct MemberCodecLookup<
30786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        OneOfFieldSpec<Struct, TagType, Member...>> {
30886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler      static constexpr TagType kTag = kFieldSpec.kTag;
30986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler
31086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler      struct Type {
31186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        using TaggedUnionType = TaggedUnion<TagType, Member...>;
31286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        using TaggedUnionMemberType =
31386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler            typename TaggedUnionType::template MemberLookup<kTag>::Type::Type;
31486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        using TaggedUnionMemberCodec = Codec<TaggedUnionMemberType>;
31586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        static constexpr WireType kWireType = TaggedUnionMemberCodec::kWireType;
31686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler
31786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        static bool Encode(const TaggedUnionType& object, ProtoWriter* writer) {
31886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler          const TaggedUnionMemberType* member = object.template get<kTag>();
31986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler          if (member) {
32086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler            return EncodeField<TaggedUnionMemberCodec>(*member, writer);
32186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler          }
32286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler          return true;
32386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        }
32486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler
32586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        static bool Decode(TaggedUnionType& object, ProtoReader* reader) {
32686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler          return DecodeField<TaggedUnionMemberCodec>(
32786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler              object.template Activate<kTag>(), reader);
32886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler        }
32986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler      };
33086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    };
33186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler
33286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler    using MemberCodec = typename MemberCodecLookup<FieldSpecType>::Type;
3333d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3343d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    // Encodes a member. Retrieves a reference to the member within |object| and
3353d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    // calls the appropriate encoder.
3363d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    static bool EncodeMember(const void* object, ProtoWriter* writer) {
3373d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      constexpr auto spec = kFieldSpec;
3383d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      return EncodeField<MemberCodec>(
3393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler          spec.Get(*static_cast<const StructType*>(object)), writer);
3403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    };
3413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3423d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    // Decodes a member. Retrieves a const reference to the member within
3433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    // |object| and calls the appropriate decoder.
3443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    static bool DecodeMember(void* object, ProtoReader* reader) {
3453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      constexpr auto spec = kFieldSpec;
3463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      return DecodeField<MemberCodec>(
3473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler          spec.Get(*static_cast<StructType*>(object)), reader);
3483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    };
3493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler   public:
3513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    // Assemble the actual descriptor for the field. Note that this is still a
3523d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    // compile-time constant (i.e. has no linkage). However, the constant is
3533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    // used below to initialize the entry in the static descriptor table.
3543d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    static constexpr FieldDescriptor kDescriptor =
3553d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler        FieldDescriptor(kFieldSpec.kFieldNumber,
3563d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                        MemberCodec::kWireType,
3573d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                        &EncodeMember,
3583d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                        &DecodeMember);
3593d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  };
3603d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3613d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler public:
3623d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // Descriptor table size.
3633d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr size_t kNumDescriptors = kFieldSpecList.kSize;
3643d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3653d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  // The actual descriptor table.
3663d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr FieldDescriptor kDescriptors[] = {
3673d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      FieldDescriptorBuilder<indices>::kDescriptor...};
3683d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
3693d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3703d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Provide a definition of the |kDescriptors| array such that the descriptor
3713d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// table gets emitted to static data.
3723d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename StructType, size_t... index>
3733d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerconstexpr FieldDescriptor
3743d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    StructDescriptor<StructType, index_sequence<index...>>::kDescriptors[];
3753d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3763d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Note that G++ versions before 5.0 have a bug in handling parameter pack
3773d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// expansions that result in an empty array initializer. To work around this,
3783d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// the following specialization is provided for empty field lists.
3793d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename StructType>
3803d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct StructDescriptor<StructType, index_sequence<>> {
3813d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr size_t kNumDescriptors = 0;
3823d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr FieldDescriptor* kDescriptors = nullptr;
3833d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
3843d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3853d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// A convenience class to initialize |MessageEncoderBase| with the descriptor
3863d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// table corresponding to |StructType| as determined by |StructDescriptor|.
3873d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename StructType>
3883d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerclass MessageEncoder : public MessageEncoderBase {
3893d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler public:
390bb621b95ea636314c87b885107c8d5331992f9bbChih-Hung Hsieh  explicit MessageEncoder(const StructType& object)
3913d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      : MessageEncoderBase(&object,
3923d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                           StructDescriptor<StructType>::kDescriptors,
3933d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                           StructDescriptor<StructType>::kNumDescriptors) {}
3943d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
3953d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Encode(const StructType& object, ProtoWriter* writer) {
3963d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return MessageEncoderBase::Encode(
3973d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler        &object, writer, StructDescriptor<StructType>::kDescriptors,
3983d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler        StructDescriptor<StructType>::kNumDescriptors);
3993d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
4003d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
4013d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4023d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// A convenience class to initialize |MessageDecoderBase| with the descriptor
4033d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// table corresponding to |StructType| as determined by |StructDescriptor|.
4043d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename StructType>
4053d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerclass MessageDecoder : public MessageDecoderBase {
4063d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler public:
407bb621b95ea636314c87b885107c8d5331992f9bbChih-Hung Hsieh  explicit MessageDecoder(StructType& object)
4083d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler      : MessageDecoderBase(&object,
4093d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                           StructDescriptor<StructType>::kDescriptors,
4103d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                           StructDescriptor<StructType>::kNumDescriptors) {}
4113d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4123d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Decode(StructType& object, ProtoReader* reader) {
4133d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return MessageDecoderBase::Decode(
4143d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler        &object, reader, StructDescriptor<StructType>::kDescriptors,
4153d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler        StructDescriptor<StructType>::kNumDescriptors);
4163d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
4173d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
4183d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4193d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}  // namespace
4203d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4213d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |Codec| specialization for struct types. The second template parameter
4223d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// evaluates to |void| if the appropriate |DescriptorForType| specialization
4233d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// exists, enabling the |Codec| specialization for that case.
4243d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//
4253d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Note that this template generates code for each struct type that needs to be
4263d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// encoded and decoded. To avoid bloating the binary, we keep the type-dependent
4273d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// code at the absolute minimum. The |MessageEncoder| and |MessageDecoder|
4283d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// templates merely obtain the appropriate descriptor table for the struct type
4293d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// and then invoke the type-agnostic encoder and decoder base classes.
4303d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename StructType>
4313d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct Codec<StructType,
4323d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler             decltype(
4333d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler                 static_cast<void>(DescriptorForType<StructType>::kFields))> {
4343d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static constexpr WireType kWireType = WireType::kLengthDelimited;
4353d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4363d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Encode(const StructType& object, ProtoWriter* writer) {
4373d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return MessageEncoder<StructType>::Encode(object, writer);
4383d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
4393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  static bool Decode(StructType& object, ProtoReader* reader) {
4413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler    return MessageDecoder<StructType>::Decode(object, reader);
4423d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  }
4433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler};
4443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}  // namespace detail
4463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Get the encoded size of an object.
4483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Struct>
4493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslersize_t GetSize(const Struct& object) {
4503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  detail::MessageEncoder<Struct> encoder(object);
4513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  return encoder.GetSize();
4523d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}
4533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4543d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Encode |object| and write the result to |stream|. Returns true if successful,
4553d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// false if encoding fails. Encoding may fail because |stream| doesn't have
4563d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// enough room to hold the encoded data.
4573d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Struct>
4583d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerbool Encode(const Struct& object, OutputStreamBuffer* stream) {
4593d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  ProtoWriter writer(stream);
4603d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  detail::MessageEncoder<Struct> encoder(object);
4613d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  return encoder.EncodeData(&writer);
4623d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}
4633d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4643d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Decode |stream| and update |object| with the decoded information. Returns
4653d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// true if successful, false if encoding fails. Failure conditions include:
4663d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * Binary data isn't valid with respect to the protobuf wire format.
4673d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * |stream| ends prematurely.
4683d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler//  * Memory allocation in |object| to hold decoded data fails.
4693d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Struct>
4703d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerbool Decode(Struct* object, InputStreamBuffer* stream) {
4713d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  ProtoReader reader(stream);
4723d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  detail::MessageDecoder<Struct> decoder(*object);
4733d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler  return decoder.DecodeData(&reader);
4743d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}
4753d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
4763d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}  // namespace proto
4773d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}  // namespace nvram
4783d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler
479a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#endif  // NVRAM_MESSAGES_PROTO_HPP_
480