[wpilib] Synchronize C++ and Java versions of BooleanEvent (#6776)

This commit is contained in:
Christopher Mahoney
2024-07-19 00:08:28 -04:00
committed by GitHub
parent 8d857cdb78
commit 45823abe86
3 changed files with 92 additions and 97 deletions

View File

@@ -12,30 +12,29 @@ import java.util.function.BiFunction;
import java.util.function.BooleanSupplier;
/**
* This class provides an easy way to link actions to high-active logic signals. Each object
* This class provides an easy way to link actions to active high logic signals. Each object
* represents a digital signal to which callback actions can be bound using {@link
* #ifHigh(Runnable)}.
*
* <p>These signals can easily be composed for advanced functionality using {@link
* #and(BooleanSupplier)}, {@link #or(BooleanSupplier)}, {@link #negate()} etc.
* <p>BooleanEvents can easily be composed for advanced functionality using {@link
* #and(BooleanSupplier)}, {@link #or(BooleanSupplier)}, and {@link #negate()}.
*
* <p>To get an event that activates only when this one changes, see {@link #falling()} and {@link
* #rising()}.
* <p>To get a new BooleanEvent that triggers when this one changes see {@link #falling()} and
* {@link #rising()}.
*/
public class BooleanEvent implements BooleanSupplier {
/** Poller loop. */
protected final EventLoop m_loop;
/** Condition. */
private final BooleanSupplier m_signal;
/** The state of the condition in the current loop poll. Nightmare to manage. */
private final AtomicBoolean m_state = new AtomicBoolean(false);
/**
* Creates a new event with the given signal determining whether it is active.
* Creates a new event that is active when the condition is true.
*
* @param loop the loop that polls this event
* @param loop the loop that polls this event.
* @param signal the digital signal represented by this object.
*/
public BooleanEvent(EventLoop loop, BooleanSupplier signal) {
@@ -46,7 +45,7 @@ public class BooleanEvent implements BooleanSupplier {
}
/**
* Check the state of this signal (high or low) as of the last loop poll.
* Returns the state of this signal (high or low) as of the last loop poll.
*
* @return true for the high state, false for the low state. If the event was never polled, it
* returns the state at event construction.
@@ -71,9 +70,61 @@ public class BooleanEvent implements BooleanSupplier {
}
/**
* Get a new event that events only when this one newly changes to true.
* A method to "downcast" a BooleanEvent instance to a subclass (for example, to a command-based
* version of this class).
*
* @return a new event representing when this one newly changes to true.
* @param ctor a method reference to the constructor of the subclass that accepts the loop as the
* first parameter and the condition/signal as the second.
* @param <T> the subclass type
* @return an instance of the subclass.
*/
public <T extends BooleanSupplier> T castTo(BiFunction<EventLoop, BooleanSupplier, T> ctor) {
return ctor.apply(m_loop, m_state::get);
}
/**
* Creates a new event that is active when this event is inactive.
*
* @return the new event.
*/
public BooleanEvent negate() {
return new BooleanEvent(m_loop, () -> !m_state.get());
}
/**
* Composes this event with another event, returning a new event that is active when both events
* are active.
*
* <p>The events must use the same event loop. If the events use different event loops, the
* composed signal won't update until both loops are polled.
*
* @param other the event to compose with.
* @return the new event.
*/
public BooleanEvent and(BooleanSupplier other) {
requireNonNullParam(other, "other", "and");
return new BooleanEvent(m_loop, () -> m_state.get() && other.getAsBoolean());
}
/**
* Composes this event with another event, returning a new event that is active when either event
* is active.
*
* <p>The events must use the same event loop. If the events use different event loops, the
* composed signal won't update until both loops are polled.
*
* @param other the event to compose with.
* @return the new event.
*/
public BooleanEvent or(BooleanSupplier other) {
requireNonNullParam(other, "other", "or");
return new BooleanEvent(m_loop, () -> m_state.get() || other.getAsBoolean());
}
/**
* Creates a new event that triggers when this one changes from false to true.
*
* @return the new event.
*/
public BooleanEvent rising() {
return new BooleanEvent(
@@ -92,9 +143,9 @@ public class BooleanEvent implements BooleanSupplier {
}
/**
* Get a new event that triggers only when this one newly changes to false.
* Creates a new event that triggers when this one changes from true to false.
*
* @return a new event representing when this one newly changes to false.
* @return the event.
*/
public BooleanEvent falling() {
return new BooleanEvent(
@@ -117,7 +168,7 @@ public class BooleanEvent implements BooleanSupplier {
* active for longer than the specified period.
*
* @param seconds The debounce period.
* @return The debounced event (rising edges debounced only)
* @return The debounced event (rising edges debounced only).
*/
public BooleanEvent debounce(double seconds) {
return debounce(seconds, Debouncer.DebounceType.kRising);
@@ -143,57 +194,4 @@ public class BooleanEvent implements BooleanSupplier {
}
});
}
/**
* Creates a new event that is active when this event is inactive, i.e. that acts as the negation
* of this event.
*
* @return the negated event
*/
public BooleanEvent negate() {
return new BooleanEvent(m_loop, () -> !m_state.get());
}
/**
* Composes this event with another event, returning a new signal that is in the high state when
* both signals are in the high state.
*
* <p>The events must use the same event loop. If the events use different event loops, the
* composed signal won't update until both loops are polled.
*
* @param other the event to compose with
* @return the event that is active when both events are active
*/
public BooleanEvent and(BooleanSupplier other) {
requireNonNullParam(other, "other", "and");
return new BooleanEvent(m_loop, () -> m_state.get() && other.getAsBoolean());
}
/**
* Composes this event with another event, returning a new signal that is high when either signal
* is high.
*
* <p>The events must use the same event loop. If the events use different event loops, the
* composed signal won't update until both loops are polled.
*
* @param other the event to compose with
* @return a signal that is high when either signal is high.
*/
public BooleanEvent or(BooleanSupplier other) {
requireNonNullParam(other, "other", "or");
return new BooleanEvent(m_loop, () -> m_state.get() || other.getAsBoolean());
}
/**
* A method to "downcast" a BooleanEvent instance to a subclass (for example, to a command-based
* version of this class).
*
* @param ctor a method reference to the constructor of the subclass that accepts the loop as the
* first parameter and the condition/signal as the second.
* @param <T> the subclass type
* @return an instance of the subclass.
*/
public <T extends BooleanSupplier> T castTo(BiFunction<EventLoop, BooleanSupplier, T> ctor) {
return ctor.apply(m_loop, m_state::get);
}
}