diff --git a/src/main/java/arachne/lib/AutoManager.java b/src/main/java/arachne/lib/AutoManager.java new file mode 100644 index 0000000..d54347c --- /dev/null +++ b/src/main/java/arachne/lib/AutoManager.java @@ -0,0 +1,51 @@ +package arachne.lib; + +import arachne.lib.scheduler.Schedulable; +import arachne.lib.sequences.ActionConductor; +import arachne.lib.sequences.Actionable; +import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; +import edu.wpi.first.wpilibj.smartdashboard.SendableChooser; + +public class AutoManager & Actionable> implements Schedulable +{ + protected static final String DASHBOARD_TAB = "Autonomous"; + protected static final String SELECTION_KEY = "Auto selection"; + + protected final ActionConductor conductor; + protected final SendableChooser autoChooser; + + public AutoManager(AutoT defaultAuto, AutoT[] autos) { + this.conductor = new ActionConductor(); + + this.autoChooser = new SendableChooser(); + this.autoChooser.setDefaultOption(defaultAuto.toString(), defaultAuto); + + for(AutoT auto : autos) { + if(auto != defaultAuto) autoChooser.addOption(auto.toString(), auto); + } + + Shuffleboard.getTab(DASHBOARD_TAB).add(SELECTION_KEY, autoChooser); + } + + public void startAuto() { + startAuto(autoChooser.getSelected()); + } + + public void startAuto(AutoT auto) { + stopAuto(); + conductor.add(auto); + } + + public void stopAuto() { + conductor.interrupt(); + } + + public boolean isRunning() { + return conductor.hasActions(); + } + + @Override + public void run() { + conductor.run(); + } +} diff --git a/src/main/java/arachne/lib/function/BooleanPredicate.java b/src/main/java/arachne/lib/function/BooleanPredicate.java index 4f0899b..32168af 100644 --- a/src/main/java/arachne/lib/function/BooleanPredicate.java +++ b/src/main/java/arachne/lib/function/BooleanPredicate.java @@ -66,4 +66,40 @@ default BooleanPredicate or(BooleanPredicate other) { Objects.requireNonNull(other); return (value) -> test(value) || other.test(value); } + + /** + * Returns a composed operator that first applies the {@code before} + * operator to its input, and then applies this operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. + * + * @param before the operator to apply before this operator is applied + * @return a composed operator that first applies the {@code before} + * operator and then applies this operator + * @throws NullPointerException if before is null + * + * @see #andThen(BooleanPredicate) + */ + default BooleanPredicate compose(BooleanPredicate before) { + Objects.requireNonNull(before); + return (boolean v) -> test(before.test(v)); + } + + /** + * Returns a composed operator that first applies this operator to + * its input, and then applies the {@code after} operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. + * + * @param after the operator to apply after this operator is applied + * @return a composed operator that first applies this operator and then + * applies the {@code after} operator + * @throws NullPointerException if after is null + * + * @see #compose(DoubleUnaryOperator) + */ + default BooleanPredicate andThen(BooleanPredicate after) { + Objects.requireNonNull(after); + return (boolean t) -> after.test(test(t)); + } } diff --git a/src/main/java/arachne/lib/hardware/DifferentialDrivetrain.java b/src/main/java/arachne/lib/hardware/DifferentialDrivetrain.java index 4b71b52..f98af8b 100644 --- a/src/main/java/arachne/lib/hardware/DifferentialDrivetrain.java +++ b/src/main/java/arachne/lib/hardware/DifferentialDrivetrain.java @@ -4,10 +4,8 @@ import arachne.lib.io.SettableDouble; import arachne.lib.listeners.DoubleProperty; -import arachne.lib.listeners.SimpleDoubleProperty; import arachne.lib.pipeline.DoublePipe; import arachne.lib.pipeline.DoubleSource; -import arachne.lib.pipeline.SimpleDoublePipe; import arachne.lib.systems.Subsystem; public abstract class DifferentialDrivetrain extends Subsystem @@ -25,10 +23,10 @@ public DifferentialDrivetrain(DoubleUnaryOperator outputModifier) { tankSource = new TankSource(); arcadeSource = new ArcadeSource(); - leftOutput = new SimpleDoublePipe(); + leftOutput = new DoublePipe(); leftOutput.setModifier(outputModifier); - rightOutput = new SimpleDoublePipe(); + rightOutput = new DoublePipe(); rightOutput.setModifier(outputModifier); } @@ -44,8 +42,8 @@ public class TankSource { protected final DoublePipe leftInput, rightInput; protected TankSource() { - leftInput = new SimpleDoublePipe(); - rightInput = new SimpleDoublePipe(); + leftInput = new DoublePipe(); + rightInput = new DoublePipe(); } public SettableDouble getLeftInput() { @@ -61,8 +59,8 @@ public class ArcadeSource { protected final DoubleProperty speedInput, rotationInput; protected ArcadeSource() { - speedInput = new SimpleDoubleProperty(); - rotationInput = new SimpleDoubleProperty(); + speedInput = new DoubleProperty(); + rotationInput = new DoubleProperty(); } public SettableDouble getSpeedInput() { diff --git a/src/main/java/arachne/lib/hardware/SimpleDifferentialDrivetrain.java b/src/main/java/arachne/lib/hardware/SimpleDifferentialDrivetrain.java index 713ee4e..817f084 100644 --- a/src/main/java/arachne/lib/hardware/SimpleDifferentialDrivetrain.java +++ b/src/main/java/arachne/lib/hardware/SimpleDifferentialDrivetrain.java @@ -5,7 +5,6 @@ import arachne.lib.io.SettableBoolean; import arachne.lib.listeners.BooleanProperty; import arachne.lib.listeners.DoubleChangeHandler; -import arachne.lib.listeners.SimpleBooleanProperty; import arachne.lib.logic.ArachneMath; public class SimpleDifferentialDrivetrain extends DifferentialDrivetrain @@ -17,7 +16,7 @@ public SimpleDifferentialDrivetrain() { } public SimpleDifferentialDrivetrain(boolean isInitiallyTankDrive, boolean squareInputs) { - this.isTankState = new SimpleBooleanProperty(isInitiallyTankDrive); + this.isTankState = new BooleanProperty(isInitiallyTankDrive); } @Override diff --git a/src/main/java/arachne/lib/io/Gettable.java b/src/main/java/arachne/lib/io/Gettable.java index b98b64f..5347322 100644 --- a/src/main/java/arachne/lib/io/Gettable.java +++ b/src/main/java/arachne/lib/io/Gettable.java @@ -4,6 +4,8 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; +import arachne.lib.logging.ArachneLogger; + @FunctionalInterface public interface Gettable extends Supplier { @@ -15,7 +17,28 @@ default GettableBoolean is(Predicate predicate) { return () -> predicate.test(get()); } - default Gettable withModifier(UnaryOperator modifier) { + default Gettable change(UnaryOperator modifier) { return () -> modifier.apply(get()); } + + public static Gettable create(Gettable lambda) { + return lambda; + } + + public static final class Wrapper implements Gettable { + protected Gettable gettable; + + public Wrapper wrap(Gettable gettable) { + this.gettable = gettable; + return this; + } + + @Override + public T get() { + if(gettable != null) return gettable.get(); + + ArachneLogger.getInstance().error("Tried to get Gettable wrapper with no contained gettable, returning null"); + return null; + } + } } diff --git a/src/main/java/arachne/lib/io/GettableBoolean.java b/src/main/java/arachne/lib/io/GettableBoolean.java index dcfae78..fbf8cee 100644 --- a/src/main/java/arachne/lib/io/GettableBoolean.java +++ b/src/main/java/arachne/lib/io/GettableBoolean.java @@ -3,6 +3,7 @@ import java.util.function.BooleanSupplier; import arachne.lib.function.BooleanPredicate; +import arachne.lib.logging.ArachneLogger; import arachne.lib.sequences.Action; import arachne.lib.sequences.Actionable; import arachne.lib.sequences.HostAction; @@ -48,4 +49,25 @@ default GettableBoolean or(GettableBoolean other) { default GettableBoolean xor(GettableBoolean other) { return () -> this.get() != other.get(); } + + public static GettableBoolean create(GettableBoolean lambda) { + return lambda; + } + + public static final class Wrapper implements GettableBoolean { + protected GettableBoolean gettable; + + public Wrapper wrap(GettableBoolean gettable) { + this.gettable = gettable; + return this; + } + + @Override + public boolean get() { + if(gettable != null) return gettable.get(); + + ArachneLogger.getInstance().error("Tried to get GettableBoolean wrapper with no contained gettable, returning false"); + return false; + } + } } diff --git a/src/main/java/arachne/lib/io/GettableDouble.java b/src/main/java/arachne/lib/io/GettableDouble.java index a1a510e..efe9d09 100644 --- a/src/main/java/arachne/lib/io/GettableDouble.java +++ b/src/main/java/arachne/lib/io/GettableDouble.java @@ -4,8 +4,7 @@ import java.util.function.DoubleSupplier; import java.util.function.DoubleUnaryOperator; -import edu.wpi.first.wpilibj.PIDSource; -import edu.wpi.first.wpilibj.PIDSourceType; +import arachne.lib.logging.ArachneLogger; @FunctionalInterface public interface GettableDouble extends DoubleSupplier @@ -25,28 +24,28 @@ default GettableBoolean is(DoublePredicate predicate) { return () -> predicate.test(get()); } - default GettableDouble withModifier(DoubleUnaryOperator modifier) { + default GettableDouble change(DoubleUnaryOperator modifier) { return () -> modifier.applyAsDouble(get()); } - default PIDSource asPIDSource(PIDSourceType pidSource) { - return new PIDSource() { - private PIDSourceType type = pidSource; - - @Override - public double pidGet() { - return GettableDouble.this.get(); - } - - @Override - public PIDSourceType getPIDSourceType() { - return type; - } + public static GettableDouble create(GettableDouble lambda) { + return lambda; + } + + public static final class Wrapper implements GettableDouble { + protected GettableDouble gettable; + + public Wrapper wrap(GettableDouble gettable) { + this.gettable = gettable; + return this; + } + + @Override + public double get() { + if(gettable != null) return gettable.get(); - @Override - public void setPIDSourceType(PIDSourceType pidSource) { - this.type = pidSource; - } - }; + ArachneLogger.getInstance().error("Tried to get GettableDouble wrapper with no contained gettable, returning 0"); + return 0; + } } } diff --git a/src/main/java/arachne/lib/io/Settable.java b/src/main/java/arachne/lib/io/Settable.java index 13e84d5..b06b83c 100644 --- a/src/main/java/arachne/lib/io/Settable.java +++ b/src/main/java/arachne/lib/io/Settable.java @@ -5,5 +5,7 @@ @FunctionalInterface public interface Settable extends Consumer { - // Empty, exists for future features + public static Settable create(Settable lambda) { + return lambda; + } } diff --git a/src/main/java/arachne/lib/io/SettableBoolean.java b/src/main/java/arachne/lib/io/SettableBoolean.java index 1a5dbfb..6699907 100644 --- a/src/main/java/arachne/lib/io/SettableBoolean.java +++ b/src/main/java/arachne/lib/io/SettableBoolean.java @@ -5,5 +5,7 @@ @FunctionalInterface public interface SettableBoolean extends BooleanConsumer { - // Empty, exists for future features + public static SettableBoolean create(SettableBoolean lambda) { + return lambda; + } } diff --git a/src/main/java/arachne/lib/io/SettableDouble.java b/src/main/java/arachne/lib/io/SettableDouble.java index 9ab64f9..f690c5c 100644 --- a/src/main/java/arachne/lib/io/SettableDouble.java +++ b/src/main/java/arachne/lib/io/SettableDouble.java @@ -2,13 +2,10 @@ import java.util.function.DoubleConsumer; -import edu.wpi.first.wpilibj.PIDOutput; - @FunctionalInterface -public interface SettableDouble extends DoubleConsumer, PIDOutput +public interface SettableDouble extends DoubleConsumer { - @Override - default void pidWrite(double output) { - accept(output); + public static SettableDouble create(SettableDouble lambda) { + return lambda; } } diff --git a/src/main/java/arachne/lib/io/sensors/BooleanSensor.java b/src/main/java/arachne/lib/io/sensors/BooleanSensor.java new file mode 100644 index 0000000..ad07bab --- /dev/null +++ b/src/main/java/arachne/lib/io/sensors/BooleanSensor.java @@ -0,0 +1,37 @@ +package arachne.lib.io.sensors; + +import arachne.lib.io.GettableBoolean; +import arachne.lib.io.SettableBoolean; +import arachne.lib.logging.ArachneLogger; + +public interface BooleanSensor extends GettableBoolean, SettableBoolean, Resettable +{ + public static final class Wrapper implements BooleanSensor { + protected BooleanSensor sensor; + + public Wrapper wrap(BooleanSensor sensor) { + this.sensor = sensor; + return this; + } + + @Override + public boolean get() { + if(sensor != null) return sensor.get(); + + ArachneLogger.getInstance().error("Tried to get BooleanSensor wrapper with no contained sensor, returning 0"); + return false; + } + + @Override + public void accept(boolean value) { + if(sensor != null) sensor.accept(value); + else ArachneLogger.getInstance().error("Tried to set BooleanSensor wrapper with no contained sensor"); + } + + @Override + public void reset() { + if(sensor != null) sensor.reset(); + else ArachneLogger.getInstance().error("Tried to reset BooleanSensor wrapper with no contained sensor"); + } + } +} diff --git a/src/main/java/arachne/lib/io/sensors/DoubleSensor.java b/src/main/java/arachne/lib/io/sensors/DoubleSensor.java new file mode 100644 index 0000000..f12590b --- /dev/null +++ b/src/main/java/arachne/lib/io/sensors/DoubleSensor.java @@ -0,0 +1,37 @@ +package arachne.lib.io.sensors; + +import arachne.lib.io.GettableDouble; +import arachne.lib.io.SettableDouble; +import arachne.lib.logging.ArachneLogger; + +public interface DoubleSensor extends GettableDouble, SettableDouble, Resettable +{ + public static final class Wrapper implements DoubleSensor { + protected DoubleSensor sensor; + + public Wrapper wrap(DoubleSensor sensor) { + this.sensor = sensor; + return this; + } + + @Override + public double get() { + if(sensor != null) return sensor.get(); + + ArachneLogger.getInstance().error("Tried to get DoubleSensor wrapper with no contained sensor, returning 0"); + return 0; + } + + @Override + public void accept(double value) { + if(sensor != null) sensor.accept(value); + else ArachneLogger.getInstance().error("Tried to set DoubleSensor wrapper with no contained sensor"); + } + + @Override + public void reset() { + if(sensor != null) sensor.reset(); + else ArachneLogger.getInstance().error("Tried to reset DoubleSensor wrapper with no contained sensor"); + } + } +} diff --git a/src/main/java/arachne/lib/io/sensors/Resettable.java b/src/main/java/arachne/lib/io/sensors/Resettable.java new file mode 100644 index 0000000..2955955 --- /dev/null +++ b/src/main/java/arachne/lib/io/sensors/Resettable.java @@ -0,0 +1,6 @@ +package arachne.lib.io.sensors; + +@FunctionalInterface +public interface Resettable { + void reset(); +} diff --git a/src/main/java/arachne/lib/io/sensors/Sensor.java b/src/main/java/arachne/lib/io/sensors/Sensor.java new file mode 100644 index 0000000..bddb756 --- /dev/null +++ b/src/main/java/arachne/lib/io/sensors/Sensor.java @@ -0,0 +1,37 @@ +package arachne.lib.io.sensors; + +import arachne.lib.io.Gettable; +import arachne.lib.io.Settable; +import arachne.lib.logging.ArachneLogger; + +public interface Sensor extends Gettable, Settable, Resettable +{ + public static final class Wrapper implements Sensor { + protected Sensor sensor; + + public Wrapper wrap(Sensor sensor) { + this.sensor = sensor; + return this; + } + + @Override + public T get() { + if(sensor != null) return sensor.get(); + + ArachneLogger.getInstance().error("Tried to set Sensor wrapper with no contained sensor"); + return null; + } + + @Override + public void accept(T value) { + if(sensor != null) sensor.accept(value); + else ArachneLogger.getInstance().error("Tried to set Sensor wrapper with no contained sensor"); + } + + @Override + public void reset() { + if(sensor != null) sensor.reset(); + else ArachneLogger.getInstance().error("Tried to reset Sensor wrapper with no contained sensor"); + } + } +} diff --git a/src/main/java/arachne/lib/io/sensors/SimpleBooleanSensor.java b/src/main/java/arachne/lib/io/sensors/SimpleBooleanSensor.java new file mode 100644 index 0000000..f3f7865 --- /dev/null +++ b/src/main/java/arachne/lib/io/sensors/SimpleBooleanSensor.java @@ -0,0 +1,36 @@ +package arachne.lib.io.sensors; + +import arachne.lib.io.GettableBoolean; +import arachne.lib.io.SettableBoolean; + +public class SimpleBooleanSensor implements BooleanSensor +{ + protected GettableBoolean getter; + protected SettableBoolean setter; + protected Resettable resetter; + + public SimpleBooleanSensor(GettableBoolean getter, SettableBoolean setter) { + this(getter, setter, () -> setter.accept(false)); + } + + public SimpleBooleanSensor(GettableBoolean getter, SettableBoolean setter, Resettable resetter) { + this.getter = getter; + this.setter = setter; + this.resetter = resetter; + } + + @Override + public boolean get() { + return getter.get(); + } + + @Override + public void accept(boolean value) { + setter.accept(value); + } + + @Override + public void reset() { + resetter.reset(); + } +} diff --git a/src/main/java/arachne/lib/io/sensors/SimpleDoubleSensor.java b/src/main/java/arachne/lib/io/sensors/SimpleDoubleSensor.java new file mode 100644 index 0000000..3cccd2e --- /dev/null +++ b/src/main/java/arachne/lib/io/sensors/SimpleDoubleSensor.java @@ -0,0 +1,36 @@ +package arachne.lib.io.sensors; + +import arachne.lib.io.GettableDouble; +import arachne.lib.io.SettableDouble; + +public class SimpleDoubleSensor implements DoubleSensor +{ + protected GettableDouble getter; + protected SettableDouble setter; + protected Resettable resetter; + + public SimpleDoubleSensor(GettableDouble getter, SettableDouble setter) { + this(getter, setter, () -> setter.accept(0)); + } + + public SimpleDoubleSensor(GettableDouble getter, SettableDouble setter, Resettable resetter) { + this.getter = getter; + this.setter = setter; + this.resetter = resetter; + } + + @Override + public double get() { + return getter.get(); + } + + @Override + public void accept(double value) { + setter.accept(value); + } + + @Override + public void reset() { + resetter.reset(); + } +} diff --git a/src/main/java/arachne/lib/io/sensors/SimpleSensor.java b/src/main/java/arachne/lib/io/sensors/SimpleSensor.java new file mode 100644 index 0000000..7bb8f81 --- /dev/null +++ b/src/main/java/arachne/lib/io/sensors/SimpleSensor.java @@ -0,0 +1,36 @@ +package arachne.lib.io.sensors; + +import arachne.lib.io.Gettable; +import arachne.lib.io.Settable; + +public class SimpleSensor implements Sensor +{ + protected Gettable getter; + protected Settable setter; + protected Resettable resetter; + + public SimpleSensor(Gettable getter, Settable setter) { + this(getter, setter, () -> setter.accept(null)); + } + + public SimpleSensor(Gettable getter, Settable setter, Resettable resetter) { + this.getter = getter; + this.setter = setter; + this.resetter = resetter; + } + + @Override + public T get() { + return getter.get(); + } + + @Override + public void accept(T value) { + setter.accept(value); + } + + @Override + public void reset() { + resetter.reset(); + } +} diff --git a/src/main/java/arachne/lib/listeners/BooleanProperty.java b/src/main/java/arachne/lib/listeners/BooleanProperty.java index 3c0a2ee..b78b768 100644 --- a/src/main/java/arachne/lib/listeners/BooleanProperty.java +++ b/src/main/java/arachne/lib/listeners/BooleanProperty.java @@ -1,14 +1,64 @@ package arachne.lib.listeners; -import arachne.lib.io.SettableBoolean; +import java.util.LinkedHashSet; +import java.util.Set; -public abstract class BooleanProperty extends ReadOnlyBooleanProperty implements SettableBoolean +import arachne.lib.function.BooleanPredicate; +import arachne.lib.pipeline.AbstractBooleanValve; + +public class BooleanProperty extends AbstractBooleanValve implements ReadOnlyBooleanProperty { + protected final Set changeHandlers; + protected boolean value; + + public BooleanProperty() { + this(false); + } + + public BooleanProperty(boolean initialValue) { + this.changeHandlers = new LinkedHashSet(); + this.value = initialValue; + } + @Override - public void accept(boolean value) { - fireChange(get(), value); - _accept(value); + public boolean get() { + return value; } - protected abstract void _accept(boolean value); + @Override + public boolean attach(BooleanChangeHandler changeHandler) { + return changeHandlers.add(changeHandler); + } + + @Override + public boolean detach(BooleanChangeHandler changeHandler) { + return changeHandlers.remove(changeHandler); + } + + @Override + public void detachAll() { + changeHandlers.clear(); + } + + @Override + protected void acceptValveValue(boolean value) { + fireChange(this.value, value); + this.value = value; + } + + protected void fireChange(boolean oldValue, boolean newValue) { + for(BooleanChangeHandler handler : changeHandlers) handler.onChange(oldValue, newValue); + } + + @Override + public BooleanProperty withModifier(BooleanPredicate modifier, BooleanPredicate... additionalModifiers) { + setModifier(modifier, additionalModifiers); + return this; + } + + @Override + public BooleanProperty withFilter(BooleanPredicate predicate) { + setFilter(predicate); + return this; + } } diff --git a/src/main/java/arachne/lib/listeners/DoubleProperty.java b/src/main/java/arachne/lib/listeners/DoubleProperty.java index 9f0c15d..79335b2 100644 --- a/src/main/java/arachne/lib/listeners/DoubleProperty.java +++ b/src/main/java/arachne/lib/listeners/DoubleProperty.java @@ -1,17 +1,68 @@ package arachne.lib.listeners; -import arachne.lib.io.SettableDouble; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.DoublePredicate; +import java.util.function.DoubleUnaryOperator; + +import arachne.lib.pipeline.AbstractDoubleValve; import edu.wpi.first.wpilibj.SpeedController; -public abstract class DoubleProperty extends ReadOnlyDoubleProperty implements SettableDouble +public class DoubleProperty extends AbstractDoubleValve implements ReadOnlyDoubleProperty { + protected final Set changeHandlers; + protected double value; + + public DoubleProperty() { + this(0); + } + + public DoubleProperty(double initialValue) { + this.changeHandlers = new LinkedHashSet(); + this.value = initialValue; + } + @Override - public void accept(double value) { - fireChange(get(), value); - _accept(value); + public double get() { + return value; } - protected abstract void _accept(double value); + @Override + public boolean attach(DoubleChangeHandler changeHandler) { + return changeHandlers.add(changeHandler); + } + + @Override + public boolean detach(DoubleChangeHandler changeHandler) { + return changeHandlers.remove(changeHandler); + } + + @Override + public void detachAll() { + changeHandlers.clear(); + } + + @Override + protected void acceptValveValue(double value) { + fireChange(this.value, value); + this.value = value; + } + + protected void fireChange(double oldValue, double newValue) { + for(DoubleChangeHandler handler : changeHandlers) handler.onChange(oldValue, newValue); + } + + @Override + public DoubleProperty withModifier(DoubleUnaryOperator modifier, DoubleUnaryOperator... additionalModifiers) { + setModifier(modifier, additionalModifiers); + return this; + } + + @Override + public DoubleProperty withFilter(DoublePredicate predicate) { + setFilter(predicate); + return this; + } public SpeedController asSpeedController() { return new SpeedController() { @@ -29,7 +80,7 @@ public void set(double speed) { @Override public void pidWrite(double output) { - DoubleProperty.this.pidWrite(output); + DoubleProperty.this.accept(output); } @Override diff --git a/src/main/java/arachne/lib/listeners/Property.java b/src/main/java/arachne/lib/listeners/Property.java index d772b2b..de3c242 100644 --- a/src/main/java/arachne/lib/listeners/Property.java +++ b/src/main/java/arachne/lib/listeners/Property.java @@ -1,14 +1,71 @@ package arachne.lib.listeners; -import arachne.lib.io.Settable; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; -public abstract class Property extends ReadOnlyProperty implements Settable +import arachne.lib.pipeline.AbstractValve; + +public class Property extends AbstractValve implements ReadOnlyProperty { + protected final Set> changeHandlers; + protected T value; + + public Property() { + this(null); + } + + public Property(T initialValue) { + this.changeHandlers = new LinkedHashSet>(); + this.value = initialValue; + } + + @Override + public T get() { + return value; + } + + @Override + public boolean attach(ChangeHandler changeHandler) { + return changeHandlers.add(changeHandler); + } + + @Override + public boolean detach(ChangeHandler changeHandler) { + return changeHandlers.remove(changeHandler); + } + + @Override + public void detachAll() { + changeHandlers.clear(); + } + + @Override + protected void acceptValveValue(T value) { + fireChange(this.value, value); + this.value = value; + } + + protected void fireChange(T oldValue, T newValue) { + for(ChangeHandler handler : changeHandlers) handler.onChange(oldValue, newValue); + } + @Override - public void accept(T value) { - fireChange(get(), value); - _accept(value); + public Property withModifier(UnaryOperator modifier) { + setModifier(modifier); + return this; } - protected abstract void _accept(T value); + @Override + public Property withModifier(UnaryOperator[] modifiers) { + setModifier(modifiers); + return this; + } + + @Override + public Property withFilter(Predicate predicate) { + setFilter(predicate); + return this; + } } diff --git a/src/main/java/arachne/lib/listeners/ReadOnlyBooleanProperty.java b/src/main/java/arachne/lib/listeners/ReadOnlyBooleanProperty.java index 31a2965..c563221 100644 --- a/src/main/java/arachne/lib/listeners/ReadOnlyBooleanProperty.java +++ b/src/main/java/arachne/lib/listeners/ReadOnlyBooleanProperty.java @@ -1,34 +1,5 @@ package arachne.lib.listeners; -import java.util.LinkedHashSet; -import java.util.Set; - import arachne.lib.io.GettableBoolean; -public abstract class ReadOnlyBooleanProperty implements GettableBoolean, BooleanHook -{ - protected final Set changeHandlers; - - public ReadOnlyBooleanProperty() { - this.changeHandlers = new LinkedHashSet(); - } - - @Override - public boolean attach(BooleanChangeHandler changeHandler) { - return changeHandlers.add(changeHandler); - } - - @Override - public boolean detach(BooleanChangeHandler changeHandler) { - return changeHandlers.remove(changeHandler); - } - - @Override - public void detachAll() { - changeHandlers.clear(); - } - - protected void fireChange(boolean oldValue, boolean newValue) { - for(BooleanChangeHandler handler : changeHandlers) handler.onChange(oldValue, newValue); - } -} +public interface ReadOnlyBooleanProperty extends GettableBoolean, BooleanHook { /* Intersection interface */ } diff --git a/src/main/java/arachne/lib/listeners/ReadOnlyDoubleProperty.java b/src/main/java/arachne/lib/listeners/ReadOnlyDoubleProperty.java index 93c1402..7ba44c1 100644 --- a/src/main/java/arachne/lib/listeners/ReadOnlyDoubleProperty.java +++ b/src/main/java/arachne/lib/listeners/ReadOnlyDoubleProperty.java @@ -1,34 +1,5 @@ package arachne.lib.listeners; -import java.util.LinkedHashSet; -import java.util.Set; - import arachne.lib.io.GettableDouble; -public abstract class ReadOnlyDoubleProperty implements GettableDouble, DoubleHook -{ - protected final Set changeHandlers; - - public ReadOnlyDoubleProperty() { - this.changeHandlers = new LinkedHashSet(); - } - - @Override - public boolean attach(DoubleChangeHandler changeHandler) { - return changeHandlers.add(changeHandler); - } - - @Override - public boolean detach(DoubleChangeHandler changeHandler) { - return changeHandlers.remove(changeHandler); - } - - @Override - public void detachAll() { - changeHandlers.clear(); - } - - protected void fireChange(double oldValue, double newValue) { - for(DoubleChangeHandler handler : changeHandlers) handler.onChange(oldValue, newValue); - } -} +public interface ReadOnlyDoubleProperty extends GettableDouble, DoubleHook { /* Intersection interface */ } diff --git a/src/main/java/arachne/lib/listeners/ReadOnlyProperty.java b/src/main/java/arachne/lib/listeners/ReadOnlyProperty.java index a249ffe..303bd51 100644 --- a/src/main/java/arachne/lib/listeners/ReadOnlyProperty.java +++ b/src/main/java/arachne/lib/listeners/ReadOnlyProperty.java @@ -1,34 +1,5 @@ package arachne.lib.listeners; -import java.util.LinkedHashSet; -import java.util.Set; - import arachne.lib.io.Gettable; -public abstract class ReadOnlyProperty implements Gettable, Hook -{ - protected final Set> changeHandlers; - - public ReadOnlyProperty() { - this.changeHandlers = new LinkedHashSet>(); - } - - @Override - public boolean attach(ChangeHandler changeHandler) { - return changeHandlers.add(changeHandler); - } - - @Override - public boolean detach(ChangeHandler changeHandler) { - return changeHandlers.remove(changeHandler); - } - - @Override - public void detachAll() { - changeHandlers.clear(); - } - - protected void fireChange(T oldValue, T newValue) { - for(ChangeHandler handler : changeHandlers) handler.onChange(oldValue, newValue); - } -} +public interface ReadOnlyProperty extends Gettable, Hook { /* Intersection interface */ } diff --git a/src/main/java/arachne/lib/listeners/ReadOnlySignal.java b/src/main/java/arachne/lib/listeners/ReadOnlySignal.java index f2bb8c1..e0daf31 100644 --- a/src/main/java/arachne/lib/listeners/ReadOnlySignal.java +++ b/src/main/java/arachne/lib/listeners/ReadOnlySignal.java @@ -1,25 +1,8 @@ package arachne.lib.listeners; -import java.util.LinkedHashSet; -import java.util.Set; - -public class ReadOnlySignal +public interface ReadOnlySignal { - protected Set handlers; - - public ReadOnlySignal() { - this.handlers = new LinkedHashSet(); - } - - public boolean attach(Runnable handler) { - return handlers.add(handler); - } - - public boolean detach(Runnable handler) { - return handlers.remove(handler); - } - - public void detachAll() { - handlers.clear(); - } + boolean attach(Runnable handler); + boolean detach(Runnable handler); + void detachAll(); } diff --git a/src/main/java/arachne/lib/listeners/Signal.java b/src/main/java/arachne/lib/listeners/Signal.java index 3b3810a..51bf898 100644 --- a/src/main/java/arachne/lib/listeners/Signal.java +++ b/src/main/java/arachne/lib/listeners/Signal.java @@ -1,7 +1,31 @@ package arachne.lib.listeners; -public class Signal extends ReadOnlySignal +import java.util.LinkedHashSet; +import java.util.Set; + +public class Signal implements ReadOnlySignal { + protected Set handlers; + + public Signal() { + this.handlers = new LinkedHashSet(); + } + + @Override + public boolean attach(Runnable handler) { + return handlers.add(handler); + } + + @Override + public boolean detach(Runnable handler) { + return handlers.remove(handler); + } + + @Override + public void detachAll() { + handlers.clear(); + } + public void fire() { for(Runnable handler : handlers) handler.run(); } diff --git a/src/main/java/arachne/lib/listeners/SimpleBooleanProperty.java b/src/main/java/arachne/lib/listeners/SimpleBooleanProperty.java deleted file mode 100644 index 373047c..0000000 --- a/src/main/java/arachne/lib/listeners/SimpleBooleanProperty.java +++ /dev/null @@ -1,25 +0,0 @@ -package arachne.lib.listeners; - -public class SimpleBooleanProperty extends BooleanProperty -{ - protected boolean value; - - public SimpleBooleanProperty() { - this(false); - } - - public SimpleBooleanProperty(boolean initialValue) { - super(); - this.value = initialValue; - } - - @Override - public boolean get() { - return value; - } - - @Override - protected void _accept(boolean value) { - this.value = value; - } -} diff --git a/src/main/java/arachne/lib/listeners/SimpleDoubleProperty.java b/src/main/java/arachne/lib/listeners/SimpleDoubleProperty.java deleted file mode 100644 index dc56f0a..0000000 --- a/src/main/java/arachne/lib/listeners/SimpleDoubleProperty.java +++ /dev/null @@ -1,25 +0,0 @@ -package arachne.lib.listeners; - -public class SimpleDoubleProperty extends DoubleProperty -{ - protected double value; - - public SimpleDoubleProperty() { - this(0); - } - - public SimpleDoubleProperty(double initialValue) { - super(); - this.value = initialValue; - } - - @Override - public double get() { - return value; - } - - @Override - protected void _accept(double value) { - this.value = value; - } -} diff --git a/src/main/java/arachne/lib/listeners/SimpleProperty.java b/src/main/java/arachne/lib/listeners/SimpleProperty.java deleted file mode 100644 index 16b929d..0000000 --- a/src/main/java/arachne/lib/listeners/SimpleProperty.java +++ /dev/null @@ -1,25 +0,0 @@ -package arachne.lib.listeners; - -public class SimpleProperty extends Property -{ - protected T value; - - public SimpleProperty() { - this(null); - } - - public SimpleProperty(T initialValue) { - super(); - this.value = initialValue; - } - - @Override - public T get() { - return value; - } - - @Override - protected void _accept(T value) { - this.value = value; - } -} diff --git a/src/main/java/arachne/lib/listeners/SimpleReadOnlyBooleanProperty.java b/src/main/java/arachne/lib/listeners/SimpleReadOnlyBooleanProperty.java deleted file mode 100644 index 3828a6e..0000000 --- a/src/main/java/arachne/lib/listeners/SimpleReadOnlyBooleanProperty.java +++ /dev/null @@ -1,20 +0,0 @@ -package arachne.lib.listeners; - -public class SimpleReadOnlyBooleanProperty extends ReadOnlyBooleanProperty -{ - protected boolean value; - - public SimpleReadOnlyBooleanProperty() { - this(false); - } - - public SimpleReadOnlyBooleanProperty(boolean initialValue) { - super(); - this.value = initialValue; - } - - @Override - public boolean get() { - return value; - } -} diff --git a/src/main/java/arachne/lib/listeners/SimpleReadOnlyDoubleProperty.java b/src/main/java/arachne/lib/listeners/SimpleReadOnlyDoubleProperty.java deleted file mode 100644 index 4adf9ef..0000000 --- a/src/main/java/arachne/lib/listeners/SimpleReadOnlyDoubleProperty.java +++ /dev/null @@ -1,20 +0,0 @@ -package arachne.lib.listeners; - -public class SimpleReadOnlyDoubleProperty extends ReadOnlyDoubleProperty -{ - protected double value; - - public SimpleReadOnlyDoubleProperty() { - this(0); - } - - public SimpleReadOnlyDoubleProperty(double initialValue) { - super(); - this.value = initialValue; - } - - @Override - public double get() { - return value; - } -} diff --git a/src/main/java/arachne/lib/listeners/SimpleReadOnlyProperty.java b/src/main/java/arachne/lib/listeners/SimpleReadOnlyProperty.java deleted file mode 100644 index ccda44b..0000000 --- a/src/main/java/arachne/lib/listeners/SimpleReadOnlyProperty.java +++ /dev/null @@ -1,20 +0,0 @@ -package arachne.lib.listeners; - -public class SimpleReadOnlyProperty extends ReadOnlyProperty -{ - protected T value; - - public SimpleReadOnlyProperty() { - this(null); - } - - public SimpleReadOnlyProperty(T initialValue) { - super(); - this.value = initialValue; - } - - @Override - public T get() { - return value; - } -} diff --git a/src/main/java/arachne/lib/logic/ArachneMath.java b/src/main/java/arachne/lib/logic/ArachneMath.java index 21624ab..7de3850 100644 --- a/src/main/java/arachne/lib/logic/ArachneMath.java +++ b/src/main/java/arachne/lib/logic/ArachneMath.java @@ -6,6 +6,15 @@ public static double inBounds(double value, double min, double max) { return Math.min(Math.max(value, min), max); } + public static double wrapAround(double value, double min, double max) { + double diff = max - min; + + while(value < min) value += diff; + while(value > max) value -= diff; + + return value; + } + public static double signedPow(double value, double exponent) { if(value < 0) return -Math.pow(-value, exponent); return Math.pow(value, exponent); diff --git a/src/main/java/arachne/lib/pipeline/SimpleBooleanPipe.java b/src/main/java/arachne/lib/pipeline/AbstractBooleanValve.java similarity index 77% rename from src/main/java/arachne/lib/pipeline/SimpleBooleanPipe.java rename to src/main/java/arachne/lib/pipeline/AbstractBooleanValve.java index 18a6cd9..39357c7 100644 --- a/src/main/java/arachne/lib/pipeline/SimpleBooleanPipe.java +++ b/src/main/java/arachne/lib/pipeline/AbstractBooleanValve.java @@ -5,17 +5,15 @@ import arachne.lib.function.BooleanPredicate; -public class SimpleBooleanPipe extends AbstractBooleanSource implements BooleanPipe +public abstract class AbstractBooleanValve implements BooleanValve { protected BooleanPredicate modifier; protected Set filters; - - protected boolean value; protected boolean hasDefaultValue; protected boolean defaultValue; - public SimpleBooleanPipe() { + public AbstractBooleanValve() { super(); this.filters = new LinkedHashSet(); @@ -33,15 +31,13 @@ public void accept(boolean value) { } } - this.value = passesFilters ? value : defaultValue; - - if(passesFilters || hasDefaultValue) feedOutputs(); - } - - @Override - protected boolean getOutputValue() { - return modifier != null ? modifier.test(value) : value; + if(passesFilters || hasDefaultValue) { + value = modifier != null ? modifier.test(value) : value; + acceptValveValue(passesFilters ? value : defaultValue); + } } + + protected abstract void acceptValveValue(boolean value); @Override public void setModifier(BooleanPredicate modifier) { diff --git a/src/main/java/arachne/lib/pipeline/SimpleDoublePipe.java b/src/main/java/arachne/lib/pipeline/AbstractDoubleValve.java similarity index 53% rename from src/main/java/arachne/lib/pipeline/SimpleDoublePipe.java rename to src/main/java/arachne/lib/pipeline/AbstractDoubleValve.java index 11e544c..f681ef3 100644 --- a/src/main/java/arachne/lib/pipeline/SimpleDoublePipe.java +++ b/src/main/java/arachne/lib/pipeline/AbstractDoubleValve.java @@ -5,19 +5,15 @@ import java.util.function.DoublePredicate; import java.util.function.DoubleUnaryOperator; -import edu.wpi.first.wpilibj.SpeedController; - -public class SimpleDoublePipe extends AbstractDoubleSource implements DoublePipe +public abstract class AbstractDoubleValve implements DoubleValve { protected DoubleUnaryOperator modifier; protected Set filters; - - protected double value; protected boolean hasDefaultValue; protected double defaultValue; - public SimpleDoublePipe() { + public AbstractDoubleValve() { super(); this.filters = new LinkedHashSet(); @@ -35,15 +31,13 @@ public void accept(double value) { } } - this.value = passesFilters ? value : defaultValue; - - if(passesFilters || hasDefaultValue) feedOutputs(); - } - - @Override - protected double getOutputValue() { - return modifier != null ? modifier.applyAsDouble(value) : value; + if(passesFilters || hasDefaultValue) { + value = modifier != null ? modifier.applyAsDouble(value) : value; + acceptValveValue(passesFilters ? value : defaultValue); + } } + + protected abstract void acceptValveValue(double value); @Override public void setModifier(DoubleUnaryOperator modifier) { @@ -80,45 +74,4 @@ public void enableFilteredOutput(double defaultValue) { public void disableFilteredOutput() { this.hasDefaultValue = false; } - - public SpeedController asSpeedController() { - return new SpeedController() { - private boolean isInverted = false; - - @Override - public double get() { - return value; - } - - @Override - public void set(double speed) { - SimpleDoublePipe.this.accept(isInverted ? -speed : speed); - } - - @Override - public void pidWrite(double output) { - SimpleDoublePipe.this.pidWrite(output); - } - - @Override - public boolean getInverted() { - return isInverted; - } - - @Override - public void setInverted(boolean isInverted) { - this.isInverted = isInverted; - } - - @Override - public void disable() { - SimpleDoublePipe.this.accept(0); - } - - @Override - public void stopMotor() { - disable(); - } - }; - } } diff --git a/src/main/java/arachne/lib/pipeline/SimplePipe.java b/src/main/java/arachne/lib/pipeline/AbstractValve.java similarity index 79% rename from src/main/java/arachne/lib/pipeline/SimplePipe.java rename to src/main/java/arachne/lib/pipeline/AbstractValve.java index 14cad3d..c52732f 100644 --- a/src/main/java/arachne/lib/pipeline/SimplePipe.java +++ b/src/main/java/arachne/lib/pipeline/AbstractValve.java @@ -5,17 +5,15 @@ import java.util.function.Predicate; import java.util.function.UnaryOperator; -public class SimplePipe extends AbstractSource implements Pipe +public abstract class AbstractValve implements Valve { protected UnaryOperator modifier; protected Set> filters; - protected T value; - protected boolean hasDefaultValue; protected T defaultValue; - public SimplePipe() { + public AbstractValve() { super(); this.filters = new LinkedHashSet>(); @@ -33,15 +31,13 @@ public void accept(T value) { } } - this.value = passesFilters ? value : defaultValue; - - if(passesFilters || hasDefaultValue) feedOutputs(); - } - - @Override - protected T getOutputValue() { - return modifier != null ? modifier.apply(value) : value; + if(passesFilters || hasDefaultValue) { + value = modifier != null ? modifier.apply(value) : value; + acceptValveValue(passesFilters ? value : defaultValue); + } } + + protected abstract void acceptValveValue(T value); @Override public void setModifier(UnaryOperator modifier) { diff --git a/src/main/java/arachne/lib/pipeline/BooleanPipe.java b/src/main/java/arachne/lib/pipeline/BooleanPipe.java index 60b4777..9e7a76e 100644 --- a/src/main/java/arachne/lib/pipeline/BooleanPipe.java +++ b/src/main/java/arachne/lib/pipeline/BooleanPipe.java @@ -1,22 +1,58 @@ package arachne.lib.pipeline; +import java.util.LinkedHashSet; +import java.util.Set; + import arachne.lib.function.BooleanPredicate; import arachne.lib.io.SettableBoolean; -public interface BooleanPipe extends BooleanSource, SettableBoolean +public class BooleanPipe extends AbstractBooleanValve implements BooleanSource { - void setModifier(BooleanPredicate modifier); - void clearModifier(); + protected Set outputs; + protected boolean value; - boolean addFilter(BooleanPredicate predicate); - boolean removeFilter(BooleanPredicate predicate); - void clearFilters(); + public BooleanPipe() { + super(); + + this.outputs = new LinkedHashSet(); + } + + @Override + public SettableT attachOutput(SettableT settable) { + outputs.add(settable); + return settable; + } + + @Override + public boolean detachOutput(SettableBoolean settable) { + return outputs.remove(settable); + } + + @Override + public void detachAllOutputs() { + outputs.clear(); + } + + @Override + public void feedOutputs() { + for(SettableBoolean output : outputs) output.accept(value); + } + + @Override + protected void acceptValveValue(boolean value) { + this.value = value; + feedOutputs(); + } - void enableFilteredOutput(boolean defaultValue); - void disableFilteredOutput(); + @Override + public BooleanPipe withModifier(BooleanPredicate modifier, BooleanPredicate... additionalModifiers) { + setModifier(modifier, additionalModifiers); + return this; + } - default void setFilter(BooleanPredicate predicate) { - clearFilters(); - addFilter(predicate); + @Override + public BooleanPipe withFilter(BooleanPredicate predicate) { + setFilter(predicate); + return this; } } diff --git a/src/main/java/arachne/lib/pipeline/BooleanSink.java b/src/main/java/arachne/lib/pipeline/BooleanSink.java new file mode 100644 index 0000000..6cfa6bc --- /dev/null +++ b/src/main/java/arachne/lib/pipeline/BooleanSink.java @@ -0,0 +1,18 @@ +package arachne.lib.pipeline; + +import arachne.lib.io.GettableBoolean; + +public class BooleanSink extends AbstractBooleanValve implements GettableBoolean +{ + protected boolean value; + + @Override + public boolean get() { + return value; + } + + @Override + protected void acceptValveValue(boolean value) { + this.value = value; + } +} diff --git a/src/main/java/arachne/lib/pipeline/BooleanValve.java b/src/main/java/arachne/lib/pipeline/BooleanValve.java new file mode 100644 index 0000000..322168f --- /dev/null +++ b/src/main/java/arachne/lib/pipeline/BooleanValve.java @@ -0,0 +1,37 @@ +package arachne.lib.pipeline; + +import arachne.lib.function.BooleanPredicate; +import arachne.lib.io.SettableBoolean; + +public interface BooleanValve extends SettableBoolean +{ + void setModifier(BooleanPredicate modifier); + void clearModifier(); + + default void setModifier(BooleanPredicate modifier, BooleanPredicate... additionalModifiers) { + for(BooleanPredicate additionalModifier : additionalModifiers) modifier = modifier.andThen(additionalModifier); + setModifier(modifier); + } + + default BooleanValve withModifier(BooleanPredicate modifier, BooleanPredicate... additionalModifiers) { + setModifier(modifier, additionalModifiers); + return this; + } + + boolean addFilter(BooleanPredicate predicate); + boolean removeFilter(BooleanPredicate predicate); + void clearFilters(); + + void enableFilteredOutput(boolean defaultValue); + void disableFilteredOutput(); + + default void setFilter(BooleanPredicate predicate) { + clearFilters(); + addFilter(predicate); + } + + default BooleanValve withFilter(BooleanPredicate predicate) { + setFilter(predicate); + return this; + } +} diff --git a/src/main/java/arachne/lib/pipeline/DoublePipe.java b/src/main/java/arachne/lib/pipeline/DoublePipe.java index 1f960ef..5e34659 100644 --- a/src/main/java/arachne/lib/pipeline/DoublePipe.java +++ b/src/main/java/arachne/lib/pipeline/DoublePipe.java @@ -1,24 +1,101 @@ package arachne.lib.pipeline; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.function.DoublePredicate; import java.util.function.DoubleUnaryOperator; import arachne.lib.io.SettableDouble; +import edu.wpi.first.wpilibj.SpeedController; -public interface DoublePipe extends DoubleSource, SettableDouble +public class DoublePipe extends AbstractDoubleValve implements DoubleSource { - void setModifier(DoubleUnaryOperator modifier); - void clearModifier(); + protected Set outputs; + protected double value; - boolean addFilter(DoublePredicate predicate); - boolean removeFilter(DoublePredicate predicate); - void clearFilters(); + public DoublePipe() { + super(); + + this.outputs = new LinkedHashSet(); + } + + @Override + public SettableT attachOutput(SettableT settable) { + outputs.add(settable); + return settable; + } + + @Override + public boolean detachOutput(SettableDouble settable) { + return outputs.remove(settable); + } + + @Override + public void detachAllOutputs() { + outputs.clear(); + } + + @Override + public void feedOutputs() { + for(SettableDouble output : outputs) output.accept(value); + } + + @Override + protected void acceptValveValue(double value) { + this.value = value; + feedOutputs(); + } - void enableFilteredOutput(double defaultValue); - void disableFilteredOutput(); + @Override + public DoublePipe withModifier(DoubleUnaryOperator modifier, DoubleUnaryOperator... additionalModifiers) { + setModifier(modifier, additionalModifiers); + return this; + } + + @Override + public DoublePipe withFilter(DoublePredicate predicate) { + setFilter(predicate); + return this; + } - default void setFilter(DoublePredicate predicate) { - clearFilters(); - addFilter(predicate); + public SpeedController asSpeedController() { + return new SpeedController() { + private boolean isInverted = false; + + @Override + public double get() { + return DoublePipe.this.value; + } + + @Override + public void set(double speed) { + DoublePipe.this.accept(isInverted ? -speed : speed); + } + + @Override + public void pidWrite(double output) { + DoublePipe.this.accept(output); + } + + @Override + public boolean getInverted() { + return isInverted; + } + + @Override + public void setInverted(boolean isInverted) { + this.isInverted = isInverted; + } + + @Override + public void disable() { + DoublePipe.this.accept(0); + } + + @Override + public void stopMotor() { + disable(); + } + }; } } diff --git a/src/main/java/arachne/lib/pipeline/DoubleSink.java b/src/main/java/arachne/lib/pipeline/DoubleSink.java new file mode 100644 index 0000000..57936fd --- /dev/null +++ b/src/main/java/arachne/lib/pipeline/DoubleSink.java @@ -0,0 +1,18 @@ +package arachne.lib.pipeline; + +import arachne.lib.io.GettableDouble; + +public class DoubleSink extends AbstractDoubleValve implements GettableDouble +{ + protected double value; + + @Override + public double get() { + return value; + } + + @Override + protected void acceptValveValue(double value) { + this.value = value; + } +} diff --git a/src/main/java/arachne/lib/pipeline/DoubleValve.java b/src/main/java/arachne/lib/pipeline/DoubleValve.java new file mode 100644 index 0000000..b80cb5f --- /dev/null +++ b/src/main/java/arachne/lib/pipeline/DoubleValve.java @@ -0,0 +1,39 @@ +package arachne.lib.pipeline; + +import java.util.function.DoublePredicate; +import java.util.function.DoubleUnaryOperator; + +import arachne.lib.io.SettableDouble; + +public interface DoubleValve extends SettableDouble +{ + void setModifier(DoubleUnaryOperator modifier); + void clearModifier(); + + default void setModifier(DoubleUnaryOperator modifier, DoubleUnaryOperator... additionalModifiers) { + for(DoubleUnaryOperator additionalModifier : additionalModifiers) modifier = modifier.andThen(additionalModifier); + setModifier(modifier); + } + + default DoubleValve withModifier(DoubleUnaryOperator modifier, DoubleUnaryOperator... additionalModifiers) { + setModifier(modifier, additionalModifiers); + return this; + } + + boolean addFilter(DoublePredicate predicate); + boolean removeFilter(DoublePredicate predicate); + void clearFilters(); + + void enableFilteredOutput(double defaultValue); + void disableFilteredOutput(); + + default void setFilter(DoublePredicate predicate) { + clearFilters(); + addFilter(predicate); + } + + default DoubleValve withFilter(DoublePredicate predicate) { + setFilter(predicate); + return this; + } +} diff --git a/src/main/java/arachne/lib/pipeline/Pipe.java b/src/main/java/arachne/lib/pipeline/Pipe.java index dd34c0f..a783466 100644 --- a/src/main/java/arachne/lib/pipeline/Pipe.java +++ b/src/main/java/arachne/lib/pipeline/Pipe.java @@ -1,24 +1,65 @@ package arachne.lib.pipeline; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.function.Predicate; import java.util.function.UnaryOperator; import arachne.lib.io.Settable; -public interface Pipe extends Source, Settable +public class Pipe extends AbstractValve implements Source { - void setModifier(UnaryOperator modifier); - void clearModifier(); + protected Set> outputs; + protected T value; - boolean addFilter(Predicate predicate); - boolean removeFilter(Predicate predicate); - void clearFilters(); + public Pipe() { + super(); + + this.outputs = new LinkedHashSet>(); + } + + @Override + public > SettableT attachOutput(SettableT settable) { + outputs.add(settable); + return settable; + } + + @Override + public boolean detachOutput(Settable settable) { + return outputs.remove(settable); + } + + @Override + public void detachAllOutputs() { + outputs.clear(); + } + + @Override + public void feedOutputs() { + for(Settable output : outputs) output.accept(value); + } + + @Override + protected void acceptValveValue(T value) { + this.value = value; + feedOutputs(); + } - void enableFilteredOutput(T defaultValue); - void disableFilteredOutput(); + @Override + public Pipe withModifier(UnaryOperator modifier) { + setModifier(modifier); + return this; + } + + @Override + public Pipe withModifier(UnaryOperator[] modifiers) { + setModifier(modifiers); + return this; + } - default void setFilter(Predicate predicate) { - clearFilters(); - addFilter(predicate); + @Override + public Pipe withFilter(Predicate predicate) { + setFilter(predicate); + return this; } } diff --git a/src/main/java/arachne/lib/pipeline/Sink.java b/src/main/java/arachne/lib/pipeline/Sink.java new file mode 100644 index 0000000..c242061 --- /dev/null +++ b/src/main/java/arachne/lib/pipeline/Sink.java @@ -0,0 +1,18 @@ +package arachne.lib.pipeline; + +import arachne.lib.io.Gettable; + +public class Sink extends AbstractValve implements Gettable +{ + protected T value; + + @Override + public T get() { + return value; + } + + @Override + protected void acceptValveValue(T value) { + this.value = value; + } +} diff --git a/src/main/java/arachne/lib/pipeline/Valve.java b/src/main/java/arachne/lib/pipeline/Valve.java new file mode 100644 index 0000000..2b13c4e --- /dev/null +++ b/src/main/java/arachne/lib/pipeline/Valve.java @@ -0,0 +1,48 @@ +package arachne.lib.pipeline; + +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +import arachne.lib.io.Settable; + +public interface Valve extends Settable +{ + void setModifier(UnaryOperator modifier); + void clearModifier(); + + default void setModifier(UnaryOperator[] modifiers) { + final UnaryOperator[] modifierChain = modifiers.clone(); + + setModifier((value) -> { + for(UnaryOperator modifier : modifierChain) value = modifier.apply(value); + return value; + }); + } + + default Valve withModifier(UnaryOperator modifier) { + setModifier(modifier); + return this; + } + + default Valve withModifier(UnaryOperator[] modifiers) { + setModifier(modifiers); + return this; + } + + boolean addFilter(Predicate predicate); + boolean removeFilter(Predicate predicate); + void clearFilters(); + + void enableFilteredOutput(T defaultValue); + void disableFilteredOutput(); + + default void setFilter(Predicate predicate) { + clearFilters(); + addFilter(predicate); + } + + default Valve withFilter(Predicate predicate) { + setFilter(predicate); + return this; + } +} diff --git a/src/main/java/arachne/lib/types/TriState.java b/src/main/java/arachne/lib/types/TriState.java new file mode 100644 index 0000000..fd3d42a --- /dev/null +++ b/src/main/java/arachne/lib/types/TriState.java @@ -0,0 +1,25 @@ +package arachne.lib.types; + +public enum TriState +{ + POSITIVE, + ZERO, + NEGATIVE; + + public static TriState fromBooleans(boolean positive, boolean negative) { + if(positive) { + if(negative) return ZERO; + else return POSITIVE; + } + else if(negative) return NEGATIVE; + + return ZERO; + } + + public static TriState fromDouble(Double value) { + if(value > 0) return POSITIVE; + else if(value < 0) return NEGATIVE; + + return ZERO; + } +} diff --git a/src/main/java/arachne/tapestry/LogicTapestry.java b/src/main/java/arachne/tapestry/LogicTapestry.java new file mode 100644 index 0000000..d4e9490 --- /dev/null +++ b/src/main/java/arachne/tapestry/LogicTapestry.java @@ -0,0 +1,20 @@ +package arachne.tapestry; + +import java.util.function.DoubleUnaryOperator; + +import arachne.lib.logic.ArachneMath; + +public class LogicTapestry +{ + public static DoubleUnaryOperator inBounds(double min, double max) { + return (value) -> ArachneMath.inBounds(value, min, max); + } + + public static DoubleUnaryOperator wrapAround(double min, double max) { + return (value) -> ArachneMath.wrapAround(value, min, max); + } + + public static DoubleUnaryOperator signedPow(double exponent) { + return (value) -> ArachneMath.signedPow(value, exponent); + } +} diff --git a/src/test/java/arachne/test/logic/LinearMapTest.java b/src/test/java/arachne/test/logic/LinearMapTest.java index e66bd2e..35bebe0 100644 --- a/src/test/java/arachne/test/logic/LinearMapTest.java +++ b/src/test/java/arachne/test/logic/LinearMapTest.java @@ -3,10 +3,8 @@ import org.junit.jupiter.api.Test; import arachne.lib.listeners.DoubleProperty; -import arachne.lib.listeners.SimpleDoubleProperty; import arachne.lib.logic.LinearMap; import arachne.lib.pipeline.DoublePipe; -import arachne.lib.pipeline.SimpleDoublePipe; import static arachne.lib.logic.DoubleComparison.*; @@ -21,8 +19,8 @@ public class LinearMapTest @BeforeEach void beforeEach() { - input = new SimpleDoublePipe(); - output = new SimpleDoubleProperty(); + input = new DoublePipe(); + output = new DoubleProperty(); } @AfterEach