25 #include "field_codec.h"
27 #include "exception.h"
30 using namespace dccl::logger;
35 dccl::FieldCodecBase::FieldCodecBase() =
default;
38 MessagePart part,
bool strict)
40 BaseRAII scoped_globals(
this, part, &field_value, strict);
45 manager().type_helper().find(field_value.GetDescriptor())->get_value(field_value),
50 const google::protobuf::FieldDescriptor* field)
55 dlog.
is(DEBUG2, ENCODE) && dlog <<
"Starting encode for field: " << field->DebugString()
59 field_pre_encode(&wire_value, field_value);
62 any_encode(&new_bits, wire_value);
63 disp_size(field, new_bits, msg_handler.field_size());
67 dlog.
is(DEBUG2, ENCODE) && dlog <<
"... produced these " << new_bits.size()
68 <<
" bits: " << new_bits << std::endl;
72 const std::vector<dccl::any>& field_values,
73 const google::protobuf::FieldDescriptor* field)
77 std::vector<dccl::any> wire_values;
78 field_pre_encode_repeated(&wire_values, field_values);
81 any_encode_repeated(&new_bits, wire_values);
82 disp_size(field, new_bits, msg_handler.field_size(), wire_values.size());
89 BaseRAII scoped_globals(
this, part, &msg);
93 field_size(bit_size, &msg,
nullptr);
97 const google::protobuf::FieldDescriptor* field)
101 dccl::any wire_value;
102 field_pre_encode(&wire_value, field_value);
104 *bit_size += any_size(wire_value);
108 const std::vector<dccl::any>& field_values,
109 const google::protobuf::FieldDescriptor* field)
113 std::vector<dccl::any> wire_values;
114 field_pre_encode_repeated(&wire_values, field_values);
116 *bit_size += any_size_repeated(wire_values);
122 BaseRAII scoped_globals(
this, part, field_value);
123 dccl::any value(field_value);
124 field_decode(bits, &value,
nullptr);
128 const google::protobuf::FieldDescriptor* field)
133 throw(
Exception(
"Decode called with NULL dccl::any"));
135 throw(
Exception(
"Decode called with NULL Bitset"));
138 dlog.
is(DEBUG2, DECODE) && dlog <<
"Starting decode for field: " << field->DebugString()
142 dlog.
is(DEBUG3, DECODE) && dlog <<
"Message thus far is: " << root_message()->DebugString()
147 unsigned bits_to_transfer = 0;
148 field_min_size(&bits_to_transfer, field);
152 dlog.
is(DEBUG2, DECODE) && dlog <<
"... using these bits: " << these_bits << std::endl;
154 dccl::any wire_value = *field_value;
156 any_decode(&these_bits, &wire_value);
158 field_post_decode(wire_value, field_value);
162 const google::protobuf::FieldDescriptor* field)
167 throw(
Exception(
"Decode called with NULL field_values"));
169 throw(
Exception(
"Decode called with NULL Bitset"));
172 dlog.
is(DEBUG2, DECODE) &&
173 dlog <<
"Starting repeated decode for field: " << field->DebugString() << std::endl;
177 unsigned bits_to_transfer = 0;
178 field_min_size(&bits_to_transfer, field);
181 dlog.
is(DEBUG2, DECODE) && dlog <<
"using these " << these_bits.size()
182 <<
" bits: " << these_bits << std::endl;
184 std::vector<dccl::any> wire_values = *field_values;
185 any_decode_repeated(&these_bits, &wire_values);
187 field_values->clear();
188 field_post_decode_repeated(wire_values, field_values);
192 const google::protobuf::Descriptor* desc, MessagePart part)
194 BaseRAII scoped_globals(
this, part, desc);
199 msg_handler.push(desc);
201 throw(
Exception(
"Max Size called with NULL Descriptor"));
203 field_max_size(bit_size,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
207 const google::protobuf::FieldDescriptor* field)
212 *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
214 *bit_size += max_size();
218 const google::protobuf::Descriptor* desc, MessagePart part)
220 BaseRAII scoped_globals(
this, part, desc);
226 msg_handler.push(desc);
228 throw(
Exception(
"Min Size called with NULL Descriptor"));
230 field_min_size(bit_size,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
234 const google::protobuf::FieldDescriptor* field)
240 *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
242 *bit_size += min_size();
247 BaseRAII scoped_globals(
this, part, desc);
251 msg_handler.push(desc);
253 throw(
Exception(
"Validate called with NULL Descriptor"));
256 field_validate(&b,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
260 const google::protobuf::FieldDescriptor* field)
264 if (field && dccl_field_options().in_head() && variable_size())
265 throw(
Exception(
"Variable size codec used in header - header fields must be encoded with "
266 "fixed size codec."));
270 "Oneof field used in header - oneof fields cannot be encoded in the header."));
278 BaseRAII scoped_globals(
this, part, desc);
282 msg_handler.push(desc);
284 throw(
Exception(
"info called with NULL Descriptor"));
286 field_info(os,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
290 const google::protobuf::FieldDescriptor* field)
294 std::stringstream ss;
295 int depth = msg_handler.count();
298 ((this_field()) ? std::to_string(this_field()->number()) +
". " + this_field()->name()
299 : this_descriptor()->full_name());
300 if (this_field() && this_field()->is_repeated())
302 (dccl_field_options().has_min_repeat()
303 ? (std::to_string(dccl_field_options().min_repeat()) +
"-")
305 std::to_string(dccl_field_options().max_repeat()) +
"]";
307 if (!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
310 const int spaces = 8;
312 std::string(spaces * (depth) + spaces / 2 * (field &&
is_part_of_oneof(field)),
315 const int full_width = 40;
317 bool is_zero_size =
false;
319 std::stringstream range;
322 unsigned max_sz = 0, min_sz = 0;
323 field_max_size(&max_sz, field);
324 field_min_size(&min_sz, field);
327 range << min_sz <<
"-" << max_sz;
332 field_max_size(&sz, field);
338 int width = this_field() ? full_width - name.size() : full_width - name.size() + spaces;
339 ss << indent << name << std::setfill(
'.') << std::setw(std::max(1, width)) << range.str()
341 << (this_field() ? manager().find(this_field(), codec_version(), has_codec_group(), codec_group())->name()
342 : manager().find(manager().codec_data().root_descriptor_)->name())
346 *os << ss.str() <<
"\n";
348 std::string specific_info = info();
349 if (!specific_info.empty())
350 *os << specific_info;
356 BaseRAII scoped_globals(
this, part, desc);
360 msg_handler.push(desc);
362 throw(
Exception(
"Hash called with NULL Descriptor"));
364 field_hash(hash,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
368 const google::protobuf::FieldDescriptor* field)
372 if (field && dccl_field_options().in_head() && variable_size())
373 throw(
Exception(
"Variable size codec used in header - header fields must be encoded with "
374 "fixed size codec."));
378 "Oneof field used in header - oneof fields cannot be encoded in the header."));
382 google::protobuf::FieldDescriptorProto field_to_hash;
383 this_field()->CopyTo(&field_to_hash);
386 field_to_hash.clear_name();
388 field_to_hash.clear_options();
389 field_to_hash.clear_type_name();
390 field_to_hash.clear_default_value();
394 hash_combine(*hash_value, field_to_hash.DebugString());
395 hash_combine(*hash_value, dccl_opts.DebugString());
401 dccl_opts.clear_max_bytes();
403 hash_combine(*hash_value, dccl_opts.DebugString());
406 hash_combine(*hash_value, hash());
409 std::string dccl::FieldCodecBase::codec_group(
const google::protobuf::Descriptor* desc)
411 if (desc->options().GetExtension(dccl::msg).has_codec_group())
412 return desc->options().GetExtension(dccl::msg).codec_group();
414 return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
423 void dccl::FieldCodecBase::any_encode_repeated(
dccl::Bitset* bits,
424 const std::vector<dccl::any>& wire_values)
428 unsigned wire_vector_size = dccl_field_options().max_repeat();
430 if (wire_values.size() > wire_vector_size && strict())
434 this->this_field(), this->this_descriptor()));
436 if (wire_values.size() < dccl_field_options().min_repeat() && strict())
438 std::string(
"Repeated size is less than min_repeat for field: ") +
440 this->this_field(), this->this_descriptor()));
443 if (codec_version() > 2)
445 wire_vector_size = std::min(
static_cast<int>(dccl_field_options().max_repeat()),
446 static_cast<int>(wire_values.size()));
448 wire_vector_size = std::max(
static_cast<int>(dccl_field_options().min_repeat()),
449 static_cast<int>(wire_vector_size));
451 Bitset size_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
452 dccl_field_options().max_repeat()),
453 wire_vector_size - dccl_field_options().min_repeat());
456 dlog.
is(DEBUG2, ENCODE) && dlog <<
"repeated size field ... produced these "
457 << size_bits.size() <<
" bits: " << size_bits << std::endl;
460 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
461 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
463 msg_handler.update_index(root_message(), this->this_field(), i);
465 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
466 dc.set_repeated_index(i);
467 if (dc.has_omit_if())
469 dc.regenerate(this_message(), root_message(), i);
475 if (i < wire_values.size())
476 any_encode(&new_bits, wire_values[i]);
478 any_encode(&new_bits, dccl::any());
483 void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits,
484 std::vector<dccl::any>* wire_values)
486 unsigned wire_vector_size = dccl_field_options().max_repeat();
487 if (codec_version() > 2)
489 Bitset size_bits(repeated_bits);
490 size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
491 dccl_field_options().max_repeat()));
493 wire_vector_size = size_bits.to_ulong() + dccl_field_options().min_repeat();
496 wire_values->resize(wire_vector_size);
498 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
499 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
501 msg_handler.update_index(root_message(), this->this_field(), i);
503 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
504 dc.set_repeated_index(i);
505 if (dc.has_omit_if())
507 dc.regenerate(this_message(), root_message(), i);
512 Bitset these_bits(repeated_bits);
513 these_bits.get_more_bits(min_size());
514 any_decode(&these_bits, &(*wire_values)[i]);
518 unsigned dccl::FieldCodecBase::any_size_repeated(
const std::vector<dccl::any>& wire_values)
521 unsigned wire_vector_size = dccl_field_options().max_repeat();
523 if (codec_version() > 2)
525 wire_vector_size = std::min(
static_cast<int>(dccl_field_options().max_repeat()),
526 static_cast<int>(wire_values.size()));
527 out += repeated_vector_field_size(dccl_field_options().min_repeat(),
528 dccl_field_options().max_repeat());
531 internal::MessageStack msg_handler(root_message(), message_data(), this->this_field());
532 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
534 msg_handler.update_index(root_message(), this->this_field(), i);
535 DynamicConditions& dc = this->dynamic_conditions(this->this_field());
536 dc.set_repeated_index(i);
537 if (dc.has_omit_if())
539 dc.regenerate(this_message(), root_message(), i);
544 if (i < wire_values.size())
545 out += any_size(wire_values[i]);
547 out += any_size(dccl::any());
552 void dccl::FieldCodecBase::check_repeat_settings()
const
554 if (!dccl_field_options().has_max_repeat())
555 throw(Exception(
"Missing (dccl.field).max_repeat option on `repeated` field: " +
556 this_field()->DebugString(),
557 this->this_descriptor()));
558 else if (dccl_field_options().max_repeat() < 1)
559 throw(Exception(
"(dccl.field).max_repeat must not be less than 1: " +
560 this_field()->DebugString(),
561 this->this_descriptor()));
562 else if (dccl_field_options().max_repeat() < dccl_field_options().min_repeat())
563 throw(Exception(
"(dccl.field).max_repeat must not be less than (dccl.field).min_repeat: " +
564 this_field()->DebugString(),
565 this->this_descriptor()));
568 unsigned dccl::FieldCodecBase::max_size_repeated()
570 check_repeat_settings();
572 if (codec_version() > 2)
573 return repeated_vector_field_size(dccl_field_options().min_repeat(),
574 dccl_field_options().max_repeat()) +
575 max_size() * dccl_field_options().max_repeat();
577 return max_size() * dccl_field_options().max_repeat();
580 unsigned dccl::FieldCodecBase::min_size_repeated()
582 check_repeat_settings();
584 if (codec_version() > 2)
585 return repeated_vector_field_size(dccl_field_options().min_repeat(),
586 dccl_field_options().max_repeat()) +
587 min_size() * dccl_field_options().min_repeat();
590 return min_size() * dccl_field_options().max_repeat();
593 void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
594 const std::vector<dccl::any>& field_values)
596 for (
const auto& field_value : field_values)
598 dccl::any wire_value;
599 any_pre_encode(&wire_value, field_value);
600 wire_values->push_back(wire_value);
603 void dccl::FieldCodecBase::any_post_decode_repeated(
const std::vector<dccl::any>& wire_values,
604 std::vector<dccl::any>* field_values)
606 for (
const auto& wire_value : wire_values)
608 dccl::any field_value;
609 any_post_decode(wire_value, &field_value);
610 field_values->push_back(field_value);
618 void dccl::FieldCodecBase::disp_size(
const google::protobuf::FieldDescriptor* field,
619 const Bitset& new_bits,
int depth,
int vector_size )
621 if (!root_descriptor())
624 if (dlog.
check(DEBUG2))
626 std::string name = ((field) ? field->name() : root_descriptor()->full_name());
627 if (vector_size >= 0)
628 name +=
"[" + std::to_string(vector_size) +
"]";
630 dlog.
is(DEBUG2, SIZE) && dlog << std::string(depth,
'|') << name << std::setfill(
'.')
631 << std::setw(40 - name.size() - depth) << new_bits.size()
635 dlog.
is(DEBUG2, SIZE) && dlog << std::endl;
641 using google::protobuf::FieldDescriptor;
642 return os <<
"[FieldCodec '" << field_codec.
name() <<
"']: field type: "
643 << field_codec.manager().type_helper().find(field_codec.
field_type())->as_str()
645 << field_codec.manager()
647 .find(FieldDescriptor::TypeToCppType(field_codec.
field_type()))
650 << field_codec.manager().type_helper().find(field_codec.
wire_type())->as_str();
655 return message_data().top_field();
660 return message_data().top_descriptor();
665 return message_data().top_message();
670 return manager().codec_data().root_message_;
673 const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor()
const
675 return manager().codec_data().root_descriptor_;
680 return manager().codec_data().message_data_;
685 return manager().codec_data().message_data_;
687 bool dccl::FieldCodecBase::has_codec_group()
689 const google::protobuf::Descriptor* root_desc = root_descriptor();
692 return root_desc->options().GetExtension(dccl::msg).has_codec_group() ||
693 root_desc->options().GetExtension(dccl::msg).has_codec_version();
701 bool dccl::FieldCodecBase::strict() {
return manager().codec_data().strict_; }
703 int dccl::FieldCodecBase::codec_version()
705 return root_descriptor()->options().GetExtension(dccl::msg).codec_version();
708 std::string dccl::FieldCodecBase::codec_group() {
return codec_group(root_descriptor()); }
711 dccl::FieldCodecBase::dynamic_conditions(
const google::protobuf::FieldDescriptor* field)
713 manager().codec_data().dynamic_conditions_.set_field(field);
714 return manager().codec_data().dynamic_conditions_;
717 dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
718 const google::protobuf::Descriptor* root_descriptor,
720 : field_codec_(field_codec)
723 field_codec_->manager().codec_data().part_ =
part;
724 field_codec_->manager().codec_data().strict_ = strict;
725 field_codec_->manager().codec_data().root_message_ =
nullptr;
726 field_codec_->manager().codec_data().root_descriptor_ = root_descriptor;
728 dccl::FieldCodecBase::BaseRAII::BaseRAII(FieldCodecBase* field_codec, MessagePart part,
730 : field_codec_(field_codec)
733 field_codec_->manager().codec_data().part_ =
part;
734 field_codec_->manager().codec_data().strict_ = strict;
735 field_codec_->manager().codec_data().root_message_ = root_message;
736 field_codec_->manager().codec_data().root_descriptor_ = root_message->GetDescriptor();
738 dccl::FieldCodecBase::BaseRAII::~BaseRAII()
740 field_codec_->manager().codec_data().part_ = dccl::UNKNOWN;
741 field_codec_->manager().codec_data().strict_ =
false;
742 field_codec_->manager().codec_data().root_message_ =
nullptr;
743 field_codec_->manager().codec_data().root_descriptor_ =
nullptr;