-
Notifications
You must be signed in to change notification settings - Fork 153
Add function to get non-ROS arguments #210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a few safety concerns, especially the use of Vec::from_raw_parts
... Could you please take a look at the suggested changes and address them?
Otherwise, this looks like a good start! Hopefully I haven't missed anything. And thank you for your contribution!!
Nodes don't have a reference to A third way is to have a private version of |
So maybe refactor In rclcpp i can see that wrapped The only way they're dealing with unprased arguments is throwing an exception here in case of bad ROS arguments (equivalent of ours #167). In order to get non-ROS arguments they retrieve arguments structure from |
Also, I have a question about workflow in this repo. While applying fixes to this PR shall I
|
Good question, we should document this. I think it's fine to force-push in the very early stages (e.g. you noticed that CI isn't passing), but generally fix commits are a little easier for reviewers. We squash commits when merging anyway. |
That is basically what I'm suggesting with my comment "A third way is to have a private version of |
I've implemented another approach. |
Also, I've generalized getting rcl_arguments, which may be useful while resolving #167, since identical steps to obtain ROS unparsed arguments would be performed as for non-ROS ones. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay - it was a long weekend over here.
rclrs/src/rcl_utils.rs
Outdated
rcl_args: *const rcl_arguments_t, | ||
allocator: rcl_allocator_t, | ||
out_ptr: *mut *mut ::std::os::raw::c_int, | ||
) -> rcl_ret_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible/desirable to have this return a Result
instead? Akin to how we use .ok()?
for most of our calls to rcl
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was intended to be just a wrapper around corresponding rcl_argument_get...
and rcl_argument_get_count...
, so i left the interface repeated.
rclrs/src/rcl_utils.rs
Outdated
// SAFETY: No preconditions for next 2 functions. | ||
let allocator = rcutils_get_default_allocator(); | ||
allocator.deallocate.unwrap()(indices_ptr as *mut c_void, null_mut()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// SAFETY: No preconditions for next 2 functions. | |
let allocator = rcutils_get_default_allocator(); | |
allocator.deallocate.unwrap()(indices_ptr as *mut c_void, null_mut()); | |
// SAFETY: No preconditions for this function. | |
let allocator = rcutils_get_default_allocator(); | |
// SAFETY: No preconditions for this function. | |
allocator.deallocate.unwrap()(indices_ptr as *mut c_void, null_mut()); |
Additionally, is there a way to re-write this to avoid the unwrap()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a reason why unwrap
could return None
here, since allocator
is retrieved by rcutils_get_default_allocator()
just above. I could add another error type to RclrsError
like I suggested here, but still I don't see a reason for that.
rclrs/src/rcl_utils.rs
Outdated
// and is allocated with size equal to one returned by rcl_arguments_get_count_unparsed. | ||
// SAFETY: No preconditions for this function. | ||
let index = *(indices_ptr.add(i)); | ||
non_ros_args.push(args.get(index as usize).unwrap().clone()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to re-write this to avoid the unwrap()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another way would be to add new error type to RclrsError
, like IndexOutOfRange
and raise it here if get
returns None
. What do you think about that?
That's also a possibility, but I actually think our idea of constructing the wait set with an |
It seems to be that we're running in circles just to avoid what |
Perhaps we should discuss this in a separate issue? I foresee the potential for a very long discussion on the merits, and I don't want to hold up @Nizerlak's PR if it can be avoided. Especially if we're fundamentally restructuring The work coming from that discussion should be a separate PR. |
I'm not against considering it in principle, but (1) we'd have the same problem here if we had a global context (since we'd still want the context instance associated with the node to be used in the wait set – it's the same in rclcpp) and (2) it's quite easy to fix. |
@Nizerlak thank you so much for iterating with us. Here's an idea that we've discussed with @jhdcs and @nnmm, let us know what you think of it. How about a free function that just extracts the arguments from fn main() {
let non_ros_args = rclrs::extract_non_ros_args(env::args());
// do rclrs stuff, create Context, create Node, etc.
} Most of the time, once the command line arguments have been parsed, there's no need to access them again. This has the advantage that we're not storing anything for the entire lifetime of a |
I like that idea @esteve. With this approach there's no problem when user passes different arguments while calling |
@Nizerlak Is this PR ready for a review? |
Yes, I forgot to mention. Sorry for that. |
rclrs/src/lib.rs
Outdated
if let Err(err) = ret { | ||
// SAFETY: No preconditions for this function | ||
unsafe { | ||
rcl_arguments_fini(&mut rcl_arguments).ok()?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's safe to rely on this being done by rcl
if rcl_parse_arguments()
fails: https://github.com/ros2/rcl/blob/4eccc3cbe65f5b58981f22efaf612a65731cb2f0/rcl/src/rcl/arguments.c#L670
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I.e. please remove this call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a question on how things are organized.
rclrs/src/rcl_utils.rs
Outdated
/// `rcl_arguments_get_count_unparsed_ros` -> `rcl_arguments_get_count_ros` | ||
/// ... | ||
pub(crate) fn get_rcl_arguments( | ||
rcl_get_count: unsafe extern "C" fn(*const rcl_arguments_t) -> std::os::raw::c_int, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason that we're passing these functions around? Couldn't we get much the same effect by having multiple outer functions that use the different API calls, and wrapping the common portions together in a different function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly I don't see how to wrap this common portions to separate functions. They're just too small and linked tightly to te rest. Maybe wrapping it into macro woud solve this, but it's a bit nasty and seems like overkill.
Current approach is on @nnmm request, so if there's still something wrong with it please agree on one version, since I'd like to start resolving other issues not being attached to this one for so long :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I had missed that. My apologies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that PR has gone on quite long, and I agree with @Nizerlak that no more common functions can be factored out.
I'm really happy with the code quality in this PR overall, most of my comments relate to the One request: Could you move everything into an And sorry about the long review time – the next one will be faster. |
rclrs/src/lib.rs
Outdated
if let Err(err) = ret { | ||
// SAFETY: No preconditions for this function | ||
unsafe { | ||
rcl_arguments_fini(&mut rcl_arguments).ok()?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I.e. please remove this call.
rclrs/src/rcl_utils.rs
Outdated
/// `rcl_arguments_get_count_unparsed_ros` -> `rcl_arguments_get_count_ros` | ||
/// ... | ||
pub(crate) fn get_rcl_arguments( | ||
rcl_get_count: unsafe extern "C" fn(*const rcl_arguments_t) -> std::os::raw::c_int, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that PR has gone on quite long, and I agree with @Nizerlak that no more common functions can be factored out.
Co-authored-by: Nikolai Morin <[email protected]>
Co-authored-by: Nikolai Morin <[email protected]>
Co-authored-by: Nikolai Morin <[email protected]>
Co-authored-by: Nikolai Morin <[email protected]>
Thanks for making all the changes! Could you just also move the code from |
Co-authored-by: Nikolai Morin <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're just one cargo fmt
away from merging it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you. I'm looking forward to what you'll tackle next :-)
Hi guys,
This is my first PR in this repo.
I faced an issue during creating this PR. In order to obtain non-ROS args, the input args (passed from console on node startup) has to be known, which is possible only during
Context
initialization (new
function). My solution was to get those non-ROS arguments and store in new field ofContext
-non_ros_arguments
- which could be accessed by getter function. Unfortunately it generated conflict with lib.rs. I made a temporary fix, but I think that, a design of Node and/or Context should be revised to resolve this conflict.