-
Notifications
You must be signed in to change notification settings - Fork 8
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
Improve error handling: impl TryFrom for I2cBuffer to ensure buffer size #19
Conversation
Turns out I was just using Not super ergonomic due to using |
src/i2c.rs
Outdated
} | ||
|
||
#[derive(Debug)] | ||
pub struct I2CBuffer<'a>(pub &'a mut [u8]); |
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.
Can you add some documentation that the buffer must hold a multiple of three bytes and enforces it with the TryFrom
?
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.
Also I think the member shouldn't be pub
, because with pub
it can be constructed without the TryFrom
, no?
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 set the member to pub(crate)
, because the crc8
needs to be able to see it.
After all this, I don't really like that the I2CBuffer type is not exactly easy to use (see usage in I2CBuffer doc comment for example). What do you think of using a slice of Sorry for bringing this up again :D the approach with I2CBuffer is ok too, I think. |
Ok, to bring this to a conclusion: I think right now there does not seem to be a way that assures this invariant while being ergonomic. I think this topic should be revisited when full const-generics land, probably later 2021. Or what do you think? |
Sorry for not answering for some time.
That may indeed be true. But at the same time I'd like to add it anyways, since it could also help in generating the data one would like to send. Something like: use sensirion_i2c::i2c::I2CBuffer;
use core::convert::TryFrom;
let mut data = [0x00; 6];
let mut i2c_buffer = I2CBuffer::try_from(&mut data[..]).unwrap();
i2c_buffer.add_u16(0x1234); // will add the two bytes and the crc
i2c_buffer.add_bytes(&[0x56, 0x78]);
// may also provide
i2c_buffer.add_u32(...);
i2c_buffer.add_float(...);
...
// it may even provide the method to write it to I2C
i2c_buffer.write(i2c);
// or a getter which returns the slice of the buffer which needs to be sent
let data_to_send = i2c_buffer.get_i2c_frame(); |
That sounds good to me. I think this could be done nicely like this: trait Append<T> {
fn append(&mut self, val: T) -> ...;
}
impl Append<u16> for I2cBuffer { ... }
impl Append<[u8; 2]> for I2cBuffer { ... }
... Things like |
Yes: The SPS30 can require more than 32 Bytes. |
In that case, we could use min_const_generics to allow the user to customise the internal buffer size. What do you think? |
Uh nice! I like where this is headed. Note that you still need to rebase this pull request for latest master (you may need to update the master branch on you fork or local checkout first). I'll need some more time to review this in depth. |
Btw. I enabled the Circle CI testing for external pull requests, that's why we see it failing now. Previously it just didn't run. We probably need to bump the minimum required Rust version so that |
Well, right now this still requires nightly, right? As far as I can tell, |
While we are at it: I noticed the sensirion-i2c-rs crate has been yanked in favor of sensirion-i2c, but this repo is still called sensirion-i2c-rs. It could be renamed (github will keep a redirect in place in case someone accesses an old link). |
I'm actually fine with the repository name indicating that it is a Rust repository. But for the crate name it is kind of redundant since it obviously is for Rust. I think it is a quite nice convention to use
I'm a bit reluctant to make the crate require nightly, but since the feature will probably hit stable in around two months (1.51.0 2021-03-25) I guess it should be fine. Switching from CircleCI to GitHub actions I'd prefer to do in a separate pull request though, since this pull-request is already quite huge (and with 30 commits a bit hard to keep an overview, needs some squashing) |
Re: nightly, we could merge this when the const generics implementation hits stable. |
Ah sorry. So there was one merge to master that happened from #18. So the master branch from your fork of the project: https://github.com/barafael/sensirion-i2c-rs/tree/master is out of sync with the master branch here. (You pushed 4 commits on it and in the meantime #18 was merged) I suggest you force push to the master branch of your fork like this: # you can skip cloning, but make sure to not destroy your working branch.
$ git clone git@github.com:barafael/sensirion-i2c-rs.git
Cloning into 'sensirion-i2c-rs'...
remote: Enumerating objects: 145, done.
remote: Counting objects: 100% (145/145), done.
remote: Compressing objects: 100% (105/105), done.
$ cd sensirion-i2c-rs
$ git remote add upstream git@github.com:Sensirion/sensirion-i2c-rs.git
$ git fetch --all
Fetching origin
Fetching upstream
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 1), reused 2 (delta 1), pack-reused 0
Unpacking objects: 100% (4/4), 1.19 KiB | 611.00 KiB/s, done.
From github.com:Sensirion/sensirion-i2c-rs
* [new branch] master -> upstream/master
$ git reset --hard upstream/master
HEAD is now at 8728692 crc8: Use explicit error type (#18)
$ git push -f
Total 0 (delta 0), reused 0 (delta 0)
To github.com:barafael/sensirion-i2c-rs.git
! [remote rejected] master -> master (permission denied)
error: failed to push some refs to 'git@github.com:barafael/sensirion-i2c-rs.git' The force push obviously fails for me, since I don't have permissions to do so. Then you can rebase your
During interactive rebase you may also squash together small fixes. I hope this helps 🙂 |
Alright, that was easier. I think that didn't erase anything. Having tests helps. Thanks for your help! |
1.51 is out 🎉🎉🎉 (wink wink, but really there is no urgency.) How does the MSRV thing work, should this be added? Or make I2cBuffer a feature? |
I don't want to push too hard - but please do let me know if there is anything I can do to get this released (my sdp800 driver release kind of depends on it). |
As a result of previous disussion in #17, I am trying to add a type which ensures that the i2c buffer given has a correct length.
So far, I have implemented the type as a tuple struct with a TryFrom implementation, as suggested by @rnestler here
So when I try to access the shared slice of bytes here, I cannot get a mutable reference! Removing the reference and lifetime gets me nowhere, as TryFrom requires
Sized
which[u8]
does not fulfil.Defining the wrapper type as
type I2cBuffer = &mut 'a [u8];
gets me nowhere either, as I run into the orphan rule.I am opening this PR to see if we can find a solution together :)