construe 0.0.2

Compile-Time Growable Array: Vec & String for const!
Documentation
construe
========

Compile-Time Growable Array: `Vec` & `String` for `const`!

[`Construe`] & [`StrConstrue`] allow you to write `const` functions that behave as though though they can collect items into a `Vec` or `&str`s into a `String`, returning an array or `&str`, whose length does *not* need to be known before the function is called.

The one caveat is that this is only possible for deterministic functions which, given the same inputs, will always return the same *amount* of items.
This is because they will be invoked twice: once to determine the size of the buffer needed and once to collect its contents.

Some other restrictions (currently) apply:
- can't overwrite previous items or assign directly to an index
- items can only be added to the end (only `.push()`)
- can't remove items from the buffer (e.g. no `.pop()`)
- it's not possible to inspect the buffer during construction
- no fallback mode for use outside of `const` contexts

## Examples

Simple compile-time [`&str`] concatenation using [`StrConstrue`]:
```rust
use construe::{StrConstrue, construe};

/// Concatenate all `&str`s into a single `&str`
const fn concat<const N: usize>(mut slice: &[&str]) -> StrConstrue<N> {
    let mut strc = StrConstrue::new();
    // no `for` in const
    while let [s, rest @ ..] = slice {
        slice = rest;
        // by-value since there's no `&mut` in const
        strc = strc.push_str(s);
    }
    strc
}

construe!(const HELLO_WORLD: &str = concat(&["Hello", " ", "World", "!"]));

assert_eq!(HELLO_WORLD, "Hello World!");
```

And a slightly more complicated example, using [`Construe`]:
```rust
use construe::{Construe, construe};

/// Multiply each item in `slice` `x` times
const fn multiply<const N: usize, T: Copy>(mut slice: &[T], x: usize)
    -> Construe<T, N>
{
    let mut c = Construe::new();
    while let [item, rest @ ..] = slice {
        slice = rest;
        let mut i = 0;
        while i < x {
            // see Construe::push docs on why we need `.0` at the end
            c = c.push(*item).0;
            i += 1;
        }
    }
    c
}

// as slice:
construe!(const NUMBERS: &[u8] = multiply(&[1, 2, 3], 2));
assert_eq!(NUMBERS, [1, 1, 2, 2, 3, 3]);

// as array:
construe!(const NUMBERS_ARRAY: [u8; _] = multiply(&[1, 2, 3], 2));
assert_eq!(NUMBERS, &NUMBERS_ARRAY);

// or with `&str`s:
construe!(const WORDS: &[&str] = multiply(&["hey", "you"], 2));
assert_eq!(WORDS, &["hey", "hey", "you", "you"]);
```

## Possible Improvements

Some of the restrictions mentioned above may or may not be remedied in future versions (roughly in the order given).

However, if a specialized version of these types is required, it would be easiest for you to just write it yourself.
For instance, if your function will need to inspect, say, the last 4 items of the buffer during construction, it would be fairly easy to write a [`Construe`] that holds a buffer of size 4 for the first run too.  
Implementing `pop()` where you don't need the result would be trivial, and if you do, it would be analogous to the previous case, as long as you can guarantee that a buffer of size `N` can keep up (e.g. "`pop()` won't be called more than once between `push()`es").
If you can't make this guarantee it might still be possible to implement: you could run your function thrice, once to determine the size of the look-back buffer, then twice like a normal [`Construe`].

Generally, I think the method used by this crate can be extended to make any computation work, given that you could implement an allocator: it would abort the computation prematurely if it runs out of space and ask for twice as much.
Then you need to invoke the computation at most log<sub>2</sub>(available_memory) times.  
Probably better to just wait until `const` support is better though.

[`Construe`]: https://docs.rs/construe/latest/construe/struct.Construe.html
[`StrConstrue`]: https://docs.rs/construe/latest/construe/struct.StrConstrue.html
[`&str`]: https://doc.rust-lang.org/std/primitive.str.html