BBQueue Storage Work

Use cases

Current: "Embedded Use Case"

  • Statically allocate storage
  • BBBuffer lives forever
  • User uses Producer and Consumer

Future:

  • Have the STORAGE for BBBuffer be provided seperately
  • Allow for uses like:
    • Statically allocated storage (like now)
    • Heap Allocation provided storage (Arc, etc.)
    • User provided storage (probably unsafe)

Sample Code for Use Cases

Static Buffer


static BB_QUEUE: BBQueue<OwnedBBBuffer<1024>> = BBQueue::new(OwnedBBBuffer::new());

fn main() {
    let (prod, cons) = BB_QUEUE.try_split().unwrap();
    // ...
}

Heap Allocation provided storage

Choice A: Simple

fn main() {
    // BBQueue<Arc<BBBuffer<1024>>
    // Producer<Arc<BBBuffer<1024>>, Consumer<Arc<BBBuffer<1024>>
    //
    // Storage is dropped when `prod` and `cons` are BOTH dropped.
    let (prod, cons) = BBQueue::new_arc::<1024>();
}

Choice B: Explicit

fn main() {
    // EDIT: This is sub-par, because this would require `arc_queue`,
    // `prod`, and `storage` to ALL be dropped
    // before the buffer is dropped.
    let arc_queue: BBQueue<Arc<BBBuffer<1024>> = BBStorage::new_arc();
    let (prod, cons) = arc_queue.try_split().unwrap();
}

NOTE: This is not yet possible as of the current state of the repo. I do intent do support it.

User provided storage

Choice A: Naive

EDIT: Not this. See below

static mut UNSAFE_BUFFER: [u8; 1024] = [0u8; 1024];

fn main() {
    let borrowed = unsafe {
        // TODO: Make sure BBQueue has lifetime shorter
        // than `'borrowed` here? In this case it is
        // 'static, but may not always be.
        BBStorageBorrowed::new(&mut UNSAFE_BUFFER);
    };
    let bbqueue = BBQueue::new(borrowed);

    // NOTE: This is NOT good, because the bound lifetime
    // of prod and cons will be that of `bbqueue`, which
    // is probably not suitable (non-'static). In many cases, we want
    // the producer and consumer to also have `Producer<'static>` lifetime
    let (prod, cons) = bbqueue.try_split().unwrap();
}

Choice B: "loadable" storage?

This would require EITHER:

  • The BBStorage methods are failable
  • The split belongs to the BBStorage item
    • (Could be an inherent or trait method)
  • Loadable storage panics on a split if not loaded
static mut UNSAFE_BUFFER: [u8; 1024] = [0u8; 1024];
static LOADABLE_BORROWED: BBStorageLoadBorrow::new();

fn main() {
    // This could probably be shortened to a single "store and take header" action.
    // Done in multiple steps here for clarity.
    let mut_buf = unsafe {
        &mut UNSAFE_BUFFER
    };
    let old = LOADABLE_BORROWED.store();    // -> Result<Option<&mut [u8]>>
                                            // Result: Err if already taken
                                            // Option: Some if other buffer already stored
    assert_eq!(Ok(None), old);

    let bbqueue = BBQueue::new(LOADABLE_BORROWED.take_header().unwrap());

    // Here prod and cons are <'static>, because LOADABLE_BORROWED is static.
    // BUUUUUT we still probably allow access of BBStorage methods, which would be totally unsafe
    //
    // EDIT: Okay, sealing the trait DOES prevent outer usage, so we're good on this regard!
    let (prod, cons) = bbqueue.try_split().unwrap();
}

NOTE: This is not yet possible as of the current state of the repo. I do intent do support it.