--- /dev/null
+/*
+ * Copyright (c) 2023 The Khronos Group Inc.
+ * Copyright (c) 2023 Valve Corporation
+ * Copyright (c) 2023 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and/or associated documentation files (the "Materials"), to
+ * deal in the Materials without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Materials, and to permit persons to whom the Materials are
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included in
+ * all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
+ * USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ * Author: Charles Giessen <charles@lunarg.com>
+ */
+
+#pragma once
+
+#include <stack>
+#include <string>
+#include <utility>
+
+// Utility class to simplify the writing of JSON manifest files
+
+struct JsonWriter {
+ std::string output;
+
+ // the bool represents whether an object has been written & a comma is needed
+ std::stack<bool> stack;
+
+ void StartObject() {
+ CommaAndNewLine();
+ Indent();
+ output += "{";
+ stack.push(false);
+ }
+ void StartKeyedObject(std::string const& key) {
+ CommaAndNewLine();
+ Indent();
+ output += "\"" + key + "\": {";
+ stack.push(false);
+ }
+ void EndObject() {
+ stack.pop();
+ output += "\n";
+ Indent();
+ output += "}";
+ }
+ void StartKeyedArray(std::string const& key) {
+ CommaAndNewLine();
+ Indent();
+ output += "\"" + key + "\": [";
+ stack.push(false);
+ }
+ void StartArray(std::string key) {
+ CommaAndNewLine();
+ Indent();
+ output += "[";
+ stack.push(false);
+ }
+ void EndArray() {
+ stack.pop();
+ output += "\n";
+ Indent();
+ output += "]";
+ }
+
+ void AddKeyedString(std::string const& key, std::string const& value) {
+ CommaAndNewLine();
+ Indent();
+ output += "\"" + key + "\": \"" + value + "\"";
+ }
+ void AddString(std::string const& value) {
+ CommaAndNewLine();
+ Indent();
+ output += "\"" + value + "\"";
+ }
+
+ void AddKeyedBool(std::string const& key, bool value) {
+ CommaAndNewLine();
+ Indent();
+ output += "\"" + key + "\": " + (value ? "true" : "false");
+ }
+ void AddBool(bool value) {
+ CommaAndNewLine();
+ Indent();
+ output += std::string(value ? "true" : "false");
+ }
+
+ private:
+ void CommaAndNewLine() {
+ if (stack.size() > 0) {
+ if (stack.top() == false) {
+ stack.top() = true;
+ } else {
+ output += ",";
+ }
+ output += "\n";
+ }
+ }
+ void Indent() {
+ for (uint32_t i = 0; i < stack.size(); i++) {
+ output += '\t';
+ }
+ }
+};
#endif
template <typename T>
-void print_list_of_t(std::string& out, const char* object_name, std::vector<T> const& vec) {
- if (vec.size() > 0) {
- out += std::string(",\n\t\t\"") + object_name + "\": {";
- for (size_t i = 0; i < vec.size(); i++) {
- if (i > 0) out += ",\t\t\t";
- out += "\n\t\t\t" + vec.at(i).get_manifest_str();
- }
- out += "\n\t\t}";
+void print_object_of_t(JsonWriter& writer, const char* object_name, std::vector<T> const& vec) {
+ if (vec.size() == 0) return;
+ writer.StartKeyedObject(object_name);
+ for (auto& element : vec) {
+ element.get_manifest_str(writer);
}
+ writer.EndObject();
}
template <typename T>
-void print_vector_of_t(std::string& out, const char* object_name, std::vector<T> const& vec) {
- if (vec.size() > 0) {
- out += std::string(",\n\t\t\"") + object_name + "\": [";
- for (size_t i = 0; i < vec.size(); i++) {
- if (i > 0) out += ",\t\t\t";
- out += "\n\t\t\t" + vec.at(i).get_manifest_str();
- }
- out += "\n\t\t]";
+void print_array_of_t(JsonWriter& writer, const char* object_name, std::vector<T> const& vec) {
+ if (vec.size() == 0) return;
+ writer.StartKeyedArray(object_name);
+ for (auto& element : vec) {
+ element.get_manifest_str(writer);
}
+ writer.EndArray();
}
-void print_vector_of_strings(std::string& out, const char* object_name, std::vector<std::string> const& strings) {
- if (strings.size() > 0) {
- out += std::string(",\n\t\t\"") + object_name + "\": [";
- for (size_t i = 0; i < strings.size(); i++) {
- if (i > 0) out += ",\t\t\t";
- out += "\"" + fs::fixup_backslashes_in_path(strings.at(i)) + "\"";
- }
- out += "]";
+void print_vector_of_strings(JsonWriter& writer, const char* object_name, std::vector<std::string> const& strings) {
+ if (strings.size() == 0) return;
+ writer.StartKeyedArray(object_name);
+ for (auto& str : strings) {
+ writer.AddString(fs::fixup_backslashes_in_path(str));
}
+ writer.EndArray();
}
std::string to_text(bool b) { return b ? std::string("true") : std::string("false"); }
std::string ManifestICD::get_manifest_str() const {
- std::string out;
- out += "{\n";
- out += " " + file_format_version.get_version_str() + "\n";
- out += " \"ICD\": {\n";
- out += " \"library_path\": \"" + fs::fixup_backslashes_in_path(lib_path) + "\",\n";
- out += " \"api_version\": \"" + version_to_string(api_version) + "\",\n";
- out += " \"is_portability_driver\": " + to_text(is_portability_driver);
- if (!library_arch.empty()) {
- out += ",\n \"library_arch\": \"" + library_arch + "\"\n";
- } else {
- out += "\n";
- }
- out += " }\n";
- out += "}\n";
- return out;
-}
-
-std::string ManifestLayer::LayerDescription::Extension::get_manifest_str() const {
- std::string out;
- out += "{ \"name\":\"" + name + "\",\n\t\t\t\"spec_version\":\"" + std::to_string(spec_version) + "\"";
- print_vector_of_strings(out, "entrypoints", entrypoints);
- out += "\n\t\t\t}";
- return out;
-}
-
-std::string ManifestLayer::LayerDescription::get_manifest_str() const {
- std::string out;
- out += "\t{\n";
- out += "\t\t\"name\":\"" + name + "\",\n";
- out += "\t\t\"type\":\"" + get_type_str(type) + "\",\n";
- if (lib_path.size() > 0) {
- out += "\t\t\"library_path\": \"" + fs::fixup_backslashes_in_path(lib_path.str()) + "\",\n";
- }
- out += "\t\t\"api_version\": \"" + version_to_string(api_version) + "\",\n";
- out += "\t\t\"implementation_version\":\"" + std::to_string(implementation_version) + "\",\n";
- out += "\t\t\"description\": \"" + description + "\"";
- print_list_of_t(out, "functions", functions);
- print_vector_of_t(out, "instance_extensions", instance_extensions);
- print_vector_of_t(out, "device_extensions", device_extensions);
+ JsonWriter writer;
+ writer.StartObject();
+ writer.AddKeyedString("file_format_version", file_format_version.get_version_str());
+ writer.StartKeyedObject("ICD");
+ writer.AddKeyedString("library_path", fs::fixup_backslashes_in_path(lib_path));
+ writer.AddKeyedString("api_version", version_to_string(api_version));
+ writer.AddKeyedBool("is_portability_driver", is_portability_driver);
+ if (!library_arch.empty()) writer.AddKeyedString("library_arch", library_arch);
+ writer.EndObject();
+ writer.EndObject();
+ return writer.output;
+}
+
+void ManifestLayer::LayerDescription::Extension::get_manifest_str(JsonWriter& writer) const {
+ writer.StartObject();
+ writer.AddKeyedString("name", name);
+ writer.AddKeyedString("spec_version", std::to_string(spec_version));
+ writer.AddKeyedString("spec_version", std::to_string(spec_version));
+ print_vector_of_strings(writer, "entrypoints", entrypoints);
+ writer.EndObject();
+}
+
+void ManifestLayer::LayerDescription::get_manifest_str(JsonWriter& writer) const {
+ writer.AddKeyedString("name", name);
+ writer.AddKeyedString("type", get_type_str(type));
+ if (!lib_path.str().empty()) {
+ writer.AddKeyedString("library_path", fs::fixup_backslashes_in_path(lib_path.str()));
+ }
+ writer.AddKeyedString("api_version", version_to_string(api_version));
+ writer.AddKeyedString("implementation_version", std::to_string(implementation_version));
+ writer.AddKeyedString("description", description);
+ print_object_of_t(writer, "functions", functions);
+ print_array_of_t(writer, "instance_extensions", instance_extensions);
+ print_array_of_t(writer, "device_extensions", device_extensions);
if (!enable_environment.empty()) {
- out += ",\n\t\t\"enable_environment\": { \"" + enable_environment + "\": \"1\" }";
+ writer.StartKeyedObject("enable_environment");
+ writer.AddKeyedString(enable_environment, "1");
+ writer.EndObject();
}
if (!disable_environment.empty()) {
- out += ",\n\t\t\"disable_environment\": { \"" + disable_environment + "\": \"1\" }";
- }
- print_vector_of_strings(out, "component_layers", component_layers);
- print_vector_of_strings(out, "blacklisted_layers", blacklisted_layers);
- print_vector_of_strings(out, "override_paths", override_paths);
- print_vector_of_strings(out, "app_keys", app_keys);
- print_list_of_t(out, "pre_instance_functions", pre_instance_functions);
+ writer.StartKeyedObject("disable_environment");
+ writer.AddKeyedString(disable_environment, "1");
+ writer.EndObject();
+ }
+ print_vector_of_strings(writer, "component_layers", component_layers);
+ print_vector_of_strings(writer, "blacklisted_layers", blacklisted_layers);
+ print_vector_of_strings(writer, "override_paths", override_paths);
+ print_vector_of_strings(writer, "app_keys", app_keys);
+ print_object_of_t(writer, "pre_instance_functions", pre_instance_functions);
if (!library_arch.empty()) {
- out += ",\n\t\t\"library_arch\": \"" + library_arch + "\"";
+ writer.AddKeyedString("library_arch", library_arch);
}
- out += "\n\t}";
-
- return out;
}
VkLayerProperties ManifestLayer::LayerDescription::get_layer_properties() const {
}
std::string ManifestLayer::get_manifest_str() const {
- std::string out;
- out += "{\n";
- out += "\t" + file_format_version.get_version_str() + "\n";
+ JsonWriter writer;
+ writer.StartObject();
+ writer.AddKeyedString("file_format_version", file_format_version.get_version_str());
if (layers.size() == 1) {
- out += "\t\"layer\": ";
- out += layers.at(0).get_manifest_str() + "\n";
+ writer.StartKeyedObject("layer");
+ layers.at(0).get_manifest_str(writer);
+ writer.EndObject();
} else {
- out += "\t\"layers\": [";
+ writer.StartKeyedArray("layers");
for (size_t i = 0; i < layers.size(); i++) {
- if (i > 0) out += ",";
- out += "\n" + layers.at(i).get_manifest_str();
+ writer.StartObject();
+ layers.at(i).get_manifest_str(writer);
+ writer.EndObject();
}
- out += "\n]";
+ writer.EndArray();
}
- out += "}\n";
- return out;
+ writer.EndObject();
+ return writer.output;
}
namespace fs {
#define FRAMEWORK_EXPORT
#endif
+#include "json_writer.h"
+
/*
* Wrapper around Environment Variables with common operations
* Since Environment Variables leak between tests, there needs to be RAII code to remove them during test cleanup
ManifestVersion(uint32_t major, uint32_t minor, uint32_t patch) noexcept : major(major), minor(minor), patch(patch){};
std::string get_version_str() const noexcept {
- return std::string("\"file_format_version\": \"") + std::to_string(major) + "." + std::to_string(minor) + "." +
- std::to_string(patch) + "\",";
+ return std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch);
}
};
BUILDER_VALUE(FunctionOverride, std::string, vk_func, {})
BUILDER_VALUE(FunctionOverride, std::string, override_name, {})
- std::string get_manifest_str() const { return std::string("\"") + vk_func + "\":\"" + override_name + "\""; }
+ void get_manifest_str(JsonWriter& writer) const { writer.AddKeyedString(vk_func, override_name); }
};
struct Extension {
Extension() noexcept {}
std::string name;
uint32_t spec_version = 0;
std::vector<std::string> entrypoints;
- std::string get_manifest_str() const;
+ void get_manifest_str(JsonWriter& writer) const;
};
BUILDER_VALUE(LayerDescription, std::string, name, {})
BUILDER_VALUE(LayerDescription, Type, type, Type::INSTANCE)
BUILDER_VECTOR(LayerDescription, std::string, app_keys, app_key)
BUILDER_VALUE(LayerDescription, std::string, library_arch, "")
- std::string get_manifest_str() const;
+ void get_manifest_str(JsonWriter& writer) const;
VkLayerProperties get_layer_properties() const;
};
BUILDER_VALUE(ManifestLayer, ManifestVersion, file_format_version, {})