Reputation: 133
For some reason I couldn't figure anything out from searching the web.
So I have a type synonym using the libc
crate (a simple wrapper):
pub type SyscallResult<R: Into<i64>> = Result<R, c_int>;
The point of having the Into<i64>
is because some syscalls have i32
or i64
results but errno
is always an i32
. (c_int
-> i32
)
There was no problems using concrete types provided by std
in the function signature.
pub fn handle_syscall_result(result: SyscallResult<i64>) -> i64
{
match result {
Ok(status: i64) => status,
Err(errno: c_int) => {
let err = unsafe { CStr::from_ptr(libc::strerror(errno)) };
println!("{:?}", err);
errno as i64
}
}
}
But when I try to propagate the trait bound into the signature of a function, things start to go haywire:
fn new_syscall_result<T>(status: Option<T>) -> SyscallResult<i64>
where
T: Into::<i64>,
{
let errno: c_int = errno();
match errno {
-1 => Err(errno),
_ => Ok(status.unwrap_or(errno)),
}
}
Gives
error[E0308]: mismatched types
-->
|
35 | fn new_syscall_result<T>(status: Option<T>) -> SyscallResult<i64>
| - this type parameter
...
43 | _ => Ok(status.unwrap_or(errno)),
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found type parameter `T`
|
= note: expected type `i64`
found type parameter `T`
which makes it look like it is doing the right thing, as the i32
was casted to an i64
, yet for some reason it doesn't satisfy the trait bound T
?
Unwrapping Option<T>
should naturally give T
and from what I've read from the std::convert::From
docs, Into<i64>
should be implemented for i64
as well (reflexivity), though even if it wasn't casted From<i32> for i64
is a valid implementation which means Into<i64> for i32
should exist.
Switching the return type to SyscallResult<T>
doesn't make a difference either
error[E0308]: mismatched types
-->
|
35 | fn new_syscall_result<T>(status: Option<T>) -> SyscallResult<T>
| - this type parameter
...
43 | _ => Ok(status.unwrap_or(errno)),
| ^^^^^ expected type parameter `T`, found `i32`
|
= note: expected type parameter `T`
found type `i32`
Upvotes: 0
Views: 1076
Reputation: 3669
You need to explicitly call into()
:
_ => Ok(status.map(Into::<i64>::into).unwrap_or(errno.into())),
// ^^^^^^^^^^^^^^^^^^^^^^
status
is a Option<T>
, bot you want an Option<i64>
. To achieve this, we transform the type contained in the Option
by using Option::map
.
There is another problem in your code:
_ => Ok(status.map(Into::<i64>::into).unwrap_or(errno.into())),
// ^^^^^^^^^^^^
errno
is a c_int
, so on most platforms a i32
, but we need an i64
. Again, into()
must be used to transform the type. Explicit type annotations are not necessary here, the compiler can deduce the correct type from context. Alternatively, you could also use a cast here:
_ => Ok(status.map(Into::<i64>::into).unwrap_or(errno as i64)),
Upvotes: 2