|
1 | 1 | use ::std::os::raw::{c_char, c_uint}; |
2 | 2 | use serde_derive::{Deserialize, Serialize}; |
| 3 | +use std::any::TypeId; |
3 | 4 |
|
4 | 5 | use crate::error::{Error, Result}; |
5 | 6 |
|
@@ -50,17 +51,28 @@ impl AcpiGenericNetlinkEvent { |
50 | 51 | /// Checks a slice of C's chars to ensure they're not signed, needed because C's `char` type could |
51 | 52 | /// be either signed or unsigned unless specified. See: https://stackoverflow.com/a/2054941/5552584 |
52 | 53 | fn get_u8_bytes(slice: &[c_char]) -> Result<Vec<u8>> { |
53 | | - slice |
54 | | - .into_iter() |
55 | | - .take_while(|c| **c != 0) |
56 | | - .map(|c| -> Result<u8> { |
57 | | - if *c < 0 { |
58 | | - Err(format!("slice contained signed char: {}", c).into()) |
59 | | - } else { |
60 | | - Ok(*c as u8) |
61 | | - } |
62 | | - }) |
63 | | - .collect::<Result<Vec<_>>>() |
| 54 | + // NOTE: on some platforms `c_char` is `i8` and on others it's `u8`. Instead of targeting those |
| 55 | + // directly with `#cfg[...]` attributes (because it's not straightforward, have a look at the |
| 56 | + // cfg match for `c_char` in the stdlib, it's huge) we instead perform a runtime comparison |
| 57 | + // with `TypeId` here. |
| 58 | + // According to my tests (with `cargo-show-asm`), this is always optimised out completely since |
| 59 | + // `TypeId` returns a constant value, so it's just as good as a compile-time check. |
| 60 | + if TypeId::of::<c_char>() == TypeId::of::<i8>() { |
| 61 | + slice |
| 62 | + .into_iter() |
| 63 | + .take_while(|c| **c != 0) |
| 64 | + .map(|c| -> Result<u8> { |
| 65 | + #[allow(unused_comparisons)] |
| 66 | + if *c < 0 { |
| 67 | + Err(format!("slice contained signed char: {}", c).into()) |
| 68 | + } else { |
| 69 | + Ok(*c as u8) |
| 70 | + } |
| 71 | + }) |
| 72 | + .collect::<Result<Vec<_>>>() |
| 73 | + } else { |
| 74 | + Ok(slice.iter().map(|&c| c as u8).collect()) |
| 75 | + } |
64 | 76 | } |
65 | 77 |
|
66 | 78 | impl<'a> TryFrom<&'a acpi_genl_event> for AcpiGenericNetlinkEvent { |
|
0 commit comments