14#include <AUI/Common/ASignal.h>
15#include <AUI/Common/APropertyPrecomputed.h>
17namespace aui::detail::property {
19template<
typename Projection,
typename Source>
20concept ProjectionBidirectional =
requires (Projection&& projectionBidirectional, Source&& source) {
22 { projectionBidirectional } -> aui::invocable<const Source&>;
25 { projectionBidirectional } -> aui::invocable<const std::invoke_result_t<Projection, const Source&>&>;
28 requires not aui::same_as<std::decay_t<
decltype(projectionBidirectional(source))>, std::decay_t<Source>>;
31template <
typename Property>
32auto makeAssignment(Property&& property) {
36 using Underlying = std::decay_t<
decltype(*property)>;
39 void operator()(
const Underlying& value)
const {
40 const_cast<Property&
>(property) = std::move(value);
42 } i = { std::forward<Property>(property) };
44 return ASlotDef<
decltype(
property.boundObject()),
decltype(i)> {
45 .boundObject =
property.boundObject(),
46 .invocable = std::move(i),
50template<
typename Property,
typename Projection>
51auto makeReadonlyProjection(Property&& property, Projection&& projection) {
52 using Underlying = std::decay_t<
decltype(*property)>;
53 auto signalProjected =
property.changed.projected(projection);
54 using Signal =
decltype(signalProjected);
55 using ProjectionResult = std::invoke_result_t<Projection, Underlying>;
56 struct PropertyReadProjection {
58 Property wrappedProperty;
59 Projection projection;
63 PropertyReadProjection(Property wrappedProperty, Projection&& projection, Signal changed)
64 : wrappedProperty(wrappedProperty), projection(std::move(projection)), changed(changed) {}
65 using Underlying = ProjectionResult;
68 auto boundObject()
const {
69 return wrappedProperty.boundObject();
73 Underlying value()
const {
74 return std::invoke(projection, wrappedProperty.value());
78 Underlying operator*() const noexcept {
82 [[nodiscard]]
operator Underlying()
const {
return value(); }
85 static_assert(APropertyReadable<PropertyReadProjection>,
"PropertyReadProjection must conform with APropertyReadable");
86 return PropertyReadProjection(std::forward<Property>(property), std::forward<Projection>(projection), std::move(signalProjected));
89template<
typename PropertyReadProjection,
typename ProjectionWrite>
90struct PropertyReadWriteProjection: PropertyReadProjection {
91 ProjectionWrite projectionWrite;
92 using Underlying =
typename PropertyReadProjection::Underlying;
93 explicit PropertyReadWriteProjection(PropertyReadProjection&& read, ProjectionWrite&& projectionWrite)
94 : PropertyReadProjection(std::move(
read)), projectionWrite(std::move(projectionWrite)) {}
96 template <aui::convertible_to<Underlying> U>
97 PropertyReadWriteProjection& operator=(U&& value)
noexcept {
98 this->wrappedProperty = std::invoke(projectionWrite, std::forward<U>(value));
102 friend class API_AUI_CORE ::AObject;
108 auto assignment() noexcept {
109 return aui::detail::property::makeAssignment(std::move(*
this));
113template<
typename Property, aui::not_overloaded_lambda ProjectionRead, aui::not_overloaded_lambda ProjectionWrite>
114auto makeBidirectionalProjection(Property&& property, ProjectionRead&& projectionRead, ProjectionWrite&& projectionWrite) {
116 makeReadonlyProjection(std::forward<Property>(property), std::forward<ProjectionRead>(projectionRead));
117 using PropertyReadProjection =
decltype(readProjected);
118 PropertyReadWriteProjection result(std::move(readProjected), std::forward<ProjectionWrite>(projectionWrite));
123template<typename Property, ProjectionBidirectional<typename std::decay_t<Property>::Underlying> Projection>
124auto makeBidirectionalProjection(Property&& property, Projection&& projection) {
126 using Source = std::decay_t<typename std::decay_t<Property>::Underlying>;
127 using Destination = std::decay_t<std::invoke_result_t<Projection, const Source&>>;
128 return makeBidirectionalProjection(
129 std::forward<Property>(property),
130 [projection](
const Source& s) -> Destination {
return std::invoke(projection, s); },
131 [projection](
const Destination& d) -> Source {
return std::invoke(projection, d); });
156struct AProperty: AObjectBase {
157 using Underlying = T;
166 template <aui::convertible_to<T> U>
167 AProperty(U&& value) noexcept : raw(std::forward<U>(value)) {}
169 AObjectBase* boundObject() {
173 template <aui::convertible_to<T> U>
174 AProperty& operator=(U&& value)
noexcept {
175 static constexpr auto IS_COMPARABLE =
requires { this->raw == value; };
176 if constexpr (IS_COMPARABLE) {
177 if (this->raw == value) [[unlikely]] {
181 this->raw = std::forward<U>(value);
182 emit changed(this->raw);
186 template <ASignalInvokable SignalInvokable>
187 void operator^(SignalInvokable&& t) {
188 t.invokeSignal(
nullptr);
192 const T& value()
const noexcept {
193 aui::property_precomputed::addDependency(changed);
198 T& value()
noexcept {
199 aui::property_precomputed::addDependency(changed);
203 [[nodiscard]]
operator const T&()
const noexcept {
return value(); }
206 const T* operator->()
const noexcept {
211 const T& operator*()
const noexcept {
216 T& operator*()
noexcept {
223 template<aui::invocable<const T&> Projection>
226 return aui::detail::property::makeReadonlyProjection(*
this, std::forward<Projection>(projection));
232 template<aui::invocable<const T&> ProjectionRead,
233 aui::invocable<const std::invoke_result_t<ProjectionRead, T>&> ProjectionWrite>
235 auto biProjected(ProjectionRead&& projectionRead, ProjectionWrite&& projectionWrite)
noexcept {
236 return aui::detail::property::makeBidirectionalProjection(*
this,
237 std::forward<ProjectionRead>(projectionRead),
238 std::forward<ProjectionWrite>(projectionWrite));
244 template<aui::detail::property::ProjectionB
idirectional<T> Projection>
247 return aui::detail::property::makeBidirectionalProjection(*
this, projectionBidirectional);
256 auto assignment() noexcept {
257 return aui::detail::property::makeAssignment(*
this);
336 using GetterReturnT =
decltype(std::invoke(
get,
base));
337 using Underlying = std::decay_t<GetterReturnT>;
360 template <aui::convertible_to<Underlying> U>
362 std::invoke(
set, *
const_cast<Model*
>(
base), std::forward<U>(u));
367 GetterReturnT value() const noexcept {
372 GetterReturnT operator*() const noexcept {
377 const Underlying* operator->() const noexcept {
378 return &std::invoke(
get,
base);
381 [[nodiscard]]
operator GetterReturnT() const noexcept {
return std::invoke(
get,
base); }
384 M* boundObject()
const {
385 return const_cast<M*
>(
base);
391 template <aui::invocable<const Underlying&> Projection>
394 return aui::detail::property::makeReadonlyProjection(std::move(*
this), std::forward<Projection>(projection));
404 auto biProjected(ProjectionRead&& projectionRead, ProjectionWrite&& projectionWrite)
noexcept {
405 return aui::detail::property::makeBidirectionalProjection(
406 std::move(*
this), std::forward<ProjectionRead>(projectionRead),
407 std::forward<ProjectionWrite>(projectionWrite));
413 template <aui::detail::property::ProjectionB
idirectional<Underlying> Projection>
416 return aui::detail::property::makeBidirectionalProjection(std::move(*
this), projectionBidirectional);
425 auto assignment() noexcept {
426 return aui::detail::property::makeAssignment(std::move(*
this));
431template<AAnyProperty Lhs,
typename Rhs>
433inline auto operator==(
const Lhs& lhs, Rhs&& rhs) {
434 return *lhs == std::forward<Rhs>(rhs);
437template<AAnyProperty Lhs,
typename Rhs>
439inline auto operator!=(
const Lhs& lhs, Rhs&& rhs) {
440 return *lhs != std::forward<Rhs>(rhs);
443template<AAnyProperty Lhs,
typename Rhs>
445inline auto operator+(
const Lhs& lhs, Rhs&& rhs) {
446 return *lhs + std::forward<Rhs>(rhs);
449template<AAnyProperty Lhs,
typename Rhs>
450inline decltype(
auto)
operator+=(Lhs& lhs, Rhs&& rhs) {
451 *lhs += std::forward<Rhs>(rhs);
455template<AAnyProperty Lhs,
typename Rhs>
456inline decltype(
auto)
operator+=(Lhs&& lhs, Rhs&& rhs) {
457 return lhs = *lhs + std::forward<Rhs>(rhs);
460template<AAnyProperty Lhs,
typename Rhs>
462inline auto operator-(
const Lhs& lhs, Rhs&& rhs) {
463 return *lhs - std::forward<Rhs>(rhs);
496template <APropertyReadable T>
struct fmt::formatter<T> {
497 template<
typename ParseContext>
498 constexpr auto parse(ParseContext& ctx)
503 auto format(T& c, format_context& ctx)
const {
504 return fmt::format_to(ctx.out(),
"{}", *c);
A base object class.
Definition AObject.h:39
Definition concepts.h:223
Definition concepts.h:107
Invokable concept.
Definition concepts.h:37
ASignal< Args... > emits
A signal declaration.
Definition ASignal.h:348
#define emit
emits the specified signal in context of this object.
Definition AObject.h:310
void API_AUI_XML read(const _< IInputStream > &is, const _< IXmlDocumentVisitor > &visitor)
Parses xml from the input stream to the IXmlDocumentVisitor.
Definition AXml.cpp:19
Property implementation to use with custom getter/setter.
Definition AProperty.h:308
const M * base
AObject which this property belongs to.
Definition AProperty.h:312
Getter get
Getter. Can be pointer-to-member(function or field) or lambda.
Definition AProperty.h:318
Setter set
Setter. Can be pointer-to-member(function or field) or lambda.
Definition AProperty.h:335
auto biProjected(ProjectionRead &&projectionRead, ProjectionWrite &&projectionWrite) noexcept
Makes a bidirectional projection of this property.
Definition AProperty.h:404
const emits< SignalArg > & changed
Reference to underlying signal emitting on value changes.
Definition AProperty.h:342
auto biProjected(Projection &&projectionBidirectional) noexcept
Makes a bidirectional projection of this property (by a single aui::lambda_overloaded).
Definition AProperty.h:415
auto readProjected(Projection &&projection) noexcept
Makes a readonly projection of this property.
Definition AProperty.h:393
Basic easy-to-use property implementation containing T.
Definition AProperty.h:156
auto biProjected(Projection &&projectionBidirectional) noexcept
Makes a bidirectional projection of this property (by a single aui::lambda_overloaded).
Definition AProperty.h:246
auto readProjected(Projection &&projection) noexcept
Makes a readonly projection of this property.
Definition AProperty.h:225
auto biProjected(ProjectionRead &&projectionRead, ProjectionWrite &&projectionWrite) noexcept
Makes a bidirectional projection of this property.
Definition AProperty.h:235