Message ID | cover.1665744170.git.viresh.kumar@linaro.org |
---|---|
Headers | show |
Series | libgpiod: Add Rust bindings | expand |
On Friday, October 14th, 2022 at 19:03, Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > On Fri, Oct 14, 2022 at 12:47 PM Viresh Kumar viresh.kumar@linaro.org wrote: > > > Here is another version of rust bindings for libgpiod v2.0, based of the > > next/libgpiod-2.0. > > > > Pushed here: > > > > https://github.com/vireshk/libgpiod v7 > > > > [I have pushed v6 and v5 there too, in case someone wants to look at the > > changes]. It looks pretty good to me. I do have a couple of minor suggestions though. https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/Cargo.toml#L10 should use 0.2.39 without >= to ensure that publishing a 0.3 version of libc with breaking changes won't break the build. Cargo treats "0.2.39" as ">=0.2.39, <0.3". At https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/Cargo.toml#L13 the vmm-sys-utils dependency should be unpinned from "=0.10.0" to "0.10.0". Otherwise having any crate depend on a newer semver compatible version will cause a build error. While Cargo allows multiple semver incompatible versions of a crate, it doesn't allow multiple semver compatible versions as it wouldn't know which version to use for a crate that says it works with both versions. At https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/src/lib.rs#L469 and elsewhere you might want to use `CStr::from_ptr(version)`. This does the `strlen` call for you and you can convert it to an `&str` using `.to_str()`. At https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/src/chip.rs#L171 you could use `CString` and use the `.as_ptr()` method to get a null-terminated string. Not sure if it would be nicer that what you currently have though. At https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/src/edge_event.rs#L46 the lifetimes are unclear. Is Event allowed to outlive the buffer? Can you add a lifetime annotation like fn event_clone<'a>(event: &Event<'a>) -> Result<Event<'a>> if it isn't allowed to outlive the buffer or fn event_clone<'a, 'b>(event: &Event<'a>) -> Result<Event<'b>> if it is allowed to outlive the buffer. I'm not sure which of the two the lifetime elision rules cause the current code to be equivalent of, but even if it is correct, explicitly stating the lifetime here is clearer IMHO. As for the question about test skipping elsewhere in this thread, rust has the #[ignore] attribute to ignore tests at compile time (with a command line flag to run ignored tests anyway), but nothing to ignore tests at runtime unfortunately. Cheers, Björn nb: I can't reply to a mail I didn't receive directly right now due to mail provider limitations. I'm working on sorting this out, but for now I'm going to reply to the mail I did receive directly.
On Friday, October 21st, 2022 at 11:39, Viresh Kumar <viresh.kumar@linaro.org> wrote: > Hi Björn, > > I have bounced (mutt's feature) the initial emails to your and other > email ids that Miguel added. The patches should be in your inbox now. Thanks! I receive the patches. > > On 20-10-22, 13:29, Björn Roy Baron wrote: > > > At > > https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/src/lib.rs#L469 > > and elsewhere you might want to use `CStr::from_ptr(version)`. This > > does the `strlen` call for you and you can convert it to an `&str` > > using `.to_str()`. > > > At > > https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/src/chip.rs#L171 > > you could use `CString` and use the `.as_ptr()` method to get a > > null-terminated string. Not sure if it would be nicer that what you > > currently have though. > > > These two were nice. Thanks. > > > At > > https://github.com/vireshk/libgpiod/blob/3e7fb99173856a3995360fc3fad51220c4b4e90e/bindings/rust/libgpiod/src/edge_event.rs#L46 > > the lifetimes are unclear. Is Event allowed to outlive the buffer? > > Can you add a lifetime annotation like fn event_clone<'a>(event: > > &Event<'a>) -> Result<Event<'a>> if it isn't allowed to outlive the > > buffer or fn event_clone<'a, 'b>(event: &Event<'a>) -> > > Result<Event<'b>> if it is allowed to outlive the buffer. I'm not > > sure which of the two the lifetime elision rules cause the current > > code to be equivalent of, but even if it is correct, explicitly > > stating the lifetime here is clearer IMHO. > > > An Event created using Event::new() can't outlive the buffer, though > an Event created using Event::event_clone() can. > > I tried to play around it based on your suggestion and here is the > diff, does it make sense ? > > diff --git a/bindings/rust/libgpiod/src/edge_event.rs b/bindings/rust/libgpiod/src/edge_event.rs > index b36c23601bb4..0d328ebb2b03 100644 > --- a/bindings/rust/libgpiod/src/edge_event.rs > +++ b/bindings/rust/libgpiod/src/edge_event.rs > @@ -33,7 +33,7 @@ pub struct Event<'b> { > > > impl<'b> Event<'b> { > > /// Get an event stored in the buffer. > - pub(crate) fn new(buffer: &'b Buffer, index: usize) -> Result<Self> { > > + pub(crate) fn new(buffer: &'b Buffer, index: usize) -> Result<Event<'b>> { This looks good to me. > > // SAFETY: The `gpiod_edge_event` returned by libgpiod is guaranteed to live as long > // as the `struct Event`. > let event = unsafe { > @@ -52,22 +52,6 @@ impl<'b> Event<'b> { > > }) > } > > - pub fn event_clone(event: &Event) -> Result<Self> { > > - // SAFETY: `gpiod_edge_event` is guaranteed to be valid here. > - let event = unsafe { gpiod::gpiod_edge_event_copy(event.event) }; > - if event.is_null() { > - return Err(Error::OperationFailed( > - OperationType::EdgeEventCopy, > - Errno::last(), > - )); > - } > - > - Ok(Self { > - buffer: None, > - event, > - }) > - } > - > /// Get the event type. > pub fn event_type(&self) -> Result<EdgeKind> { > > // SAFETY: `gpiod_edge_event` is guaranteed to be valid here. > @@ -105,6 +89,27 @@ impl<'b> Event<'b> { > > } > } > > +impl<'e, 'b> Event<'e> { > > + pub fn event_clone(event: &Event<'b>) -> Result<Event<'e>> > > + where > + 'e: 'b, Using `Event<'b>` on both sides should work fine. `Event` is covariant in it's lifetime parameter, so `Event<'b>` can be turned into `Event<'e>` with `'e` being a shorter lifetime than `'b`. What you wrote here is not incorrect, so if you prefer keeping it this way that is fine with me. > + { > + // SAFETY: `gpiod_edge_event` is guaranteed to be valid here. > + let event = unsafe { gpiod::gpiod_edge_event_copy(event.event) }; > + if event.is_null() { > + return Err(Error::OperationFailed( > + OperationType::EdgeEventCopy, > + Errno::last(), > + )); > + } > + > + Ok(Self { > + buffer: None, > + event, > + }) > + } > +} > + > > -- > viresh Cheers, Björn
On Tuesday, October 25th, 2022 at 08:42, Viresh Kumar <viresh.kumar@linaro.org> wrote: > On 21-10-22, 14:34, Björn Roy Baron wrote: > > > > impl<'b> Event<'b> { > > > > > > /// Get an event stored in the buffer. > > > - pub(crate) fn new(buffer: &'b Buffer, index: usize) -> Result<Self> { > > > > > > + pub(crate) fn new(buffer: &'b Buffer, index: usize) -> Result<Event<'b>> { > > > > This looks good to me. > > > > +impl<'e, 'b> Event<'e> { > > > > > > + pub fn event_clone(event: &Event<'b>) -> Result<Event<'e>> > > > > > > + where > > > + 'e: 'b, > > > > Using `Event<'b>` on both sides should work fine. `Event` is > > covariant in it's lifetime parameter, so `Event<'b>` can be turned > > into `Event<'e>` with `'e` being a shorter lifetime than `'b`. What > > you wrote here is not incorrect, so if you prefer keeping it this > > way that is fine with me. > > > That doesn't let the cloned event to live past read_edge_events(). > > error[E0502]: cannot borrow `buffer` as mutable because it is also borrowed as immutable > --> libgpiod/examples/gpio_events.rs:70:50 > > | > 64 | let event = buffer.event(0)?; > | --------------- immutable borrow occurs here > ... > 70 | let count = request.read_edge_events(&mut buffer)?; > | ^^^^^^^^^^^ mutable borrow occurs here > ... > 86 | } > | - immutable borrow might be used here, when `cloned_event` is dropped and runs the `Drop` code for type `libgpiod::request::Event` > > -- > viresh I would have expected that to work fine, but as it doesn't work keeping your code with two separate lifetimes is fine. Cheers, Bjorn