Skip to content

Commit cf3462d

Browse files
authored
Rework sync handler and value validation (#181)
* rework * javadoc n stuff * non extendable
1 parent 6f4e395 commit cf3462d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+742
-285
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package com.cleanroommc.modularui.api.value;
2+
3+
import org.jetbrains.annotations.ApiStatus;
4+
import org.jetbrains.annotations.NotNull;
5+
import org.jetbrains.annotations.Nullable;
6+
7+
/**
8+
* An interface that is implemented on {@link IValue} and {@link com.cleanroommc.modularui.value.sync.SyncHandler SyncHandler} for easier
9+
* validation and setters.
10+
*/
11+
@ApiStatus.NonExtendable
12+
public interface ISyncOrValue {
13+
14+
/**
15+
* A sync handler or value representing null.
16+
*/
17+
ISyncOrValue EMPTY = new ISyncOrValue() {
18+
@Override
19+
public <T> @Nullable T castNullable(Class<T> type) {
20+
return null;
21+
}
22+
23+
@Override
24+
public boolean isTypeOrEmpty(Class<?> type) {
25+
return true;
26+
}
27+
};
28+
29+
/**
30+
* Returns the given sync handler or value or {@link #EMPTY} if null.
31+
*
32+
* @param syncOrValue sync handler or value
33+
* @return a non-null representation of the given sync handler or value
34+
*/
35+
@NotNull
36+
static ISyncOrValue orEmpty(@Nullable ISyncOrValue syncOrValue) {
37+
return syncOrValue != null ? syncOrValue : EMPTY;
38+
}
39+
40+
/**
41+
* Returns if this sync handler or value is an instance of the given type or if this represents null. This is useful, when the value or
42+
* sync handler can be null in the widget.
43+
*
44+
* @param type type to check for
45+
* @return if this sync handler or value is an instance of the type or empty
46+
*/
47+
default boolean isTypeOrEmpty(Class<?> type) {
48+
return type.isAssignableFrom(getClass());
49+
}
50+
51+
/**
52+
* Casts this sync handler or value to the given type or null if this isn't a subtype of the given type.
53+
*
54+
* @param type type to cast this sync handle or value to
55+
* @param <T> type to cast to
56+
* @return this cast sync handler or value
57+
*/
58+
@Nullable
59+
@SuppressWarnings("unchecked")
60+
default <T> T castNullable(Class<T> type) {
61+
return type.isAssignableFrom(getClass()) ? (T) this : null;
62+
}
63+
64+
/**
65+
* Casts this sync handler or value to a {@link IValue IValue&lt;V&gt;} if it is a value handler and the containing value is of type
66+
* {@link V} else null.
67+
*
68+
* @param valueType expected type of the containing value
69+
* @param <V> expected type of the containing value
70+
* @return a {@link IValue IValue&lt;V&gt;} if types match or null
71+
*/
72+
@Nullable
73+
default <V> IValue<V> castValueNullable(Class<V> valueType) {
74+
return null;
75+
}
76+
77+
/**
78+
* Casts this sync handler or value to the given type or throws an exception if this isn't a subtype of the given type.
79+
*
80+
* @param type type to cast this sync handle or value to
81+
* @param <T> type to cast to
82+
* @return this cast sync handler or value
83+
* @throws IllegalStateException if this is not a subtype of the given type
84+
*/
85+
default <T> T castOrThrow(Class<T> type) {
86+
T t = castNullable(type);
87+
if (t == null) {
88+
if (!isSyncHandler() && !isValueHandler()) {
89+
throw new IllegalStateException("Empty sync handler or value can't be used for anything.");
90+
}
91+
String self = isSyncHandler() ? "sync handler" : "value";
92+
throw new IllegalStateException("Can't cast " + self + " of type '" + getClass().getSimpleName() + "' to type '" + type.getSimpleName() + "'.");
93+
}
94+
return t;
95+
}
96+
97+
/**
98+
* Returns if the containing value of this is of the given type. If this is not a value it will always return false.
99+
*
100+
* @param type expected value type
101+
* @return if the containing value of this is of the given type
102+
*/
103+
default boolean isValueOfType(Class<?> type) {
104+
return false;
105+
}
106+
107+
/**
108+
* @return if this is a sync handler (false if this represents null)
109+
*/
110+
default boolean isSyncHandler() {
111+
return false;
112+
}
113+
114+
/**
115+
* @return if this is a value handler (false if this represents null)
116+
*/
117+
default boolean isValueHandler() {
118+
return false;
119+
}
120+
}

src/main/java/com/cleanroommc/modularui/api/value/IValue.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* @param <T> value type
77
*/
8-
public interface IValue<T> {
8+
public interface IValue<T> extends ISyncOrValue {
99

1010
/**
1111
* Gets the current value.
@@ -20,4 +20,21 @@ public interface IValue<T> {
2020
* @param value new value
2121
*/
2222
void setValue(T value);
23+
24+
Class<T> getValueType();
25+
26+
default boolean isValueOfType(Class<?> type) {
27+
return type.isAssignableFrom(getValueType());
28+
}
29+
30+
@SuppressWarnings("unchecked")
31+
@Override
32+
default <V> IValue<V> castValueNullable(Class<V> valueType) {
33+
return isValueOfType(valueType) ? (IValue<V>) this : null;
34+
}
35+
36+
@Override
37+
default boolean isValueHandler() {
38+
return true;
39+
}
2340
}

src/main/java/com/cleanroommc/modularui/api/widget/ISynced.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cleanroommc.modularui.api.widget;
22

3+
import com.cleanroommc.modularui.api.value.ISyncOrValue;
34
import com.cleanroommc.modularui.value.sync.GenericSyncValue;
45
import com.cleanroommc.modularui.value.sync.ModularSyncManager;
56
import com.cleanroommc.modularui.value.sync.SyncHandler;
@@ -29,21 +30,32 @@ default W getThis() {
2930
* Called when this widget gets initialised or when this widget is added to the gui
3031
*
3132
* @param syncManager sync manager
32-
* @param late
33+
* @param late if this is called at any point after the panel this widget belongs to opened
3334
*/
3435
void initialiseSyncHandler(ModularSyncManager syncManager, boolean late);
3536

3637
/**
37-
* Checks and return if the received sync handler is valid for this widget This is usually an instanceof check. <br />
38-
* <b>Synced widgets must override this!</b>
39-
*
40-
* @param syncHandler received sync handler
41-
* @return true if sync handler is valid
38+
* @deprecated use {@link #isValidSyncOrValue(ISyncOrValue)}
4239
*/
40+
@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
41+
@Deprecated
4342
default boolean isValidSyncHandler(SyncHandler syncHandler) {
4443
return false;
4544
}
4645

46+
/**
47+
* Returns if the given value or sync handler is valid for this widget. This is usually a call to
48+
* {@link ISyncOrValue#isTypeOrEmpty(Class)}. If the widget must specify a value (disallow null) instanceof check can be used. You can
49+
* check for primitive types which don't have a dedicated {@link com.cleanroommc.modularui.api.value.IValue IValue} interface with
50+
* {@link ISyncOrValue#isValueOfType(Class)}.
51+
*
52+
* @param syncOrValue a sync handler or a value, but never null
53+
* @return if the value or sync handler is valid for this class
54+
*/
55+
default boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) {
56+
return !(syncOrValue instanceof SyncHandler syncHandler) || isValidSyncHandler(syncHandler);
57+
}
58+
4759
/**
4860
* Checks if the given sync handler is valid for this widget and throws an exception if not.
4961
* Override {@link #isValidSyncHandler(SyncHandler)}
@@ -52,17 +64,21 @@ default boolean isValidSyncHandler(SyncHandler syncHandler) {
5264
* @throws IllegalStateException if the given sync handler is invalid for this widget.
5365
*/
5466
@ApiStatus.NonExtendable
55-
default void checkValidSyncHandler(SyncHandler syncHandler) {
56-
if (!isValidSyncHandler(syncHandler)) {
67+
default void checkValidSyncOrValue(ISyncOrValue syncHandler) {
68+
if (!isValidSyncOrValue(syncHandler)) {
5769
throw new IllegalStateException("SyncHandler of type '" + syncHandler.getClass().getSimpleName() + "' is not valid " +
5870
"for widget '" + this + "'.");
5971
}
6072
}
6173

74+
@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
75+
@Deprecated
6276
default <T> T castIfTypeElseNull(SyncHandler syncHandler, Class<T> clazz) {
6377
return castIfTypeElseNull(syncHandler, clazz, null);
6478
}
6579

80+
@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
81+
@Deprecated
6682
@SuppressWarnings("unchecked")
6783
default <T> T castIfTypeElseNull(SyncHandler syncHandler, Class<T> clazz, @Nullable Consumer<T> setup) {
6884
if (syncHandler != null && clazz.isAssignableFrom(syncHandler.getClass())) {
@@ -73,10 +89,14 @@ default <T> T castIfTypeElseNull(SyncHandler syncHandler, Class<T> clazz, @Nulla
7389
return null;
7490
}
7591

92+
@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
93+
@Deprecated
7694
default <T> GenericSyncValue<T> castIfTypeGenericElseNull(SyncHandler syncHandler, Class<T> clazz) {
7795
return castIfTypeGenericElseNull(syncHandler, clazz, null);
7896
}
7997

98+
@ApiStatus.ScheduledForRemoval(inVersion = "3.2.0")
99+
@Deprecated
80100
default <T> GenericSyncValue<T> castIfTypeGenericElseNull(SyncHandler syncHandler, Class<T> clazz,
81101
@Nullable Consumer<GenericSyncValue<T>> setup) {
82102
if (syncHandler instanceof GenericSyncValue<?> genericSyncValue && genericSyncValue.isOfType(clazz)) {

src/main/java/com/cleanroommc/modularui/screen/ModularPanel.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.cleanroommc.modularui.api.UpOrDown;
99
import com.cleanroommc.modularui.api.layout.IViewport;
1010
import com.cleanroommc.modularui.api.layout.IViewportStack;
11+
import com.cleanroommc.modularui.api.value.ISyncOrValue;
1112
import com.cleanroommc.modularui.api.widget.IDragResizeable;
1213
import com.cleanroommc.modularui.api.widget.IFocusedWidget;
1314
import com.cleanroommc.modularui.api.widget.IWidget;
@@ -25,7 +26,6 @@
2526
import com.cleanroommc.modularui.utils.ObjectList;
2627
import com.cleanroommc.modularui.value.sync.PanelSyncHandler;
2728
import com.cleanroommc.modularui.value.sync.PanelSyncManager;
28-
import com.cleanroommc.modularui.value.sync.SyncHandler;
2929
import com.cleanroommc.modularui.widget.ParentWidget;
3030
import com.cleanroommc.modularui.widget.WidgetTree;
3131
import com.cleanroommc.modularui.widget.sizer.Area;
@@ -112,15 +112,19 @@ public void onInit() {
112112
}
113113

114114
@Override
115-
public boolean isValidSyncHandler(SyncHandler syncHandler) {
116-
return syncHandler instanceof IPanelHandler;
115+
public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) {
116+
return syncOrValue.isTypeOrEmpty(IPanelHandler.class);
117117
}
118118

119-
@ApiStatus.Internal
120119
@Override
121-
public void setSyncHandler(@Nullable SyncHandler syncHandler) {
122-
super.setSyncHandler(syncHandler);
123-
setPanelHandler((IPanelHandler) syncHandler);
120+
protected void setSyncOrValue(@NotNull ISyncOrValue syncOrValue) {
121+
super.setSyncOrValue(syncOrValue);
122+
setPanelHandler(syncOrValue.castNullable(IPanelHandler.class));
123+
}
124+
125+
@ApiStatus.Internal
126+
public void setPanelSyncHandler(PanelSyncHandler syncHandler) {
127+
setSyncOrValue(ISyncOrValue.orEmpty(syncHandler));
124128
}
125129

126130
/**
@@ -612,7 +616,7 @@ public boolean onMouseDrag(int mouseButton, long timeSinceClick) {
612616
mouseButton == this.mouse.lastButton &&
613617
this.mouse.lastPressed != null &&
614618
this.mouse.lastPressed.getElement() instanceof Interactable interactable &&
615-
this.mouse.lastPressed.getElement().isValid()) {
619+
this.mouse.lastPressed.getElement().isValid()) {
616620
this.mouse.lastPressed.applyMatrix(getContext());
617621
interactable.onMouseDrag(mouseButton, timeSinceClick);
618622
this.mouse.lastPressed.unapplyMatrix(getContext());

src/main/java/com/cleanroommc/modularui/utils/serialization/ByteBufAdapters.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.io.IOException;
1515
import java.math.BigDecimal;
1616
import java.math.BigInteger;
17+
import java.util.Objects;
1718

1819
public class ByteBufAdapters {
1920

@@ -108,8 +109,7 @@ public boolean areEqual(@NotNull BigDecimal t1, @NotNull BigDecimal t2) {
108109
}
109110
};
110111

111-
public static <T> IByteBufAdapter<T> makeAdapter(@NotNull IByteBufDeserializer<T> deserializer, @NotNull IByteBufSerializer<T> serializer, @Nullable IEquals<T> comparator) {
112-
final IEquals<T> tester = comparator != null ? comparator : IEquals.defaultTester();
112+
public static <T> IByteBufAdapter<T> makeAdapter(@NotNull IByteBufDeserializer<T> deserializer, @NotNull IByteBufSerializer<T> serializer, @Nullable IEquals<T> tester) {
113113
return new IByteBufAdapter<>() {
114114
@Override
115115
public T deserialize(PacketBuffer buffer) throws IOException {
@@ -123,7 +123,7 @@ public void serialize(PacketBuffer buffer, T u) throws IOException {
123123

124124
@Override
125125
public boolean areEqual(@NotNull T t1, @NotNull T t2) {
126-
return tester.areEqual(t1, t2);
126+
return tester != null ? tester.areEqual(t1, t2) : Objects.equals(t1, t2);
127127
}
128128
};
129129
}

src/main/java/com/cleanroommc/modularui/value/BoolValue.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ public void setStringValue(String val) {
5454
setBoolValue(Boolean.parseBoolean(val));
5555
}
5656

57+
@Override
58+
public Class<Boolean> getValueType() {
59+
return Boolean.class;
60+
}
61+
5762
public static class Dynamic implements IBoolValue<Boolean>, IIntValue<Boolean>, IStringValue<Boolean> {
5863

5964
private final BooleanSupplier getter;
@@ -103,5 +108,10 @@ public int getIntValue() {
103108
public void setIntValue(int val) {
104109
setBoolValue(val == 1);
105110
}
111+
112+
@Override
113+
public Class<Boolean> getValueType() {
114+
return Boolean.class;
115+
}
106116
}
107117
}

src/main/java/com/cleanroommc/modularui/value/ByteValue.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public void setValue(Byte value) {
3030
setByteValue(value);
3131
}
3232

33+
@Override
34+
public Class<Byte> getValueType() {
35+
return Byte.class;
36+
}
37+
3338
public static class Dynamic extends ByteValue {
3439

3540
private final Supplier getter;

src/main/java/com/cleanroommc/modularui/value/ConstValue.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,9 @@ public T getValue() {
2626
public void setValue(T value) {
2727
this.value = value;
2828
}
29+
30+
@Override
31+
public Class<T> getValueType() {
32+
return (Class<T>) value.getClass();
33+
}
2934
}

src/main/java/com/cleanroommc/modularui/value/DoubleValue.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ public void setFloatValue(float val) {
6565
setDoubleValue(val);
6666
}
6767

68+
@Override
69+
public Class<Double> getValueType() {
70+
return Double.class;
71+
}
72+
6873
public static class Dynamic implements IDoubleValue<Double>, IStringValue<Double> {
6974

7075
private final DoubleSupplier getter;
@@ -104,5 +109,10 @@ public Double getValue() {
104109
public void setValue(Double value) {
105110
setDoubleValue(value);
106111
}
112+
113+
@Override
114+
public Class<Double> getValueType() {
115+
return Double.class;
116+
}
107117
}
108118
}

src/main/java/com/cleanroommc/modularui/value/DynamicValue.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,9 @@ public void setValue(T value) {
3535
this.setter.accept(value);
3636
}
3737
}
38+
39+
@Override
40+
public Class<T> getValueType() {
41+
return (Class<T>) this.getter.get().getClass();
42+
}
3843
}

0 commit comments

Comments
 (0)