-
Notifications
You must be signed in to change notification settings - Fork 21
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
Discussion: Streamline "attr_read" and "attr_write" methods? #15
Comments
Something to keep in mind is that the IIO has a nicely defined kernel API, but is exposed to user space through some fairly bizarre sysfs interfaces. That makes writing user-space apps fairly difficult, and the beauty of libiio is that it makes a lot of the nonsensical aspects a little more tame. So the attributes are passed to and from the kernel as strings. Period. All those libiio calls are merely convenience functions converting the different types to and from strings, and then calling the string read or write function. (I didn't realize this when I first wrote the library, otherwise I might have done it differently). So, in the Rust layer, we could write generic functions to read and write attributes. Anything would work so long as the type could be converted to/from a string in a generic manner (such as having the For reading, we could have an
or
Going beyond this to try and predict the specific type desired for each attribute is probably not worth it. I did something like this in my Paho MQTT library where each property has a very specific type and must be read or written as that type or the operation fails. That got really messy and I probably need to rewrite the whole thing at some point. |
OK. I started pushing some code to the develop branch as described above, starting with devices and buffers. Should have it finished (including channels, etc) and cleaned up in a day or so. |
It's funny that even a simple generic that only needs to work with a few mostly primitive types (int, float, bool, and string) can still run into complications. In this case, going to and from strings for all the types mostly works - except for bool. Sysfs uses "0" and "1" for boolean values, whereas Rust uses "false" and "true". Trying to make a special case for bools becomes difficult without partial specialization. I put in a hack for now, but need to come up with something better and more stable. |
Sorry, I attempted to compile the iio_dummy kernel module for my device, failed and got a bit frustrated about it... I see that you're using the regular Display trait to convert the types values to strings. What about if we add our own trait that has the "attr_to_string" and "string_to_attr" methods? We could then add a default implementation that handles all cases and do a specialized implementation for the bool type that handles the special case. I've hacked some code for this, you can find it here. I'd really like to hear your opinion on this! |
OK. I think I like this idea... But maybe we can clean it up a bit and get rid of some redundancies. For now I want to keep all the explicit calls like As for implementing your trait:
So, something like:
But, one issue with this is that you can't implement the trait for &str since you can't return the reference in Perhaps what we could do is split the trait into two different ones. One for converting to an attribute string and one for converting from an attribute string. Something like this might be good:
This also gets rid of the possible confusion of The final thing I wonder is whether we need the
When using the traits from a generic
Would you have time to get this implemented in the next day or two? I'm supposed to have the next release out by the end of the week, but at a minimum, I'd like to finish any changes by Friday and then test and debug over the weekend. |
OK. I'm in a hurry to get this release out this week. So I went ahead and added it with the separate @Funky185540 Let me know if this works for you. |
Well things have certainly picked up pace in terms of time between releases now. :-) First up: Thanks for the feedback! I really appreciate it. I won't be near my PC for the rest of the day (UTC+1 here), but I'll be glad to have a detailed look tomorrow and give a more thorough reply to your last message! The code looks good on the first glance. |
Of course. I think I've read too much C-code in my life...
I just named them like this to be compatible with the functions you had written. I don't really insist on this naming. ;-)
Okay, good to know. Thanks!
Yeah I see what you mean. You'd like to support
I don't know. Can it really not fail? What if the host runs out of memory to allocate another (possibly very long) string, or any other unlikely scenario? Of course I'm not an experienced Rust programmer, but having these functions return a
It does! I think it looks pretty and reads very nicely now. Just another thing:
Wouldn't this sort of thing (changing the public API) be a breaking change in terms of semver? Shouldn't we bump the major release number then (i.e. make it 1.0.0)? After all I mean users could update their crates simply by using |
I have some cleanup code that I'm in the middle of finishing. Hopefully up today. (Fixing the unit tests, etc) The only thing that stinks is that trait also needs to be implemented for every integer type that the app or drivers might want to use (i32, u32, u64, etc). So I added a few more that will get pushed today as well.
Yes. These are breaking changes. With semver, versions prior to 1.0 (meaning 0.x.y) are considered "pre-release". The meaning of the version numbers shift down a level. So going from 0.4.x to 0.5.0 allows for API breaking changes. By keeping the version 0.x, you indicate to users that the library and API are in active development and will be breaking often as you settle into an API. Once you move to v 1.0.0, it's an indication that the library has reached a certain maturity and will not be introducing breaking changes very often, if at all. We're certainly not there yet with this library! Thanks for all the help. It's looking good. |
Although I think one could call this a luxury problem. The C lib only offers 4 types in total after all. But some luxury certainly won't hurt... :-) Thanks for clarifying! I'll close this now as the issue pretty much seems done. |
But the C lib implicitly converts. So it works with all the integer types... although it doesn't report out-of-range errors. And now I'm debating whether or not to get rid of the individual attribute functions and consolidate. The only thing I'm not sure about is that the floating-point conversions in |
Ah, yeah I see. Good point. How would you propose to test this? I may do it and I have some very few sensors here, but I don't think that any of them have float values as IIO attributes... Do you have some in your head that work with float values? |
Hello,
I'm currently seeking to document the 'channel' module, and I wonder whether it might be possible to streamline all "attr_read_" and "attr_write_" calls into one of "attr_read/write" respectively?
I'm just throwing in thoughts here: Upon creating a Channel instance, the library could get all attributes and determine which datatype they have. As channels are always bound to exactly one device, the channel could carry around a HashMap of all attribute entries, along with their data types. Then we could take some T from the user, and cast it to the type needed to set the attributes (or the other way round for reading).
As an added bonus we could check whether an attribute the user attempts to set/get really exists (if it has a matching key in the HashMap), and return a descriptive error if it doesn't, or if the argument can't be converted to the requested attributes type.
I'm aware that it's very debatable (and probably naive!), because we would need to gather this information at channel creation, but I thought I'd put it up for discussion nonetheless.
Or, seeing that libiio exposes 15 functions merely to work with attributes, would it be worthwhile to make structs for the attributes, too? Then each channel could carry around a slice of attributes, where each instance holds it's name (as string), it's data type, and possibly it's current value...
Thoughts? Would this even be possible?
The text was updated successfully, but these errors were encountered: