Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
serialization.h
1// SPDX-FileCopyrightText: © 2024-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <memory>
7#include <string>
8
9#include "utils/exceptions.h"
10#include "utils/qt.h"
11#include "utils/traits.h"
12#include "utils/types.h"
13
14#include <QUuid>
15
16#include <au/au.hh>
17#include <boost/unordered/concurrent_flat_map_fwd.hpp>
18#include <nlohmann/json.hpp>
19
21
22inline void
23to_json (nlohmann::json &j, const QString &s)
24{
25 j = s.toStdString ();
26}
27inline void
28from_json (const nlohmann::json &j, QString &s)
29{
30 s = QString::fromUtf8 (j.get<std::string> ());
31}
32
33inline void
34to_json (nlohmann::json &j, const QUuid &uuid)
35{
36 j = uuid.toString (QUuid::WithoutBraces);
37}
38inline void
39from_json (const nlohmann::json &j, QUuid &uuid)
40{
41 uuid = QUuid::fromString (j.get<QString> ());
42}
43
44namespace zrythm::utils::serialization
45{
46
47static constexpr auto kFormatMajorKey = "formatMajor"sv;
48static constexpr auto kFormatMinorKey = "formatMinor"sv;
49static constexpr auto kDocumentTypeKey = "documentType"sv;
50static constexpr auto kVariantIndexKey = "index"sv;
51static constexpr auto kVariantValueKey = "value"sv;
52
63template <StdVariant Variant, ObjectBuilder BuilderT>
64inline auto
65variant_from_json_with_builder (
66 const nlohmann::json &j,
67 Variant &var,
68 const BuilderT &builder)
69{
70 const auto index =
71 j.at (zrythm::utils::serialization::kVariantIndexKey).get<int> ();
72 auto creator = [&]<size_t... I> (std::index_sequence<I...>) {
73 Variant result{};
74
75 auto create_type_if_current_index = [&]<size_t N> () {
76 using Type = std::variant_alternative_t<N, Variant>;
77 using StrippedType = std::remove_pointer_t<Type>;
78 if (N == index)
79 {
80 auto object_ptr = builder.template build<StrippedType> ();
81 if constexpr (std::is_pointer_v<Type>)
82 {
83 j.at (zrythm::utils::serialization::kVariantValueKey)
84 .get_to (*object_ptr);
85 result = object_ptr.release ();
86 }
87 else if constexpr (std::is_copy_constructible_v<Type>)
88 {
89 j.at (zrythm::utils::serialization::kVariantValueKey)
90 .get_to (*object_ptr);
91 result = *object_ptr;
92 }
93 else if constexpr (is_derived_from_template_v<QObjectUniquePtr, Type>)
94 {
95 Type t = std::move (*object_ptr);
96 j.at (zrythm::utils::serialization::kVariantValueKey).get_to (*t);
97 result = std::move (t);
98 }
99 else
100 {
101 DEBUG_TEMPLATE_PARAM (Type)
102 static_assert (
103 false,
104 "Only variant of pointers or copy-constructible types is currently supported");
105 }
106 }
107 };
108
109 (create_type_if_current_index.template operator()<I> (), ...);
110
111 return result;
112 };
113
114 var = creator (std::make_index_sequence<std::variant_size_v<Variant>>{});
115}
116
117}; // namespace zrythm::utils::serialization
118
119namespace nlohmann
120{
122template <typename T> struct adl_serializer<T *>
123{
124 static void to_json (json &j, const T * ptr)
125 {
126 if (ptr)
127 j = *ptr;
128 else
129 j = nullptr;
130 }
131 // from_json would be unsafe due to raw memory allocation, so handle each case
132 // manually in each type
133};
134
136template <typename... Args> struct adl_serializer<std::variant<Args...>>
137{
138 static void to_json (json &j, std::variant<Args...> const &v)
139 {
140 std::visit (
141 [&] (auto &&value) {
142 j[zrythm::utils::serialization::kVariantIndexKey] = v.index ();
143 j[zrythm::utils::serialization::kVariantValueKey] =
144 std::forward<decltype (value)> (value);
145 },
146 v);
147 }
148};
149
151template <typename T> struct adl_serializer<std::unique_ptr<T>>
152{
153 static void to_json (json &json_value, const std::unique_ptr<T> &ptr)
154 {
155 if (ptr.get ())
156 {
157 json_value = *ptr;
158 }
159 else
160 {
161 json_value = nullptr;
162 }
163 }
164 static void from_json (const json &json_value, std::unique_ptr<T> &ptr)
165 requires std::is_default_constructible_v<T>
166 {
167 ptr = std::make_unique<T> ();
168 json_value.get_to (*ptr);
169 }
170};
171
173template <typename T> struct adl_serializer<std::shared_ptr<T>>
174{
175 static void to_json (json &json_value, const std::shared_ptr<T> &ptr)
176 {
177 if (ptr.get ())
178 {
179 json_value = *ptr;
180 }
181 else
182 {
183 json_value = nullptr;
184 }
185 }
186 static void from_json (const json &json_value, std::shared_ptr<T> &ptr)
187 requires std::is_default_constructible_v<T>
188 {
189 ptr = std::make_shared<T> ();
190 json_value.get_to (*ptr);
191 }
192};
193
195template <typename T> struct adl_serializer<zrythm::utils::QObjectUniquePtr<T>>
196{
197 static void
198 to_json (json &json_value, const zrythm::utils::QObjectUniquePtr<T> &ptr)
199 {
200 if (ptr.get ())
201 {
202 json_value = *ptr;
203 }
204 else
205 {
206 json_value = nullptr;
207 }
208 }
209 static void
210 from_json (const json &json_value, zrythm::utils::QObjectUniquePtr<T> &ptr)
211 requires std::is_default_constructible_v<T>
212 {
213 ptr = new T ();
214 json_value.get_to (*ptr);
215 }
216};
217
219template <StrongTypedef T> struct adl_serializer<T>
220{
221 static void to_json (json &json_value, const T &strong_type)
222 {
223 json_value = type_safe::get (strong_type);
224 }
225 static void from_json (const json &json_value, T &strong_type)
226 {
227 json_value.get_to (type_safe::get (strong_type));
228 }
229};
230
231template <typename Key, typename T>
232struct adl_serializer<boost::unordered::concurrent_flat_map<Key, T>>
233{
234 using ConcurrentHashMap = boost::unordered::concurrent_flat_map<Key, T>;
235 // convert to std::map since nlohmann::json knows how to serialize it
236 static void to_json (json &j, const ConcurrentHashMap &map)
237 {
238 std::map<Key, T> temp;
239 map.visit_all ([&temp] (const auto &kv) {
240 temp.emplace (kv.first, kv.second);
241 });
242 j = temp;
243 }
244
245 static void from_json (const json &j, ConcurrentHashMap &map)
246 {
247 auto temp = j.get<std::map<Key, T>> (); // Deserialize to std::map first
248 map.clear ();
249 for (const auto &kv : temp)
250 {
251 map.emplace (kv.first, kv.second);
252 }
253 }
254};
255
257template <typename Unit, typename Rep>
258struct adl_serializer<au::Quantity<Unit, Rep>>
259{
260 static void to_json (json &j, const au::Quantity<Unit, Rep> &quantity)
261 {
262 j = quantity.in (Unit{});
263 }
264
265 static void from_json (const json &j, au::Quantity<Unit, Rep> &quantity)
266 {
267 Rep raw_value;
268 j.get_to (raw_value);
269 quantity = au::QuantityMaker<Unit>{}(raw_value);
270 }
271};
272
273} // namespace nlohmann
A unique pointer for QObject objects that also works with QObject-based ownership.
Definition qt.h:38
Base class for exceptions in Zrythm.
Definition exceptions.h:20