unsafe Rust has its own UB pitfalls that don't exist in C nor Zig, particularly in regards to the lifetimes of references [0] and preserving provenance through experimental apis [1].
[0]: the compiler is allowed to emit extra reads/writes to references so a mut and shared one to the same memory location cant be alive at the same time, across threads, and across sometimes non-obvious scoping rules.
unsafe Rust is also less ergonomic when dealing with concepts that go against the borrow checker like Pinning for intrusive memory, ptr::read/write and ManuallyDrop for controlling unorthodox object ownership/lifetime, and MaybeUninit/NonNull for facilitating certain data layout/access optimizations. Such designs often can't be wrapped in safe-Rust without introducing runtime overhead the patterns were used to originally avoid. Languages like Zig and C however make these patterns natural or event pleasant enough to consider it over unsafe Rust.
[0]: the compiler is allowed to emit extra reads/writes to references so a mut and shared one to the same memory location cant be alive at the same time, across threads, and across sometimes non-obvious scoping rules.
[1]: [pointer::set_ptr_value](https://doc.rust-lang.org/std/primitive.pointer.html#method....) is used by containers like Arc for `from_raw` in order to carry over aliasing, mutability, and other location meta data.
unsafe Rust is also less ergonomic when dealing with concepts that go against the borrow checker like Pinning for intrusive memory, ptr::read/write and ManuallyDrop for controlling unorthodox object ownership/lifetime, and MaybeUninit/NonNull for facilitating certain data layout/access optimizations. Such designs often can't be wrapped in safe-Rust without introducing runtime overhead the patterns were used to originally avoid. Languages like Zig and C however make these patterns natural or event pleasant enough to consider it over unsafe Rust.