Better demo program.
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
87
main.cpp
87
main.cpp
@@ -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();
|
||||
|
@@ -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": [
|
||||
{
|
||||
|
36
src/JSON.cpp
36
src/JSON.cpp
@@ -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;
|
||||
|
Reference in New Issue
Block a user