Search through config for schema of specified flatbuffer type

Allow user to call function that returns a schema reflection in
the config for flatbuffer type instead of having to find a
matching schema manually.

Signed-off-by: Nathan Leong <100028864@mvla.net>
Change-Id: I40e836e8f379ac48f32633d49d8c01a1530697df
Signed-off-by: Nathan Leong <100028864@mvla.net>
diff --git a/aos/BUILD b/aos/BUILD
index 596996b..164f40b 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -514,6 +514,7 @@
         "configuration_test.cc",
     ],
     data = [
+        "//aos/events:ping_fbs_reflection_out",
         "//aos/events:pingpong_config",
         "//aos/events:pong_fbs_reflection_out",
         "//aos/testdata:test_configs",
@@ -521,6 +522,7 @@
     target_compatible_with = ["@platforms//os:linux"],
     deps = [
         ":configuration",
+        "//aos/events:ping_fbs",
         "//aos/testing:flatbuffer_eq",
         "//aos/testing:googletest",
         "//aos/testing:path",
diff --git a/aos/configuration.cc b/aos/configuration.cc
index d5ac2a1..ad6fb54 100644
--- a/aos/configuration.cc
+++ b/aos/configuration.cc
@@ -68,7 +68,6 @@
 }
 
 }  // namespace
-
 // Define the compare and equal operators for Channel and Application so we can
 // insert them in the btree below.
 bool operator<(const FlatbufferDetachedBuffer<Channel> &lhs,
@@ -1594,5 +1593,30 @@
   return channel->num_readers() + channel->num_senders();
 }
 
+// Searches through configurations for schemas that include a certain type
+const reflection::Schema *GetSchema(const Configuration *config,
+                                    std::string_view schema_type) {
+  if (config->has_channels()) {
+    std::vector<flatbuffers::Offset<Channel>> channel_offsets;
+    for (const Channel *c : *config->channels()) {
+      if (schema_type == c->type()->string_view()) {
+        return c->schema();
+      }
+    }
+  }
+  return nullptr;
+}
+
+// Copy schema reflection into detached flatbuffer
+std::optional<FlatbufferDetachedBuffer<reflection::Schema>>
+GetSchemaDetachedBuffer(const Configuration *config,
+                        std::string_view schema_type) {
+  const reflection::Schema *found_schema = GetSchema(config, schema_type);
+  if (found_schema == nullptr) {
+    return std::nullopt;
+  }
+  return RecursiveCopyFlatBuffer(found_schema);
+}
+
 }  // namespace configuration
 }  // namespace aos
diff --git a/aos/configuration.h b/aos/configuration.h
index 8515b18..4d84b23 100644
--- a/aos/configuration.h
+++ b/aos/configuration.h
@@ -212,7 +212,20 @@
 // Returns the number of scratch buffers in the queue.
 int QueueScratchBufferSize(const Channel *channel);
 
-// TODO(austin): GetSchema<T>(const Flatbuffer<Configuration> &config);
+// Searches through configurations for schemas that include a certain type.
+const reflection::Schema *GetSchema(const Configuration *config,
+                                    std::string_view schema_type);
+
+// GetSchema template
+template <typename T>
+const reflection::Schema *GetSchema(const Configuration *config) {
+  return GetSchema(config, T::GetFullyQualifiedName());
+}
+
+// Copy schema reflection into detached flatbuffer
+std::optional<FlatbufferDetachedBuffer<reflection::Schema>>
+GetSchemaDetachedBuffer(const Configuration *config,
+                        std::string_view schema_type);
 
 }  // namespace configuration
 
@@ -222,6 +235,7 @@
                const FlatbufferDetachedBuffer<Channel> &rhs);
 bool operator==(const FlatbufferDetachedBuffer<Channel> &lhs,
                 const FlatbufferDetachedBuffer<Channel> &rhs);
+
 }  // namespace aos
 
 #endif  // AOS_CONFIGURATION_H_
diff --git a/aos/configuration_test.cc b/aos/configuration_test.cc
index fa74e20..fc45d88 100644
--- a/aos/configuration_test.cc
+++ b/aos/configuration_test.cc
@@ -1,6 +1,7 @@
 #include "aos/configuration.h"
 
 #include "absl/strings/strip.h"
+#include "aos/events/ping_generated.h"
 #include "aos/json_to_flatbuffer.h"
 #include "aos/testing/flatbuffer_eq.h"
 #include "aos/testing/path.h"
@@ -1007,10 +1008,47 @@
       JsonToFlatbuffer<Channel>(
           "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"num_readers\": 5, "
           "\"num_senders\": 10 }");
-
   EXPECT_EQ(QueueScratchBufferSize(&channel.message()), 15);
 }
 
+// Tests that GetSchema returns schema of specified type
+TEST_F(ConfigurationTest, GetSchema) {
+  FlatbufferDetachedBuffer<Configuration> config =
+      ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
+  FlatbufferVector<reflection::Schema> expected_schema =
+      FileToFlatbuffer<reflection::Schema>(
+          ArtifactPath("aos/events/ping.bfbs"));
+  EXPECT_EQ(FlatbufferToJson(GetSchema(&config.message(), "aos.examples.Ping")),
+            FlatbufferToJson(expected_schema));
+  EXPECT_EQ(GetSchema(&config.message(), "invalid_name"), nullptr);
+}
+
+// Tests that GetSchema template returns schema of specified type
+TEST_F(ConfigurationTest, GetSchemaTemplate) {
+  FlatbufferDetachedBuffer<Configuration> config =
+      ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
+  FlatbufferVector<reflection::Schema> expected_schema =
+      FileToFlatbuffer<reflection::Schema>(
+          ArtifactPath("aos/events/ping.bfbs"));
+  EXPECT_EQ(FlatbufferToJson(GetSchema<aos::examples::Ping>(&config.message())),
+            FlatbufferToJson(expected_schema));
+}
+
+// Tests that GetSchemaDetachedBuffer returns detached buffer of specified type
+TEST_F(ConfigurationTest, GetSchemaDetachedBuffer) {
+  FlatbufferDetachedBuffer<Configuration> config =
+      ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
+  FlatbufferVector<reflection::Schema> expected_schema =
+      FileToFlatbuffer<reflection::Schema>(
+          ArtifactPath("aos/events/ping.bfbs"));
+  EXPECT_EQ(FlatbufferToJson(
+                GetSchemaDetachedBuffer(&config.message(), "aos.examples.Ping")
+                    .value()),
+            FlatbufferToJson(expected_schema));
+  EXPECT_EQ(GetSchemaDetachedBuffer(&config.message(), "invalid_name"),
+            std::nullopt);
+}
+
 }  // namespace testing
 }  // namespace configuration
 }  // namespace aos