<DaltonCaron[m]>
thejpster: I'm working with the R9A02G021. Got custom hardware and a Peripheral Access Crate generated for it. In earlier chats, I saw that you bricked yours. I was wondering if you were still planning to work with this chip.
EthanGardner[m] has quit [Quit: Idle timeout reached: 172800s]
<FrreJacques[m]>
I am a bit confused that no_std is lacking the trait Error. I was roughly following this article for errors https://sabrinajewson.org/blog/errors#guidelines-for-good-errors. Having the errors containg each other, but using from to make it a bit concise. But when I wanted to impl Error I realised it's not there.
<JamesMunns[m]>
it's relatively recent, if you have an old version of the compiler
<JamesMunns[m]>
(about 6 months ago)
<FrreJacques[m]>
Ahh, thx. Wasn't added automatically when I tried to use it and found outdated info on the net.
<FrreJacques[m]>
Because it's so young ehal doesn't use it. So I don't really know how I could use embedded_hal::digital::ErrorKind to be used as a return value for core::error::Error::source()
<FrreJacques[m]>
But maybe I just have to drop what comes from there and simply start a new error trace from there.
<FrreJacques[m]>
This is merged to master but not included to embedded_hal 1.0 right?
<FrreJacques[m]>
So I would need to use this wrapper crate embedded-hal-error right?
dirbaio[m] has joined #rust-embedded
<dirbaio[m]>
what are you trying to solve exactly
<dirbaio[m]>
embedded-hal can't require core::error::Error for error types because it's a breaking change, it will require embedded-hal v2.0 which will likely not happen anytime soon.
<dirbaio[m]>
but you shouldn't need core::error::Error for most tasks
<FrreJacques[m]>
I have then a BusError that has a BusPinError as source and so on.
<FrreJacques[m]>
But maybe I could then use the fmt of Errorkind to include the information to BusPinErrorKind and simply return a None for for source.
<dirbaio[m]>
yeah, it's simpler to not impl source(), or not impl Error at all even
<dirbaio[m]>
source is not great on embedded because it causes bloat due to dyn, so not much value is lost..
<dirbaio[m]>
btw i'd recommend using generics to return the exact error type from the HAL, not "convert" it to ErrorKind
<dirbaio[m]>
the full error type will likely have more info
<dirbaio[m]>
or for gpio it's most commonly core::convert::Infallible which is uninhabited so the compiler knows errors are impossible, Results compile to no overhead and error checking branches are optimized out.
<FrreJacques[m]>
Bummer, thought I sorted it out. Do you know a good reference create to learn how to do this error handling efficiently?
<FrreJacques[m]>
And if source is not a good idea on embedded, I am even more confused, why Error is added to core and embedded-hal.
<dirbaio[m]>
yes, i'm also confused why people want it
<whitequark[cis]1>
probably to share code between std/non-std builds?
<whitequark[cis]1>
i hit this problem when trying to do a "core::io"
<FrreJacques[m]>
Is there then another good way to use errors to create a meaningfull error trace.
<whitequark[cis]1>
afaict we aren't getting "core::io" any time soon, and without that i guess the motivation is limited, but i'm still happy to see core::error, with all its downsides
<dirbaio[m]>
hmm but even if you're writing code for std, you're not forced to use core::error::Error
<dirbaio[m]>
you do need it if you want to use anyhow/thiserror
<dirbaio[m]>
but you don't need .source() to be implemented for it
<dirbaio[m]>
I mean, I do see some point as impl Error for MyError{} as a marker trait to get anyhow/thiserror to accept your error
<whitequark[cis]1>
i think the main motivation for me implementing the trait was to "play nice" with any API consumers that would expect it to be there
<dirbaio[m]>
I don't see the point of the rest of functionality in core::error::Error, using the trait as more than just a marker trait
<dirbaio[m]>
like .source()
<dirbaio[m]>
even in std where you can afford the bloat, inspecting errors with dyn and downcast is annoying and error-prone
<dirbaio[m]>
when you can just do a match :D
<whitequark[cis]1>
oh i see, last time i looked at error::Error it only had description and cause and cause was useless
<whitequark[cis]1>
now we have source and request huh
<whitequark[cis]1>
* now we have source and provide huh
<whitequark[cis]1>
provide is an interesting API
<whitequark[cis]1>
but the trait as a whole looks like a melted crater :D
<dirbaio[m]>
yeah cause is deprecated in favor of source, the added +'static is needed for downcast because reasons
<dirbaio[m]>
and provide is a gnarly API, I hope it never gets stabilized
<whitequark[cis]1>
yeah you can't downcast stuff with lifetimes in it
<whitequark[cis]1>
provide is... something for sure
<whitequark[cis]1>
i can see the usefulness but also holy shit
<whitequark[cis]1>
oh right, we'll never get `core::io` because of a `Box<Error>`
<whitequark[cis]1>
or i suppose we could have libcore_io that depends on libcore+liballoc
<whitequark[cis]1>
* or i suppose we could have libcore_io that depends on libcore+liballoc (and be compatible with libstd)
<dirbaio[m]>
dirbaio[m]: causing wasting 16 bytes of RAM immediately, for everyone, even in nightly with the feature disabled, even in stable
<dirbaio[m]>
because unstable features can't dynamically add/remove fields from structs because it'd require recompiling std
<dirbaio[m]>
the already-merged LocalWaker is also wasting 8 bytes in Context already
<whitequark[cis]1>
what's a LocalWaker
<whitequark[cis]1>
the description is incomprehensible
<whitequark[cis]1>
is it basically just RefCell<Option<Waker>>
<dirbaio[m]>
it's Waker but not Send
<dirbaio[m]>
the idea is executors would provide both Waker and LocalWaker in the context, and futures that don't need to send wakers would use the LocalWaker instead of the Waker today
<dirbaio[m]>
so the executor could provide a more optimized implementation for the LocalWaker because it can e.g. skip using atomics or mutexes..
<dirbaio[m]>
I find it a bit questionable because the LocalWaker optimizations an executor can do while still providing a Waker are very limited
starblue has quit [Quit: WeeChat 3.8]
<dirbaio[m]>
the good ones would be if the executor was allowed to provide only a LocalWaker, so everything really is local.
<dirbaio[m]>
that's not gonna happen since all futures written today expect a Waker and would explode
<dirbaio[m]>
š«
<dirbaio[m]>
so while some people "experiment" with that nightly feature and not ship anything, everyone else gets 8 (or 24!) wasted bytes.
starblue has joined #rust-embedded
<whitequark[cis]1>
unpleasant
<FrreJacques[m]>
<dirbaio[m]> "but you don't need .source..." <- How can I impl `core::error::Error` without adding `.source()`??? Or did you mean they actually don't need the trait?
<dirbaio[m]>
implementing .source() is optional
<dirbaio[m]>
there's a default implementation that always returns None
<FrreJacques[m]>
Ah, and in that case there is no dyn overhead, although it is a None of type dyn Error?
<FrreJacques[m]>
If I don't implement source is this matroshka style of Error structs still beneficial? Is there a goto style for that?
<FrreJacques[m]>
Because I have an Lcd struct that holds a bus struct, which holds pins. And if I call a method on that Lcd, and some method on a pin would fail it would be most likely not helpful to only have either the info that the top level method failed, nor that some pin failed.
<dirbaio[m]>
the 'dyn' bloat only applies if it's used. even if you did implement .source() if the user doesn't call it there's no bloat
<dirbaio[m]>
FrreJacques[m]: the user can see what failed by inspecting your enum
<dirbaio[m]>
if you make the enum contain the inner errors from the HAL
<dirbaio[m]>
if you want to simplify, you can make a single enum LcdError with all the possible errors in it
<dirbaio[m]>
then printing it with {:?} will show everything they need to know
<dirbaio[m]>
and they can use match if they want to handle some errors differently than others
<dirbaio[m]>
instead of 4 layers like LcdError, LcdErrorKind, BusError, BusErrorKind
<FrreJacques[m]>
Okay that was the first idea, having a mod error with an enum and all errors. But then I read this https://sabrinajewson.org/blog/errors#guidelines-for-good-errors where this approach was discouraged. But maybe that is an oppinionated topic.
<dirbaio[m]>
yeah people have different opinion on things
<dirbaio[m]>
my opinion is usually "keep things as simple and dumb as possible unless there's a very good reason"
<dirbaio[m]>
:D
GrantM11235[m] has joined #rust-embedded
<GrantM11235[m]>
My rule of thumb is to pass along any error you encounter without trying to simplify it
<FrreJacques[m]>
But if you have multiple posdible Errors in one function you would then end up with Box dyn Error, don't you?
<GrantM11235[m]>
No, you can create an enum of all the possible error types. It's basically like using enum dispatch instead of dyn dispatch
<GrantM11235[m]>
That allows you to pass along the exact error value that you encountered. Compare that to the old version of the error enum, which could only tell you that some kind of CS error or DC error occurred, without actually telling you what the full error was https://docs.rs/display-interface/0.5.0/display_interface/enum.DisplayError.html
<FrreJacques[m]>
But wouldn't a possible user expect an Error Type to impl Error Traits?
<FrreJacques[m]>
Okay, one can do the blank impl of Error. And then use Display to match on the enum and provide more context. I guess more context is probably not needed, because one will see in the trace all the methods that where called till the error occured.
<FrreJacques[m]>
But I am still unsure how to handle the generic ErrorType of ehal, but to only use it for a map_err and work with my own types. The only meaningful usage beside that I can see, would be to get the ErrorKind and then use the Display or Debug to get any possible message.
<GrantM11235[m]>
You should almost never use any of the ErrorKinds, they will always have less information than the actual error. The main reason to use it is to check if you got an i2c NAK
<FrreJacques[m]>
<dirbaio[m]> "or for gpio it's most commonly..." <- I am a bit confused about that. That only makes sense in a binary crate, doesn't it? Like when I use embassy_stm32 and know that Result of ehal gpios will always be Ok().
<FrreJacques[m]>
<GrantM11235[m]> "You should almost never use..." <- But I can't know anything about the ErrorType in the ehal, despite that it has function kind()
<GrantM11235[m]>
As a driver author, you don't need to know anything about it, you just need to return it to the user
<FrreJacques[m]>
GrantM11235[m]: Thanks
<FrreJacques[m]>
The type system of Rust makes it really hard to work with generics you don't know anything about.
<FrreJacques[m]>
If I want to put this generic Error type inside an enum variant and have this enum variant to derive Debug, I run into the problem that it's not clear if it has Debug.
<GrantM11235[m]>
`#derive(Debug)` will impl Debug with the bounds that all your generics must also impl Debug, like this: `impl<X: Debug, Y: Debug> Debug for MyError<X, Y>`
<danielb[m]>
funny how I first fixed a typo in the deprecation notices, then went on to delete them :D
<JamesMunns[m]>
don't worry, I put them back :D
<danielb[m]>
ah hmm, apparently I should have read your wishlist once more :D thanks
<FrreJacques[m]>
<GrantM11235[m]> "All embedded-hal error types..." <- Hmm I think I just stumble of my illiteracy with generics. For some basic usage I found ways how to use them, but this puzzle is not solved for me yet^^.
<FrreJacques[m]>
Ah I can assume that the generic Error E will impl Debug, so I can write `impl<E: Debug> Error for MyError<E> {}`
<FrreJacques[m]>
I completely oversaw that in the signature of the trait and didn't saw Debug listed as impl, which is my bad, because Error is a trait not a struct.
<FrreJacques[m]>
I hope I don't bother you all too much š
<rafael[m]>
<Ralph[m]> "it sounds like you're looking..." <- Oh that looks more like a way to sanitize measurement data and predict state between measurements. Not what I was looking for but very interesting and also likely quite useful for the measurements themselves. So thx a lot for the links!
<GrantM11235[m]>
e-h doesn't require error types to impl core::error::Error, but they still can. That means that MyError may or may not impl Error depending on the inner type(s). So you can either always impl Error without any source, or only impl Error when you can actually pass along the source. There are pros and cons to each
<GrantM11235[m]>
But don't worry too much either way, because no one actually uses core::error::Error in embedded š
<FrreJacques[m]>
Okay, I will just use the blanket implementation of Error and try to keep things simple.
<rafael[m]>
<Ralph[m]> "it sounds like you're looking..." <- oh reading further into this thing it seems like you are correct, there is applications of fusing there. Interesting!
ouilemur has left #rust-embedded [WeeChat 4.5.1]
sajattack[m]1 has quit [Quit: Idle timeout reached: 172800s]
berkus[m] has quit [Quit: Idle timeout reached: 172800s]
jason-kairos[m] has quit [Quit: Idle timeout reached: 172800s]