VLink  2.0.0
A high-performance communication middleware
schema_plugin_base.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file schema_plugin_base.h
26  * @brief Reference base class mapping @c SchemaPluginInterface onto Protobuf descriptors and a BFBS registry.
27  *
28  * @details
29  * @c SchemaPluginBase is a header-only implementation that downstream schema plugins normally
30  * derive from. It supplies the canonical Protobuf and FlatBuffers backends so that custom
31  * plugins only need to specialise version information and any extra metadata; behavioural
32  * compatibility with the original protobuf-only runtime is preserved by funnelling every
33  * Protobuf lookup through @c DescriptorPool::generated_pool() and serialising payloads as a
34  * @c FileDescriptorSet captured from the linked descriptor graph. FlatBuffers does not provide
35  * an analogous global pool, so the concrete plugin is expected to register BFBS blobs through
36  * the @c FlatbuffersRegistry singleton (or the @c VLINK_REGISTER_FLATBUFFERS macro) before any
37  * lookups occur.
38  *
39  * | Implemented method | Behaviour |
40  * | -------------------------------- | -------------------------------------------------------------------- |
41  * | @c search_schema() | probe over Protobuf, FlatBuffers, and @c vlink::zerocopy::* |
42  * | @c get_all_schemas() | import all known BFBS blobs and return the cached schema set |
43  * | @c search_protobuf_descriptor() | cache and return descriptors from the generated Protobuf pool |
44  * | @c create_protobuf_message() | build a dynamic message via @c DynamicMessageFactory and cache it |
45  * | @c search_flatbuffers_schema() | verify the BFBS blob and return a stable @c reflection::Schema |
46  * | @c create_flatbuffers_parser() | deserialise the BFBS blob into a parser and remember it for cleanup |
47  *
48  * @par Integration diagram
49  * @code
50  * +---------------------+ +-----------------------+ +--------------------------+
51  * | downstream plugin | -----> | SchemaPluginBase | -----> | DescriptorPool / generated|
52  * | (overrides version) | | (this header) | +--------------------------+
53  * +---------------------+ | | +--------------------------+
54  * | | -----> | FlatbuffersRegistry |
55  * | | | (static BFBS slots) |
56  * +-----------------------+ +--------------------------+
57  * @endcode
58  */
59 
60 #pragma once
61 
62 #include <algorithm>
63 #include <cctype>
64 #include <cstring>
65 #include <memory>
66 #include <mutex>
67 #include <queue>
68 #include <string>
69 #include <string_view>
70 #include <unordered_map>
71 #include <unordered_set>
72 #include <vector>
73 
74 #include "../base/helpers.h"
76 
77 //
78 #include "./flatbuffers_registry.h"
79 #include "./protobuf_registry.h"
80 
81 namespace vlink {
82 
83 /**
84  * @class SchemaPluginBase
85  * @brief Reusable base implementation of @c SchemaPluginInterface for mixed Protobuf / FlatBuffers metadata.
86  *
87  * @details
88  * Concrete plugins derive from this class and typically only override @c get_version_info().
89  * The base class is header-only so that linked Protobuf descriptors and registered BFBS blobs
90  * remain in the same translation unit as the plugin binary, which is required for the static
91  * registries to publish the expected types.
92  *
93  * Internal caches are protected by a single mutex; all public methods are safe to call from
94  * multiple threads.
95  */
97  protected:
98  /**
99  * @brief Initialises the schema caches and primes the VLink memory pool.
100  */
102 
103  /**
104  * @brief Releases cached dynamic messages and FlatBuffers parsers owned by the plugin.
105  */
106  ~SchemaPluginBase() override;
107 
108  /**
109  * @brief Locates a schema by name within an optional family.
110  *
111  * @param name Serialisation type or fully qualified message name.
112  * @param schema_type Family hint, or @c SchemaType::kUnknown for cross-family probing.
113  * @return Cached or freshly imported @c SchemaData, or an empty record on miss.
114  */
115  [[nodiscard]] SchemaData search_schema(const std::string& name,
116  SchemaType schema_type = SchemaType::kUnknown) override;
117 
118  /**
119  * @brief Returns every cached schema, optionally restricted to a single family.
120  *
121  * @param schema_type Family filter, or @c SchemaType::kUnknown for everything.
122  * @return Snapshot vector of cached entries.
123  */
124  [[nodiscard]] std::vector<SchemaData> get_all_schemas(SchemaType schema_type = SchemaType::kUnknown) override;
125 
126  /**
127  * @brief Returns the Protobuf descriptor for a fully qualified type name.
128  *
129  * @param name Fully qualified Protobuf message name.
130  * @return Opaque descriptor pointer, or @c nullptr when unknown.
131  */
132  [[nodiscard]] ProtobufDescriptorPtr search_protobuf_descriptor(const std::string& name) override;
133 
134  /**
135  * @brief Returns a cached dynamic Protobuf message instance for the type.
136  *
137  * @param name Fully qualified Protobuf message name.
138  * @return Opaque message pointer, or @c nullptr when unknown.
139  */
140  [[nodiscard]] ProtobufMessagePtr create_protobuf_message(const std::string& name) override;
141 
142  /**
143  * @brief Returns a verified FlatBuffers BFBS reflection schema.
144  *
145  * @param name Fully qualified FlatBuffers root type name.
146  * @return Opaque @c reflection::Schema pointer, or @c nullptr when unknown.
147  */
148  [[nodiscard]] FlatbuffersSchemaPtr search_flatbuffers_schema(const std::string& name) override;
149 
150  /**
151  * @brief Returns a freshly constructed FlatBuffers parser for the named root type.
152  *
153  * @param name Fully qualified FlatBuffers root type name.
154  * @return Opaque @c flatbuffers::Parser pointer, or @c nullptr when unknown.
155  */
156  [[nodiscard]] FlatbuffersParserPtr create_flatbuffers_parser(const std::string& name) override;
157 
158  private:
159  static std::string normalize_schema_encoding(std::string_view encoding);
160 
161  static bool is_flatbuffers_schema_type(std::string_view encoding);
162 
163  bool cache_schema_data_locked(const SchemaData& schema);
164 
165 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
166  ProtobufDescriptorPtr find_protobuf_descriptor_locked(const std::string& name);
167 
168  static SchemaData build_protobuf_schema_data(const google::protobuf::Descriptor& descriptor);
169 #endif
170 
171 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
172  void import_all_flatbuffers_schema_data_locked();
173 
174  bool import_flatbuffers_schema_data_locked(const std::string& name);
175 
176  const SchemaData* find_cached_flatbuffers_schema_locked(const std::string& name) const;
177 
178  void clear_flatbuffers_parser_cache_locked(const std::string& name);
179 #endif
180 
181 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
182  google::protobuf::DynamicMessageFactory factory_;
183 #endif
184  std::unordered_map<std::string, ProtobufDescriptorPtr> protobuf_descriptor_map_;
185  std::unordered_map<std::string, std::vector<SchemaData>> schema_map_;
186  std::unordered_map<std::string, ProtobufMessagePtr> protobuf_message_map_;
187  std::unordered_map<std::string, std::vector<FlatbuffersParserPtr>> flatbuffers_parser_map_;
188  std::vector<FlatbuffersParserPtr> retired_flatbuffers_parsers_;
189  std::unordered_map<std::string, std::unique_ptr<Bytes>> flatbuffers_schema_snapshots_;
190  std::vector<std::unique_ptr<Bytes>> retired_flatbuffers_schema_snapshots_;
191  std::mutex mtx_;
192 
194 };
195 
196 ////////////////////////////////////////////////////////////////
197 /// Details
198 ////////////////////////////////////////////////////////////////
199 
201 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
202  : factory_(google::protobuf::DescriptorPool::generated_pool())
203 #endif
204 {
206 }
207 
209 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
210  for (auto& [name, ptr] : protobuf_message_map_) {
211  (void)name;
212  delete reinterpret_cast<google::protobuf::Message*>(ptr);
213  }
214 #endif
215 
216  for (auto& [name, ptr_list] : flatbuffers_parser_map_) {
217  (void)name;
218 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
219  for (auto* ptr : ptr_list) { // LCOV_EXCL_LINE GCOVR_EXCL_LINE
220  delete reinterpret_cast<flatbuffers::Parser*>(ptr); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
221  }
222 #endif
223  }
224 
225 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
226  for (auto* ptr : retired_flatbuffers_parsers_) {
227  delete reinterpret_cast<flatbuffers::Parser*>(ptr);
228  }
229 #endif
230 
231  protobuf_message_map_.clear();
232  flatbuffers_parser_map_.clear();
233  retired_flatbuffers_parsers_.clear();
234  flatbuffers_schema_snapshots_.clear();
235  retired_flatbuffers_schema_snapshots_.clear();
236 }
237 
238 inline SchemaData SchemaPluginBase::search_schema(const std::string& name, SchemaType schema_type) {
239  std::lock_guard lock(mtx_);
240 
241  auto iter = schema_map_.find(name);
242 
243  if VLIKELY (iter != schema_map_.end()) {
244  if (schema_type != SchemaType::kUnknown) {
245  for (const auto& schema : iter->second) {
246  if (schema.schema_type == schema_type) {
247  return schema;
248  }
249  }
250  }
251  }
252 
253  SchemaData schema;
254  schema.name = name;
255 
256  if (schema_type == SchemaType::kZeroCopy && Helpers::has_startwith(name, "vlink::zerocopy::")) {
257  schema.encoding = "vlink_msg";
259  (void)cache_schema_data_locked(schema);
260  return schema;
261  }
262 
263  if (schema_type == SchemaType::kUnknown) {
264  std::vector<SchemaData> matches;
265  matches.reserve(3);
266 
267  [[maybe_unused]] bool has_cached_protobuf = false;
268  [[maybe_unused]] bool has_cached_flatbuffers = false;
269  [[maybe_unused]] bool has_cached_zerocopy = false;
270 
271  if VLIKELY (iter != schema_map_.end()) {
272  for (const auto& cached_schema : iter->second) {
273  switch (cached_schema.schema_type) {
275  has_cached_protobuf = true;
276  break;
278  has_cached_flatbuffers = true;
279  break;
281  has_cached_zerocopy = true;
282  break;
283  default: // LCOV_EXCL_LINE GCOVR_EXCL_LINE
284  break; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
285  }
286 
287  matches.emplace_back(cached_schema);
288  }
289  }
290 
291 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
292 
293  if VUNLIKELY (!has_cached_protobuf) {
294  if (auto* desc_ptr = find_protobuf_descriptor_locked(name); desc_ptr != nullptr) {
295  auto* desc = reinterpret_cast<google::protobuf::Descriptor*>(desc_ptr);
296  auto proto_schema = build_protobuf_schema_data(*desc);
297 
298  if VLIKELY (!proto_schema.encoding.empty()) {
299  (void)cache_schema_data_locked(proto_schema);
300  matches.emplace_back(std::move(proto_schema));
301  }
302  }
303  }
304 #endif
305 
306 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
307 
308  if VUNLIKELY (!has_cached_flatbuffers) {
309  if (const auto* cached_schema = find_cached_flatbuffers_schema_locked(name)) {
310  matches.emplace_back(*cached_schema);
311  }
312  }
313 #endif
314 
315  if (!has_cached_zerocopy && Helpers::has_startwith(name, "vlink::zerocopy::")) {
316  SchemaData zerocopy_schema;
317  zerocopy_schema.name = name;
318  zerocopy_schema.encoding = "vlink_msg";
319  zerocopy_schema.schema_type = SchemaType::kZeroCopy;
320  (void)cache_schema_data_locked(zerocopy_schema);
321  matches.emplace_back(std::move(zerocopy_schema));
322  }
323 
324  if (matches.size() == 1) {
325  return matches.front();
326  }
327 
328  return {};
329  }
330 
331 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
332 
333  if (schema_type == SchemaType::kProtobuf) {
334  auto* desc_ptr = find_protobuf_descriptor_locked(name);
335 
336  if (desc_ptr != nullptr) {
337  auto* desc = reinterpret_cast<google::protobuf::Descriptor*>(desc_ptr);
338  schema = build_protobuf_schema_data(*desc);
339 
340  if VLIKELY (!schema.encoding.empty()) {
341  (void)cache_schema_data_locked(schema);
342  return schema;
343  }
344  }
345  }
346 #endif
347 
348 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
349 
350  if (schema_type == SchemaType::kFlatbuffers) {
351  if (const auto* cached_schema = find_cached_flatbuffers_schema_locked(name)) {
352  return *cached_schema;
353  }
354  }
355 #endif
356 
357  return schema;
358 }
359 
360 inline std::vector<SchemaData> SchemaPluginBase::get_all_schemas(SchemaType schema_type) {
361  std::lock_guard lock(mtx_);
362 
363 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
364 
365  if (schema_type == SchemaType::kUnknown || schema_type == SchemaType::kFlatbuffers) {
366  import_all_flatbuffers_schema_data_locked();
367  }
368 #endif
369 
370  size_t schema_count = 0;
371 
372  for (const auto& [name, items] : schema_map_) {
373  (void)name;
374  schema_count += items.size();
375  }
376 
377  std::vector<SchemaData> schemas;
378  schemas.reserve(schema_count);
379 
380  for (const auto& [name, items] : schema_map_) {
381  (void)name;
382 
383  for (const auto& schema : items) {
384  if (schema_type != SchemaType::kUnknown && schema.schema_type != schema_type) {
385  continue;
386  }
387 
388  schemas.emplace_back(schema);
389  }
390  }
391 
392  return schemas;
393 }
394 
396  const std::string& name) {
397  std::lock_guard lock(mtx_);
398 
399 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
400  return find_protobuf_descriptor_locked(name);
401 #else
402  (void)name;
403  return nullptr;
404 #endif
405 }
406 
408  std::lock_guard lock(mtx_);
409 
410  auto iter = protobuf_message_map_.find(name);
411 
412  if VLIKELY (iter != protobuf_message_map_.end()) {
413  return iter->second;
414  }
415 
416 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
417  auto* desc_ptr = find_protobuf_descriptor_locked(name);
418 
419  if VUNLIKELY (!desc_ptr) {
420  return nullptr;
421  }
422 
423  const auto* prototype = factory_.GetPrototype(reinterpret_cast<google::protobuf::Descriptor*>(desc_ptr));
424 
425  if VUNLIKELY (!prototype) {
426  return nullptr; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
427  }
428 
429  auto* target_ptr = reinterpret_cast<ProtobufMessagePtr>(prototype->New());
430  protobuf_message_map_.emplace(name, target_ptr);
431  return target_ptr;
432 #else
433  (void)name;
434  return nullptr;
435 #endif
436 }
437 
439  const std::string& name) {
440  std::lock_guard lock(mtx_);
441 
442 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
443  const auto* schema = find_cached_flatbuffers_schema_locked(name);
444 
445  if VUNLIKELY (!schema) {
446  return nullptr;
447  }
448 
449  flatbuffers::Verifier verifier(schema->data.data(), schema->data.size());
450 
451  if VUNLIKELY (!reflection::VerifySchemaBuffer(verifier)) {
452  return nullptr; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
453  }
454 
455  auto snapshot_iter = flatbuffers_schema_snapshots_.find(name);
456 
457  if VLIKELY (snapshot_iter != flatbuffers_schema_snapshots_.end() && snapshot_iter->second &&
458  snapshot_iter->second->size() == schema->data.size() &&
459  std::memcmp(snapshot_iter->second->data(), schema->data.data(), schema->data.size()) == 0) {
460  return reinterpret_cast<FlatbuffersSchemaPtr>(
461  const_cast<reflection::Schema*>(reflection::GetSchema(snapshot_iter->second->data())));
462  }
463 
464  auto snapshot = std::make_unique<Bytes>(Bytes::deep_copy(schema->data.data(), schema->data.size()));
465 
466  if VUNLIKELY (snapshot->empty()) {
467  return nullptr; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
468  }
469 
470  const auto* snapshot_data = snapshot->data();
471 
472  if VLIKELY (snapshot_iter != flatbuffers_schema_snapshots_.end()) {
473  if VLIKELY (snapshot_iter->second) {
474  retired_flatbuffers_schema_snapshots_.emplace_back(std::move(snapshot_iter->second));
475  }
476 
477  snapshot_iter->second = std::move(snapshot);
478  } else {
479  flatbuffers_schema_snapshots_.emplace(name, std::move(snapshot));
480  }
481 
482  return reinterpret_cast<FlatbuffersSchemaPtr>(const_cast<reflection::Schema*>(reflection::GetSchema(snapshot_data)));
483 #else
484  (void)name;
485  return nullptr;
486 #endif
487 }
488 
490  const std::string& name) {
491  std::lock_guard lock(mtx_);
492 
493 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
494  const auto* schema = find_cached_flatbuffers_schema_locked(name);
495 
496  if VUNLIKELY (!schema) {
497  return nullptr;
498  }
499 
500  auto parser = std::make_unique<flatbuffers::Parser>();
501 
502  if VUNLIKELY (!parser->Deserialize(reinterpret_cast<const uint8_t*>(schema->data.data()), schema->data.size())) {
503  return nullptr; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
504  }
505 
506  if VUNLIKELY (!parser->SetRootType(name.c_str())) {
507  return nullptr;
508  }
509 
510  auto* target_ptr = reinterpret_cast<FlatbuffersParserPtr>(parser.get());
511  flatbuffers_parser_map_[name].emplace_back(target_ptr);
512 
513  (void)parser.release(); // NOLINT(bugprone-unused-return-value)
514 
515  return target_ptr;
516 #else
517  (void)name;
518  return nullptr;
519 #endif
520 }
521 
522 inline std::string SchemaPluginBase::normalize_schema_encoding(std::string_view encoding) {
523  std::string normalized{encoding};
524  std::transform(normalized.begin(), normalized.end(), normalized.begin(),
525  [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
526 
527  if (normalized == "proto") {
528  return "protobuf"; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
529  }
530 
531  if (normalized == "flatbuffer" || normalized == "flatbuffers" || normalized == "fbs" || normalized == "bfbs") {
532  return "flatbuffers";
533  }
534 
535  return normalized;
536 }
537 
538 inline bool SchemaPluginBase::is_flatbuffers_schema_type(std::string_view encoding) {
539  return normalize_schema_encoding(encoding) == "flatbuffers";
540 }
541 
542 inline bool SchemaPluginBase::cache_schema_data_locked(const SchemaData& schema) {
543  if VUNLIKELY (schema.name.empty() || schema.encoding.empty()) {
544  return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
545  }
546 
547 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
548 
549  if (is_flatbuffers_schema_type(schema.encoding)) {
550  flatbuffers::Verifier verifier(schema.data.data(), schema.data.size());
551 
552  if VUNLIKELY (!reflection::VerifySchemaBuffer(verifier)) {
553  return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
554  }
555 
556  clear_flatbuffers_parser_cache_locked(schema.name);
557  }
558 #endif
559 
560  auto cached_schema_type = SchemaData::is_valid_type(schema.schema_type) ? schema.schema_type : SchemaType::kUnknown;
561 
562  if VUNLIKELY (!SchemaData::is_real_type(cached_schema_type)) {
563  return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
564  }
565 
566  auto& cached_schemas = schema_map_[schema.name];
567 
568  for (auto& cached_schema : cached_schemas) {
569  if (cached_schema.schema_type == cached_schema_type) {
570  cached_schema = schema;
571  return true;
572  }
573  }
574 
575  cached_schemas.emplace_back(schema);
576  return true;
577 }
578 
579 #ifdef VLINK_HAS_SCHEMA_PLUGIN_PROTOBUF
580 inline SchemaPluginInterface::ProtobufDescriptorPtr SchemaPluginBase::find_protobuf_descriptor_locked(
581  const std::string& name) {
582  auto iter = protobuf_descriptor_map_.find(name);
583 
584  if VLIKELY (iter != protobuf_descriptor_map_.end()) {
585  return iter->second;
586  }
587 
588  const auto* desc = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(name);
589 
590  if VUNLIKELY (!desc) {
591  return nullptr;
592  }
593 
594  auto* target_ptr = reinterpret_cast<ProtobufDescriptorPtr>(const_cast<google::protobuf::Descriptor*>(desc));
595  protobuf_descriptor_map_.emplace(name, target_ptr);
596  return target_ptr;
597 }
598 
599 inline SchemaData SchemaPluginBase::build_protobuf_schema_data(const google::protobuf::Descriptor& descriptor) {
600  SchemaData schema;
601  schema.name = descriptor.full_name();
602  schema.encoding = "protobuf";
603  schema.schema_type = SchemaType::kProtobuf;
604 
605  if VUNLIKELY (!descriptor.file()) {
606  schema.encoding.clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
607  schema.schema_type = SchemaType::kUnknown; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
608  return schema; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
609  }
610 
611  google::protobuf::FileDescriptorSet proto_fd_set;
612  std::queue<const google::protobuf::FileDescriptor*> to_add;
613 
614  to_add.push(descriptor.file());
615 
616 #if GOOGLE_PROTOBUF_VERSION >= 6030000
617  std::unordered_set<std::string_view> seen_dependencies;
618 #else
619  std::unordered_set<std::string> seen_dependencies;
620 #endif
621 
622  seen_dependencies.insert(descriptor.file()->name());
623 
624  while (!to_add.empty()) {
625  const auto* next = to_add.front();
626  to_add.pop();
627 
628  next->CopyTo(proto_fd_set.add_file());
629 
630  for (int i = 0; i < next->dependency_count(); ++i) {
631  // LCOV_EXCL_START GCOVR_EXCL_START
632  const auto* dep = next->dependency(i);
633 
634  if (dep == nullptr || seen_dependencies.find(dep->name()) != seen_dependencies.end()) {
635  continue;
636  }
637 
638  seen_dependencies.insert(dep->name());
639  to_add.push(dep);
640  // LCOV_EXCL_STOP GCOVR_EXCL_STOP
641  }
642  }
643 
644  schema.data = Bytes::create(proto_fd_set.ByteSizeLong());
645 
646  if VUNLIKELY (!proto_fd_set.SerializeToArray(schema.data.data(), schema.data.size())) {
647  schema.encoding.clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
648  schema.schema_type = SchemaType::kUnknown; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
649  schema.data.clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
650  }
651 
652  return schema;
653 }
654 #endif
655 
656 #ifdef VLINK_HAS_SCHEMA_PLUGIN_FLATBUFFERS
657 inline void SchemaPluginBase::import_all_flatbuffers_schema_data_locked() {
658  for (const auto& schema : FlatbuffersRegistry::get().get_all_schemas()) {
659  (void)cache_schema_data_locked(schema);
660  }
661 }
662 
663 inline bool SchemaPluginBase::import_flatbuffers_schema_data_locked(const std::string& name) {
664  auto schema = FlatbuffersRegistry::get().search_schema(name);
665 
666  if (!is_flatbuffers_schema_type(schema.encoding) || schema.data.empty()) {
667  return false;
668  }
669 
670  return cache_schema_data_locked(schema);
671 }
672 
673 inline const SchemaData* SchemaPluginBase::find_cached_flatbuffers_schema_locked(const std::string& name) const {
674  auto* self = const_cast<SchemaPluginBase*>(this);
675  auto iter = self->schema_map_.find(name);
676 
677  if (iter == self->schema_map_.end()) {
678  (void)self->import_flatbuffers_schema_data_locked(name);
679  iter = self->schema_map_.find(name);
680  }
681 
682  if (iter == self->schema_map_.end()) {
683  return nullptr;
684  }
685 
686  for (const auto& schema : iter->second) {
687  if (schema.schema_type != SchemaType::kFlatbuffers) {
688  continue;
689  }
690 
691  if (!is_flatbuffers_schema_type(schema.encoding) || schema.data.empty()) {
692  return nullptr;
693  }
694 
695  return &schema;
696  }
697 
698  return nullptr;
699 }
700 
701 inline void SchemaPluginBase::clear_flatbuffers_parser_cache_locked(const std::string& name) {
702  auto iter = flatbuffers_parser_map_.find(name);
703 
704  if (iter == flatbuffers_parser_map_.end()) {
705  return;
706  }
707 
708  retired_flatbuffers_parsers_.insert(retired_flatbuffers_parsers_.end(), iter->second.begin(), iter->second.end());
709  flatbuffers_parser_map_.erase(iter);
710 }
711 #endif
712 
713 } // namespace vlink
Process-local lookup table for compiled-in FlatBuffers BFBS reflection blobs.
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLIKELY(...)
Short alias for VLINK_LIKELY.
Definition: macros.h:284
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174
Header probe that enables Protobuf-backed schema-plugin code when available.
Abstract contract for runtime Protobuf / FlatBuffers schema discovery plugins.
Definition: serializer-inl.h:142