- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
67 lines
2.1 KiB
C++
67 lines
2.1 KiB
C++
/*
|
|
* Copyright 2025 Axel Waggershauser
|
|
*/
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#pragma once
|
|
|
|
#include "ZXAlgorithms.h"
|
|
|
|
#include <cstring>
|
|
#ifdef __cpp_lib_format // not available on gcc 12
|
|
#include <format>
|
|
#endif
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
namespace ZXing {
|
|
|
|
std::string JsonEscapeStr(std::string_view str);
|
|
std::string JsonUnEscapeStr(std::string_view str);
|
|
|
|
template<typename T>
|
|
inline std::string JsonProp(std::string_view key, const T& val, const T& ignore = {})
|
|
{
|
|
#define ZX_JSON_KEY_VAL(...) StrCat("\"", key, "\":", __VA_ARGS__, ',')
|
|
#if !defined(__cpp_lib_to_chars) || !defined(__cpp_lib_format) // not available on older macOS / gcc 12
|
|
#define ZX_JSON_FMT_FLOAT(val) (std::to_string(int(val)) + '.' + std::to_string(int(val * 100) % 100))
|
|
#else
|
|
#define ZX_JSON_FMT_FLOAT(val) std::format("{:.2f}", val)
|
|
#endif
|
|
|
|
if constexpr (std::is_same_v<T, bool>)
|
|
return val != ignore ? ZX_JSON_KEY_VAL(val ? "true" : "false") : "";
|
|
else if constexpr (std::is_floating_point_v<T>)
|
|
return val != ignore ? ZX_JSON_KEY_VAL(ZX_JSON_FMT_FLOAT(val)) : "";
|
|
else if constexpr (std::is_integral_v<T>)
|
|
return val != ignore ? ZX_JSON_KEY_VAL(std::to_string(val)) : "";
|
|
else if constexpr (std::is_convertible_v<T, std::string_view>)
|
|
return std::string_view(val) != std::string_view(ignore) ? ZX_JSON_KEY_VAL("\"", JsonEscapeStr(val), "\"") : "";
|
|
else
|
|
static_assert("unsupported JSON value type");
|
|
#undef ZX_JSON_KEY_VAL
|
|
}
|
|
|
|
// Finds the (potentially escaped / raw) value of the provided key
|
|
std::string_view JsonFind(std::string_view json, std::string_view key);
|
|
|
|
template <typename T>
|
|
inline std::optional<T> JsonGet(std::string_view json, std::string_view key)
|
|
{
|
|
auto str = JsonFind(json, key);
|
|
if (!str.data())
|
|
return std::nullopt;
|
|
|
|
if constexpr (std::is_same_v<bool, T>)
|
|
return str.empty() || Contains("1tT", str.front()) ? std::optional(true) : std::nullopt;
|
|
else if constexpr (std::is_arithmetic_v<T>)
|
|
return str.empty() ? std::nullopt : std::optional(FromString<T>(str));
|
|
else if constexpr (std::is_same_v<std::string, T>)
|
|
return JsonUnEscapeStr(str);
|
|
else
|
|
static_assert("unsupported JSON value type");
|
|
}
|
|
|
|
} // ZXing
|