001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj2.command; 006 007import static edu.wpi.first.util.ErrorMessages.requireNonNullParam; 008 009import edu.wpi.first.util.sendable.SendableBuilder; 010import java.util.Set; 011import java.util.function.Supplier; 012 013/** 014 * Defers Command construction to runtime. Runs the command returned by a supplier when this command 015 * is initialized, and ends when it ends. Useful for performing runtime tasks before creating a new 016 * command. If this command is interrupted, it will cancel the command. 017 * 018 * <p>Note that the supplier <i>must</i> create a new Command each call. For selecting one of a 019 * preallocated set of commands, use {@link SelectCommand}. 020 * 021 * <p>This class is provided by the NewCommands VendorDep 022 */ 023public class DeferredCommand extends Command { 024 private final Command m_nullCommand = 025 new PrintCommand("[DeferredCommand] Supplied command was null!"); 026 027 private final Supplier<Command> m_supplier; 028 private Command m_command = m_nullCommand; 029 030 /** 031 * Creates a new DeferredCommand that directly runs the supplied command when initialized, and 032 * ends when it ends. Useful for lazily creating commands when the DeferredCommand is initialized, 033 * such as if the supplied command depends on runtime state. The {@link Supplier} will be called 034 * each time this command is initialized. The Supplier <i>must</i> create a new Command each call. 035 * 036 * @param supplier The command supplier 037 * @param requirements The command requirements. This is a {@link Set} to prevent accidental 038 * omission of command requirements. Use {@link Set#of()} to easily construct a requirement 039 * set. 040 */ 041 @SuppressWarnings("this-escape") 042 public DeferredCommand(Supplier<Command> supplier, Set<Subsystem> requirements) { 043 m_supplier = requireNonNullParam(supplier, "supplier", "DeferredCommand"); 044 addRequirements(requirements.toArray(new Subsystem[0])); 045 } 046 047 @Override 048 public void initialize() { 049 var cmd = m_supplier.get(); 050 if (cmd != null) { 051 m_command = cmd; 052 CommandScheduler.getInstance().registerComposedCommands(m_command); 053 } 054 m_command.initialize(); 055 } 056 057 @Override 058 public void execute() { 059 m_command.execute(); 060 } 061 062 @Override 063 public boolean isFinished() { 064 return m_command.isFinished(); 065 } 066 067 @Override 068 public void end(boolean interrupted) { 069 m_command.end(interrupted); 070 m_command = m_nullCommand; 071 } 072 073 @Override 074 @SuppressWarnings("PMD.CompareObjectsWithEquals") 075 public void initSendable(SendableBuilder builder) { 076 super.initSendable(builder); 077 builder.addStringProperty( 078 "deferred", () -> m_command == m_nullCommand ? "null" : m_command.getName(), null); 079 } 080}