Better demo program.

This commit is contained in:
2025-03-27 16:36:52 -04:00
parent c643eb167f
commit 9546b2bcfe
4 changed files with 109 additions and 74 deletions

View File

@@ -11,8 +11,10 @@
#include <memory>
#include <optional>
#include <string>
#include <cassert>
// TODO: Implement standard iterators for json::object_val and json::array_val
// TODO: API compatibility with json::value and derived types.
// TODO: Auto-conversion from json::value *to* represented type.
/// Redacted Software JSON API - Parse, Serialize, Validate, and Build JSON files.
namespace JJX::json {
@@ -81,11 +83,13 @@ namespace JJX::json {
/// The default constructor initializes to a JSON null value.
explicit value();
/// Constructs a json value that represents the corresponding number.
value(double v);
value(double v);
value(int v);
value(float v);
/// Constructs a json value that represents a string.
value(const std::string& v);
value(const std::string& v);
value(bool v) : boolean(v), type(value_type::boolean) {}
value(bool v);
/// Constructs a json value that represents an array.
explicit value(const std::vector<value>& v);
/// Constructs a json value that represents an object.
@@ -93,7 +97,7 @@ namespace JJX::json {
/// Constructs a json value that represents an object, from a key-value pair.
explicit value(const std::pair<std::string, value>& kvp) : object({kvp}), type(value_type::object) {}
/// Constructs a json value that represents an object, from a list of key-value pairs.
explicit value(const std::vector<std::pair<std::string, value>>& kvp_list);
//explicit value(const std::vector<std::pair<std::string, value>>& kvp_list);
/// Assigns this value to a number, and sets the value_type::number.
value& operator=(double in);
@@ -124,6 +128,23 @@ namespace JJX::json {
/// Converts all JSON values contained in this object / array to the derived json value types.
void convert_descendants();
#pragma region Object Access Members
/// @return The json value associated with the given key.
value& at(const std::string& key);
/// @see object::at()
value& operator[] (const std::string& key);
const value& operator[] (const std::string& key) const;
/// @return True if a key-value pair in this object has a key that matches the given value.
bool contains(const std::string& key);
#pragma endregion
#pragma region Array Access Members
value& operator[] (int key);
#pragma endregion
};
/// A specialized json::value which provides STL-compatibility with std::string, and other functions for convenience.
@@ -223,16 +244,14 @@ namespace JJX::json {
using iterator = std::vector<value>::iterator;
using const_iterator = std::vector<value>::const_iterator;
iterator begin() { return value::array->begin(); }
iterator end() { return value::array->end(); }
[[nodiscard]] const_iterator begin() const;
[[nodiscard]] const_iterator end() const;
[[nodiscard]] const_iterator cbegin() const;
[[nodiscard]] const_iterator cend() const;
};
iterator begin() { return value::array->begin(); }
iterator end() { return value::array->end(); }
[[nodiscard]] const_iterator begin() const;
[[nodiscard]] const_iterator end() const;
[[nodiscard]] const_iterator cbegin() const;
[[nodiscard]] const_iterator cend() const;
};
}

View File

@@ -4,6 +4,7 @@
using namespace JJX;
/// Open a text file and return the contents.
std::string read_file(const std::string& file_path)
{
std::ifstream file(file_path, std::ios::binary);
@@ -30,7 +31,6 @@ void parse_json_file(const std::string& file_path) {
if (!parse_error.empty())
std::cerr << "Error while parsing json: " << parse_error << std::endl;
std::cout << json::deparse(text) << std::endl;
}
@@ -41,24 +41,22 @@ struct Vector3
/// Creates json array out of Vector3 type.
json::value vector3_to_json(const Vector3& input)
{
auto x = json::number(input.x);
auto y = json::number(input.y);
auto z = json::number(input.z);
return json::array({x, y, z});
json::value vector3_to_json(const Vector3& v) {
//auto x = json::number(input.x);
//auto y = json::number(input.y);
//auto z = json::number(input.z);
return json::array({v.x, v.y, v.z});
}
/// Creates Vector3 type out of json array object.
Vector3 json_to_vector3(const json::value& obj)
{
Vector3 json_to_vector3(const json::value& obj) {
Vector3 value;
value.x = obj.array->at(0).number.value_or(0);
value.y = obj.array->at(1).number.value_or(0);
value.z = obj.array->at(2).number.value_or(0);
return value;
return {value};
}
/// I personally recommend using the following signatures for serializing and deserializing your objects
@@ -67,18 +65,18 @@ Vector3 json_to_vector3(const json::value& obj)
struct json_serializable {
// json::value serialize() const { ... }
virtual json::value serialize() const { /* Create a json::value, add data, and return. */; };
virtual json::value serialize() const = 0; //{ /* Create a json::value, add data, and return. */; };
};
struct json_deserializable {
json_deserializable(const json::value&) = delete;
explicit json_deserializable(const json::value&) = delete;
};
struct json_convertible : json_serializable, json_deserializable {};
struct product_info
{
json::value serialize() const;
[[nodiscard]] json::value serialize() const;
product_info() = default;
/// @schema object {string category, string description, boolean is_available, string name, number price, array[@review] reviews}
/// @note This class design assumes all entries in `reviews` are serializable to @struct review,
@@ -91,14 +89,9 @@ struct product_info
};
/// @schema { rating : number, review_text : string, user : string }
struct review
{
struct review {
[[nodiscard]] json::value serialize() const;
review(const json::value& jv) {
if (jv.type != json::value_type::object)
throw std::runtime_error("Malformed JSON for review!");
}
explicit review(const json::value& jv);
int rating;
std::string review_text;
@@ -125,16 +118,17 @@ json::value product_info::serialize() const {
root += {"description", this->description};
root += {"name", this->name};
auto root_review_list = json::array();
for (auto& rev : this->reviews) {
auto review = rev.serialize();
auto review_list = json::array();
for (auto& rev : this->reviews)
review_list += rev.serialize();
root["ratings"] = {
{"average", this->ratings.average},
{"total", this->ratings.total}
};
root_review_list += review;
}
root += {"reviews", root_review_list};
root["reviews"] = root_review_list;
root["taters"] = 5.0;
root += {"reviews", review_list};
root += {"taters", 5.0};
return root;
}
@@ -143,22 +137,22 @@ product_info::product_info(const json::value &jv) {
if (jv.type != json::value_type::object)
throw std::runtime_error("Malformed JSON for product info!");
auto json_object = jv.as_object();
auto jvo = jv.as_object();
this->category = json_object["category"].string.value();
this->description = json_object["description"].string.value();
this->is_available = json_object["is_available"].boolean.value();
this->manufacturer = json_object["manufacturer"].string.value();
this->name = json_object["name"].string.value();
this->price = double(json_object["price"]);
this->category = jvo["category"].string.value();
this->description = jvo["description"].string.value();
this->is_available = jvo["is_available"].boolean.value();
this->manufacturer = jvo["manufacturer"].string.value();
this->name = jvo["name"].string.value();
this->price = double(jvo["price"]);
auto reviews = json_object["reviews"].as_array();
//json::array subobj = better_root["reviews"].as_array();
for (auto& review_json : reviews) {
this->reviews.push_back(review(review_json));
for (auto& review_json : jvo["reviews"].as_array()) {
this->reviews.emplace_back(review_json);
}
this->ratings.average = jvo["ratings"]["average"].number.value();
this->ratings.total = jvo["ratings"]["total"].number.value();
}
json::value product_info::review::serialize() const {
@@ -169,6 +163,11 @@ json::value product_info::review::serialize() const {
return obj;
}
product_info::review::review(const json::value &jv) {
if (jv.type != json::value_type::object)
throw std::runtime_error("Malformed JSON for review!");
}
void test_product_info()
{
std::cout << "Testing parsing of product_info file." << std::endl;
@@ -198,6 +197,10 @@ void test_tile_data() {
//parse_json_file("../samples/tiles.json");
}
void test_widgets() {
}
// Some progress has been made on small scale.
int main(int argc, char* argv[]) {
test_product_info();

View File

@@ -1,29 +1,16 @@
{
"product_id": "SKU12345",
"name": "Example Product",
"description": "This is an example product.",
"category": "Electronics",
"price": 199.99,
"stock_quantity": 50,
"manufacturer": "TechCo",
"release_date": "2022-05-10",
"is_available": true,
"ratings": {
"average": 4.5,
"total": 100
},
"reviews": [
{

View File

@@ -173,11 +173,6 @@ namespace JJX::json {
return lex_keyword(raw_json, "false", token_type::boolean, index);
}
value::value(const std::vector<std::pair<std::string, value>> &kvp_list): type(value_type::object) {
for (auto& kvp : kvp_list)
object->insert(kvp);
}
json::value& value::operator=(double in)
{
type = value_type::number;
@@ -571,6 +566,37 @@ namespace JJX::json {
value::value(const std::map<std::string, value> &v): object(v), type(value_type::object) {}
value::value(bool v) : boolean(v), type(value_type::boolean) {}
value::value(int v) : number(v), type(value_type::number) {}
value::value(float v) : number(v), type(value_type::number) {}
value &value::at(const std::string &key) {
assert(type == value_type::object);
return this->as_object().at(key);
}
value &value::operator[](const std::string &key) {
assert(type == value_type::object);
return this->as_object()[key];
}
const value &value::operator[](const std::string &key) const {
assert(type == value_type::object);
return this->as_object()[key];
}
bool value::contains(const std::string &key) {
assert(type == value_type::object);
return this->as_object().contains(key);
}
value &value::operator[](int key) {
assert(type == value_type::array);
return as_array()[key];
}
struct string string(const std::string &text) {
struct string out;
out.type = value_type::string;