Sygaldry
Loading...
Searching...
No Matches
sygbp-rapid_json.hpp
1#pragma once
2/*
3Copyright 2023 Travis J. West, https://traviswest.ca, Input Devices and Music Interaction Laboratory
4(IDMIL), Centre for Interdisciplinary Research in Music Media and Technology
5(CIRMMT), McGill University, Montréal, Canada, and Univ. Lille, Inria, CNRS,
6Centrale Lille, UMR 9189 CRIStAL, F-59000 Lille, France
7
8SPDX-License-Identifier: MIT
9*/
10
11
12#include <rapidjson/document.h>
13#include "sygac-endpoints.hpp"
14#include "sygac-components.hpp"
15#include "sygah-metadata.hpp"
16#include "sygbp-osc_string_constants.hpp"
17#include "sygbp-session_data.hpp"
18
19namespace sygaldry { namespace sygbp {
24
25template<typename IStream, typename OStream, typename Components>
27{
28 rapidjson::Document json{};
29
31 template<typename T>
32 static void apply_with_json_member_value(auto& json, auto&& f)
33 {
34 if (not json.HasMember(osc_path_v<T, Components>)) return;
35 auto& m = json[osc_path_v<T, Components>];
36 if constexpr (has_value<T>)
37 {
38 if constexpr (std::integral<value_t<T>>)
39 {
40 if constexpr (std::is_signed_v<value_t<T>>)
41 {
42 if (m.IsInt()) f(m.GetInt());
43 else if (m.IsInt64()) f(m.GetInt64());
44 } else
45 {
46 if (m.IsUint()) f(m.GetUint());
47 else if (m.IsUint64()) f(m.GetUint64());
48 }
49 } else if constexpr (std::floating_point<value_t<T>>)
50 {
51 if (m.IsDouble()) f(static_cast<value_t<T>>(m.GetDouble()));
52 } else if constexpr (string_like<value_t<T>>)
53 {
54 if (m.IsString()) f(m.GetString());
55 } else if constexpr (array_like<value_t<T>>)
56 {
57 if (!m.IsArray() || m.Empty() || m.Size() != size<value_t<T>>()) return;
58 if constexpr (std::integral<element_t<T>>)
59 {
60 if (m[0].IsInt())
61 f(m, [](auto& arr, auto idx) { return arr[idx].GetInt(); });
62 else if (m[0].IsInt64())
63 f(m, [](auto& arr, auto idx) { return arr[idx].GetInt64(); });
64 } else if constexpr (std::floating_point<element_t<T>>)
65 {
66 if (m[0].IsDouble())
67 f(m, [](auto& arr, auto idx) { return arr[idx].GetDouble(); });
68 } else if constexpr (string_like<element_t<T>>)
69 {
70 if (m[0].IsString())
71 f(m, [](auto& arr, auto idx) { return arr[idx].GetString(); });
72 }
73 }
74 }
75 }
76
77 void init(IStream& istream, Components& components)
78 {
79 json.ParseStream(istream);
80 if (not json.IsObject())
81 {
82 json.SetObject();
83 return;
84 }
85 for_each_session_datum(components, [&]<typename T>(T& endpoint)
86 {
87 if constexpr (array_like<value_t<T>>)
88 apply_with_json_member_value<T>(json, [&](auto& arr, auto&& get)
89 {
90 for (std::size_t i = 0; i < size<value_t<T>>(); ++i)
91 value_of(endpoint)[i] = get(arr, i);
92 });
93 else apply_with_json_member_value<T>(json, [&](auto value)
94 {
95 set_value(endpoint, value);
96 });
97
98 });
99 }
100
101 void external_destinations(Components& components)
102 {
103 bool updated = false;
104 for_each_session_datum(components, [&]<typename T>(T& endpoint)
105 {
106 if constexpr (has_value<T>)
107 {
108 if (not json.HasMember(osc_path_v<T, Components>))
109 {
110 if constexpr (string_like<value_t<T>>)
111 {
112 rapidjson::Value v{value_of(endpoint).c_str(), json.GetAllocator()};
113 json.AddMember(rapidjson::GenericStringRef{osc_path_v<T, Components>}, v, json.GetAllocator());
114 }
115 else if constexpr (array_like<value_t<T>>)
116 {
117 rapidjson::Value v{rapidjson::kArrayType};
118 v.Reserve(3, json.GetAllocator());
119 for (auto& element : value_of(endpoint)) v.PushBack(rapidjson::Value{element}, json.GetAllocator());
120 json.AddMember(rapidjson::GenericStringRef{osc_path_v<T, Components>}, v, json.GetAllocator());
121 }
122 else
123 {
124 json.AddMember(rapidjson::GenericStringRef{osc_path_v<T, Components>}, value_of(endpoint), json.GetAllocator());
125 }
126 updated = true;
127 }
128 else
129 {
130 bool endpoint_updated = false;
131 if constexpr (OccasionalValue<T>)
132 endpoint_updated = flag_state_of(endpoint);
133 else if constexpr (array_like<value_t<T>>)
134 apply_with_json_member_value<T>(json, [&](auto& arr, auto&& get)
135 {
136 for (std::size_t i = 0; i < size<value_t<T>>(); ++i)
137 endpoint_updated = endpoint_updated || (value_of(endpoint)[i] != get(arr, i));
138 });
139 else apply_with_json_member_value<T>(json, [&](auto value)
140 {
141 endpoint_updated = value != value_of(endpoint);
142 });
143 if (endpoint_updated)
144 {
145 if constexpr (string_like<value_t<T>>)
146 json[osc_path_v<T, Components>].SetString(value_of(endpoint).c_str(), json.GetAllocator());
147 else if constexpr (array_like<value_t<T>>)
148 {
149 auto& arr = json[osc_path_v<T, Components>];
150 for (std::size_t i = 0; i < size<value_t<T>>(); ++i)
151 {
152 arr[i] = value_of(endpoint)[i];
153 }
154 }
155 else json[osc_path_v<T, Components>] = value_of(endpoint);
156 updated = true;
157 }
158 }
159 }
160 });
161 if (updated)
162 {
163 OStream ostream{};
164 json.Accept(ostream.writer);
165 }
166 }
167};
168
171} }
Definition sygac-endpoints.hpp:166
Definition sygac-endpoints.hpp:121
Definition sygac-endpoints.hpp:161
Definition sygbp-rapid_json.hpp:27
static void apply_with_json_member_value(auto &json, auto &&f)
apply the functor f to the value of each member of the JSON object json extracted depending on the ty...
Definition sygbp-rapid_json.hpp:32