feat(macros): derive ParameterVariant for enums and newtypes - #693
Open
azerupi wants to merge 1 commit into
Open
feat(macros): derive ParameterVariant for enums and newtypes#693azerupi wants to merge 1 commit into
azerupi wants to merge 1 commit into
Conversation
A parameter could only be declared with a type rclrs knew about, so a
closed set of choices had to be handled as a string and compared against
string literals at every use, and a value with a unit had to be an
unadorned f64.
representation. Which one follows from the shape of the type:
#[derive(ParameterVariant, Clone, Copy, PartialEq)]
#[parameter(rename_all = "snake_case")]
enum ControlMode { Velocity, Position, #[parameter(rename = "torque")] Effort }
An enum whose variants carry no data becomes a string of variant names,
which is how a choice is written in a parameter file. The valid values go
into the descriptor's constraints, so `ros2 param describe` reports them,
and a value that is not one of them is rejected -- including over the
parameter services -- with a message naming them.
value's representation, along with its range type and its validation, so a
Meters(f64) parameter takes a range in metres and a Port(u16) one rejects
70000 exactly as a u16 would. #[parameter(from_str)] stores a type as a
string via FromStr and Display, reporting the FromStr error as the reason
a value was rejected.
Structs whose fields are individually meaningful are groups of parameters
rather than values, and the macro says so rather than trying to represent
them.
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.
Problem
Using a custom enum or newtype as a parameter is boilerplate heavy. It requires three trait implementations, and a constraints string kept in step with the type by hand:
Solution
#[derive(ParameterVariant)]generates all of that. The representation follows from the shape of the type, so the enum above becomes:The valid values reach the descriptor, so introspection reports them without any declaration restating them:
This works for 3 type patterns:
#[parameter(transparent)]on a newtype or struct with one field#[parameter(from_str)]FromStrandDisplaytransparentuses the inner type's range and its validation, so units cost nothing:and a
Port(u16)rejects70000exactly as au16does, because it is au16underneath.from_stris for a type that already parses itself. TheFromStrerror becomes the reason a value was rejected, so it is worth writing well:A derived type is a parameter value everywhere: through the builder, as a field of a
#[derive(ParameterSet)]struct, and throughdeclare_parameter_with, sinceParameterConversion::of_variantassembles a conversion from what the derive emits.The derive also emits
declare_parameter_field!, so a derived type is usable as a set field with no further work.