Reputation: 3549
I had some code
fn read_inner<'b>(&'b mut self, buf: &mut [u8]) -> Result<usize, Box<dyn Error + 'b>> {
...
buf[rval] = reader.next_spi_byte()?
...
that worked in an std environment. I used the core_error
crate to make the transition to no_std a little easier. But now I'm getting errors.
error[E0277]: `?` couldn't convert the error to `Box<dyn core_error::Error>`
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/camera.rs:90:47
|
90 | buf[rval] = reader.next_spi_byte()?;
| ^ the trait `From<CamError<<CS as embedded_hal::digital::v2::OutputPin>::Error, ES, EI>>` is not implemented for `Box<dyn core_error::Error>`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `From<T>`:
<Box<CStr> as From<&CStr>>
<Box<CStr> as From<CString>>
<Box<CStr> as From<Cow<'_, CStr>>>
<Box<T> as From<T>>
<Box<[T], A> as From<Vec<T, A>>>
<Box<[T]> as From<&[T]>>
<Box<[T]> as From<Cow<'_, [T]>>>
<Box<[T]> as From<[T; N]>>
and 4 others
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, CamError<<CS as embedded_hal::digital::v2::OutputPin>::Error, ES, EI>>>` for `Result<usize, Box<dyn core_error::Error>>`
I tried to work around it a couple of different ways
buf[rval] = reader.next_spi_byte().map_err(|e| Box::new(e))?;
buf[rval] = reader.next_spi_byte().map_err(|e| Box::<dyn Error+'b>::new(e))?;
buf[rval] = reader.next_spi_byte().map_err(|e| {
let tmp: Box<dyn Error + 'b> = Box::new(e);
tmp
})?;
Only the last one actually worked. The other two triggered errors
error[E0277]: `?` couldn't convert the error to `Box<dyn core_error::Error>`
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/camera.rs:91:72
|
91 | buf[rval] = reader.next_spi_byte().map_err(|e| Box::new(e))?;
| ^ the trait `From<Box<CamError<<CS as embedded_hal::digital::v2::OutputPin>::Error, ES, EI>>>` is not implemented for `Box<dyn core_error::Error>`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `From<T>`:
<Box<CStr> as From<&CStr>>
<Box<CStr> as From<CString>>
<Box<CStr> as From<Cow<'_, CStr>>>
<Box<T> as From<T>>
<Box<[T], A> as From<Vec<T, A>>>
<Box<[T]> as From<&[T]>>
<Box<[T]> as From<Cow<'_, [T]>>>
<Box<[T]> as From<[T; N]>>
and 4 others
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, Box<CamError<<CS as embedded_hal::digital::v2::OutputPin>::Error, ES, EI>>>>` for `Result<usize, Box<dyn core_error::Error>>`
error[E0599]: the function or associated item `new` exists for struct `Box<(dyn core_error::Error + 'b)>`, but its trait bounds were not satisfied
--> /home/thoth/src/rust-esp32-experiments/http-camera/webcam-applib/src/camera.rs:92:81
|
92 | buf[rval] = reader.next_spi_byte().map_err(|e| Box::<dyn Error+'b>::new(e))?;
| ^^^ function or associated item cannot be called on `Box<(dyn core_error::Error + 'b)>` due to unsatisfied trait bounds
|
::: /home/thoth/.cargo/registry/src/github.com-1ecc6299db9ec823/core-error-0.0.0/src/error_trait.rs:19:1
|
19 | pub trait Error: Debug + Display {
| -------------------------------- doesn't satisfy `dyn core_error::Error: Sized`
|
= note: the following trait bounds were not satisfied:
`dyn core_error::Error: Sized`
Why is the second one different from the last/third one?
The suggestion from isaactfa
buf[rval] = reader.next_spi_byte().map_err(|e| Box::new(e) as Box::<dyn Error+'b>)?;
appears to work. It still puzzles me that Box::<dyn Error+'b>::new(e)
can not be converted to a Box<dyn Error+'b>
by the ?
operator.
Upvotes: 0
Views: 92
Reputation: 60272
Essentially this boils down to how ?
works and how unsized coercions work.
Going from T
to dyn Trait
(if T
implements Trait
) requires an unsized coercion, as does going from Box<T>
to Box<dyn Trait>
. The ?
operator does not do unsized coercions, it uses the Into
conversion trait. It may have worked before with the std::error::Error
trait since there is an Into
implementation that does the unsized coercion internally E: Error
to Box<dyn Error>
. It does not appear that core_error::Error
has such an implementation, so that's why the first method doesn't work.
The reason Box::<dyn Error+'b>::new
doesn't work is because you cannot have a variable of type dyn Trait
. A dyn Trait
is a dynamically-sized type and must be used through some kind of indirection: a reference &
, a Box
, etc. Basically you are trying to coerce the type into a trait object too early; new
would have to accept a dyn Error
parameter, which is not allowed.
The way the last method works is because you put the value in a Box<T>
and then coerce it to a Box<dyn Trait>
. Then ?
will work since it will just use the identity blanket implementation of Into
.
Upvotes: 1