DCCL v4
Loading...
Searching...
No Matches
field_codec.h
1// Copyright 2011-2023:
2// GobySoft, LLC (2013-)
3// Massachusetts Institute of Technology (2007-2014)
4// Community contributors (see AUTHORS file)
5// File authors:
6// Toby Schneider <toby@gobysoft.org>
7//
8//
9// This file is part of the Dynamic Compact Control Language Library
10// ("DCCL").
11//
12// DCCL is free software: you can redistribute it and/or modify
13// it under the terms of the GNU Lesser General Public License as published by
14// the Free Software Foundation, either version 2.1 of the License, or
15// (at your option) any later version.
16//
17// DCCL is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU Lesser General Public License for more details.
21//
22// You should have received a copy of the GNU Lesser General Public License
23// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
24#ifndef DCCLFIELDCODEC20110322H
25#define DCCLFIELDCODEC20110322H
26
27#include <map>
28#include <string>
29
30#include <google/protobuf/descriptor.h>
31#include <google/protobuf/descriptor.pb.h>
32#include <google/protobuf/message.h>
33
34#include "any.h"
35#include "binary.h"
36#include "common.h"
37#include "dynamic_conditions.h"
38#include "exception.h"
39#include "internal/field_codec_message_stack.h"
40#include "internal/type_helper.h"
41#include "oneof.h"
42#include "option_extensions.pb.h"
43
44namespace dccl
45{
46class Codec;
47namespace internal
48{
49class MessageStack;
50}
51
54{
55 public:
57
58
60 virtual ~FieldCodecBase() = default;
62
64
65
66 std::string name() const { return name_; }
70 google::protobuf::FieldDescriptor::Type field_type() const { return field_type_; }
75 google::protobuf::FieldDescriptor::CppType wire_type() const { return wire_type_; }
76
80 const google::protobuf::FieldDescriptor* this_field() const;
81
95 const google::protobuf::Descriptor* this_descriptor() const;
96
97 const google::protobuf::Message* this_message();
98
99 // currently encoded or (partially) decoded root message
100 const google::protobuf::Message* root_message();
101
102 const google::protobuf::Descriptor* root_descriptor() const;
103
104 internal::MessageStackData& message_data();
105
106 const internal::MessageStackData& message_data() const;
107
108 bool has_codec_group();
109
110 static std::string codec_group(const google::protobuf::Descriptor* desc);
111
112 std::string codec_group();
113
114 int codec_version();
115
117 MessagePart part();
118
119 bool strict();
120
122 void set_force_use_required(bool force_required = true) { force_required_ = force_required; }
123
125
136
137
143 void base_encode(Bitset* bits, const google::protobuf::Message& msg, MessagePart part,
144 bool strict);
145
151 void base_size(unsigned* bit_size, const google::protobuf::Message& msg, MessagePart part);
152
158 void base_decode(Bitset* bits, google::protobuf::Message* msg, MessagePart part);
159
165 void base_max_size(unsigned* bit_size, const google::protobuf::Descriptor* desc,
166 MessagePart part);
167
173 void base_min_size(unsigned* bit_size, const google::protobuf::Descriptor* desc,
174 MessagePart part);
175
180 void base_validate(const google::protobuf::Descriptor* desc, MessagePart part);
181
187 void base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessagePart part);
188
194 void base_hash(std::size_t* hash, const google::protobuf::Descriptor* desc, MessagePart part);
196
198 //
207
208
213 void field_pre_encode(dccl::any* wire_value, const dccl::any& field_value)
214 {
215 any_pre_encode(wire_value, field_value);
216 }
217
222 void field_pre_encode_repeated(std::vector<dccl::any>* wire_values,
223 const std::vector<dccl::any>& field_values)
224 {
225 any_pre_encode_repeated(wire_values, field_values);
226 }
227
228 // traverse const
229
235 void field_encode(Bitset* bits, const dccl::any& field_value,
236 const google::protobuf::FieldDescriptor* field);
237
243 void field_encode_repeated(Bitset* bits, const std::vector<dccl::any>& field_values,
244 const google::protobuf::FieldDescriptor* field);
245
251 void field_size(unsigned* bit_size, const dccl::any& field_value,
252 const google::protobuf::FieldDescriptor* field);
253
259 void field_size_repeated(unsigned* bit_size, const std::vector<dccl::any>& field_values,
260 const google::protobuf::FieldDescriptor* field);
261
262 // traverse mutable
268 void field_decode(Bitset* bits, dccl::any* field_value,
269 const google::protobuf::FieldDescriptor* field);
270
276 void field_decode_repeated(Bitset* bits, std::vector<dccl::any>* field_values,
277 const google::protobuf::FieldDescriptor* field);
278
283 void field_post_decode(const dccl::any& wire_value, dccl::any* field_value)
284 {
285 any_post_decode(wire_value, field_value);
286 }
287
292 void field_post_decode_repeated(const std::vector<dccl::any>& wire_values,
293 std::vector<dccl::any>* field_values)
294 {
295 any_post_decode_repeated(wire_values, field_values);
296 }
297
298 // traverse schema (Descriptor)
299
304 void field_max_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
309 void field_min_size(unsigned* bit_size, const google::protobuf::FieldDescriptor* field);
310
316 void field_validate(bool* b, const google::protobuf::FieldDescriptor* field);
317
322 void field_info(std::ostream* os, const google::protobuf::FieldDescriptor* field);
323
328 void field_hash(std::size_t* hash, const google::protobuf::FieldDescriptor* field);
330
335 {
336 if (this_field())
337 return this_field()->options().GetExtension(dccl::field);
338 else
339 throw(Exception(
340 "Cannot call dccl_field on base message (has no *field* option extension"));
341 }
342
348 void require(bool b, const std::string& description)
349 {
350 if (!b)
351 {
352 if (this_field())
353 throw(Exception("Field " + this_field()->name() +
354 " failed validation: " + description,
355 this->this_descriptor()));
356 else
357 throw(Exception("Message " + this_descriptor()->name() +
358 " failed validation: " + description,
359 this->this_descriptor()));
360 }
361 }
362
363 DynamicConditions& dynamic_conditions(const google::protobuf::FieldDescriptor* field);
364
365 FieldCodecManagerLocal& manager()
366 {
367 if (manager_)
368 return *manager_;
369 else
370 throw(Exception("FieldCodecManagerLocal is not set"), this->this_descriptor());
371 }
372
373 const FieldCodecManagerLocal& manager() const
374 {
375 if (manager_)
376 return *manager_;
377 else
378 throw(Exception("FieldCodecManagerLocal is not set"), this->this_descriptor());
379 }
380
381 virtual void set_manager(FieldCodecManagerLocal* manager) { manager_ = manager; }
382
383 protected:
386 {
387 if (force_required_)
388 return true;
389
390 const google::protobuf::FieldDescriptor* field = this_field();
391 DynamicConditions& dc = dynamic_conditions(field);
392 // expensive, so don't do this unless we're going to use it
393 if (dc.has_required_if())
394 dc.regenerate(this_message(), root_message());
395
396 if (!field)
397 return true;
398 else if (codec_version() > 3) // use required for repeated, required and oneof fields
399 return field->is_required() || field->is_repeated() || is_part_of_oneof(field) ||
400 (dc.has_required_if() && dc.required());
401 else if (codec_version() > 2) // use required for both repeated and required fields
402 return field->is_required() || field->is_repeated() ||
403 (dc.has_required_if() && dc.required());
404 else // use required only for required fields
405 return field->is_required();
406 }
407
408 //
409 // VIRTUAL
410 //
411
412 // contain dccl::any
417 virtual void any_encode(Bitset* bits, const dccl::any& wire_value) = 0;
418
423 virtual void any_decode(Bitset* bits, dccl::any* wire_value) = 0;
424
429 virtual void any_pre_encode(dccl::any* wire_value, const dccl::any& field_value)
430 {
431 *wire_value = field_value;
432 }
433
438 virtual void any_post_decode(const dccl::any& wire_value, dccl::any* field_value)
439 {
440 *field_value = wire_value;
441 }
442
447 virtual unsigned any_size(const dccl::any& wire_value) = 0;
448
449 // no dccl::any
451 virtual void validate() {}
452
456 virtual std::string info();
457
459 virtual std::size_t hash() { return 0; }
460
464 virtual unsigned max_size() = 0;
465
469 virtual unsigned min_size() = 0;
470
471 virtual void any_encode_repeated(Bitset* bits, const std::vector<dccl::any>& wire_values);
472 virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<dccl::any>* field_values);
473
474 virtual void any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
475 const std::vector<dccl::any>& field_values);
476
477 virtual void any_post_decode_repeated(const std::vector<dccl::any>& wire_values,
478 std::vector<dccl::any>* field_values);
479
480 virtual unsigned any_size_repeated(const std::vector<dccl::any>& wire_values);
481 virtual unsigned max_size_repeated();
482 virtual unsigned min_size_repeated();
483 void check_repeat_settings() const;
484
485 friend class FieldCodecManagerLocal;
486
487 private:
488 // codec information
489 void set_name(const std::string& name) { name_ = name; }
490 void set_field_type(google::protobuf::FieldDescriptor::Type type) { field_type_ = type; }
491 void set_wire_type(google::protobuf::FieldDescriptor::CppType type) { wire_type_ = type; }
492
493 bool variable_size()
494 {
495 if (this_field() && this_field()->is_repeated())
496 return max_size_repeated() != min_size_repeated();
497 else
498 return max_size() != min_size();
499 }
500
501 int repeated_vector_field_size(int min_repeat, int max_repeat)
502 {
503 return dccl::ceil_log2(max_repeat - min_repeat + 1);
504 }
505
506 void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits,
507 int depth, int vector_size = -1);
508
509 private:
510 // sets global statics relating the current message begin processed
511 // and unsets them on destruction
512 struct BaseRAII
513 {
514 BaseRAII(FieldCodecBase* field_codec, MessagePart part,
515 const google::protobuf::Descriptor* root_descriptor, bool strict = false);
516
517 BaseRAII(FieldCodecBase* field_codec, MessagePart part,
518 const google::protobuf::Message* root_message, bool strict = false);
519 ~BaseRAII();
520
521 private:
522 FieldCodecBase* field_codec_;
523 };
524 friend struct BaseRAII;
525
526 std::string name_;
527 google::protobuf::FieldDescriptor::Type field_type_;
528 google::protobuf::FieldDescriptor::CppType wire_type_;
529
530 bool force_required_{false};
531
532 FieldCodecManagerLocal* manager_{nullptr};
533};
534
535std::ostream& operator<<(std::ostream& os, const FieldCodecBase& field_codec);
536
537inline Exception type_error(const std::string& action, const std::type_info& expected,
538 const std::type_info& got)
539{
540 std::string e = "error " + action + ", expected: ";
541 e += expected.name();
542 e += ", got ";
543 e += got.name();
544 return Exception(e);
545}
546
547} // namespace dccl
548
549#endif
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition bitset.h:43
Exception class for DCCL.
Definition exception.h:47
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition field_codec.h:54
void field_encode(Bitset *bits, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Encode a non-repeated field.
void set_force_use_required(bool force_required=true)
Force the codec to always use the "required" field encoding, regardless of the FieldDescriptor settin...
void field_size(unsigned *bit_size, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
void base_hash(std::size_t *hash, const google::protobuf::Descriptor *desc, MessagePart part)
Provide a hash of the DCCL message definition to detect changes in the DCCL message.
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
virtual void any_pre_encode(dccl::any *wire_value, const dccl::any &field_value)
Virtual method used to pre-encode (convert from FieldType to WireType). The default implementation of...
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
google::protobuf::FieldDescriptor::CppType wire_type() const
the C++ type used "on the wire". This is the type visible after pre_encode and before post_decode fun...
Definition field_codec.h:75
virtual void any_post_decode(const dccl::any &wire_value, dccl::any *field_value)
Virtual method used to post-decode (convert from WireType to FieldType). The default implementation o...
void field_post_decode(const dccl::any &wire_value, dccl::any *field_value)
Post-decodes a non-repeated (i.e. optional or required) field by converting the WireType (the type us...
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
MessagePart part()
the part of the message currently being encoded (head or body)
void require(bool b, const std::string &description)
Essentially an assertion to be used in the validate() virtual method.
void field_encode_repeated(Bitset *bits, const std::vector< dccl::any > &field_values, const google::protobuf::FieldDescriptor *field)
Encode a repeated field.
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
std::string name() const
the name of the codec used to identifier it in the .proto custom option extension
Definition field_codec.h:66
virtual unsigned min_size()=0
Calculate minimum size of the field in bits.
void field_post_decode_repeated(const std::vector< dccl::any > &wire_values, std::vector< dccl::any > *field_values)
Post-decodes a repeated field.
void base_validate(const google::protobuf::Descriptor *desc, MessagePart part)
Validate this part of the message to make sure all required extensions are set.
void field_decode(Bitset *bits, dccl::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
dccl::DCCLFieldOptions dccl_field_options() const
Get the DCCL field option extension value for the current field.
void field_pre_encode_repeated(std::vector< dccl::any > *wire_values, const std::vector< dccl::any > &field_values)
Pre-encodes a repeated field.
void base_info(std::ostream *os, const google::protobuf::Descriptor *desc, MessagePart part)
Get human readable information (size of fields, etc.) about this part of the DCCL message.
virtual unsigned any_size(const dccl::any &wire_value)=0
Virtual method for calculating the size of a field (in bits).
void base_min_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the minimum size of a message given its Descriptor alone (no data)
void base_max_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the maximum size of a message given its Descriptor alone (no data)
virtual std::size_t hash()
Generate a field specific hash to be combined with the descriptor hash.
void field_hash(std::size_t *hash, const google::protobuf::FieldDescriptor *field)
Provide a hash for this field definition.
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
void base_size(unsigned *bit_size, const google::protobuf::Message &msg, MessagePart part)
Calculate the size (in bits) of a part of the base message when it is encoded.
google::protobuf::FieldDescriptor::Type field_type() const
the type exposed to the user in the original and decoded Protobuf messages
Definition field_codec.h:70
void field_min_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the lower bound on this field's size (in bits)
void base_encode(Bitset *bits, const google::protobuf::Message &msg, MessagePart part, bool strict)
Encode this part (body or head) of the base message.
virtual unsigned max_size()=0
Calculate maximum size of the field in bits.
virtual void any_decode(Bitset *bits, dccl::any *wire_value)=0
Virtual method used to decode.
bool use_required()
Whether to use the required or optional encoding.
void field_validate(bool *b, const google::protobuf::FieldDescriptor *field)
Validate this field, checking that all required option extensions are set (e.g. (dccl....
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field's size (in bits)
void field_decode_repeated(Bitset *bits, std::vector< dccl::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
void field_size_repeated(unsigned *bit_size, const std::vector< dccl::any > &field_values, const google::protobuf::FieldDescriptor *field)
Calculate the size of a repeated field.
void field_info(std::ostream *os, const google::protobuf::FieldDescriptor *field)
Write human readable information about the field and its bounds to the provided stream.
virtual void any_encode(Bitset *bits, const dccl::any &wire_value)=0
Virtual method used to encode.
void field_pre_encode(dccl::any *wire_value, const dccl::any &field_value)
Pre-encodes a non-repeated (i.e. optional or required) field by converting the FieldType representati...
A class for managing the various field codecs. Here you can add and remove field codecs....
Dynamic Compact Control Language namespace.
Definition any.h:47
bool is_part_of_oneof(const google::protobuf::FieldDescriptor *field_desc)
Checks whether a given field is part to a oneof or not.
Definition oneof.h:36
unsigned ceil_log2(dccl::uint64 v)
Definition binary.h:178