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).
> An out-of-memory condition is a runtime error so panics aren't an appropriate way to handle it anyway. Any case where runtime errors can only be handled via exceptions would make the dialect without exceptions second-class.

I'm not sure I follow your reasoning here, can you elaborate? Do we have any written guidelines for what should panic/abort? Or are you picturing a future where calling `alloc::oom` is configurable to do something more useful than aborting?

I agree that there are plenty of cases that *are* the same error. That's why I noted the "you still have tons of memory, you just asked for something too big" case. However if the allocator spits out null, we have no way (that I'm aware of) to identify the problem. We don't know if we were just stupid and asked for too much or a weird align/size combination, or if the system is genuinely out of space for a very reasonable request. 

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 think use cases where out-of-memory needs to be handled are important and I don't like the idea of a solution solving 5% of the problem and discouraging a proper implementation.

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?

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.