diff --git a/src/brayns/core/engine/Camera.h b/src/brayns/core/engine/Camera.h index 818091ede..a480ac974 100644 --- a/src/brayns/core/engine/Camera.h +++ b/src/brayns/core/engine/Camera.h @@ -72,9 +72,9 @@ struct PerspectiveCameraSettings { float fovy = radians(60.0F); float aspect = 1.0F; - std::optional depthOfField = std::nullopt; + std::optional depthOfField = {}; bool architectural = false; - std::optional stereo = std::nullopt; + std::optional stereo = {}; }; class PerspectiveCamera : public Camera diff --git a/src/brayns/core/engine/Framebuffer.h b/src/brayns/core/engine/Framebuffer.h index 3bd0a896c..0c6884901 100644 --- a/src/brayns/core/engine/Framebuffer.h +++ b/src/brayns/core/engine/Framebuffer.h @@ -60,8 +60,8 @@ struct FramebufferSettings Size2 resolution; FramebufferFormat format = FramebufferFormat::Srgba8; std::set channels = {FramebufferChannel::Color}; - std::optional accumulation = std::nullopt; - std::optional> operations = std::nullopt; + std::optional accumulation = {}; + std::optional> operations = {}; }; class FramebufferData diff --git a/src/brayns/core/engine/GeometricModel.h b/src/brayns/core/engine/GeometricModel.h index 5811f89d0..f7ff00b1a 100644 --- a/src/brayns/core/engine/GeometricModel.h +++ b/src/brayns/core/engine/GeometricModel.h @@ -37,7 +37,7 @@ struct Materials { std::variant> values; std::variant> colors = {}; - std::optional> indices = std::nullopt; + std::optional> indices = {}; }; struct GeometricModelSettings diff --git a/src/brayns/core/engine/Geometry.h b/src/brayns/core/engine/Geometry.h index 63f19f8ff..9adbbf719 100644 --- a/src/brayns/core/engine/Geometry.h +++ b/src/brayns/core/engine/Geometry.h @@ -40,9 +40,9 @@ class Geometry : public Managed struct MeshSettings { Data positions; - std::optional> normals = std::nullopt; - std::optional> colors = std::nullopt; - std::optional> uvs = std::nullopt; + std::optional> normals = {}; + std::optional> colors = {}; + std::optional> uvs = {}; }; class Mesh : public Geometry @@ -56,7 +56,7 @@ class Mesh : public Geometry struct TriangleMeshSettings { MeshSettings base; - std::optional> indices = std::nullopt; + std::optional> indices = {}; }; class TriangleMesh : public Mesh @@ -70,7 +70,7 @@ TriangleMesh createTriangleMesh(Device &device, const TriangleMeshSettings &sett struct QuadMeshSettings { MeshSettings base; - std::optional> indices = std::nullopt; + std::optional> indices = {}; }; class QuadMesh : public Mesh @@ -84,7 +84,7 @@ QuadMesh createQuadMesh(Device &device, const QuadMeshSettings &settings); struct SphereSettings { Data spheres; - std::optional> uvs = std::nullopt; + std::optional> uvs = {}; }; class Spheres : public Geometry @@ -98,8 +98,8 @@ Spheres createSpheres(Device &device, const SphereSettings &settings); struct DiscSettings { Data spheres; - std::optional> normals = std::nullopt; - std::optional> uvs = std::nullopt; + std::optional> normals = {}; + std::optional> uvs = {}; }; class Discs : public Geometry @@ -114,8 +114,8 @@ struct CylinderSettings { Data spheres; Data indices; - std::optional> colors = std::nullopt; - std::optional> uvs = std::nullopt; + std::optional> colors = {}; + std::optional> uvs = {}; }; class Cylinders : public Geometry @@ -170,8 +170,8 @@ struct CurveSettings { Data spheres; Data indices; - std::optional> colors = std::nullopt; - std::optional> uvs = std::nullopt; + std::optional> colors = {}; + std::optional> uvs = {}; CurveType type = RoundCurve(); CurveBasis basis = LinearCurve(); }; @@ -200,7 +200,7 @@ Boxes createBoxes(Device &device, const BoxSettings &settings); struct PlaneSettings { Data coefficients; - std::optional> bounds = std::nullopt; + std::optional> bounds = {}; }; class Planes : public Geometry diff --git a/src/brayns/core/engine/Renderer.h b/src/brayns/core/engine/Renderer.h index 6bce100d8..01d284e2f 100644 --- a/src/brayns/core/engine/Renderer.h +++ b/src/brayns/core/engine/Renderer.h @@ -51,7 +51,7 @@ struct RendererSettings float minContribution = 0.001F; float varianceThreshold = 0.0F; Background background = Color4(0.0F, 0.0F, 0.0F, 0.0F); - std::optional maxDepth = std::nullopt; + std::optional maxDepth = {}; PixelFilter pixelFilter = PixelFilter::Gauss; }; diff --git a/src/brayns/core/engine/Volume.h b/src/brayns/core/engine/Volume.h index f30c79a13..b8c539905 100644 --- a/src/brayns/core/engine/Volume.h +++ b/src/brayns/core/engine/Volume.h @@ -56,7 +56,7 @@ struct RegularVolumeSettings Vector3 spacing = {1.0F, 1.0F, 1.0F}; VolumeType type = VolumeType::VertexCentered; VolumeFilter filter = VolumeFilter::Linear; - std::optional background = std::nullopt; + std::optional background = {}; }; class RegularVolume : public Volume diff --git a/src/brayns/core/engine/World.h b/src/brayns/core/engine/World.h index da85caba9..ad1872138 100644 --- a/src/brayns/core/engine/World.h +++ b/src/brayns/core/engine/World.h @@ -32,10 +32,10 @@ namespace brayns { struct GroupSettings { - std::optional> geometries = std::nullopt; - std::optional> clippingGeometries = std::nullopt; - std::optional> volumes = std::nullopt; - std::optional> lights = std::nullopt; + std::optional> geometries = {}; + std::optional> clippingGeometries = {}; + std::optional> volumes = {}; + std::optional> lights = {}; }; class Group : public Managed @@ -67,7 +67,7 @@ Instance createInstance(Device &device, const InstanceSettings &settings); struct WorldSettings { - std::optional> instances = std::nullopt; + std::optional> instances = {}; }; class World : public Managed diff --git a/src/brayns/core/json/Json.h b/src/brayns/core/json/Json.h index 7f4723883..60ab94cc5 100644 --- a/src/brayns/core/json/Json.h +++ b/src/brayns/core/json/Json.h @@ -27,6 +27,7 @@ #include "JsonValue.h" #include "types/Arrays.h" +#include "types/Buffer.h" #include "types/Consts.h" #include "types/Enums.h" #include "types/Maps.h" @@ -35,5 +36,6 @@ #include "types/Primitives.h" #include "types/Schema.h" #include "types/Sets.h" +#include "types/Update.h" #include "types/Variants.h" #include "types/Vectors.h" diff --git a/src/brayns/core/json/JsonSchema.h b/src/brayns/core/json/JsonSchema.h index 4a7ab1919..afe3167f3 100644 --- a/src/brayns/core/json/JsonSchema.h +++ b/src/brayns/core/json/JsonSchema.h @@ -161,16 +161,16 @@ struct JsonSchema { std::string description = {}; bool required = true; - std::optional defaultValue = std::nullopt; + std::optional defaultValue = {}; std::vector oneOf = {}; JsonType type = JsonType::Undefined; JsonValue constant = {}; - std::optional minimum = std::nullopt; - std::optional maximum = std::nullopt; + std::optional minimum = {}; + std::optional maximum = {}; std::vector items = {}; bool uniqueItems = false; - std::optional minItems = std::nullopt; - std::optional maxItems = std::nullopt; + std::optional minItems = {}; + std::optional maxItems = {}; std::map properties = {}; bool operator==(const JsonSchema &) const = default; diff --git a/src/brayns/core/json/types/Buffer.h b/src/brayns/core/json/types/Buffer.h new file mode 100644 index 000000000..ad38da8c8 --- /dev/null +++ b/src/brayns/core/json/types/Buffer.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2015-2024 EPFL/Blue Brain Project + * All rights reserved. Do not distribute without permission. + * + * Responsible Author: adrien.fleury@epfl.ch + * + * This file is part of Brayns + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +namespace brayns +{ +template +class JsonBuffer +{ +public: + const JsonValue &get() const + { + return _json; + } + + void store(const JsonValue &json) + { + _json = json; + } + + void extract(T &value) const + { + deserializeJson(_json, value); + } + +private: + JsonValue _json; +}; + +template +struct JsonReflector> +{ + static JsonSchema getSchema() + { + return getJsonSchema(); + } + + static void serialize(const JsonBuffer &value, JsonValue &json) + { + json = value.get(); + } + + static void deserialize(const JsonValue &json, JsonBuffer &value) + { + value.store(json); + } +}; +} diff --git a/src/brayns/core/json/types/Objects.h b/src/brayns/core/json/types/Objects.h index cde5b5317..6f391689e 100644 --- a/src/brayns/core/json/types/Objects.h +++ b/src/brayns/core/json/types/Objects.h @@ -217,15 +217,6 @@ JsonField convertJsonField(const JsonField &child, JsonChildGette }; } -inline void removeJsonObjectDefaults(std::map &properties) -{ - for (auto &[key, field] : properties) - { - field.defaultValue = std::nullopt; - removeJsonObjectDefaults(field.properties); - } -} - class JsonFieldBuilder { public: @@ -328,15 +319,6 @@ class JsonBuilder } } - void removeDefaultValues() - { - for (auto &field : _info.fields) - { - field.schema.defaultValue = std::nullopt; - removeJsonObjectDefaults(field.schema.properties); - } - } - JsonObjectInfo build() { return std::exchange(_info, {}); diff --git a/src/brayns/core/json/types/Update.h b/src/brayns/core/json/types/Update.h new file mode 100644 index 000000000..a812ec4e2 --- /dev/null +++ b/src/brayns/core/json/types/Update.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2015-2024 EPFL/Blue Brain Project + * All rights reserved. Do not distribute without permission. + * + * Responsible Author: adrien.fleury@epfl.ch + * + * This file is part of Brayns + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include "Objects.h" + +namespace brayns +{ +template +struct JsonUpdate +{ + T value; +}; + +template +struct JsonObjectReflector> +{ + static auto reflect() + { + auto builder = JsonBuilder>(); + builder.extend([](auto &object) { return &object.value; }); + + auto info = builder.build(); + + for (auto &field : info.fields) + { + field.schema.required = false; + field.schema.defaultValue.reset(); + } + + return info; + } +}; +} diff --git a/src/brayns/core/json/types/Variants.h b/src/brayns/core/json/types/Variants.h index 1542c22c2..6d118c1c2 100644 --- a/src/brayns/core/json/types/Variants.h +++ b/src/brayns/core/json/types/Variants.h @@ -53,7 +53,7 @@ struct JsonReflector> { if (json.isEmpty()) { - value = std::nullopt; + value.reset(); return; } diff --git a/src/brayns/core/jsonrpc/Parser.h b/src/brayns/core/jsonrpc/Parser.h index f55f8c9b0..971ce2fb5 100644 --- a/src/brayns/core/jsonrpc/Parser.h +++ b/src/brayns/core/jsonrpc/Parser.h @@ -34,5 +34,5 @@ std::string composeAsText(const JsonRpcSuccessResponse &response); std::string composeAsText(const JsonRpcErrorResponse &response); std::string composeAsBinary(const JsonRpcSuccessResponse &response); JsonRpcError composeError(const JsonRpcException &e); -JsonRpcErrorResponse composeErrorResponse(const JsonRpcException &e, std::optional id = std::nullopt); +JsonRpcErrorResponse composeErrorResponse(const JsonRpcException &e, std::optional id = {}); } diff --git a/src/brayns/core/websocket/WebSocketServer.h b/src/brayns/core/websocket/WebSocketServer.h index c70581cb6..8a997ed26 100644 --- a/src/brayns/core/websocket/WebSocketServer.h +++ b/src/brayns/core/websocket/WebSocketServer.h @@ -49,7 +49,7 @@ struct WebSocketServerSettings std::size_t maxThreadCount = 1; std::size_t maxQueueSize = 64; std::size_t maxFrameSize = std::numeric_limits::max(); - std::optional ssl = std::nullopt; + std::optional ssl = {}; }; class WebSocketServer diff --git a/tests/core/json/TestJsonReflection.cpp b/tests/core/json/TestJsonReflection.cpp index fde6dad45..748d96808 100644 --- a/tests/core/json/TestJsonReflection.cpp +++ b/tests/core/json/TestJsonReflection.cpp @@ -92,37 +92,36 @@ struct JsonObjectReflector } }; -struct Updatable +struct Extended { - int value; + Internal child; + std::string additional; }; template<> -struct JsonObjectReflector +struct JsonObjectReflector { static auto reflect() { - auto builder = JsonBuilder(); - builder.field("value", [](auto &object) { return &object.value; }).defaultValue(0); - builder.removeDefaultValues(); + auto builder = JsonBuilder(); + builder.extend([](auto &object) { return &object.child; }); + builder.field("additional", [](auto &object) { return &object.additional; }); return builder.build(); } }; -struct Extended +struct Update { - Updatable child; - std::string additional; + int test; }; template<> -struct JsonObjectReflector +struct JsonObjectReflector { static auto reflect() { - auto builder = JsonBuilder(); - builder.extend([](auto &object) { return &object.child; }); - builder.field("additional", [](auto &object) { return &object.additional; }); + auto builder = JsonBuilder(); + builder.field("test", [](auto &object) { return &object.test; }).defaultValue(2); return builder.build(); } }; @@ -384,15 +383,32 @@ TEST_CASE("Object") CHECK_EQ(stringifyToJson(test), stringifyToJson(json)); } -TEST_CASE("Empty field") +TEST_CASE("Update") { - auto object = Updatable{1}; + using T = JsonUpdate; + using Buffer = JsonBuffer; + + auto schema = getJsonSchema(); + auto child = getJsonSchema(); + child.required = false; + + CHECK_EQ(schema.type, JsonType::Object); + CHECK_EQ(schema.properties.size(), 1); + CHECK_EQ(schema.properties.at("test"), child); + + auto json = R"({"test":1})"; - auto json = JsonValue(createJsonObject()); + auto buffer = parseJsonAs(json); + auto update = T{}; - deserializeJson(json, object); + buffer.extract(update); + CHECK_EQ(update.value.test, 1); - CHECK_EQ(object.value, 1); + CHECK_EQ(stringifyToJson(buffer), json); + + buffer = parseJsonAs("{}"); + buffer.extract(update); + CHECK_EQ(update.value.test, 1); } TEST_CASE("Extension") @@ -400,4 +416,15 @@ TEST_CASE("Extension") auto schema = getJsonSchema(); CHECK_EQ(schema.properties.size(), 2); + CHECK_EQ(schema.properties.at("value"), getJsonSchema()); + CHECK_EQ(schema.properties.at("additional"), getJsonSchema()); + + auto json = R"({"additional":"test","value":1})"; + + auto value = parseJsonAs(json); + + CHECK_EQ(value.child.value, 1); + CHECK_EQ(value.additional, "test"); + + CHECK_EQ(stringifyToJson(value), json); }