14#include <AUI/Common/ASignal.h>
15#include <AUI/Common/APropertyPrecomputed.h>
16#include <AUI/Common/PropertyModifier.h>
18namespace aui::detail::property {
20template<
typename Projection,
typename Source>
21concept ProjectionBidirectional =
requires (Projection&& projectionBidirectional, Source&& source) {
23 { projectionBidirectional } -> aui::invocable<const Source&>;
26 { projectionBidirectional } -> aui::invocable<const std::invoke_result_t<Projection, const Source&>&>;
29 requires not aui::same_as<std::decay_t<
decltype(projectionBidirectional(source))>, std::decay_t<Source>>;
32template <
typename Property>
33auto makeAssignment(Property&& property) {
37 using Underlying = std::decay_t<
decltype(*property)>;
40 void operator()(
const Underlying& value)
const {
43 if (property.changed.isAtSignalEmissionState()) {
46 const_cast<Property&
>(property) = std::move(value);
48 } i = { std::forward<Property>(property) };
50 return ASlotDef<
decltype(
property.boundObject()),
decltype(i)> {
51 property.boundObject(),
56template<
typename Property,
typename Projection>
57auto makeReadonlyProjection(Property&& property, Projection&& projection) {
58 using Underlying = std::decay_t<
decltype(*property)>;
59 auto signalProjected =
property.changed.projected(projection);
60 using Signal =
decltype(signalProjected);
61 using ProjectionResult = std::invoke_result_t<Projection, Underlying>;
62 struct PropertyReadProjection {
64 Property wrappedProperty;
65 Projection projection;
69 PropertyReadProjection(Property wrappedProperty, Projection&& projection, Signal changed)
70 : wrappedProperty(wrappedProperty), projection(std::move(projection)), changed(changed) {}
71 using Underlying = ProjectionResult;
74 auto boundObject()
const {
75 return wrappedProperty.boundObject();
79 Underlying value()
const {
80 return std::invoke(projection, wrappedProperty.value());
84 Underlying operator*() const noexcept {
88 [[nodiscard]]
operator Underlying()
const {
return value(); }
91 static_assert(APropertyReadable<PropertyReadProjection>,
"PropertyReadProjection must conform with APropertyReadable");
92 return PropertyReadProjection(std::forward<Property>(property), std::forward<Projection>(projection), std::move(signalProjected));
95template<
typename PropertyReadProjection,
typename ProjectionWrite>
96struct PropertyReadWriteProjection: PropertyReadProjection {
97 ProjectionWrite projectionWrite;
98 using Underlying =
typename PropertyReadProjection::Underlying;
99 explicit PropertyReadWriteProjection(PropertyReadProjection&& read, ProjectionWrite&& projectionWrite)
100 : PropertyReadProjection(std::move(
read)), projectionWrite(std::move(projectionWrite)) {}
102 template <aui::convertible_to<Underlying> U>
103 PropertyReadWriteProjection& operator=(U&& value)
noexcept {
104 this->wrappedProperty = std::invoke(projectionWrite, std::forward<U>(value));
112 this->wrappedProperty.notify();
115 friend class API_AUI_CORE ::AObject;
121 auto assignment() noexcept {
122 return aui::detail::property::makeAssignment(std::move(*
this));
126template<
typename Property, aui::not_overloaded_lambda ProjectionRead, aui::not_overloaded_lambda ProjectionWrite>
127auto makeBidirectionalProjection(Property&& property, ProjectionRead&& projectionRead, ProjectionWrite&& projectionWrite) {
129 makeReadonlyProjection(std::forward<Property>(property), std::forward<ProjectionRead>(projectionRead));
130 using PropertyReadProjection =
decltype(readProjected);
131 PropertyReadWriteProjection result(std::move(readProjected), std::forward<ProjectionWrite>(projectionWrite));
136template<typename Property, ProjectionBidirectional<typename std::decay_t<Property>::Underlying> Projection>
137auto makeBidirectionalProjection(Property&& property, Projection&& projection) {
139 using Source = std::decay_t<typename std::decay_t<Property>::Underlying>;
140 using Destination = std::decay_t<std::invoke_result_t<Projection, const Source&>>;
141 return makeBidirectionalProjection(
142 std::forward<Property>(property),
143 [projection](
const Source& s) -> Destination {
return std::invoke(projection, s); },
144 [projection](
const Destination& d) -> Source {
return std::invoke(projection, d); });
void API_AUI_CORE read(aui::no_escape< ISeekableInputStream > stream, const std::function< void(const FileEntry &)> &visitor)
ZIP reader.