If you want this to work for arbitrary T then I think you’re doomed because Julia can use some funky non-contiguous memory layouts.
For example, a Vector{Union{Int, Nothing}} is represented in memory as a block of Int values followed by a block of Bool values identifying which items are actually nothing. So the value of a single item in the vector is spread over two locations in memory. This is all implementation detail of course.
This means that unsafe_load(::Ptr{Union{Int,Nothing}}) throws an error (and unsafe_wrap).
I think you need your user-supplied buffer to be a Vector{T} from the start.