active_standby 0.8.4

A concurrency primitive for high concurrency reads with a single writer.
Documentation
A concurrency library for high concurrency reads with a single writer.

This library is named after the 2 (identical) tables that we hold
internally:
- Active - this is the table that all Readers view. This table will never be
  write locked, so readers never face contention.
- Standby - this is the table the the Writer mutates. A writer should face
  minimal contention retrieving this table for mutation since Readers move
  to reading the Active table when they are swapped.

The cost of providing no contention to readers, and minimal contention to
writers is:
1. Memory - Internally we hold 2 copies of the underlying type the user
   created. This is needed to allow there to always be a table that Readers
   can check out without contention.
2. Writer thread CPU usage - The writer must apply all updates twice, once
   to each table. Lock contention for the writer should be less than with a
   plain RwLock due to Readers using the active_table.

The usage is meant to be similar to a RwLock. Instead of multiple threads
holding an RwLock though and calling read/write, there is a single Writer that
acquire a write guard to the tables, and N Readers which can acquire read guards
to the tables. Some of the inspiration came from the
[left_right](https://crates.io/crates/left-right) crate, so feel free to check
that out.

Minimizing lock contention also makes batching a more effective strategy for
Reader performance. Now you can grab a ReadGuard, and handle multiple requests
without worrying about starving the writer since it will be able to work on the
standby table, as opposed to with an RwLock. This means multiple requests can be
handled without having to relock the active_table. Similarly you can batch with
the Writer without starving the Readers.

Creation is done through the Writer, which can then spawn Readers (Readers
are clonable).

We provide 2 modules:
1. primitives - these are building blocks that can be used to create an
   AsLockHandle for a given table. Typically the only primitive a client
   library will need is UpdateTables (see example below).
2. collections - active standby version of common collections. Check out the
   implementations for examples of how to implement your own AsLockHandle.

Example:
```rust
use std::thread::sleep;
use std::time::Duration;

pub mod aslock {
    use active_standby::primitives::UpdateTables;

    // Generate an AsLockHandle, which will give wait free 
    // read accees to the underlying data. This also generates 
    // the associated WriteGuard which is used to mutate the 
    // data. Users should interact with this similarly to 
    // Arc<RwLock<i32>>.
    active_standby::generate_aslock_handle!(i32);

    // Client's must implement the mutable interface that 
    // they want to offer users of their active standby data 
    // structure. This is not automatically generated.
    impl<'w> WriteGuard<'w> {
        pub fn add_one(&mut self) {
            struct AddOne {}

            impl<'a> UpdateTables<'a, i32, ()> for AddOne {
                fn apply_first(&mut self, table: &'a mut i32) {
                    *table = *table + 1;
                }
                fn apply_second(mut self, table: &mut i32) {
                    self.apply_first(table);
                }
            }

            self.guard.update_tables(AddOne {})
        }
    }
}

fn main() {
    let table = aslock::AsLockHandle::new(0);
    let table2 = table.clone();
    let handle = std::thread::spawn(move || {
        while *table2.read() != 1 {
            sleep(Duration::from_micros(100));
        }
    });

    {
        let mut wg = table.write();
        wg.add_one();
    }
    handle.join();
}
```

If your table has large elements, you may want to save memory by only
holding each element once (e.g. vec::AsLockHandle<Arc<i32>>). This can be
done safely so long as no elements of the table are mutated, only inserted
and removed. So, keeping with our vector example, if you wanted a function
that increases the value of the first element by 1, you would not increment
the value behind the Arc. You would reassign the first element to a new Arc
with the incremented value.