config/json.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief Configurations as JSON: parsing, loading, writing, catalog and schema. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/config/config.h" | ||
| 6 | |||
| 7 | #include <filesystem> | ||
| 8 | #include <stdexcept> | ||
| 9 | #include <string> | ||
| 10 | #include <string_view> | ||
| 11 | |||
| 12 | namespace terraingen { | ||
| 13 | |||
| 14 | /// A problem with a configuration, located by the JSON path of the offending value, such as | ||
| 15 | /// "layers[1].density.age_gyr" or "layers[0].stack[1].octaves". | ||
| 16 | class ConfigError : public std::runtime_error { | ||
| 17 | public: | ||
| 18 | /// An error at a path; the message is "path: message", or the message alone at the root. | ||
| 19 | /// @param path The JSON path of the value; empty for the document as a whole. | ||
| 20 | ConfigError(std::string path, const std::string& message); | ||
| 21 | |||
| 22 | /// The JSON path of the value; empty for the document as a whole. | ||
| 23 | 226 | const std::string& Path() const { | |
| 24 | 226 | return path_; | |
| 25 | } | ||
| 26 | |||
| 27 | private: | ||
| 28 | std::string path_; | ||
| 29 | }; | ||
| 30 | |||
| 31 | /// Reads a configuration from JSON text. | ||
| 32 | /// | ||
| 33 | /// {"schema_version": 1, | ||
| 34 | /// "layers": [{"type": "noise", "stack": [{"wavelength": 500, "amplitude": 50}]}, | ||
| 35 | /// {"type": "craters", | ||
| 36 | /// "density": {"type": "production_surface", "age_gyr": 3.5}, | ||
| 37 | /// "rim_smoothing": {"sigma_radii": 0.05}}], | ||
| 38 | /// "outputs": [{"type": "heightmap", "path": "terrain.tif", | ||
| 39 | /// "region": {"width": 513, "height": 513, "pixel_size": 2}}]} | ||
| 40 | /// | ||
| 41 | /// Keys are snake_case versions of the C++ fields; bodies, bases, layers, outputs and models are | ||
| 42 | /// objects with a "type". Omitted keys take their defaults and omitted lists are empty. | ||
| 43 | /// @throws ConfigError for malformed JSON, a missing or unsupported "schema_version", an unknown | ||
| 44 | /// key, or a value of the wrong type. | ||
| 45 | TerrainConfig ParseConfig(std::string_view json); | ||
| 46 | |||
| 47 | /// `ParseConfig` on the contents of a file. | ||
| 48 | /// @throws ConfigError as `ParseConfig`, or when the file cannot be read. | ||
| 49 | TerrainConfig LoadConfig(const std::filesystem::path& path); | ||
| 50 | |||
| 51 | /// A configuration as JSON with every value written out but an unset base and albedo; parsing it | ||
| 52 | /// gives back an equal configuration. | ||
| 53 | std::string ConfigToJson(const TerrainConfig& config, int indent = 2); | ||
| 54 | |||
| 55 | /// A reference of every configuration type with its defaults, as JSON. | ||
| 56 | /// | ||
| 57 | /// The lists "body", "base", "layers" and "outputs" hold each type of their kind, | ||
| 58 | /// "albedo" the albedo, and "models" one noise layer and every density, ages, degradation, | ||
| 59 | /// profile, boulder size, region shape, albedo source and albedo layer type. Each entry parses | ||
| 60 | /// where its kind belongs in a configuration. | ||
| 61 | std::string ConfigCatalog(int indent = 2); | ||
| 62 | |||
| 63 | /// The structure of a configuration as JSON, for editors: what each field holds and its | ||
| 64 | /// default, from the same field lists the parser reads. | ||
| 65 | /// | ||
| 66 | /// The document has "schema_version", "root" (the configuration object) and "definitions", each | ||
| 67 | /// struct and choice described once by id ("d0", "d1", ...) and referred to as | ||
| 68 | /// {"kind": "ref", "ref": id}. A schema has a "kind": | ||
| 69 | /// - "number", "integer" ("minimum" 0 for counts, "fixed" for the schema version), "boolean", | ||
| 70 | /// "string"; | ||
| 71 | /// - "enum" with its "choices" and their "descriptions"; | ||
| 72 | /// - "optional" and "array" with the schema "of" what they hold and that thing's "default"; | ||
| 73 | /// - "object" with its "fields", each {"name", "description", "unit", "schema", "default"}, and for | ||
| 74 | /// a bounded number (or each number of a list) "minimum" and "exclusive_minimum", "maximum" | ||
| 75 | /// and "exclusive_maximum"; | ||
| 76 | /// - "choice" with its "alternatives", each {"type", "description", "fields", "default"}. | ||
| 77 | std::string ConfigSchema(int indent = 2); | ||
| 78 | |||
| 79 | /// A layer's JSON "type", with the type of the layer inside for a region: "region (boulders)". | ||
| 80 | std::string LayerType(const LayerSpec& layer); | ||
| 81 | |||
| 82 | } // namespace terraingen | ||
| 83 |