Smarter integer type handing in json_val

This commit is contained in:
Kovid Goyal 2023-01-25 11:04:43 +05:30
parent ecc3e96da8
commit aa11af3510
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -170,11 +170,12 @@ serialize_float(std::ostream &out, T val, std::chars_format fmt = std::chars_for
class json_val { // {{{ class json_val { // {{{
private: private:
enum { DT_INT, DT_STRING, DT_LIST, DT_OBJECT, DT_NONE, DT_BOOL, DT_FLOAT } type; enum { DT_INT, DT_UINT, DT_STRING, DT_LIST, DT_OBJECT, DT_NONE, DT_BOOL, DT_FLOAT } type;
std::string s; std::string s;
bool b; bool b;
double f; double f;
int64_t i; int64_t i;
uint64_t u;
std::vector<json_val> list; std::vector<json_val> list;
std::map<std::string, json_val> object; std::map<std::string, json_val> object;
@ -187,6 +188,9 @@ private:
case DT_INT: case DT_INT:
// this is not really correct since JS has various limits on numeric types, but good enough for us // this is not really correct since JS has various limits on numeric types, but good enough for us
serialize_integer(out, i); break; serialize_integer(out, i); break;
case DT_UINT:
// this is not really correct since JS has various limits on numeric types, but good enough for us
serialize_integer(out, u); break;
case DT_FLOAT: case DT_FLOAT:
// again not technically correct // again not technically correct
serialize_float(out, f); break; serialize_float(out, f); break;
@ -230,10 +234,6 @@ public:
json_val(std::map<std::string, json_val> &&m) : type(DT_OBJECT), object(m) {} json_val(std::map<std::string, json_val> &&m) : type(DT_OBJECT), object(m) {}
json_val(std::initializer_list<std::pair<const std::string, json_val>> const& vals) : type(DT_OBJECT), object(vals) { } json_val(std::initializer_list<std::pair<const std::string, json_val>> const& vals) : type(DT_OBJECT), object(vals) { }
static json_val from_bool(bool x) { json_val ans; ans.type = DT_BOOL; ans.b = x; return ans; }
static json_val from_double(double x) { json_val ans; ans.type = DT_FLOAT; ans.f = x; return ans; }
static json_val from_integer(int64_t x) { json_val ans; ans.type = DT_INT; ans.i = x; return ans; }
static json_val from_hresult(HRESULT hr) { static json_val from_hresult(HRESULT hr) {
json_val ans; ans.type = DT_STRING; json_val ans; ans.type = DT_STRING;
std::array<char, 16> str; std::array<char, 16> str;
@ -300,11 +300,30 @@ public:
{"type", json_val(label)}, {"type", json_val(label)},
{"text", json_val(cue.Text())}, {"text", json_val(cue.Text())},
{"start_time", json_val(cue.StartTime())}, {"start_time", json_val(cue.StartTime())},
{"start_pos_in_text", json_val::from_integer(cue.StartPositionInInput().Value())}, {"start_pos_in_text", json_val(cue.StartPositionInInput().Value())},
{"end_pos_in_text", json_val::from_integer(cue.EndPositionInInput().Value())}, {"end_pos_in_text", json_val(cue.EndPositionInInput().Value())},
}; };
} }
template<typename T> json_val(T x) {
static_assert(sizeof(bool) < sizeof(int16_t), "The bool type on this machine is more than one byte");
if constexpr (std::is_same_v<T, int64_t> || std::is_same_v<T, int32_t> || std::is_same_v<T, int16_t>) {
type = DT_INT;
i = x;
} else if constexpr (std::is_same_v<T, uint64_t> || std::is_same_v<T, uint32_t> || std::is_same_v<T, uint16_t>) {
type = DT_UINT;
u = x;
} else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>) {
type = DT_FLOAT;
f = x;
} else if constexpr (std::is_same_v<T, bool>) {
type = DT_BOOL;
b = x;
} else {
static_assert(false, "Unknown type T cannot be converted to JSON");
}
}
friend std::ostream& operator<<(std::ostream &os, const json_val &self) { friend std::ostream& operator<<(std::ostream &os, const json_val &self) {
self.serialize(os); self.serialize(os);
return os; return os;
@ -322,7 +341,7 @@ output(id_type cmd_id, std::string_view const &msg_type, json_val const &&msg) {
static void static void
output_error(id_type cmd_id, std::string_view const &msg, std::string_view const &error, int64_t line, HRESULT hr=S_OK) { output_error(id_type cmd_id, std::string_view const &msg, std::string_view const &error, int64_t line, HRESULT hr=S_OK) {
std::map<std::string, json_val> m = {{"msg", json_val(msg)}, {"error", json_val(error)}, {"file", json_val("winspeech.cpp")}, {"line", json_val::from_integer(line)}}; std::map<std::string, json_val> m = {{"msg", json_val(msg)}, {"error", json_val(error)}, {"file", json_val("winspeech.cpp")}, {"line", json_val(line)}};
if (hr != S_OK) m["hr"] = json_val::from_hresult(hr); if (hr != S_OK) m["hr"] = json_val::from_hresult(hr);
output(cmd_id, "error", std::move(m)); output(cmd_id, "error", std::move(m));
} }
@ -833,7 +852,7 @@ class Synthesizer {
stop_current_activity(); stop_current_activity();
current_cmd_id.store(cmd_id); current_cmd_id.store(cmd_id);
} }
output(cmd_id, "synthesizing", {{"ssml", json_val::from_bool(is_ssml)}}); output(cmd_id, "synthesizing", {{"ssml", json_val(is_ssml)}});
bool ok = false; bool ok = false;
try { try {
if (is_ssml) stream = co_await synth.SynthesizeSsmlToStreamAsync(text); if (is_ssml) stream = co_await synth.SynthesizeSsmlToStreamAsync(text);
@ -934,7 +953,7 @@ handle_stdin_message(winrt::hstring const &&msg) {
auto vol = parse_double(parts[0].data()); auto vol = parse_double(parts[0].data());
sx.volume(vol); sx.volume(vol);
} }
output(cmd_id, "volume", {{"value", json_val::from_double(sx.volume())}}); output(cmd_id, "volume", {{"value", json_val(sx.volume())}});
} }
else throw std::string("Unknown command: ") + winrt::to_string(command); else throw std::string("Unknown command: ") + winrt::to_string(command);
} CATCH_ALL_EXCEPTIONS("Error handling input message", cmd_id); } CATCH_ALL_EXCEPTIONS("Error handling input message", cmd_id);