mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:17:34 +00:00
LibGUI: Introduce property deserializers for GML property values
This commit is contained in:
parent
fb6a9dd2f5
commit
1689ec9100
4 changed files with 186 additions and 0 deletions
|
@ -94,6 +94,7 @@ set(SOURCES
|
||||||
ProcessChooser.cpp
|
ProcessChooser.cpp
|
||||||
Progressbar.cpp
|
Progressbar.cpp
|
||||||
Property.cpp
|
Property.cpp
|
||||||
|
PropertyDeserializer.cpp
|
||||||
RadioButton.cpp
|
RadioButton.cpp
|
||||||
RangeSlider.cpp
|
RangeSlider.cpp
|
||||||
RegularEditingEngine.cpp
|
RegularEditingEngine.cpp
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <LibCore/EventReceiver.h>
|
#include <LibCore/EventReceiver.h>
|
||||||
#include <LibGUI/Forward.h>
|
#include <LibGUI/Forward.h>
|
||||||
#include <LibGUI/Property.h>
|
#include <LibGUI/Property.h>
|
||||||
|
#include <LibGUI/PropertyDeserializer.h>
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
@ -59,6 +60,43 @@ protected:
|
||||||
|
|
||||||
void register_property(ByteString const& name, Function<JsonValue()> getter, Function<bool(JsonValue const&)> setter = nullptr);
|
void register_property(ByteString const& name, Function<JsonValue()> getter, Function<bool(JsonValue const&)> setter = nullptr);
|
||||||
|
|
||||||
|
template<typename Getter, typename Deserializer, typename Setter>
|
||||||
|
void register_property(StringView name, Getter&& getter, Deserializer&& deserializer, Setter&& setter)
|
||||||
|
{
|
||||||
|
Function<JsonValue()> getter_fn = nullptr;
|
||||||
|
Function<bool(JsonValue const&)> setter_fn = nullptr;
|
||||||
|
|
||||||
|
if constexpr (!SameAs<Getter, nullptr_t>) {
|
||||||
|
static_assert(ConvertibleTo<InvokeResult<Getter>, JsonValue>);
|
||||||
|
getter_fn = [captured_getter = forward<Getter>(getter)]() -> JsonValue {
|
||||||
|
return captured_getter();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(SameAs<Deserializer, nullptr_t> == SameAs<Setter, nullptr_t>);
|
||||||
|
if constexpr (!SameAs<Deserializer, nullptr_t>) {
|
||||||
|
using DeserializerReturnValue = RemoveReference<InvokeResult<Deserializer, JsonValue const&>>;
|
||||||
|
static_assert(SpecializationOf<DeserializerReturnValue, ErrorOr>);
|
||||||
|
using DeserializedValue = RemoveReference<typename DeserializerReturnValue::ResultType>;
|
||||||
|
// FIXME: Should we allow setter to fail?
|
||||||
|
static_assert(SameAs<InvokeResult<Setter, DeserializedValue&&>, void>);
|
||||||
|
|
||||||
|
setter_fn = [captured_deserializer = forward<Deserializer>(deserializer), captured_setter = forward<Setter>(setter)](JsonValue const& value) -> bool {
|
||||||
|
DeserializerReturnValue deserializer_return_value = captured_deserializer(value);
|
||||||
|
if (deserializer_return_value.is_error()) {
|
||||||
|
// FIXME: Propagate error up to a place where we have enough context to print/show meaningful message.
|
||||||
|
dbgln("Got error while deserializing GML property: {}", deserializer_return_value.error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DeserializedValue deserialized_value = deserializer_return_value.release_value();
|
||||||
|
captured_setter(move(deserialized_value));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
register_property(name, move(getter_fn), move(setter_fn));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HashMap<ByteString, NonnullOwnPtr<Property>> m_properties;
|
HashMap<ByteString, NonnullOwnPtr<Property>> m_properties;
|
||||||
};
|
};
|
||||||
|
|
117
Userland/Libraries/LibGUI/PropertyDeserializer.cpp
Normal file
117
Userland/Libraries/LibGUI/PropertyDeserializer.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PropertyDeserializer.h"
|
||||||
|
#include <AK/JsonObject.h>
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <LibGfx/Rect.h>
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
ErrorOr<bool> PropertyDeserializer<bool>::operator()(JsonValue const& value) const
|
||||||
|
{
|
||||||
|
if (value.is_bool())
|
||||||
|
return value.as_bool();
|
||||||
|
return Error::from_string_literal("Boolean is expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
ErrorOr<String> PropertyDeserializer<String>::operator()(JsonValue const& value) const
|
||||||
|
{
|
||||||
|
if (value.is_string()) {
|
||||||
|
// FIXME: Port JsonValue to the new String class.
|
||||||
|
return String::from_deprecated_string(value.as_string());
|
||||||
|
}
|
||||||
|
return Error::from_string_literal("UTF-8 string is expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
ErrorOr<DeprecatedString> PropertyDeserializer<DeprecatedString>::operator()(JsonValue const& value) const
|
||||||
|
{
|
||||||
|
if (value.is_string())
|
||||||
|
return value.as_string();
|
||||||
|
return Error::from_string_literal("String is expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
ErrorOr<Gfx::IntRect> PropertyDeserializer<Gfx::IntRect>::operator()(JsonValue const& value) const
|
||||||
|
{
|
||||||
|
if (!value.is_object() && !(value.is_array() && value.as_array().size() == 4))
|
||||||
|
return Error::from_string_literal("An array with 4 integers or an object is expected");
|
||||||
|
|
||||||
|
Gfx::IntRect rect;
|
||||||
|
|
||||||
|
Optional<int> x;
|
||||||
|
Optional<int> y;
|
||||||
|
Optional<int> width;
|
||||||
|
Optional<int> height;
|
||||||
|
|
||||||
|
if (value.is_object()) {
|
||||||
|
auto const& object = value.as_object();
|
||||||
|
|
||||||
|
if (object.size() != 4 || !object.has("x"sv) || !object.has("y"sv) || !object.has("width"sv) || !object.has("height"sv))
|
||||||
|
return Error::from_string_literal("Object with keys \"x\", \"y\", \"width\", and \"height\" is expected");
|
||||||
|
|
||||||
|
x = object.get_i32("x"sv);
|
||||||
|
y = object.get_i32("y"sv);
|
||||||
|
width = object.get_i32("width"sv);
|
||||||
|
height = object.get_i32("height"sv);
|
||||||
|
} else {
|
||||||
|
auto const& array = value.as_array();
|
||||||
|
|
||||||
|
auto get_i32 = [](JsonValue const& value) -> Optional<int> {
|
||||||
|
if (value.is_integer<i32>())
|
||||||
|
return value.to_i32();
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
x = get_i32(array[0]);
|
||||||
|
y = get_i32(array[1]);
|
||||||
|
width = get_i32(array[2]);
|
||||||
|
height = get_i32(array[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!x.has_value())
|
||||||
|
return Error::from_string_literal("X coordinate must be an integer");
|
||||||
|
if (!y.has_value())
|
||||||
|
return Error::from_string_literal("Y coordinate must be an integer");
|
||||||
|
if (!width.has_value())
|
||||||
|
return Error::from_string_literal("Width must be an integer");
|
||||||
|
if (!height.has_value())
|
||||||
|
return Error::from_string_literal("Height must be an integer");
|
||||||
|
|
||||||
|
rect.set_x(x.value());
|
||||||
|
rect.set_y(y.value());
|
||||||
|
rect.set_width(width.value());
|
||||||
|
rect.set_height(height.value());
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
ErrorOr<Gfx::IntSize> PropertyDeserializer<Gfx::IntSize>::operator()(JsonValue const& value) const
|
||||||
|
{
|
||||||
|
if (!value.is_array() || value.as_array().size() != 2)
|
||||||
|
return Error::from_string_literal("Expected array with 2 integers");
|
||||||
|
|
||||||
|
auto const& array = value.as_array();
|
||||||
|
|
||||||
|
auto const& width = array[0];
|
||||||
|
if (!width.is_integer<i32>())
|
||||||
|
return Error::from_string_literal("Width must be an integer");
|
||||||
|
auto const& height = array[1];
|
||||||
|
if (!height.is_integer<i32>())
|
||||||
|
return Error::from_string_literal("Height must be an integer");
|
||||||
|
|
||||||
|
Gfx::IntSize size;
|
||||||
|
size.set_width(width.to_i32());
|
||||||
|
size.set_height(height.to_i32());
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
30
Userland/Libraries/LibGUI/PropertyDeserializer.h
Normal file
30
Userland/Libraries/LibGUI/PropertyDeserializer.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/JsonValue.h>
|
||||||
|
#include <LibGfx/Forward.h>
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct PropertyDeserializer {
|
||||||
|
ErrorOr<T> operator()(JsonValue const& value) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<Integral T>
|
||||||
|
requires(!IsSame<T, bool>)
|
||||||
|
struct PropertyDeserializer<T> {
|
||||||
|
ErrorOr<T> operator()(JsonValue const& value) const
|
||||||
|
{
|
||||||
|
if (!value.is_integer<T>())
|
||||||
|
return Error::from_string_literal("Value is either not an integer or out of range for requested type");
|
||||||
|
return value.to_number<T>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue