feat(macros): derive ParameterSet for enums - #699
Open
azerupi wants to merge 1 commit into
Open
Conversation
…veral shapes
A configuration is often one of several things, each needing different
parameters: a sensor that is either a lidar or a camera, a controller that
is either PID or bang-bang. Expressed as a struct, that means a field for
every parameter of every shape, all declared whether they apply or not,
and nothing saying which combination is meaningful.
An enum says it directly:
#[derive(ParameterSet, Debug)]
#[parameters(rename_all = "snake_case")]
enum SensorConfig {
Lidar { #[param(default = 30)] rate: i64 },
Camera(CameraConfig),
Disabled,
}
ROS 2 parameters are declared statically, so this is declared in two
steps: a read-only string parameter -- the tag, `type` unless renamed --
is declared first, and the parameters of whichever variant it names are
then declared alongside it. Only the selected variant's parameters exist,
so nothing is declared for a lidar when the file says camera.
The tag is read-only because what is declared depends on it. Changing it
at runtime would mean undeclaring one group of parameters and declaring
another, which would invalidate handles the caller is holding. Changing
which variant a node uses is a restart.
Struct variants declare their fields under the set's own namespace,
newtype variants over another set delegate to it so an existing config
struct can be reused unchanged, and unit variants declare nothing beyond
the tag. An enum set nests inside a struct set like any other, so the two
compose.
Assisted-by: Claude:claude-opus-5 [Claude Code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The code in this PR was assisted by Claude Code.
This PR extends the macro and lifts a limitation. The
ParameterSettrait can now be implemented for an enum that contains alternative sets of parameters but only one set is declared at any one time.Problem
A node's configuration can sometimes represent mutually exclusive sets of parameters. Let's say for example a sensor that is either a lidar or a camera, a controller that is either PID or bang-bang. In both cases you would want to have different parameters depending on which type the sensor or controller is. A struct cannot express that easily.
Solution
#[derive(ParameterSet)]now accepts an enum. Each variant is one shape of the configuration, carrying only the parameters that belong to it:A parameter file picks the shape, and that shape's values arrive as plain Rust:
Declaration
In order to support this, the parameters for such enums are declared in two steps. First, the tag is declared as a read-only string parameter. And depending on the value that it is set to, the parameters of the chosen variant are then declared. Only the selected variant's parameters exist:
The variants reach the tag's descriptor, and the enum's doc comment becomes its description, so an operator can discover the shapes without reading the source:
A tag naming no variant fails the declaration the same way enum parameters do:
The tag is read-only because what is declared depends on it. Changing it at runtime would mean undeclaring one group of parameters and declaring another, invalidating handles the caller is holding. Changing which variant a node uses needs a restart.
Handles
declare_parametersreturns live handles, as it does for a struct set. The generatedSensorConfigParamsholds the tag and aSensorConfigVariantParamsmirroring the enum: