How to build constant integers from letter expressions?

Is there a way to build an integer const from a literal byte expression using either a byte string or a macro that builds an integer?

For instance:

 const MY_ID: u16 = u16_code!(ID); const MY_WORD: u32 = u32_code!(WORD); const MY_LONG: u64 = u64_code!(LONGWORD); 

Or something similar, bypassing b"ID" instead of ID ? *

It should not compile when the wrong number of characters is transmitted, something that I could not figure out how to achieve when using bit offset in a literal string.


Here is a simple example that works at a basic level, but does not provide the correct argument sizes.

 // const MY_ID: u16 = u16_code!(b"ID"); #[cfg(target_endian = "little")] macro_rules! u16_code { ($w:expr) => { ((($w[0] as u16) << 0) | (($w[1] as u16) << 8)) } } #[cfg(target_endian = "big")] macro_rules! u16_code { ($w:expr) => { ((($w[1] as u16) << 0) | (($w[0] as u16) << 8)) } } 

* See related question: Is there a byte equivalent to the macro 'stringify'?

+3
source share
2 answers

You can create a macro for each type by pointing it to an array and moving the parts to the correct position. An example expression for your u16 is

 ((b"ID"[0] as u16) << 8) | (b"ID"[1] as u16) 

You can replace b"ID" replacing the macro $e , which comes from $e:expr .

To perform a length check, you can insert a useless *$e as [u8; 2] *$e as [u8; 2] , which will not be able to compile if the types do not match.

+3
source

Based on the @ker suggestion, portable macros are presented here that create persistent identifiers based on fixed-size byte strings:

Warning: there are some restrictions on these constants that are not immediately obvious (see notes below).

Support for the following macros:

 const MY_ID: u16 = u16_code!(b"ID"); const MY_WORD: u32 = u32_code!(b"WORD"); const MY_LONG: u64 = u64_code!(b"LONGWORD"); 

Implementation:

 #[cfg(target_endian = "little")] #[macro_export] macro_rules! u16_code { ($w:expr) => { ((($w[0] as u16) << 0) | (($w[1] as u16) << 8) | ((*$w as [u8; 2])[0] as u16 * 0)) } } #[cfg(target_endian = "big")] #[macro_export] macro_rules! u16_code { ($w:expr) => { ((($w[1] as u16) << 0) | (($w[0] as u16) << 8) | ((*$w as [u8; 2])[0] as u16 * 0)) } } #[cfg(target_endian = "little")] #[macro_export] macro_rules! u32_code { ($w:expr) => { ((($w[0] as u32) << 0) | (($w[1] as u32) << 8) | (($w[2] as u32) << 16) | (($w[3] as u32) << 24) | ((*$w as [u8; 4])[0] as u32 * 0)) } } #[cfg(target_endian = "big")] #[macro_export] macro_rules! u32_code { ($w:expr) => { ((($w[3] as u32) << 0) | (($w[2] as u32) << 8) | (($w[1] as u32) << 16) | (($w[0] as u32) << 24) | ((*$w as [u8; 4])[0] as u32 * 0)) } } #[cfg(target_endian = "little")] #[macro_export] macro_rules! u64_code { ($w:expr) => { ((($w[0] as u64) << 0) | (($w[1] as u64) << 8) | (($w[2] as u64) << 16) | (($w[3] as u64) << 24) | (($w[4] as u64) << 32) | (($w[5] as u64) << 40) | (($w[6] as u64) << 48) | (($w[7] as u64) << 56) | ((*$w as [u8; 8])[0] as u64 * 0)) } } #[cfg(target_endian = "big")] #[macro_export] macro_rules! u64_code { ($w:expr) => { ((($w[7] as u64) << 0) | (($w[6] as u64) << 8) | (($w[5] as u64) << 16) | (($w[4] as u64) << 24) | (($w[3] as u64) << 32) | (($w[2] as u64) << 40) | (($w[1] as u64) << 48) | (($w[0] as u64) << 56) | ((*$w as [u8; 8])[0] as u64 * 0)) } } 

Note 1) a string that checks the size needed for or'd with a constant, because individual statements are not supported in constant expressions ( E0016 ).

I would also prefer to use if cfg!(target_endian = "big") inside one macro, but the same restriction on constants prevents it.

Note 2) . There is a potential problem with using these macros for inconsistent input, where an argument can be created for each byte (and possibly a health check for size). I looked at the purpose of the variable, but it also causes error E0016 .

Note 3) While Rust allows you to declare these values โ€‹โ€‹as const , they cannot be used in match statements.

eg:

 error[E0080]: constant evaluation error --> src/mod.rs:112:23 | 112 | const MY_DATA: u32 = u32_code!(b"DATA"); | ^^^^^^^^^^^^^^^^^^ the index operation on const values is unstable | note: for pattern here --> src/mod.rs:224:13 | 224 | MY_DATA => { | ^^^^^^^ 
+2
source

Source: https://habr.com/ru/post/1014932/


All Articles