Statically create const Uuid from &str

huangapple go评论62阅读模式
英文:

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 &amp;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: &amp;str) -&gt; ExampleId {
    // Hash the str slice to get a &quot;random&quot; value
    let hash: const_sha1::Digest =
        const_sha1::sha1(&amp;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&#39;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(&quot;example_id&quot;);
error[E0277]: the trait bound `[u8; 16]: From&lt;&amp;[u8]&gt;` is not satisfied
  --&gt; crates/bevy_diagnostic/src/diagnostic.rs:22:46
   |
22 |         let bytes_16: [u8; 16] = bytes[..16].try_into().unwrap();
   |                                              ^^^^^^^^ the trait `~const From&lt;&amp;[u8]&gt;` is not implemented for `[u8; 16]`
   |
   = note: required for `&amp;[u8]` to implement `~const Into&lt;[u8; 16]&gt;`
   = note: required for `[u8; 16]` to implement `~const TryFrom&lt;&amp;[u8]&gt;`
   = note: required for `&amp;[u8]` to implement `~const TryInto&lt;[u8; 16]&gt;`

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() &gt;= 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 &lt; 16 {
    bytes_16[i] = bytes[i];
    i += 1;
}

huangapple
  • 本文由 发表于 2023年5月25日 21:28:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332837.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定