building
This commit is contained in:
@@ -81,9 +81,11 @@ namespace JJX::json {
|
||||
/// The default constructor initializes to a JSON null value.
|
||||
explicit value();
|
||||
/// Constructs a json value that represents the corresponding number.
|
||||
explicit value(double v);
|
||||
value(double v);
|
||||
/// Constructs a json value that represents a string.
|
||||
explicit value(const std::string& v);
|
||||
value(const std::string& v);
|
||||
|
||||
value(bool v) : boolean(v), type(value_type::boolean) {}
|
||||
/// Constructs a json value that represents an array.
|
||||
explicit value(const std::vector<value>& v);
|
||||
/// Constructs a json value that represents an object.
|
||||
@@ -162,12 +164,12 @@ namespace JJX::json {
|
||||
/// Shorthand operator for adding a key-value pair to this object,
|
||||
json::object& operator+=(const std::pair<std::string, value>& kvp);
|
||||
/// Shorthand operator for adding a boolean-value to this object, with a string key.
|
||||
json::object& operator+=(const std::pair<std::string, bool>& kvp);
|
||||
/*json::object& operator+=(const std::pair<std::string, bool>& kvp);
|
||||
|
||||
json::object& operator+=(const std::pair<std::string, double>& kvp);
|
||||
|
||||
json::object& operator+=(const std::pair<std::string, std::string>& kvp);
|
||||
|
||||
*/
|
||||
/// @return The json value associated with the given key.
|
||||
value& at(const std::string& key);
|
||||
|
||||
|
147
main.cpp
147
main.cpp
@@ -61,28 +61,48 @@ Vector3 json_to_vector3(const json::value& obj)
|
||||
return value;
|
||||
}
|
||||
|
||||
/// I personally recommend using the following signatures for serializing and deserializing your objects
|
||||
/// as this will be considered the standard interface for the library, going forward.
|
||||
/// It may end up being a template so don't worry so much about inheriting these structs, specifically.
|
||||
|
||||
struct json_serializable {
|
||||
// json::value serialize() const { ... }
|
||||
virtual json::value serialize() const { /* Create a json::value, add data, and return. */; };
|
||||
};
|
||||
struct json_deserializable {
|
||||
json_deserializable(const json::value&) = delete;
|
||||
};
|
||||
|
||||
struct json_convertible : json_serializable, json_deserializable {};
|
||||
|
||||
struct product_info
|
||||
{
|
||||
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,
|
||||
///
|
||||
explicit product_info(const json::value& jv);
|
||||
|
||||
struct rating_metrics {
|
||||
double average;
|
||||
int total;
|
||||
};
|
||||
|
||||
/// @schema { rating : number, review_text : string, user : string }
|
||||
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!");
|
||||
}
|
||||
|
||||
int rating;
|
||||
std::string review_text;
|
||||
std::string user;
|
||||
|
||||
operator json::object() const
|
||||
{
|
||||
json::object obj = json::object();
|
||||
obj["rating"] = json::number(rating);
|
||||
obj["review_text"] = json::string(review_text);
|
||||
obj["user"] = json::string(user);
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
std::string category;
|
||||
@@ -97,90 +117,89 @@ struct product_info
|
||||
std::vector<review> reviews;
|
||||
};
|
||||
|
||||
|
||||
product_info pinfo_fromjson(json::value root)
|
||||
{
|
||||
if (root.type != json::value_type::object)
|
||||
std::cerr << "Malformed product info file!" << std::endl;
|
||||
|
||||
product_info this_product;
|
||||
|
||||
auto root_obj = root.as_object();
|
||||
|
||||
this_product.category = root_obj["category"].string.value();
|
||||
this_product.description = root_obj["description"].string.value();
|
||||
this_product.is_available = bool(root_obj["is_available"]);
|
||||
this_product.manufacturer = root_obj["manufacturer"].string.value();
|
||||
this_product.name = root_obj["name"].string.value();
|
||||
this_product.price = double(root_obj["price"]);
|
||||
|
||||
auto reviews = root_obj["reviews"].as_array();
|
||||
|
||||
//json::array subobj = better_root["reviews"].as_array();
|
||||
|
||||
|
||||
for (auto& review_data_pre : reviews)
|
||||
{
|
||||
json::object review_data = review_data_pre.as_object();
|
||||
product_info::review going_in;
|
||||
going_in.rating = double(review_data["rating"]);
|
||||
going_in.user = review_data["user"].string.value();
|
||||
going_in.review_text = review_data["review_text"].string.value();
|
||||
this_product.reviews.push_back(going_in);
|
||||
}
|
||||
|
||||
return this_product;
|
||||
}
|
||||
|
||||
json::value pinfo_tojson(product_info input)
|
||||
{
|
||||
json::value product_info::serialize() const {
|
||||
json::object root;
|
||||
root["category"] = json::string(input.category);
|
||||
root["manufacturer"] = json::string(input.manufacturer);
|
||||
root["is_available"] = input.is_available;
|
||||
//root.add("category", input.category);
|
||||
root += {"description", input.description};
|
||||
root["name"] = input.name;
|
||||
root += {"category", this->category};
|
||||
root += {"manufacturer", this->manufacturer};
|
||||
root += {"is_available", this->is_available};
|
||||
root += {"description", this->description};
|
||||
root += {"name", this->name};
|
||||
|
||||
auto root_review_list = json::array();
|
||||
for (auto& rev : input.reviews) {
|
||||
auto review = json::object();
|
||||
for (auto& rev : this->reviews) {
|
||||
auto review = rev.serialize();
|
||||
|
||||
review["rating"] = double(rev.rating);
|
||||
review["review_text"] = rev.review_text;
|
||||
review["user"] = rev.user;
|
||||
|
||||
root_review_list += review;
|
||||
}
|
||||
root += {"reviews", root_review_list};
|
||||
root["reviews"] = root_review_list;
|
||||
root["taters"] = 5.0;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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"]);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
json::value product_info::review::serialize() const {
|
||||
json::object obj = json::object();
|
||||
obj["rating"] = json::number(rating);
|
||||
obj["review_text"] = json::string(review_text);
|
||||
obj["user"] = json::string(user);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void test_product_info()
|
||||
{
|
||||
parse_json_file("../samples/product_info.json");
|
||||
std::cout << "Testing parsing of product_info file." << std::endl;
|
||||
//parse_json_file("../samples/product_info.json");
|
||||
auto file_contents = read_file("../samples/product_info.json");
|
||||
|
||||
auto [text, err] = json::parse(file_contents);
|
||||
|
||||
product_info test = pinfo_fromjson(text);
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = pinfo_tojson(test);
|
||||
std::cout << "Testing deserialization of product_info json." << std::endl;
|
||||
// Construct from json object.
|
||||
product_info test(text);
|
||||
|
||||
std::cout << "Testing serialization of product_info struct." << std::endl;
|
||||
|
||||
json::value result = test.serialize();
|
||||
|
||||
result.convert_descendants();
|
||||
std::cout << json::deparse(result);
|
||||
}
|
||||
|
||||
void test_tile_data() {
|
||||
parse_json_file("../samples/tiles.json");
|
||||
//parse_json_file("../samples/tiles.json");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Some progress has been made on small scale.
|
||||
int main(int argc, char* argv[]) {
|
||||
test_product_info();
|
||||
test_tile_data();
|
||||
}
|
||||
|
19
src/JSON.cpp
19
src/JSON.cpp
@@ -486,10 +486,10 @@ namespace JJX::json {
|
||||
switch(token.type) {
|
||||
case token_type::number: {
|
||||
double n = std::stod(token.value);
|
||||
return {json::value(n), index + 1, ""};
|
||||
return {json::number(n), index + 1, ""};
|
||||
}
|
||||
case token_type::boolean:
|
||||
return {json::value(token.value == "true"), index + 1, ""};
|
||||
return {json::boolean(token.value == "true"), index + 1, ""};
|
||||
case token_type::null:
|
||||
return {json::value(), index+1, ""};
|
||||
case token_type::string:
|
||||
@@ -644,21 +644,6 @@ namespace JJX::json {
|
||||
return *this;
|
||||
}
|
||||
|
||||
json::object & object::operator+=(const std::pair<std::string, bool> &kvp) {
|
||||
insert({kvp.first, json::boolean(kvp.second)});
|
||||
return *this;
|
||||
}
|
||||
|
||||
json::object & object::operator+=(const std::pair<std::string, double> &kvp) {
|
||||
insert({kvp.first, json::number(kvp.second)});
|
||||
return *this;
|
||||
}
|
||||
|
||||
json::object & object::operator+=(const std::pair<std::string, std::string> &kvp) {
|
||||
insert({kvp.first, json::string(kvp.second)});
|
||||
return *this;
|
||||
}
|
||||
|
||||
value &object::at(const std::string &key) {
|
||||
return this->value::object.value()[key];
|
||||
}
|
||||
|
Reference in New Issue
Block a user