Skip to content

Commit

Permalink
Simplify pipelining
Browse files Browse the repository at this point in the history
  • Loading branch information
DevNatan committed Dec 10, 2023
1 parent 4b14fa6 commit 289c63a
Show file tree
Hide file tree
Showing 19 changed files with 205 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -1,40 +1,6 @@
package me.devnatan.inventoryframework.component;

import me.devnatan.inventoryframework.VirtualView;
import me.devnatan.inventoryframework.context.IFComponentContext;
import me.devnatan.inventoryframework.context.IFComponentRenderContext;
import me.devnatan.inventoryframework.context.IFComponentUpdateContext;
import me.devnatan.inventoryframework.context.IFSlotClickContext;
import me.devnatan.inventoryframework.pipeline.PipelineInterceptor;
import org.jetbrains.annotations.NotNull;

public abstract class ComponentHandle implements PipelineInterceptor<VirtualView> {

/**
* Renders this component to the given context.
*
* @param context The context that this component will be rendered on.
*/
void rendered(@NotNull IFComponentRenderContext context) {}

/**
* Called when this component is updated in the given context.
*
* @param context The update context.
*/
void updated(@NotNull IFComponentUpdateContext context) {}

/**
* Clears this component from the given context.
*
* @param context The context that this component will be cleared from.
*/
public void cleared(@NotNull IFComponentContext context) {}

/**
* Called when a viewer clicks in that component.
*
* @param context The click context.
*/
void clicked(@NotNull IFSlotClickContext context) {}
}
public abstract class ComponentHandle implements PipelineInterceptor<VirtualView> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package me.devnatan.inventoryframework.context;

import me.devnatan.inventoryframework.ViewContainer;

