> The same code the parent poster highlighted [1] is
> undefined behavior in C/C++ (with standard types). So
> really no language has the ability to express those
> concepts. Your doing pointer casts and possibly unaligned
> dereferences at the same time. This has zero consistency
> between CPU vendors.

It's undefined behavior in Rust, too. Rust code that type-puns an unaligned pointer into an integer would crash on MIPS or SPARC just like the C code would. And that crash could potentially be triggered by malicious input. "unsafe" doesn't make behavior well-defined in Rust anymore than an explicit cast makes it well-defined in C.

Moreover, type-punning is generally a warning of bad code in C. Both C and Rust will generally[1] diagnose a type-pun. And you can silence the diagnostic in both languages by using special syntax--unsafe in Rust, a cast in C. But in both cases the way that you silence the warning is over-broad; you often need to silence it for good reason, X, while accidentally silencing the diagnostic for usage Y.

The correct way to read in a little-endian integer in C is the same way you'd do it anywhere else:

unsigned char *p;
size_t plen;
uint64_t n;
// initialize p and plen
_Static_assert(CHAR_BIT == 8, "CHAR_BIT != 8"); // [2]
n = 0;
for (size_t i = 0; i < MIN(plen, sizeof n); i++) {
n |= p[i] << (8 * i);
}

It's correct regardless of endianness and regardless of whether the address is aligned. And the above loop can be unrolled, too, so that it pipelines well. If performance is so important that you can't be bothered to care about alignment constraints, you may as well drop down into assembly and use SIMD instructions directly. Type-punning with a C-style cast or Rust-style unsafe block is just a bad idea, IMO.

I've never seen a situation in C where type-punning of this sort was a good idea. The performance aspect is negligible. My parsers generally runs rings around code that uses type-punning. The gains are nothing compared to what you can get by better restructuring of higher-level code.
For example, with hashing functions you're generally hashing small strings; thus the alignment checks you would need to add would typically cost more than the benefit because they couldn't be amortized well.

If you really had to, then C11 provides _Alignof that can be used to type-pun in a safe manner just like you could in Rust. (If a builtin type has padding issues, so would the same Rust code. It just so happens that Rust affirmatively has selected at the outset to never support such architectures. Thus, running the same code on the same architecture would work correctly in both languages.) It's not even type-punning if in addition to correct alignment you can prove that all bits are value bits. That would be the case for both the fixed-sized integer types, as well as for unsigned types where you can prove there are no padding bits (which can be accomplished using well-defined code as well).

So for general usage, if you really want to you could implement two versions of the code--one that type-punned correctly for long strings, and a simpler, more concise, more obviously correct one for typical strings. So it can be done correctly while still reaping the same performance; it's just more hassle than writing incorrect code. But even the incorrect code is more obtuse than the trivially correct version, which is why I've never had a good reason to type-pun.

[1] The exception in C is implicit conversions through a void pointer. But in C++, which lacks implicit void pointer conversions, engineers will often instinctively add an explicit cast where you would normally use a void pointer in C, substantially blunting the benefit of removing the implicit conversion from the language. And that habit to cast can easily lead to more bugs, just like in this case, where unsafe was used to permit the use of a broken idiom that is poor code even in C.

Good C rarely uses casts. Avoiding casts is a good habit to get into in C. And I've personally never seen good reason to type-pun anything, period, in C.

[2] The code could be trivially made correct on platforms where CHAR_BIT > 8 if the convention was that input strings only filled the bottom 8 bits of char. It would just be a distraction here, though.