WIP: Add Faux allocator API

This adds a alloc::faux module that implements an interpretation of @pnkfelix's proposed high-level allocator API (rust-lang/rfcs#244), optimized for the libstd usecases. This moves all of the tedious oom/zst/capacity-overflow logic into a central place, so that collections and other things don't need to think about it.

As part of this PR I have migrated RingBuf to this API as a proof of concept. Migrating Vec will likely be more tricky, because it does a lot more special tricks based on ZSTs, making the logic more tangled. It is possible that migrating to this API would cause a perf regression for duplicated checks/extra branching. However most of the checks are largely based on compile-time-constants, so I am optimistic about LLVM's ability to optimize these to death.

I guessed out the best semantics I could for some iffy things, like how the `alloc_array` API should handle `len = 0`.

I also am considering adding triple_alloc_array/triple_dealloc_array methods to handle the HashMap usecase (which BTree can also benefit from longterm).
> I'm not sure I follow your reasoning here, can you elaborate? Do we have any written guidelines for what should panic vs abort?

Panic is supposed to be for *logic errors* and using it for a runtime error like out-of-memory would be misuse. It can't be our strategy for handling out-of-memory because it would prevent first tier support for disabling unwinding and will force losing an entire thread.

> However in the case of our expect, we know for a fact that it was the parent asking for more memory than can even exist, and we can provide more info than just calling abort. If the panic OOMs, well, that sucks but it's not like we really lost anything for trying?

I don't see why the API should be complicated by splitting out this error condition from out-of-memory but not all others. This is also a performance critical API and you're adding a significant amount of code bloat for a very dubious reason.

> I am also interested in handling these usecases in a reasonable way. My inquiries in to this matter with other team members has amounted to "that's not a problem the standard library should try to handle gracefully, just bail out with panic/abort". Can you elaborate on, or direct me to, what you believe the right solution to be?

The right solution is bubbling up the out-of-memory errors. Panics are not an acceptable solution to runtime errors. I think it's unacceptable to force people to use unwinding to have a not-even-half-working way of handling OOM. It's worse to provide a 5% solution to this problem that's going to get in the way of future progress than it is to simply abort.

> Note that the point of this API isn't to provide a longterm solution to All The Allocation Problems. Just to cleanup up our current implementations while we wait for a better allocator API to arrive.

It's going to be a step backwards for performance and is not going to be as clean as simply using `Vec<T>` inside of the ring buffer implementation. The hash table and vector implementation are the only compelling use cases for the API, and I don't see the need for this extra complexity / code bloat to factor out a couple calls to the lower level API.