Conversation
This way they can remain part of the crate without breaking other ros package builds Other packages can load the dependency through cargo
remove -e flag from echo to not add it to bashrc
esteve
left a comment
There was a problem hiding this comment.
@balthasarschuess @BCSol thanks for the PR, it doesn't seem necessary to have a separate crate only for the macros, can you move that into rclrs? Thanks.
Hey @esteve :) I might be mistaken, but I could not find any resource claiming that this restriction has been lifted. |
This reverts commit a9c91f9.
On windows the build fails because there is no binary to build. Try adding package.xml to avoid this.
|
Colcon autodiscovers |
This reverts commit 3e084c7.
|
@esteve I finally made the windows build work, can you have another look 🙏 |
azerupi
left a comment
There was a problem hiding this comment.
Hey @balthasarschuess @BCSol,
I was reviewing this PR because I'm excited about this feature but as I was looking through the code and trying to understand some design decisions I was thinking about slightly different approaches that could be taken and I ended up doing some exploration with AI help which resulted in #612
I apologize, my goal wasn't to dismiss the work that was done in this PR, it was just easier for me to come up with an alternative proposal than to dump a bunch of review comments here.
Feel free to take anything from #612 and incorporate it into this PR if you want. If however the decision is to move forward with #612, then I'll happily add both of you as co-authors on the commits as the work was based on the initial ideas in this PR.
| } | ||
|
|
||
| impl<T: crate::ParameterVariant> StructuredParameters for crate::MandatoryParameter<T> {} | ||
| impl<T: crate::ParameterVariant> StructuredParametersMeta<T> for crate::MandatoryParameter<T> { |
There was a problem hiding this comment.
The three implementations of this trait seem to be almost identical except for the last calls to mandatory(), read_only() and optional(). Can the common code be extracted into a single function that gets called in all three impls?
There was a problem hiding this comment.
Not really unless we generate them directly as in #612
| impl From<DefaultForbidden> for crate::ParameterValue { | ||
| fn from(_value: DefaultForbidden) -> Self { | ||
| // cannot be instantiated cannot be called | ||
| // let's satisfy the type checker | ||
| unreachable!() | ||
| } | ||
| } | ||
| impl From<crate::ParameterValue> for DefaultForbidden { | ||
| fn from(_value: crate::ParameterValue) -> Self { | ||
| // cannot be instantiated cannot be called | ||
| // let's satisfy the type checker | ||
| unreachable!() | ||
| } | ||
| } |
There was a problem hiding this comment.
The constraint is a consequence of having the same Trait for both nodes and leafs, where the declare signature contains parameters.
The default value requires this bound, but there is not a 1:1 correspondence between a ParameterVariant and a "parameter container".
That's why the DefaultForbidden type was added so that we can implement/derive the trait and keep the information, that there cannot be a default value.
There was a problem hiding this comment.
Maybe it's possible to remove the ParameterVariant constraint from the type parameter for the trait.
Then these two implementations could be removed.
There was a problem hiding this comment.
Hey @azerupi
I am really happy about your feedback!
I think your solution is more elegant in terms of that it avoids the somewhat unsound type implementation. It would be interesting to evaluate, which version yields better compiler errors. My version was lacking in this regard a bit.
The major reason why I chose this implementation over directly generating the leaf implementations, was that I wanted users to give the option to implement the Trait for their custom type.
In our use case we would like to support struct values, which would be internally declared as ReadOnlyParameter<Arc<str>> but are directly deserialized with serde_json to a more complex data structure. As ros parameters don't support more complex map types or conditional parsing yet.
I would be nice if something like that worked without intermediate structs
#[derive(serde::Deserialize)]
struct Config {
param: String,
param2: Map<String, String>,
}
node.declare_parameters::<Config>()
This all begs the question if we should directly support serde deserializable as ParameterType.
| impl From<DefaultForbidden> for crate::ParameterValue { | ||
| fn from(_value: DefaultForbidden) -> Self { | ||
| // cannot be instantiated cannot be called | ||
| // let's satisfy the type checker | ||
| unreachable!() | ||
| } | ||
| } | ||
| impl From<crate::ParameterValue> for DefaultForbidden { | ||
| fn from(_value: crate::ParameterValue) -> Self { | ||
| // cannot be instantiated cannot be called | ||
| // let's satisfy the type checker | ||
| unreachable!() | ||
| } | ||
| } |
There was a problem hiding this comment.
The constraint is a consequence of having the same Trait for both nodes and leafs, where the declare signature contains parameters.
The default value requires this bound, but there is not a 1:1 correspondence between a ParameterVariant and a "parameter container".
That's why the DefaultForbidden type was added so that we can implement/derive the trait and keep the information, that there cannot be a default value.
| } | ||
|
|
||
| impl<T: crate::ParameterVariant> StructuredParameters for crate::MandatoryParameter<T> {} | ||
| impl<T: crate::ParameterVariant> StructuredParametersMeta<T> for crate::MandatoryParameter<T> { |
There was a problem hiding this comment.
Not really unless we generate them directly as in #612
|
@balthasarschuess that's an interesting requirement! I think this feature is somewhat orthogonal to the derive macro so let's talk about what the builder API would look like. When you say without intermediate structs, you mean without a wrapper type like a hypothetical API like below for example? #[derive(Clone, Serialize, Deserialize, Default)]
struct SensorConfig {
rate: f64,
filters: HashMap<String, String>,
}
let sensors: MandatoryParameter<JsonParameter<SensorConfig>> = node
.declare_parameter("sensors")
.default(JsonParameter(SensorConfig::default()))
.description("Sensor configuration as JSON")
.mandatory()?;
// Read the value
let config: SensorConfig = sensors.get();
println!("rate: {}", config.rate); |
|
@azerupi Sorry my previous example was drafted up with little time. So what I'd like to be able to achieve is: The idea is, that the user can extend the leaf declaration with arbitrary parsing logic -> serde yaml, serde json, some weird DSL, without having to:
|
Proposal for structured parameters derive macro (#496)
Changes:
StructuredParametersrclrs_proc_macrostest_msgsandexample_messageswith apt, without the cargo build without colon would fail to link rosidl message (I'd be happy about some help there)TODO:
NodeState/Node@mxgrey before I continue here, I'd be happy about some feedback, whether this is what you had in mind or how we could improve upon this POC.