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