英文:
Statically create const Uuid from &str
问题
I'm trying to create a Uuid
in a const
context by passing in a &str
slice but I keep getting various errors.
这是我尝试在const
上下文中通过传递&str
片段来创建Uuid
,但我一直收到各种错误。
This answer gave me the non-const solution but it doesn't seem to work in const
due to the reference.
这个答案给了我非const解决方案,但由于引用,它似乎在const
中不起作用。
How can I use the first 16 bytes of the hash as an input for a Uuid
? Is this actually possible in a const
context?
如何使用哈希的前16个字节作为Uuid
的输入?在const
上下文中是否真的可以实现这一点?
struct ExampleId(Uuid);
pub const fn from_str(value: &str) -> ExampleId {
// Hash the str slice to get a "random" value
let hash: const_sha1::Digest =
const_sha1::sha1(&const_sha1::ConstBuffer::from_slice(value.as_bytes()));
// This gives a 20 byte hash
let bytes: [u8; 20] = hash.bytes();
// We only need 16 of these for a UUID but it doesn't seem possible to do this in a const context
let bytes_16: [u8; 16] = bytes[..16].try_into().unwrap();
ExampleId(Uuid::from_bytes(bytes_16))
}
const EXAMPLE: ExampleId = ExampleId::from_str("example_id");
error[E0277]: the trait bound `[u8; 16]: From<&[u8]>` is not satisfied
--> crates/bevy_diagnostic/src/diagnostic.rs:22:46
|
22 | let bytes_16: [u8; 16] = bytes[..16].try_into().unwrap();
| ^^^^^^^^ the trait `const From<&[u8]>` is not implemented for `[u8; 16]`
|
= note: required for `&[u8]` to implement `const Into<[u8; 16]>`
= note: required for `[u8; 16]` to implement `const TryFrom<&[u8]>`
= note: required for `&[u8]` to implement `const TryInto<[u8; 16]>`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `bevy_diagnostic` due to previous error
为了补充上下文,目前这段代码使用了u128
,看起来像这样ExampleId::from_u128(0x8EE938B3184729691BCCD346823B631C)
,用户必须生成一个唯一的128位数/十六进制数。为了更简单,我想允许传递一个字符串来生成Id。UUID是API的一部分,因此无法更改,这意味着我需要从任意字符串片段生成UUID。最后,由于此ID需要在编译时生成,因此需要将其作为const
函数执行。
英文:
I'm trying to create a Uuid
in a const
context by passing in a &str
slice but I keep getting various errors.
This answer gave me the non-const solution but it doesn't seem to work in const
due to the reference.
How can I use the first 16 bytes of the hash as an input for a Uuid
? Is this actually possible in a const
context?
struct ExampleId(Uuid);
pub const fn from_str(value: &str) -> ExampleId {
// Hash the str slice to get a "random" value
let hash: const_sha1::Digest =
const_sha1::sha1(&const_sha1::ConstBuffer::from_slice(value.as_bytes()));
// This gives a 20 byte hash
let bytes: [u8; 20] = hash.bytes();
// We only need 16 of these for a UUID but it doesn't seem possible to do this in a const context
let bytes_16: [u8; 16] = bytes[..16].try_into().unwrap();
ExampleId(Uuid::from_bytes(bytes_16))
}
const EXAMPLE: ExampleId = ExampleId::from_str("example_id");
error[E0277]: the trait bound `[u8; 16]: From<&[u8]>` is not satisfied
--> crates/bevy_diagnostic/src/diagnostic.rs:22:46
|
22 | let bytes_16: [u8; 16] = bytes[..16].try_into().unwrap();
| ^^^^^^^^ the trait `~const From<&[u8]>` is not implemented for `[u8; 16]`
|
= note: required for `&[u8]` to implement `~const Into<[u8; 16]>`
= note: required for `[u8; 16]` to implement `~const TryFrom<&[u8]>`
= note: required for `&[u8]` to implement `~const TryInto<[u8; 16]>`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `bevy_diagnostic` due to previous error
For added context, currently this code uses a u128
and looks something like ExampleId::from_u128(0x8EE938B3184729691BCCD346823B631C)
, with the user having to generate a unique 128 bit number/hex. To make it easier, I would like to allow passing in a string to generate the Id. The UUID is an exposed part of the API so it can't be changed which means I need to generate a UUID from an arbitrary string slice. Finally, because this ID is required at compile time, this needs to be done as a const
function.
答案1
得分: 1
以下是您要翻译的内容:
我是说,有这个愚蠢的解决方案,逐个复制字节,也许某处有一个宏可以做到这一点:
let bytes_16: [u8; 16] = [
bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5], bytes[6], bytes[7],
bytes[8], bytes[9], bytes[10], bytes[11],
bytes[12], bytes[13], bytes[14], bytes[15],
];
如果您愿意使用unsafe
,您也可以让编译器为您生成所有的复制代码:
// 安全性:我们断言至少有16个元素是已知的好的,所以我们可以安全地转换为*const [_; 16],并解引用它。
let bytes_16 = unsafe {
assert!(bytes.len() >= 16);
*(bytes.as_ptr() as *const [_; 16])
};
这两者都不会像Sven Marnachs的解决方案那样初始化最终的数组两次,但它们都有其他缺点,尽管在这种情况下,除非您多次使用它,否则这不是一个真正的问题。
英文:
I mean there is this dumb solution copying the bytes one by one maybe somewhere there is a macro for it:
let bytes_16: [u8; 16] = [
bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5], bytes[6], bytes[7],
bytes[8], bytes[9], bytes[10], bytes[11],
bytes[12], bytes[13], bytes[14], bytes[15],
];
If you're willing to use unafe
you can also let the compiler generate all the copying code for you:
// SAFETY: we assert that at least 16 elements are known good, so we can safely convert to a *const [_; 16] and dereference that.
let bytes_16 = unsafe {
assert!(bytes.len() >= 16);
*(bytes.as_ptr() as *const [_; 16])
};
Both of these do not initialize the final array twice unlike the Sven Marnachs solution, but they both have other drawbacks instead, admittedly in this case that's not really a concern unless you use it many times.
答案2
得分: 1
For loops are not allowed in const functions yet, but you can use a while loop:
let mut bytes_16 = [0; 16];
let mut i = 0;
while i < 16 {
bytes_16[i] = bytes[i];
i += 1;
}
英文:
For loops are not allowed in const functions yet, but you can use a while loop:
let mut bytes_16 = [0; 16];
let mut i = 0;
while i < 16 {
bytes_16[i] = bytes[i];
i += 1;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论