master
h 188 lines 4.09 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 JsonUtils.h
8
9 Abstract:
10
11 This file contains various JSON helper methods.
12
13 --*/
14
15 #pragma once
16
17 #include <nlohmann/json.hpp>
18 #include "stringshared.h"
19
20 #ifdef WIN32
21 #include "wslservice.h"
22 #include "ExecutionContext.h"
23 #include "wslc.h"
24 #endif
25
26 #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_FROM_ONLY(Type, ...) \
27 inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) \
28 { \
29 const Type nlohmann_json_default_obj{}; \
30 NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) \
31 }
32
33 namespace wsl::shared {
34
35 constexpr int c_jsonPrettyPrintIndent = 2;
36
37 // A negative indent makes nlohmann::json::dump() emit the document on a single line.
38 constexpr int c_jsonCompactIndent = -1;
39
40 struct EmptyObject
41 {
42 };
43
44 inline void to_json(nlohmann::json& j, const EmptyObject&)
45 {
46 j = nlohmann::json::object();
47 }
48
49 inline void from_json(const nlohmann::json&, EmptyObject&)
50 {
51 }
52
53 template <typename T>
54 std::string ToJson(const T& Value, int indent = -1)
55 {
56 return nlohmann::json(Value).dump(indent);
57 }
58
59 template <typename T>
60 std::wstring ToJsonW(const T& Value, int indent = -1)
61 {
62 return wsl::shared::string::MultiByteToWide(ToJson(Value, indent));
63 }
64
65 template <typename T, typename TJson = nlohmann::json>
66 T FromJson(const char* Value)
67 {
68 try
69 {
70 auto json = TJson::parse(Value);
71 T object{};
72 from_json(json, object);
73
74 return object;
75 }
76 catch (const TJson::exception& e)
77 {
78
79 #ifdef WIN32
80
81 THROW_HR_WITH_USER_ERROR_MSG(
82 WSL_E_INVALID_JSON, wsl::shared::Localization::MessageInvalidJson(e.what()), "Invalid JSON: %hs", Value);
83
84 #else
85 LOG_ERROR("Failed to deserialize json: '{}'. Error: {}", Value, e.what());
86 THROW_ERRNO(EINVAL);
87
88 #endif
89 }
90 }
91
92 template <typename T, typename TJson = nlohmann::json>
93 T FromJson(const wchar_t* Value)
94 {
95 return FromJson<T, TJson>(wsl::shared::string::WideToMultiByte(Value).c_str());
96 }
97
98 template <typename T>
99 std::string JsonEnumToString(T value)
100 {
101 nlohmann::json json;
102 to_json(json, value);
103
104 return json.get<std::string>();
105 }
106 } // namespace wsl::shared
107
108 namespace nlohmann {
109
110 template <>
111 struct adl_serializer<std::wstring>
112 {
113 static void to_json(json& j, const std::wstring& str)
114 {
115 j = wsl::shared::string::WideToMultiByte(str);
116 }
117
118 static void from_json(const json& j, std::wstring& str)
119 {
120 str = wsl::shared::string::MultiByteToWide(j.get<std::string>());
121 }
122 };
123
124 template <typename T>
125 struct adl_serializer<std::optional<T>>
126 {
127 static void to_json(json& j, const std::optional<T>& input)
128 {
129 if (input.has_value())
130 {
131 j = input.value();
132 }
133 else
134 {
135 j = nullptr;
136 }
137 }
138
139 static void from_json(const json& j, std::optional<T>& input)
140 {
141 if (!j.is_null())
142 {
143 input.emplace(); // Assumes that object is default constructible.
144 adl_serializer<T>::from_json(j, input.value());
145 }
146 }
147 };
148
149 template <>
150 struct adl_serializer<GUID>
151 {
152 static void to_json(json& j, const GUID& input)
153 {
154 j = wsl::shared::string::GuidToString<char>(input, wsl::shared::string::GuidToStringFlags::None);
155 }
156
157 static void from_json(const json& j, GUID& output)
158 {
159 const auto parsed = wsl::shared::string::ToGuid(j.get<std::string>());
160 if (parsed.has_value())
161 {
162 output = parsed.value();
163 }
164 }
165 };
166
167 template <>
168 struct adl_serializer<wsl::shared::string::MacAddress>
169 {
170 static void to_json(json& j, const wsl::shared::string::MacAddress& input)
171 {
172 j = wsl::shared::string::FormatMacAddress(input, '-');
173 }
174
175 static void from_json(const json& j, wsl::shared::string::MacAddress& output)
176 {
177 if (j.is_string())
178 {
179 auto parsed = wsl::shared::string::ParseMacAddressNoThrow(j.get<std::string>());
180 if (parsed.has_value())
181 {
182 output = std::move(parsed.value());
183 }
184 }
185 }
186 };
187
188 } // namespace nlohmann