更新接口
This commit is contained in:
@@ -289,15 +289,15 @@ int main() {
|
||||
const auto inherited = adminive::to_descriptor_json<Json, Inherited_Config>();
|
||||
assert(inherited.at("fields").at(0).at("name") == "alpha");
|
||||
assert(inherited.at("fields").at(1).at("name") == "beta");
|
||||
adminive::Synchronized_Value<Inherited_Config> synchronized_inherited;
|
||||
synchronized_inherited.field<0>().write([](int& value) {
|
||||
adminive::Managed_Value<Inherited_Config> managed_inherited;
|
||||
managed_inherited.field<0>().write([](int& value) {
|
||||
value = 12;
|
||||
});
|
||||
synchronized_inherited.field<1>().write([](std::string& value) {
|
||||
managed_inherited.field<1>().write([](std::string& value) {
|
||||
value = "changed";
|
||||
});
|
||||
assert(synchronized_inherited.field<0>().snapshot() == 12);
|
||||
assert(synchronized_inherited.field<1>().snapshot() == "changed");
|
||||
assert(managed_inherited.field<0>().snapshot() == 12);
|
||||
assert(managed_inherited.field<1>().snapshot() == "changed");
|
||||
Control_Config controls;
|
||||
const auto control_form = adminive::to_amis_form_schema<Json>(controls);
|
||||
assert(control_form.at("body").at(0).at("type") == "input-color");
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
#include "adminive/adapters/nlohmann_json.hpp"
|
||||
#include "adminive/http.hpp"
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
namespace managed_test {
|
||||
using Json = nlohmann::json;
|
||||
struct Section_Config {
|
||||
int editable_value{1};
|
||||
int immutable_value{2};
|
||||
int backend_value{3};
|
||||
int unsynchronized_value{4};
|
||||
};
|
||||
struct Root_Config {
|
||||
Section_Config section;
|
||||
int immutable_value{5};
|
||||
};
|
||||
struct Concurrent_Config {
|
||||
int first{};
|
||||
int second{};
|
||||
int immutable_value{7};
|
||||
};
|
||||
struct Probe_Lock {
|
||||
static inline std::atomic<int> exclusive_locks{};
|
||||
static inline std::atomic<int> shared_locks{};
|
||||
void lock() noexcept {
|
||||
exclusive_locks.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
void unlock() noexcept {}
|
||||
void lock_shared() noexcept {
|
||||
shared_locks.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
void unlock_shared() noexcept {}
|
||||
static void reset() noexcept {
|
||||
exclusive_locks.store(0, std::memory_order_relaxed);
|
||||
shared_locks.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
};
|
||||
template <class Field>
|
||||
concept Writable_Field = requires(Field field) {
|
||||
field.write([](auto& value) {
|
||||
++value;
|
||||
});
|
||||
};
|
||||
template <class Field>
|
||||
concept Reference_Escaping_Read = requires(Field field) {
|
||||
field.read([](const auto& value) -> const auto& {
|
||||
return value;
|
||||
});
|
||||
};
|
||||
}
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<managed_test::Section_Config> {
|
||||
static auto get() {
|
||||
using T = managed_test::Section_Config;
|
||||
return object<T>("section", "Section", ADMINIVE_FIELD(T, editable_value).editable(), ADMINIVE_FIELD(T, immutable_value), ADMINIVE_FIELD(T, backend_value).read_write(), ADMINIVE_FIELD(T, unsynchronized_value).editable().unsynchronized());
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_Descriptor<managed_test::Root_Config> {
|
||||
static auto get() {
|
||||
using T = managed_test::Root_Config;
|
||||
return object<T>("root", "Root", ADMINIVE_FIELD(T, section), ADMINIVE_FIELD(T, immutable_value));
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_Descriptor<managed_test::Concurrent_Config> {
|
||||
static auto get() {
|
||||
using T = managed_test::Concurrent_Config;
|
||||
return object<T>("concurrent", "Concurrent", ADMINIVE_FIELD(T, first).editable(), ADMINIVE_FIELD(T, second).editable(), ADMINIVE_FIELD(T, immutable_value));
|
||||
}
|
||||
};
|
||||
}
|
||||
int main() {
|
||||
using namespace managed_test;
|
||||
using Guarded = adminive::Managed_Value<Section_Config, adminive::Mutex_Policy<Probe_Lock>>;
|
||||
Guarded guarded;
|
||||
auto immutable = guarded.member<&Section_Config::immutable_value>();
|
||||
auto editable = guarded.member<&Section_Config::editable_value>();
|
||||
auto backend = guarded.member<&Section_Config::backend_value>();
|
||||
auto unsynchronized = guarded.member<&Section_Config::unsynchronized_value>();
|
||||
static_assert(!Writable_Field<decltype(immutable)>);
|
||||
static_assert(Writable_Field<decltype(editable)>);
|
||||
static_assert(Writable_Field<decltype(backend)>);
|
||||
static_assert(Writable_Field<decltype(unsynchronized)>);
|
||||
static_assert(!Reference_Escaping_Read<decltype(immutable)>);
|
||||
const auto resolved = guarded.resolved_synchronization();
|
||||
assert(resolved.lock_count == 2);
|
||||
assert(resolved.slot(0) != structive::Resolved_Synchronization_View::unsynchronized_slot);
|
||||
assert(resolved.slot(1) == structive::Resolved_Synchronization_View::unsynchronized_slot);
|
||||
assert(resolved.slot(2) != structive::Resolved_Synchronization_View::unsynchronized_slot);
|
||||
assert(resolved.slot(0) != resolved.slot(2));
|
||||
assert(resolved.slot(3) == structive::Resolved_Synchronization_View::unsynchronized_slot);
|
||||
Probe_Lock::reset();
|
||||
assert(immutable.snapshot() == 2);
|
||||
assert(Probe_Lock::exclusive_locks.load(std::memory_order_relaxed) == 0);
|
||||
assert(Probe_Lock::shared_locks.load(std::memory_order_relaxed) == 0);
|
||||
Probe_Lock::reset();
|
||||
editable.write([](int& value) {
|
||||
value = 11;
|
||||
});
|
||||
assert(Probe_Lock::exclusive_locks.load(std::memory_order_relaxed) == 1);
|
||||
assert(Probe_Lock::shared_locks.load(std::memory_order_relaxed) == 0);
|
||||
Probe_Lock::reset();
|
||||
backend.write([](int& value) {
|
||||
value = 12;
|
||||
});
|
||||
assert(Probe_Lock::exclusive_locks.load(std::memory_order_relaxed) == 1);
|
||||
Probe_Lock::reset();
|
||||
unsynchronized.write([](int& value) {
|
||||
value = 13;
|
||||
});
|
||||
assert(Probe_Lock::exclusive_locks.load(std::memory_order_relaxed) == 0);
|
||||
assert(Probe_Lock::shared_locks.load(std::memory_order_relaxed) == 0);
|
||||
const auto descriptor = adminive::to_descriptor_json<Json, Section_Config>();
|
||||
assert(descriptor.at("protocol_version") == 4);
|
||||
assert(!descriptor.at("fields").at(0).contains("lock_mode"));
|
||||
assert(descriptor.at("fields").at(0).at("writable") == true);
|
||||
assert(descriptor.at("fields").at(0).at("synchronized") == true);
|
||||
assert(descriptor.at("fields").at(1).at("writable") == false);
|
||||
assert(descriptor.at("fields").at(1).at("synchronized") == false);
|
||||
assert(descriptor.at("fields").at(2).at("writable") == true);
|
||||
assert(descriptor.at("fields").at(2).at("editable") == false);
|
||||
assert(descriptor.at("fields").at(2).at("synchronized") == true);
|
||||
assert(descriptor.at("fields").at(3).at("writable") == true);
|
||||
assert(descriptor.at("fields").at(3).at("synchronized") == false);
|
||||
adminive::Managed_Value<Root_Config, adminive::Mutex_Policy<Probe_Lock>> nested;
|
||||
auto section = nested.member<&Root_Config::section>();
|
||||
static_assert(!Writable_Field<decltype(section)>);
|
||||
Probe_Lock::reset();
|
||||
assert(section.member<&Section_Config::immutable_value>().snapshot() == 2);
|
||||
assert(Probe_Lock::shared_locks.load(std::memory_order_relaxed) == 0);
|
||||
Probe_Lock::reset();
|
||||
section.member<&Section_Config::editable_value>().write([](int& value) {
|
||||
value = 31;
|
||||
});
|
||||
assert(Probe_Lock::exclusive_locks.load(std::memory_order_relaxed) == 1);
|
||||
Probe_Lock::reset();
|
||||
section.member<&Section_Config::unsynchronized_value>().write([](int& value) {
|
||||
value = 32;
|
||||
});
|
||||
assert(Probe_Lock::exclusive_locks.load(std::memory_order_relaxed) == 0);
|
||||
adminive::Managed_Value<Section_Config, structive::No_Lock_Policy> no_lock;
|
||||
adminive::Resource_Service<Section_Config, Json> service(no_lock, "/section");
|
||||
const auto rejected = service.update_response(R"({"backend_value":99,"immutable_value":88})");
|
||||
assert(rejected.status == 422);
|
||||
const auto update = service.update_response(R"({"editable_value":21,"unsynchronized_value":22})");
|
||||
assert(update.status == 200);
|
||||
const auto no_lock_snapshot = no_lock.snapshot();
|
||||
assert(no_lock_snapshot.editable_value == 21);
|
||||
assert(no_lock_snapshot.backend_value == 3);
|
||||
assert(no_lock_snapshot.immutable_value == 2);
|
||||
assert(no_lock_snapshot.unsynchronized_value == 22);
|
||||
adminive::Managed_Value<Concurrent_Config> concurrent;
|
||||
std::atomic<bool> start{};
|
||||
auto first_writer = std::thread([&] {
|
||||
while(!start.load(std::memory_order_acquire)) {}
|
||||
for(int index = 0; index < 5000; ++index) {
|
||||
concurrent.member<&Concurrent_Config::first>().write([index](int& value) {
|
||||
value = index;
|
||||
});
|
||||
}
|
||||
});
|
||||
auto second_writer = std::thread([&] {
|
||||
while(!start.load(std::memory_order_acquire)) {}
|
||||
for(int index = 0; index < 5000; ++index) {
|
||||
concurrent.member<&Concurrent_Config::second>().write([index](int& value) {
|
||||
value = index;
|
||||
});
|
||||
}
|
||||
});
|
||||
auto serializer = std::thread([&] {
|
||||
while(!start.load(std::memory_order_acquire)) {}
|
||||
for(int index = 0; index < 1000; ++index) {
|
||||
const Json value = adminive::to_json<Json>(concurrent);
|
||||
assert(value.at("immutable_value") == 7);
|
||||
}
|
||||
});
|
||||
start.store(true, std::memory_order_release);
|
||||
first_writer.join();
|
||||
second_writer.join();
|
||||
serializer.join();
|
||||
const auto concurrent_snapshot = concurrent.snapshot();
|
||||
assert(concurrent_snapshot.first == 4999);
|
||||
assert(concurrent_snapshot.second == 4999);
|
||||
assert(concurrent_snapshot.immutable_value == 7);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user