This is not possible, because Rust still stores a discriminant even when the enum values don't overlap.
As far as I can tell, the only situation where Rust doesn't store a discriminant is when either the Ok
or Err
variant is zero-sized, and the other variant has a niche. So, Result<(), ErrorEnum>
can be represented as an integer, but Result
can not.
You can still use enums, and implement simple conversions like this:
#[repr(i8)]
pub enum Error {
E1 = -1,
E2 = -2,
E3 = -3,
E4 = -4,
}
#[repr(i8)]
pub enum Success {
S0 = 0,
S1 = 1,
S2 = 2,
S3 = 3,
}
pub type LibResult = Result;
pub fn number_to_result(value: i32) -> Option {
match value {
-4 ..= -1 => Some(Err(unsafe { std::mem::transmute(value as i8) })),
0 ..= 3 => Some(Err(unsafe { std::mem::transmute(value as i8) })),
_ => return None,
}
}
pub fn result_to_number(res: LibResult) -> i32 {
match res {
Ok(value) => value as i32,
Err(error) => error as i32,
}
}
P.S. Sorry that the generics aren't displayed due to Lemmy's bad santiziation.
It matters because the conversion between i32 and the Result is only "free" if they have the same layout (which they do not, because of the discriminant). So a more costly conversion method is required.
You are right, because the compiler is able to optimize your code quite well. However, if that optimization were to break at some point (as there is no guarantee that an optimization will continue to work in the future), it would become less efficient.