public interface IFComponentClearContext extends IFComponentContext, IFConfinedContext {

IFRenderContext getParent();

ViewContainer getContainer();

boolean isCancelled();

void setCancelled(boolean cancelled);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.devnatan.inventoryframework.state;

import java.util.concurrent.atomic.AtomicLong;
import me.devnatan.inventoryframework.IFDebug;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

Expand Down Expand Up @@ -54,6 +55,8 @@ public interface State<T> {
* @return A new unique state id.
*/
static long next() {
return ids.getAndIncrement();
final long id = ids.getAndIncrement();
IFDebug.debug("New state id generated: %d", id);
return id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

public abstract class AbstractComponent implements Component {

private static final ComponentHandle NOOP_HANDLE = new NoopComponentHandle();

private final String key;
private final VirtualView root;
private final Ref<Component> reference;
Expand All @@ -43,6 +41,7 @@ protected AbstractComponent(
this.reference = reference;
this.watchingStates = watchingStates;
this.displayCondition = displayCondition;
setHandle(NoopComponentHandle.INSTANCE);
}

@Override
Expand Down Expand Up @@ -124,20 +123,20 @@ public final void hide() {

@Override
public final @NotNull ComponentHandle getHandle() {
return handle == null ? NOOP_HANDLE : handle;
return handle;
}

@Override
public final void setHandle(ComponentHandle handle) {
if (this.handle != null) getPipeline().removeInterceptor(this.handle);
if (handle != null) {
for (final PipelinePhase phase :
new PipelinePhase[] {Component.RENDER, Component.UPDATE, Component.CLEAR, Component.CLICK}) {
if (handle == null)
throw new IllegalArgumentException("Component handle argument in #setHandle cannot be null");

getPipeline().intercept(phase, handle);
}
}
for (final PipelinePhase phase :
new PipelinePhase[] {Component.RENDER, Component.UPDATE, Component.CLEAR, Component.CLICK}) {

getPipeline().intercept(phase, handle);
}
this.handle = handle;
}

Expand All @@ -162,9 +161,25 @@ protected final boolean wasForceUpdated() {
return wasForceUpdated;
}
// endregion

@Override
public String toString() {
return "AbstractComponent{" + "key='"
+ key + '\'' + ", root="
+ root + ", reference="
+ reference + ", watchingStates="
+ watchingStates + ", displayCondition="
+ displayCondition + ", pipeline="
+ pipeline + ", handle="
+ handle + ", isVisible="
+ isVisible + ", wasForceUpdated="
+ wasForceUpdated + '}';
}
}

final class NoopComponentHandle extends ComponentHandle {
class NoopComponentHandle extends ComponentHandle {

static final ComponentHandle INSTANCE = new NoopComponentHandle();

@Override
public void intercept(PipelineContext<VirtualView> pipeline, VirtualView subject) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
Expand All @@ -21,8 +20,6 @@
import me.devnatan.inventoryframework.VirtualView;
import me.devnatan.inventoryframework.context.*;
import me.devnatan.inventoryframework.internal.LayoutSlot;
import me.devnatan.inventoryframework.pipeline.PipelineContext;
import me.devnatan.inventoryframework.pipeline.PipelinePhase;
import me.devnatan.inventoryframework.state.State;
import me.devnatan.inventoryframework.state.StateValue;
import me.devnatan.inventoryframework.state.StateValueHost;
Expand Down Expand Up @@ -82,7 +79,6 @@ public PaginationImpl(
boolean isAsync,
boolean isComputed) {
super(key, root, reference, watchingStates, displayCondition);
setHandle(new Handle(this));
this.internalStateId = internalStateId;
this.layoutTarget = layoutTarget;
this.sourceProvider = sourceProvider;
Expand Down Expand Up @@ -148,7 +144,7 @@ private CompletableFuture<List<?>> loadSourceForTheCurrentPage() {
simulateStateUpdate();

// TODO Do some error treatment here, even if we expect to the user to handle it
return createProvidedNewSource().handle((result, exception) -> {
return createNewProvidedSource().handle((result, exception) -> {
if (exception != null) {
debug("[Pagination] An error occurred on data source computation: %s", exception.getMessage());
exception.printStackTrace();
Expand All @@ -166,9 +162,11 @@ private CompletableFuture<List<?>> loadSourceForTheCurrentPage() {
}

@SuppressWarnings("unchecked")
private CompletableFuture<List<?>> createProvidedNewSource() {
private CompletableFuture<List<?>> createNewProvidedSource() {
CompletableFuture<List<?>> job = new CompletableFuture<>();

System.out.println("getRoot() = " + getRoot());

final Object source = _srcFactory.apply(getRoot());
if (isAsync()) job = (CompletableFuture<List<?>>) source;
else if (isComputed() || isLazy()) job.complete((List<?>) source);
Expand Down Expand Up @@ -383,20 +381,15 @@ public void set(Object value) {
// do nothing since Pagination is not immutable but unmodifiable directly
}

private void accessStateHost(Consumer<StateValueHost> consumer) {
if (!(getRoot() instanceof StateValueHost)) return;
consumer.accept((StateValueHost) getRoot());
}

/**
* Simulate state update to call listeners thus calling watches in parent components.
* <p>
* Used when something changes in pagination. It allows the end user and developers to "listen"
* for changes in {@link #isLoading()} and current page states.
*/
private void simulateStateUpdate() {
debug("[Pagination] State update simulation triggered on %d", internalStateId);
accessStateHost(host -> host.updateState(internalStateId, this));
debug("[Pagination] State update simulation triggered on %d", internalId());
((StateValueHost) getRoot()).updateState(internalId(), this);
}
// endregion

Expand Down Expand Up @@ -682,22 +675,3 @@ public String toString() {
+ super.toString();
}
}

class Handle extends ComponentHandle {

private final PaginationImpl pagination;

public Handle(PaginationImpl pagination) {
this.pagination = pagination;
}

@Override
public void intercept(PipelineContext<VirtualView> pipeline, VirtualView subject) {
final PipelinePhase phase = Objects.requireNonNull(
pipeline.getPhase(), "Pipeline phase cannot be null in ComponentHandle interceptor");
if (phase == Component.RENDER) pagination.render((IFComponentRenderContext) subject);
else if (phase == Component.UPDATE) pagination.updated((IFComponentUpdateContext) subject);
else if (phase == Component.CLEAR) pagination.cleared((IFRenderContext) subject);
else if (phase == Component.CLICK) pagination.clicked((IFSlotClickContext) subject);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ public StateValue getInternalStateValue(State<?> state) {
if (value == null) {
value = state.factory().create(this, state);
initializeState(id, value);
IFDebug.debug("State %s initialized (initialValue = %s)", id, value.toString());
}

return value;
Expand All @@ -57,6 +56,8 @@ public StateValue getInternalStateValue(State<?> state) {
@Override
public void initializeState(long id, @NotNull StateValue value) {
valuesMap.put(id, value);
IFDebug.debug(
"State %s initialized in %s (initialValue = %s)", id, getClass().getName(), value.toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import me.devnatan.inventoryframework.IFDebug;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

Expand All @@ -26,6 +27,11 @@ public final class StateRegistry implements Iterable<State<?>> {
public void registerState(@NotNull State<?> state, Object caller) {
synchronized (stateMap) {
stateMap.put(state.internalId(), state);
IFDebug.debug(
"State %s (id: %d) registered in %s",
state.getClass().getName(),
state.internalId(),
caller.getClass().getName());
if (state instanceof StateWatcher) ((StateWatcher) state).stateRegistered(state, caller);
}
}
Expand All @@ -38,6 +44,9 @@ public void registerState(@NotNull State<?> state, Object caller) {
public void unregisterState(long stateId, Object caller) {
synchronized (stateMap) {
final State<?> state = stateMap.remove(stateId);
IFDebug.debug(
"State %s unregistered from %s",
state.internalId(), caller.getClass().getName());
if (state instanceof StateWatcher) ((StateWatcher) state).stateUnregistered(state, caller);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
package me.devnatan.inventoryframework.component;

import java.util.Objects;
import me.devnatan.inventoryframework.VirtualView;
import me.devnatan.inventoryframework.context.ComponentClearContext;
import me.devnatan.inventoryframework.context.ComponentRenderContext;
import me.devnatan.inventoryframework.context.ComponentUpdateContext;
import me.devnatan.inventoryframework.context.Context;
import me.devnatan.inventoryframework.context.RenderContext;
import me.devnatan.inventoryframework.context.SlotClickContext;
import me.devnatan.inventoryframework.pipeline.PipelineContext;
import me.devnatan.inventoryframework.pipeline.PipelinePhase;

public abstract class BukkitComponentHandle<T> extends AbstractComponentHandle<Context, T> {
public abstract class BukkitComponentHandle<T> extends PlatformComponentHandle<Context, T> {

/**
* Renders the component in the given context.
*
* @param context The context that this component will be rendered on.
*/
protected abstract void rendered(ComponentRenderContext context);

/**
* Called when the component is updated in the given context.
*
* @param context The update context.
*/
protected void updated(ComponentUpdateContext context) {}

// TODO Create ComponentClearContext
protected void cleared(RenderContext context) {}
/**
* Called when the component is cleared from the given context.
*
* @param context The context that this component will be cleared from.
*/
protected void cleared(ComponentClearContext context) {}

/**
* Called when a viewer clicks in the component.
*
* @param context The click context.
*/
protected void clicked(SlotClickContext context) {}

@Override
public final void intercept(PipelineContext<VirtualView> pipeline, VirtualView subject) {
if (pipeline.getPhase() == Component.RENDER) rendered((ComponentRenderContext) subject);
if (pipeline.getPhase() == Component.UPDATE) updated((ComponentUpdateContext) subject);
if (pipeline.getPhase() == Component.CLICK) clicked((SlotClickContext) subject);
if (pipeline.getPhase() == Component.CLEAR) cleared((RenderContext) subject);
final PipelinePhase phase = Objects.requireNonNull(
pipeline.getPhase(), "Pipeline phase cannot be null in ComponentHandle interceptor");

if (phase == Component.RENDER) rendered((ComponentRenderContext) subject);
if (phase == Component.UPDATE) updated((ComponentUpdateContext) subject);
if (phase == Component.CLEAR) cleared((ComponentClearContext) subject);
if (phase == Component.CLICK) clicked((SlotClickContext) subject);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public final class BukkitItemComponentImpl extends PlatformComponent implements
updateOnClick);
this.position = position;
this.stack = itemStack;
setHandle(new BukkitItemComponentImplHandle());
}

@Override
Expand Down
Loading

0 comments on commit 289c63a

Please sign in to comment.