<commit_before>use std::cell::UnsafeCell;
use std::ops::BitAnd;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

/// A single-producer multiple-consumer buffer, useful for thread-safe data
/// sharing. More general variant of triple buffering for multiple consumers.
///
/// Triple buffering is an extremely efficient synchronization protocol when
/// a producer thread wants to constantly update a value that is visible by a
/// single consumer thread. However, it is not safe to use in the presence of
/// multiple consumers, because the consumer thread can no longer assume that
/// it is the only thread having access to the read buffer.
///
/// Reference counting techniques can be used to build a variant of triple
/// buffering which works for multiple consumers, remains provably wait-free
/// wait-free if one extra buffer plus one per supplementary consumer is added,
/// and degrades gracefully when a smaller amount of buffers is used. I call the
/// resulting synchronization primitive an SPMC buffer.
///
pub struct SPMCBuffer<T: Clone> {
    /// Input object used by the producer to send updates
    input: SPMCBufferInput<T>,

    /// Clonable output object, used by consumers to read the current value
    output: SPMCBufferOutput<T>,
}
//
impl<T: Clone> SPMCBuffer<T> {
    /// Construct an SPMC buffer allowing for wait-free writes under up to N
    /// concurrent readouts to distinct buffers, and with some initial content.
    pub fn new(max_conc_readers: usize, initial: T) -> Self {
        // Translate max_conc_readers into an actual buffer count
        let num_buffers = max_conc_readers + 3;

        // Start with the shared state. Initially, buffer 0 is the "latest" one.
        let shared_state = Arc::new(
            SPMCBufferSharedState {
                buffers: vec![
                    Buffer {
                        data: UnsafeCell::new(initial),
                        done_readers: AtomicRefCount::new(0),
                    };
                    num_buffers
                ],
                latest_buf: AtomicSharedIndex::new(0),
            }
        );

        // ...then construct the input and output structs. Any consumer should
        // be initialized with an invalid read index so that it increments the
        // refcount of the latest buffer on its first read.
        let mut result = SPMCBuffer {
            input: SPMCBufferInput {
                shared: shared_state.clone(),
                reference_counts: vec![0; num_buffers],
            },
            output: SPMCBufferOutput {
                shared: shared_state,
                read_idx: INVALID_INDEX,
            },
        };

        // Mark the public buffer with an "infinite" reference count, in order
        // to remind ourselves to never write into it (it's reader-visible!)
        result.input.reference_counts[0] = INFINITE_REFCOUNT;

        // Return the resulting valid SPMC buffer
        result
    }

    /// Extract input and output of the SPMC buffer
    pub fn split(self) -> (SPMCBufferInput<T>, SPMCBufferOutput<T>) {
        (self.input, self.output)
    }
}

/// Producer interface to SPMC buffers
///
/// The producer can use this struct to submit updates to the SPMC buffer
/// whenever he likes. These updates may or may not be nonblocking depending
/// on the buffer size and the readout pattern.
///
pub struct SPMCBufferInput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Amount of readers who potentially have access to each (unreachable)
    /// buffer. The latest buffer, which is still reachable, is marked with an
    /// "infinite" reference count to warn that we don't know the true one.
    reference_counts: Vec<RefCount>,
}
//
impl<T: Clone> SPMCBufferInput<T> {
    /// Write a new value into the SPMC buffer
    pub fn write(&mut self, value: T) {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Go into a spin-loop, looking for an "old" buffer with no live reader
        let mut write_pos: Option<usize> = None;
        while write_pos == None {
            // We want to iterate over both buffers and associated refcounts
            let mut buf_rc_iter =
                shared_state.buffers.iter()
                                    .zip(self.reference_counts.iter());

            // We want to find a buffer which is unreachable, and whose previous
            // readers have all moved on to more recent data. Unreachability is
            // guaranteed by the fact that we artificially set the refcount of
            // the public buffer to infinity, but we still need to check what
            // the former readers of the unreachable buffers are doing.
            write_pos = buf_rc_iter.position(|tuple| {
                let (buffer, refcount) = tuple;
                let done_readers = buffer.done_readers.load(Ordering::Relaxed);
                done_readers == *refcount
            });
        }
        let write_idx = write_pos.unwrap();

        // The buffer that we just obtained is provably unused by old readers
        // and unreachable by new readers, so we can safely allocate it as a
        // write buffer and put our data into it
        let ref write_buffer = shared_state.buffers[write_idx];
        let write_ptr = write_buffer.data.get();
        unsafe { *write_ptr = value; }

        // To avoid overflow, we should reset the buffer's reference count
        // on publication: there's no need to account for previous readers.
        write_buffer.done_readers.store(0, Ordering::Relaxed);

        // Publish our write buffer as the new latest buffer, and retrieve
        // the old buffer's shared index
        let former_latest_buf = shared_state.latest_buf.swap(
            write_idx * SHARED_INDEX_MULTIPLIER,
            Ordering::Release  // Publish updated buffer state to the readers
        );

        // In debug mode, make sure that overflow did not occur
        debug_assert!(former_latest_buf.bitand(SHARED_OVERFLOW_BIT) == 0);

        // Decode the information contained in the former shared index
        let former_idx = former_latest_buf.bitand(SHARED_INDEX_MASK)
                                          / SHARED_INDEX_MULTIPLIER;
        let former_readcount = former_latest_buf.bitand(SHARED_READCOUNT_MASK);

        // Write down the former buffer's refcount, and set the latest buffer's
        // refcount to infinity so that we don't accidentally write to it
        self.reference_counts[former_idx] = former_readcount;
        self.reference_counts[write_idx] = INFINITE_REFCOUNT;
    }
}

/// Consumer interface to SPMC buffers
///
/// A consumer of data can use this struct to access the latest published update
/// from the producer whenever he likes. Readout is nonblocking: a collision
/// between the producer and a consumer will result cache contention induced
/// slowdown, but deadlocks and scheduling-induced slowdowns cannot happen.
///
pub struct SPMCBufferOutput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Index of the buffer which the consumer is currently reading from
    read_idx: BufferIndex,
}
//
impl<T: Clone> SPMCBufferOutput<T> {
    /// Access the latest value from the SPMC buffer
    pub fn read(&mut self) -> &T {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Check if the producer has submitted an update
        let latest_buf = shared_state.latest_buf.load(Ordering::Relaxed);
        let update_available =
            latest_buf.bitand(SHARED_INDEX_MASK)
                != self.read_idx * SHARED_INDEX_MULTIPLIER;

        // If so, exchange our current read buffer with the latest buffer
        if update_available {
            // Acquire access to the latest buffer, incrementing its
            // refcount to tell the producer that we have access to it
            let latest_buf = shared_state.latest_buf.fetch_add(
                1,
                Ordering::Acquire  // Get the associated buffer state
            );

            // Drop our current read buffer. Because we already needed an
            // acquire fence above, and the buffer discarding operation contains
            // a read, we can safely use relaxed atomic order here: neither the
            // CPU nor the compiler can reorder this operation before the fence.
            unsafe { self.discard_read_buffer(Ordering::Relaxed); }

            // In debug mode, make sure that overflow did not occur
            debug_assert!((latest_buf+1).bitand(SHARED_OVERFLOW_BIT) == 0);

            // Extract the index of our new read buffer
            self.read_idx = latest_buf.bitand(SHARED_INDEX_MASK)
                                      / SHARED_INDEX_MULTIPLIER;
        }

        // Access data from the current (read-only) read buffer
        let read_ptr = shared_state.buffers[self.read_idx].data.get();
        unsafe { &*read_ptr }
    }

    /// Drop the current read buffer. This is unsafe because it allows the
    /// writer to write into it, which means that the read buffer must never be
    /// accessed after this operation completes. Be extremely careful with
    /// memory ordering: this must NEVER be reordered before a buffer read!
    unsafe fn discard_read_buffer(&self, order: Ordering) {
        self.shared.buffers[self.read_idx].done_readers.fetch_add(1, order);
    }
}
//
impl<T: Clone> Clone for SPMCBufferOutput<T> {
    // Create a new reader associated with a given SPMC buffer
    fn clone(&self) -> Self {
        SPMCBufferOutput {
            shared: self.shared.clone(),
            read_idx: INVALID_INDEX,
        }
    }
}
//
impl<T: Clone> Drop for SPMCBufferOutput<T> {
    // Discard our read buffer on thread exit
    fn drop(&mut self) {
        // We must use release ordering here in order to prevent preceding
        // buffer reads from being reordered after the buffer is discarded
        unsafe { self.discard_read_buffer(Ordering::Release); }
    }
}

/// Shared state for SPMC buffers
///
/// This struct provides both a set of shared buffers for single-producer
/// multiple-consumer broadcast communication and
///
/// The number of buffers N is a design tradeoff: the larger it is, the more
/// robust the primitive is against contention, at the cost of increased memory
/// usage. An SPMC buffer is provably wait-free for both readers and writers if
/// N = Nreaders + 3, where Nreaders is the amount of data consumers, but it
/// can work correctly in a degraded regime which is wait-free for readers and
/// potentially blocking for writers as long as N >= 2.
///
/// Note that for 1 reader, we need 4 buffers to be provably wait-free, rather
/// than 3 in the case of triple buffering. The explanation for this boils down
/// to the fact that we need to use two separate atomic variables to signal
/// incoming and departing readers, which means that atomic buffer swap is not
/// available anymore, and thus that the writer can observe a state where a
/// reader has access to a new buffer, but not yet discarded the previous one.
///
struct SPMCBufferSharedState<T: Clone> {
    /// Data storage buffers
    buffers: Vec<Buffer<T>>,

    /// Combination of reader count and latest buffer index (see below)
    latest_buf: AtomicSharedIndex,
}
//
struct Buffer<T: Clone> {
    /// Actual data must be in an UnsafeCell so that Rust knows it's mutable
    data: UnsafeCell<T>,

    /// Amount of readers who are done with this buffer and switched to another
    done_readers: AtomicRefCount,
}
//
impl<T: Clone> Clone for Buffer<T> {
    /// WARNING: Buffers are NOT safe to clone, because a writer might be
    ///          concurrently writing to them. The only reason why I'm not
    ///          marking this function as unsafe is that Rust won't allow me to
    ///          while staying compatible with the vec! single-item constructor
    fn clone(&self) -> Self {
        Buffer {
            data: UnsafeCell::new(
                unsafe { (*self.data.get()).clone() }
            ),
            done_readers: AtomicRefCount::new(
                self.done_readers.load(Ordering::Relaxed)
            ),
        }
    }
}

/// Atomic "shared index", combining "latest buffer" and "reader count" info
/// in a single large integer through silly bit tricks.
///
/// At the start of the readout process, a reader must atomically announce
/// itself as in the process of reading the current buffer (so that said buffer
/// does not get reclaimed) and determine which buffer is the current buffer.
///
/// Here is why these operations cannot be separated:
///
/// - Assume that the reader announces that it is reading, then determines which
///   buffer is the current buffer. In this case, the reader can only make the
///   generic announcement that it is reading "some" buffer, because it does not
///   know yet which buffer it'll be reading. This means that other threads do
///   not know which buffers are busy, and no buffer can be liberated until the
///   reader clarifies its intent or goes away. This way of operating is thus
///   effectively equivalent to a reader-directed update lock.
/// - Assume that the reader determines which buffer is the current buffer, then
///   announces itself as being in the process of reading this specific buffer.
///   Inbetween these two actions, the current buffer may have changed, so the
///   reader may increment the wrong refcount. Furthermore, the buffer that is
///   now targeted by the reader may have already be tagged as safe for reuse or
///   deletion by the writer, so if the reader proceeds with reading it, it may
///   accidentally end up in a data race w/ the writer. This follows the
///   classical rule of thumb that one should always reserve resources before
///   accessing them, however lightly.
///
/// To combine latest buffer index readout and reader count increment, we need
/// to pack both of these quantities into a single shared integer variable that
/// we can manipulate through a atomic operations. For refcounting, fetch_add
/// sounds like a good choice, so we want an atomic integer type whose low-order
/// bits act as a refcount and whose high-order bit act as a buffer index.
/// Here's an example for a 16-bit unsigned integer, allowing up to 64 buffers
/// and 511 concurrent readers on each buffer:
///
///   bit (high-order first):       15 .. 10  9  8 .. 0
///                                +--------+--+-------+
///   Contents:                    |BUFFERID|OF|READCNT|
///                                +--------+--+-------+
///
/// In this scheme, BUFFERID is the index of the "latest buffer", which contains
/// the newest data from the writer, and READCNT is the amount of readers who
/// have acquired access to this data. In principle, the later counter could
/// overflow in the presence of 512+ concurrent readers, all accessing the same
/// buffer without a single update happening in meantime. This scenario is
/// highly implausible on current hardware architectures (even many-core ones),
/// but we nevertheless account for it by adding an overflow "OF" bit, which is
/// checked in debug builds. A thread which detects such overflow should panic.
///
/// TODO: Switch to U16 / AtomicU16 once the later is stable
///
type BufferIndex = usize;
const INVALID_INDEX: BufferIndex = 0xffff;
//
type RefCount = usize;
const INFINITE_REFCOUNT: RefCount = 0xffff;
type AtomicRefCount = AtomicUsize;
//
type SharedIndex = usize;
type AtomicSharedIndex = AtomicUsize;
const SHARED_READCOUNT_MASK:   SharedIndex = 0b0000_0001_1111_1111;
const SHARED_OVERFLOW_BIT:     SharedIndex = 0b0000_0010_0000_0000;
const SHARED_INDEX_MASK:       SharedIndex = 0b1111_1100_0000_0000;
const SHARED_INDEX_MULTIPLIER: SharedIndex = 0b0000_0100_0000_0000;

// TODO: Add tests
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Documentation fixes<commit_after>use std::cell::UnsafeCell;
use std::ops::BitAnd;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

/// A single-producer multiple-consumer buffer, useful for thread-safe data
/// sharing. More general variant of triple buffering for multiple consumers.
///
/// Triple buffering is an extremely efficient synchronization protocol when
/// a producer thread wants to constantly update a value that is visible by a
/// single consumer thread. However, it is not safe to use in the presence of
/// multiple consumers, because the consumer thread can no longer assume that
/// it is the only thread having access to the read buffer.
///
/// Reference counting techniques can be used to build a variant of triple
/// buffering which works for multiple consumers, remains provably wait-free
/// wait-free if one extra buffer plus one per supplementary consumer is added,
/// and degrades gracefully when a smaller amount of buffers is used. I call the
/// resulting synchronization primitive an SPMC buffer.
///
pub struct SPMCBuffer<T: Clone> {
    /// Input object used by the producer to send updates
    input: SPMCBufferInput<T>,

    /// Clonable output object, used by consumers to read the current value
    output: SPMCBufferOutput<T>,
}
//
impl<T: Clone> SPMCBuffer<T> {
    /// Construct an SPMC buffer allowing for wait-free writes under up to N
    /// concurrent readouts to distinct buffers, and with some initial content.
    pub fn new(max_conc_readers: usize, initial: T) -> Self {
        // Translate max_conc_readers into an actual buffer count
        let num_buffers = max_conc_readers + 3;

        // Start with the shared state. Initially, buffer 0 is the "latest" one.
        let shared_state = Arc::new(
            SPMCBufferSharedState {
                buffers: vec![
                    Buffer {
                        data: UnsafeCell::new(initial),
                        done_readers: AtomicRefCount::new(0),
                    };
                    num_buffers
                ],
                latest_buf: AtomicSharedIndex::new(0),
            }
        );

        // ...then construct the input and output structs. Any consumer should
        // be initialized with an invalid read index so that it increments the
        // refcount of the latest buffer on its first read.
        let mut result = SPMCBuffer {
            input: SPMCBufferInput {
                shared: shared_state.clone(),
                reference_counts: vec![0; num_buffers],
            },
            output: SPMCBufferOutput {
                shared: shared_state,
                read_idx: INVALID_INDEX,
            },
        };

        // Mark the latest buffer with an "infinite" reference count, in order
        // to remind ourselves to never write into it (it's reader-visible!)
        result.input.reference_counts[0] = INFINITE_REFCOUNT;

        // Return the resulting valid SPMC buffer
        result
    }

    /// Extract input and output of the SPMC buffer
    pub fn split(self) -> (SPMCBufferInput<T>, SPMCBufferOutput<T>) {
        (self.input, self.output)
    }
}

/// Producer interface to SPMC buffers
///
/// The producer can use this struct to submit updates to the SPMC buffer
/// whenever he likes. These updates may or may not be nonblocking depending
/// on the buffer size and the readout pattern.
///
pub struct SPMCBufferInput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Amount of readers who potentially have access to each (unreachable)
    /// buffer. The latest buffer, which is still reachable, is marked with an
    /// "infinite" reference count, to warn that we don't know the true count.
    reference_counts: Vec<RefCount>,
}
//
impl<T: Clone> SPMCBufferInput<T> {
    /// Write a new value into the SPMC buffer
    pub fn write(&mut self, value: T) {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Go into a spin-loop, looking for an "old" buffer with no live reader
        let mut write_pos: Option<usize> = None;
        while write_pos == None {
            // We want to iterate over both buffers and associated refcounts
            let mut buf_rc_iter =
                shared_state.buffers.iter()
                                    .zip(self.reference_counts.iter());

            // We want to find a buffer which is unreachable, and whose previous
            // readers have all moved on to more recent data. Unreachability is
            // guaranteed by the fact that we artificially set the refcount of
            // the public buffer to infinity, but we still need to check what
            // the former readers of the unreachable buffers are doing.
            write_pos = buf_rc_iter.position(|tuple| {
                let (buffer, refcount) = tuple;
                let done_readers = buffer.done_readers.load(Ordering::Relaxed);
                done_readers == *refcount
            });
        }
        let write_idx = write_pos.unwrap();

        // The buffer that we just obtained is provably unused by old readers
        // and unreachable by new readers, so we can safely allocate it as a
        // write buffer and put our data into it
        let ref write_buffer = shared_state.buffers[write_idx];
        let write_ptr = write_buffer.data.get();
        unsafe { *write_ptr = value; }

        // To avoid overflow, we should reset the buffer's reference count
        // on publication: there's no need to account for previous readers.
        write_buffer.done_readers.store(0, Ordering::Relaxed);

        // Publish our write buffer as the new latest buffer, and retrieve
        // the old buffer's shared index
        let former_latest_buf = shared_state.latest_buf.swap(
            write_idx * SHARED_INDEX_MULTIPLIER,
            Ordering::Release  // Publish updated buffer state to the readers
        );

        // In debug mode, make sure that overflow did not occur
        debug_assert!(former_latest_buf.bitand(SHARED_OVERFLOW_BIT) == 0);

        // Decode the information contained in the former shared index
        let former_idx = former_latest_buf.bitand(SHARED_INDEX_MASK)
                                          / SHARED_INDEX_MULTIPLIER;
        let former_readcount = former_latest_buf.bitand(SHARED_READCOUNT_MASK);

        // Write down the former buffer's refcount, and set the latest buffer's
        // refcount to infinity so that we don't accidentally write to it
        self.reference_counts[former_idx] = former_readcount;
        self.reference_counts[write_idx] = INFINITE_REFCOUNT;
    }
}

/// Consumer interface to SPMC buffers
///
/// A consumer of data can use this struct to access the latest published update
/// from the producer whenever he likes. Readout is nonblocking: a collision
/// between the producer and a consumer will result cache contention induced
/// slowdown, but deadlocks and scheduling-induced slowdowns cannot happen.
///
pub struct SPMCBufferOutput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Index of the buffer which the consumer is currently reading from
    read_idx: BufferIndex,
}
//
impl<T: Clone> SPMCBufferOutput<T> {
    /// Access the latest value from the SPMC buffer
    pub fn read(&mut self) -> &T {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Check if the producer has submitted an update
        let latest_buf = shared_state.latest_buf.load(Ordering::Relaxed);
        let update_available =
            latest_buf.bitand(SHARED_INDEX_MASK)
                != self.read_idx * SHARED_INDEX_MULTIPLIER;

        // If so, exchange our current read buffer with the latest buffer
        if update_available {
            // Acquire access to the latest buffer, incrementing its
            // refcount to tell the producer that we have access to it
            let latest_buf = shared_state.latest_buf.fetch_add(
                1,
                Ordering::Acquire  // Get the associated buffer state
            );

            // Drop our current read buffer. Because we already needed an
            // acquire fence above, and the buffer discarding operation contains
            // a read, we can safely use relaxed atomic order here: neither the
            // CPU nor the compiler can reorder this operation before the fence.
            unsafe { self.discard_read_buffer(Ordering::Relaxed); }

            // In debug mode, make sure that overflow did not occur
            debug_assert!((latest_buf+1).bitand(SHARED_OVERFLOW_BIT) == 0);

            // Extract the index of our new read buffer
            self.read_idx = latest_buf.bitand(SHARED_INDEX_MASK)
                                      / SHARED_INDEX_MULTIPLIER;
        }

        // Access data from the current (read-only) read buffer
        let read_ptr = shared_state.buffers[self.read_idx].data.get();
        unsafe { &*read_ptr }
    }

    /// Drop the current read buffer. This is unsafe because it allows the
    /// writer to write into it, which means that the read buffer must never be
    /// accessed after this operation completes. Be extremely careful with
    /// memory ordering: this must NEVER be reordered before a buffer read!
    unsafe fn discard_read_buffer(&self, order: Ordering) {
        self.shared.buffers[self.read_idx].done_readers.fetch_add(1, order);
    }
}
//
impl<T: Clone> Clone for SPMCBufferOutput<T> {
    // Create a new reader associated with a given SPMC buffer
    fn clone(&self) -> Self {
        SPMCBufferOutput {
            shared: self.shared.clone(),
            read_idx: INVALID_INDEX,
        }
    }
}
//
impl<T: Clone> Drop for SPMCBufferOutput<T> {
    // Discard our read buffer on thread exit
    fn drop(&mut self) {
        // We must use release ordering here in order to prevent preceding
        // buffer reads from being reordered after the buffer is discarded
        unsafe { self.discard_read_buffer(Ordering::Release); }
    }
}

/// Shared state for SPMC buffers
///
/// This struct provides both a set of shared buffers for single-producer
/// multiple-consumer broadcast communication and
///
/// The number of buffers N is a design tradeoff: the larger it is, the more
/// robust the primitive is against contention, at the cost of increased memory
/// usage. An SPMC buffer is provably wait-free for both readers and writers if
/// N = Nreaders + 3, where Nreaders is the amount of data consumers, but it
/// can work correctly in a degraded regime which is wait-free for readers and
/// potentially blocking for writers as long as N >= 2.
///
/// Note that for 1 reader, we need 4 buffers to be provably wait-free, rather
/// than 3 in the case of triple buffering. The explanation for this boils down
/// to the fact that we need to use two separate atomic variables to signal
/// incoming and departing readers, which means that atomic buffer swap is not
/// available anymore, and thus that the writer can observe a state where a
/// reader has access to a new buffer, but not yet discarded the previous one.
///
struct SPMCBufferSharedState<T: Clone> {
    /// Data storage buffers
    buffers: Vec<Buffer<T>>,

    /// Combination of reader count and latest buffer index (see below)
    latest_buf: AtomicSharedIndex,
}
//
struct Buffer<T: Clone> {
    /// Actual data must be in an UnsafeCell so that Rust knows it's mutable
    data: UnsafeCell<T>,

    /// Amount of readers who are done with this buffer and switched to another
    done_readers: AtomicRefCount,
}
//
impl<T: Clone> Clone for Buffer<T> {
    /// WARNING: Buffers are NOT safe to clone, because a writer might be
    ///          concurrently writing to them. The only reason why I'm not
    ///          marking this function as unsafe is that Rust won't allow me to
    ///          while staying compatible with the vec! single-item constructor
    fn clone(&self) -> Self {
        Buffer {
            data: UnsafeCell::new(
                unsafe { (*self.data.get()).clone() }
            ),
            done_readers: AtomicRefCount::new(
                self.done_readers.load(Ordering::Relaxed)
            ),
        }
    }
}

/// Atomic "shared index", combining "latest buffer" and "reader count" info
/// in a single large integer through silly bit tricks.
///
/// At the start of the readout process, a reader must atomically announce
/// itself as in the process of reading the current buffer (so that said buffer
/// does not get reclaimed) and determine which buffer is the current buffer.
///
/// Here is why these operations cannot be separated:
///
/// - Assume that the reader announces that it is reading, then determines which
///   buffer is the current buffer. In this case, the reader can only make the
///   generic announcement that it is reading "some" buffer, because it does not
///   know yet which buffer it'll be reading. This means that other threads do
///   not know which buffers are busy, and no buffer can be liberated until the
///   reader clarifies its intent or goes away. This way of operating is thus
///   effectively equivalent to a reader-directed update lock.
/// - Assume that the reader determines which buffer is the current buffer, then
///   announces itself as being in the process of reading this specific buffer.
///   Inbetween these two actions, the current buffer may have changed, so the
///   reader may increment the wrong refcount. Furthermore, the buffer that is
///   now targeted by the reader may have already be tagged as safe for reuse or
///   deletion by the writer, so if the reader proceeds with reading it, it may
///   accidentally end up in a data race w/ the writer. This follows the
///   classical rule of thumb that one should always reserve resources before
///   accessing them, however lightly.
///
/// To combine latest buffer index readout and reader count increment, we need
/// to pack both of these quantities into a single shared integer variable that
/// we can manipulate through a atomic operations. For refcounting, fetch_add
/// sounds like a good choice, so we want an atomic integer type whose low-order
/// bits act as a refcount and whose high-order bit act as a buffer index.
/// Here's an example for a 16-bit unsigned integer, allowing up to 64 buffers
/// and 511 concurrent readers on each buffer:
///
///   bit (high-order first):       15 .. 10  9  8 .. 0
///                                +--------+--+-------+
///   Contents:                    |BUFFERID|OF|READCNT|
///                                +--------+--+-------+
///
/// In this scheme, BUFFERID is the index of the "latest buffer", which contains
/// the newest data from the writer, and READCNT is the amount of readers who
/// have acquired access to this data. In principle, the later counter could
/// overflow in the presence of 512+ concurrent readers, all accessing the same
/// buffer without a single update happening in meantime. This scenario is
/// highly implausible on current hardware architectures (even many-core ones),
/// but we nevertheless account for it by adding an overflow "OF" bit, which is
/// checked in debug builds. A thread which detects such overflow should panic.
///
/// TODO: Switch to U16 / AtomicU16 once the later is stable
///
type BufferIndex = usize;
const INVALID_INDEX: BufferIndex = 0xffff;
//
type RefCount = usize;
const INFINITE_REFCOUNT: RefCount = 0xffff;
type AtomicRefCount = AtomicUsize;
//
type SharedIndex = usize;
type AtomicSharedIndex = AtomicUsize;
const SHARED_READCOUNT_MASK:   SharedIndex = 0b0000_0001_1111_1111;
const SHARED_OVERFLOW_BIT:     SharedIndex = 0b0000_0010_0000_0000;
const SHARED_INDEX_MASK:       SharedIndex = 0b1111_1100_0000_0000;
const SHARED_INDEX_MULTIPLIER: SharedIndex = 0b0000_0100_0000_0000;

// TODO: Add tests
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before><commit_msg>Refactor algorithm into a lib<commit_after>extern crate random_choice;

use std::collections::{HashSet, HashMap};
use std::cmp::max;
use self::random_choice::random_choice;

pub struct GSDMM {
    alpha: f64,
    beta: f64,
    K:usize,
    V:f64,
    D:usize,
    maxit:isize,
    docs:Vec<Vec<String>>,
    labels: Vec<usize>,
    cluster_counts: Vec<u32>,
    cluster_word_counts:Vec<u32>,
    cluster_word_distributions: Vec<HashMap<String,u32>>
}

impl GSDMM {
    pub fn new(alpha:f64, beta:f64, K: usize, maxit:isize, vocab:HashSet<String>, docs:Vec<Vec<String>>) -> GSDMM {
        let D = docs.len();

        // compute utilized vocabulary size.
        let mut utilized_vocab = HashSet::with_capacity(vocab.len());
        for doc in &docs {
            for word in doc {
                utilized_vocab.insert(word.clone());
            }
        }
        let V = utilized_vocab.len() as f64;
        println!("Fitting with alpha={}, beta={}, K={}, maxit={}, vocab size={}", alpha, beta, K, maxit, V as u32);

        let labels = (0_usize..K).collect::<Vec<usize>>();
        let mut d_z: Vec<usize> = (0_usize..D).map(|_| 0_usize).collect::<Vec<usize>>(); // doc labels
        let mut m_z: Vec<u32> = GSDMM::zero_vector(K);  // cluster sizes
        let mut n_z: Vec<u32> = GSDMM::zero_vector(K);  // cluster word counts
        let mut n_z_w = Vec::<HashMap<String, u32>>::with_capacity(K);  // container for cluster word distributions
        for _ in 0_usize..K {
            let mut m = HashMap::<String, u32>::with_capacity(max(vocab.len() / 10, 100));
            &n_z_w.push(m);
        }

        // randomly initialize cluster assignment
        let mut p = (0..K).map(|_| 1_f64 / (K as f64)).collect::<Vec<f64>>();
        let choices = random_choice().random_choice_f64(&labels, &p, D);
        for i in 0..D {
            let z = choices[i].clone();
            let ref doc = docs[i];
            d_z[i] = z;
            m_z[z] += 1;
            n_z[z] += doc.len() as u32;
            let ref mut clust_words: HashMap<String, u32> = n_z_w[z];
            for word in doc {
                if !clust_words.contains_key(word) {
                    clust_words.insert(word.clone(), 0_u32);
                }
                    * clust_words.get_mut(word).unwrap() += 1_u32;
            }
        }

        GSDMM {
            alpha: alpha,
            beta: beta,
            K: K,
            V: V,
            D: D,
            maxit:maxit,
            docs:docs,
            labels: d_z,
            cluster_counts: m_z,
            cluster_word_counts: n_z,
            cluster_word_distributions: n_z_w
        }
    }

    pub fn fit(&mut self) {
        let mut number_clusters = self.K;
        for it in 0..self.maxit {
            let mut total_transfers = 0;
            for i in 0..self.D {
                let ref doc = self.docs[i];
                let doc_size = doc.len() as u32;

                // remove the doc from its current cluster
                let z_old = self.labels[i];
                self.cluster_counts[z_old] -= 1;
                self.cluster_word_counts[z_old] -= doc_size;

                // modify the map: enclose it in a block so we can borrow views again.
                {
                    let ref mut old_clust_words: HashMap<String, u32> = self.cluster_word_distributions[z_old];
                    for word in doc {
                        *old_clust_words.get_mut(word).unwrap() -= 1_u32;

                        // compact dictionary once a key is exausted.
                        if old_clust_words[word] == 0_u32 {
                            old_clust_words.remove(word);
                        }
                    }
                }

                // update the probability vector
                let p = self.score(&doc);

                // choose the next cluster randomly according to the computed probability
                let z_new: usize = random_choice().random_choice_f64(&self.labels, &p, 1)[0].clone();

                // transfer document to the new cluster
                if z_new != z_old {
                    total_transfers += 1;
                }
                self.labels[i] = z_new;
                self.cluster_counts[z_new] += 1_u32;
                self.cluster_word_counts[z_new] += doc_size;

                {
                    let ref mut new_clust_words: HashMap<String, u32> = self.cluster_word_distributions[z_new];
                    for word in doc {
                        if !new_clust_words.contains_key(word) {
                            new_clust_words.insert(word.clone(), 0_u32);
                        }
                            * new_clust_words.get_mut(word).unwrap() += 1_u32;
                    }
                }
            }
            let new_number_clusters = self.cluster_word_distributions.iter().map(|c| if c.len()>0 {1} else {0} ).sum();
            println!("Iteration {}: {} docs transferred with {} clusters populated.", it, total_transfers, new_number_clusters);

            // apply ad-hoc convergence test
            if total_transfers==0 && new_number_clusters==number_clusters {
                println!("Converged after {} iterations. Solution has {} clusters.", it, new_number_clusters);
                break
            }
            number_clusters = new_number_clusters;
        }
    }

    fn score(&self, doc:&Vec<String>) -> Vec<f64> {
        let mut p = (0..self.K).map(|_| 0_f64).collect::<Vec<f64>>();
        let lD1 = ((self.D - 1) as f64 + (self.K as f64) * self.alpha).ln();
        let doc_size = doc.len() as u32;
        for label in 0_usize..self.K {
            let N1 = self.cluster_counts[label] as f64 + self.alpha;
            let lN1 = if N1 > 0_f64 { N1.ln() } else { 0_f64 };
            let mut lN2 = 0_f64;
            let mut lD2 = 0_f64;

            let ref cluster: HashMap<String, u32> = self.cluster_word_distributions[label];

            for word in doc {
                lN2 += (*cluster.get(word).unwrap_or(&0_u32) as f64 + self.beta).ln();
            }
            for j in 1_u32..(doc_size+1) {
                lD2 += ((self.cluster_word_counts[label] + j) as f64 - 1_f64 + self.V * self.beta).ln();
            }
            p[label] = (lN1 - lD1 + lN2 - lD2).exp();
        }
        let pnorm: f64 = p.iter().sum();
        for label in 0_usize..self.K {
            p[label] = p[label] / pnorm;
        }
        p
    }

    fn zero_vector(size:usize) -> Vec<u32>
    {
        let mut v = Vec::<u32>::with_capacity(size);
        for _ in 0_usize..size {
            v.push(0_u32)
        }
        v
    }
}

<|endoftext|>


<commit_before>macro_rules! swrite {
    (@one $writer:expr, ($e:expr)) => { write!($writer, "{}", $e) };
    (@one $writer:expr, [$e:expr]) => { write!($writer, "{:?}", $e) };
    (@one $writer:expr, {$e:tt : $($fmt:tt)*}) => {
        write!($writer, concat!("{:", stringify!($($fmt)*), "}"), $e)
    };
    (@one $writer:expr, {$($arg:tt)*}) => {
        write!($writer, $($arg)*)
    };
    (@one $writer:expr, $string:tt) => {
        write!($writer, "{}", { let s: &str = $string; s })
    };
    ($writer:expr, $($part:tt)*) => {
        (||{
            let mut _w = $writer;
            $(
                try!( swrite!(@one _w, $part) );
            )*
            let ret: ::std::fmt::Result = Ok(());
            ret
        })()
    };
    ($writer:expr) => { swrite!($writer,) };
}

macro_rules! swriteln {
    ($($arg:tt)*) => { swrite!($($arg)* "\n") }
}

macro_rules! sprint {
    ($($arg:tt)*) => { {
        let o = ::std::io::stdout();
        swrite!(o.lock(), $($arg)*).unwrap();
    } }
}

macro_rules! sprintln {
    ($($arg:tt)*) => { sprint!($($arg)* "\n") }
}

macro_rules! sformat {
    () => { String::new() };
    ($($arg:tt)*) => { {
        use ::std::fmt::Write;
        let mut _s = String::new(); // TODO with capacity
        swrite!(&mut _s, $($arg)*).ok();
        _s
    } }
}

#[test]
fn basics() {
    let world = "World";
    assert_eq!(sformat!("Hello, "(world)"!"), "Hello, World!");
    let x = 3;
    assert_eq!(sformat!((x)" * 2 = "(x * 2)), "3 * 2 = 6");
}

#[test]
fn empty() {
    assert_eq!(sformat!(), "");
}

#[test]
fn vec() {
    let v = vec![1,2,3];
    assert_eq!(sformat!([v]), "[1, 2, 3]");
}

#[test]
fn write() {
    use std::io::Write;
    let mut v = Vec::new();
    writeln!(&mut v, "hi!").unwrap();
    assert_eq!(v, "hi!\n".as_bytes());
}

#[test]
fn format() {
    assert_eq!( sformat!({5:02}), "05" );
    assert_eq!( sformat!({"{}-{}", 4, 2}), "4-2" );
}
<commit_msg>support both std::{io,fmt}::Write<commit_after>macro_rules! swrite {
    (@one $writer:expr, ($e:expr)) => { write!($writer, "{}", $e) };
    (@one $writer:expr, [$e:expr]) => { write!($writer, "{:?}", $e) };
    (@one $writer:expr, {$e:tt : $($fmt:tt)*}) => {
        write!($writer, concat!("{:", stringify!($($fmt)*), "}"), $e)
    };
    (@one $writer:expr, {$($arg:tt)*}) => {
        write!($writer, $($arg)*)
    };
    (@one $writer:expr, $string:tt) => {
        write!($writer, "{}", { let s: &str = $string; s })
    };
    ($writer:expr, $($part:tt)*) => {
        (||{
            let mut _w = $writer;
            $(
                match swrite!(@one _w, $part) {
                    Ok(()) => (),
                    error => return error,
                }
            )*
            Ok(())
        })()
    };
    ($writer:expr) => { swrite!($writer,) };
}

macro_rules! swriteln {
    ($($arg:tt)*) => { swrite!($($arg)* "\n") }
}

macro_rules! sprint {
    ($($arg:tt)*) => { {
        use ::std::io::Write;
        let o = ::std::io::stdout();
        swrite!(o.lock(), $($arg)*).unwrap();
    } }
}

macro_rules! sprintln {
    ($($arg:tt)*) => { sprint!($($arg)* "\n") }
}

macro_rules! sformat {
    () => { String::new() };
    ($($arg:tt)*) => { {
        use ::std::fmt::Write;
        let mut _s = String::new(); // TODO with capacity
        swrite!(&mut _s, $($arg)*).ok();
        _s
    } }
}

#[test]
fn basics() {
    let world = "World";
    assert_eq!(sformat!("Hello, "(world)"!"), "Hello, World!");
    let x = 3;
    assert_eq!(sformat!((x)" * 2 = "(x * 2)), "3 * 2 = 6");
}

#[test]
fn empty() {
    assert_eq!(sformat!(), "");
}

#[test]
fn vec() {
    let v = vec![1,2,3];
    assert_eq!(sformat!([v]), "[1, 2, 3]");
}

#[test]
fn write() {
    use std::io::Write;
    let mut v = Vec::new();
    swriteln!(&mut v, "hi" "!").unwrap();
    assert_eq!(v, "hi!\n".as_bytes());
}

#[test]
fn format() {
    assert_eq!( sformat!({5:02}), "05" );
    assert_eq!( sformat!({"{}-{}", 4, 2}), "4-2" );
}

#[test]
fn hello() {
    let foo = "foo";
    let x = 2;
    let y = 4;
    sprintln!("Bar "(foo)" and "(x));
    sprintln!( (x)"<"(y) );
}
<|endoftext|>


<commit_before>#![recursion_limit = "256"]

use serde::{Deserialize, Serialize};
use yew::services::storage::{Area, StorageService};
use yew::{html, Component, ComponentLink, Html, Renderable, ShouldRender};

type Ref = i32;

pub struct Model {
    file: File,
    store: StorageService,
    selected: Option<Ref>,
    cursor: Option<Cursor>,
}

#[derive(Debug)]
pub struct Cursor {
    node: Ref,
    offset: usize,
}

impl Model {
    fn lookup(&self, reference: Ref) -> Option<&Node> {
        self.file.lookup(reference)
    }
    fn lookup_mut(&mut self, reference: Ref) -> Option<&mut Node> {
        self.file.lookup_mut(reference)
    }

    fn selected_node(&self) -> Option<&Node> {
        self.selected.and_then(|reference| self.lookup(reference))
    }
}

#[derive(Clone)]
pub enum Msg {
    Select(Ref),
    Rename(Ref, String),

    Store,
    Load,

    AddArgument,
    NewFn,

    SetValue(Value),
}

#[derive(Serialize, Deserialize)]
struct File {
    bindings: Vec<Ref>,
    nodes: Vec<Node>,
    next_reference: Ref,
}

impl File {
    fn lookup(&self, reference: Ref) -> Option<&Node> {
        self.nodes
            .iter()
            .filter(|v| v.reference == reference)
            .next()
    }

    fn lookup_mut(&mut self, reference: Ref) -> Option<&mut Node> {
        self.nodes
            .iter_mut()
            .filter(|v| v.reference == reference)
            .next()
    }

    fn add_node(&mut self, value: Value) -> Ref {
        let reference = self.next_reference();
        let node = Node {
            reference: reference,
            value: value,
        };
        self.nodes.push(node);
        reference
    }

    fn next_reference(&mut self) -> Ref {
        let reference = self.next_reference;
        self.next_reference += 1;
        reference
    }
}

#[derive(Serialize, Deserialize)]
struct Node {
    reference: Ref,
    value: Value,
}

const ERROR_NODE: Node = Node {
    reference: 1111111111,
    value: Value::Hole,
};

#[derive(Serialize, Deserialize, Clone)]
pub enum Value {
    Hole,

    Bool(bool),
    Int(i32),
    Float(f32),
    String(String),

    Ref(Ref),
    Binding(BindingValue),
    Pattern(PatternValue),

    Block(BlockValue),
    List(ListValue),
    If(IfValue),
    FunctionDefinition(FunctionDefinitionValue),
    FunctionCall(FunctionCallValue),
    BinaryOperator(BinaryOperatorValue),
}

impl Node {
    fn label(&self) -> Option<&Label> {
        match &self.value {
            Value::Binding(ref v) => Some(&v.label),
            Value::Pattern(ref v) => Some(&v.label),
            Value::FunctionDefinition(ref v) => Some(&v.label),
            _ => None,
        }
    }
    fn rename(&mut self, name: String) {
        match &mut self.value {
            Value::Binding(ref mut v) => v.label.name = name,
            Value::Pattern(ref mut v) => v.label.name = name,
            Value::FunctionDefinition(ref mut v) => v.label.name = name,
            _ => {}
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub struct BindingValue {
    label: Label,
    value: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct PatternValue {
    label: Label,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct BlockValue {
    expressions: Vec<Ref>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct ListValue {
    items: Vec<Ref>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct IfValue {
    conditional: Ref,
    true_body: Ref,
    false_body: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct FunctionDefinitionValue {
    label: Label,
    arguments: Vec<Ref>,
    body: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct FunctionCallValue {
    function: Ref,
    arguments: Vec<Ref>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct BinaryOperatorValue {
    operator: String,
    left: Ref,
    right: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct Pattern {
    label: Label,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct Label {
    name: String,
    colour: String,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
        Model {
            store: StorageService::new(Area::Local),
            file: File {
                next_reference: 1000,
                nodes: vec![
                    Node {
                        reference: 111,
                        value: Value::FunctionDefinition(FunctionDefinitionValue {
                            label: Label {
                                name: "main".to_string(),
                                colour: "red".to_string(),
                            },
                            arguments: vec![],
                            body: 123,
                        }),
                    },
                    Node {
                        reference: 124,
                        value: Value::Int(123),
                    },
                    Node {
                        reference: 12,
                        value: Value::FunctionDefinition(FunctionDefinitionValue {
                            label: Label {
                                name: "factorial".to_string(),
                                colour: "red".to_string(),
                            },
                            arguments: vec![222],
                            body: 228,
                        }),
                    },
                    Node {
                        reference: 222,
                        value: Value::Pattern(PatternValue {
                            label: Label {
                                name: "x".to_string(),
                                colour: "".to_string(),
                            },
                        }),
                    },
                    Node {
                        reference: 228,
                        value: Value::BinaryOperator(BinaryOperatorValue {
                            operator: "*".to_string(),
                            left: 1231,
                            right: 1232,
                        }),
                    },
                    Node {
                        reference: 1231,
                        value: Value::Ref(222),
                    },
                    Node {
                        reference: 1232,
                        value: Value::FunctionCall(FunctionCallValue {
                            function: 12,
                            arguments: vec![229],
                        }),
                    },
                    Node {
                        reference: 229,
                        value: Value::BinaryOperator(BinaryOperatorValue {
                            operator: "-".to_string(),
                            left: 230,
                            right: 231,
                        }),
                    },
                    Node {
                        reference: 230,
                        value: Value::Ref(222),
                    },
                    Node {
                        reference: 231,
                        value: Value::Int(1),
                    },
                ],
                bindings: vec![111, 12],
            },
            selected: None,
            cursor: None,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        const KEY: &str = "linc_file";
        match msg {
            Msg::Select(reference) => {
                self.selected = Some(reference);
            }
            Msg::Rename(reference, name) => {
                if let Some(node) = self.lookup_mut(reference) {
                    node.rename(name);
                }
            }

            Msg::Store => {
                self.store.store(KEY, yew::format::Json(&self.file));
            }
            Msg::Load => {
                if let yew::format::Json(Ok(file)) = self.store.restore(KEY) {
                    self.file = file;
                }
            }

            Msg::AddArgument => {
                let reference = self.file.add_node(Value::Pattern(PatternValue {
                    label: Label {
                        name: "xxx".to_string(),
                        colour: "red".to_string(),
                    },
                }));
                if let Some(node) = self
                    .selected
                    .and_then(|reference| self.lookup_mut(reference))
                {
                    if let Value::FunctionDefinition(ref mut v) = node.value {
                        v.arguments.push(reference);
                    }
                }
            }
            Msg::NewFn => {
                let reference =
                    self.file
                        .add_node(Value::FunctionDefinition(FunctionDefinitionValue {
                            label: Label {
                                name: "xxx".to_string(),
                                colour: "red".to_string(),
                            },
                            arguments: vec![],
                            body: 11111,
                        }));
                self.file.bindings.push(reference);
            }

            Msg::SetValue(v) => {}
        };
        true
    }
}

impl Renderable<Model> for Model {
    fn view(&self) -> Html<Self> {
        let selected_node = self
            .selected
            .and_then(|reference| self.lookup(reference))
            .unwrap_or(&ERROR_NODE);
        let serialized_node =
            serde_json::to_string_pretty(selected_node).expect("could not serialize to JSON");
        html! {

{ "LINC" }

{ self.view_actions() }

{ self.view_file(&self.file) }

{ self.view_file_json(&self.file) }

{ format!("Cursor: {:?}", self.cursor) }

{ format!("Selected: {:?}", self.selected) }

{ serialized_node }

        }
    }
}

struct Action {
    text: String,
    msg: Msg,
}

impl Model {
    fn view_actions(&self) -> Html<Model> {
        let actions = vec![
            Action {
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                text: "+arg".to_string(),
                msg: Msg::AddArgument,
            },
            Action {
                text: "+fn".to_string(),
                msg: Msg::NewFn,
            },
            Action {
                text: "Int".to_string(),
                msg: Msg::SetValue(Value::Int(0)),
            },
        ];
        let mut actions = actions.iter().map(|a| self.view_action(a));
        html! {

            { for actions }

        }
    }

    fn view_action(&self, action: &Action) -> Html<Model> {
        let m = action.msg.clone();
        html! {

            { &action.text }

        }
    }

    fn view_file(&self, file: &File) -> Html<Model> {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ for file.bindings.iter().map(|v| self.view_binding(*v)) }

        }
    }

    fn view_file_json(&self, file: &File) -> Html<Model> {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ serialized }

        }
    }

    fn view_label(&self, label: &Label, reference: Ref) -> Html<Model> {
        html! {
            <input oninput=|e| Msg::Rename(reference, e.value)
                type="text"
                value=label.name/>
        }
    }

    fn view_binding(&self, reference: Ref) -> Html<Model> {
        let node = self.lookup(reference).unwrap_or(&ERROR_NODE);
        html! {

{ self.view_node(node) }

        }
    }

    fn view_node(&self, node: &Node) -> Html<Model> {
        let reference = node.reference;
        let selected = match self.selected {
            None => false,
            Some(selected_reference) => selected_reference == reference,
        };
        let target = match self.selected_node() {
            None => false,
            Some(n) => {
                if let Value::Ref(target_reference) = n.value {
                    target_reference == reference
                } else {
                    false
                }
            }
        };
        // TODO: Use Vec.
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        if target {
            classes.push("target".to_string());
        }
        html! {

                { self.view_value(&node.value, reference) }

        }
    }

    fn view_value(&self, value: &Value, reference: Ref) -> Html<Model> {
        match value {
            Value::Hole => {
                html! { { "@" } }
            }
            Value::Bool(v) => {
                let v = if *v { "true" } else { "false" };
                html! { { v } }
            }
            Value::Int(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::Float(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::String(v) => {
                html! { { v } }
            }
            Value::Ref(reference) => {
                let node = self.lookup(*reference);
                let text = node
                    .and_then(|n| n.label())
                    .map(|l| l.name.clone())
                    .unwrap_or("<UNKNOWN>".to_string());
                html! { { text } }
            }
            Value::Binding(v) => {
                let label = self.view_label(&v.label, reference);
                let value = self.lookup(v.value).unwrap_or(&ERROR_NODE);
                html! {

                    { label }{ "=" }{ self.view_node(value) }

                }
            }
            Value::Pattern(v) => {
                html! {

                    { self.view_label(&v.label, reference) }

                }
            }
            Value::Block(_) => {
                html! { { "xxx" } }
            }
            Value::List(_) => {
                html! { { "xxx" } }
            }
            Value::If(_) => {
                html! { { "xxx" } }
            }
            Value::FunctionDefinition(v) => {
                let label = self.view_label(&v.label, reference);
                let mut args = v
                    .arguments
                    .iter()
                    // TODO: We should not filter out invalid nodes.
                    .filter_map(|r| self.lookup(*r))
                    .map(|n| self.view_node(n));
                let body = self.lookup(v.body).unwrap_or(&ERROR_NODE);
                html! {

                    { "fn" }{ label }
                    { "(" }{ for args }{ ")" }
                    { self.view_node(body) }

                }
            }
            Value::FunctionCall(v) => {
                let node = self.file.lookup(v.function);
                let function_name = node
                    .and_then(|n| n.label())
                    .map(|l| l.name.clone())
                    .unwrap_or("<UNKNOWN>".to_string());
                let mut args = v
                    .arguments
                    .iter()
                    // TODO: We should not filter out invalid nodes.
                    .filter_map(|r| self.lookup(*r))
                    .map(|n| self.view_node(n));
                html! {

                    { function_name }
                    { "(" }{ for args }{ ")" }

                }
            }
            Value::BinaryOperator(v) => {
                let left = self.lookup(v.left).unwrap_or(&ERROR_NODE);
                let right = self.lookup(v.right).unwrap_or(&ERROR_NODE);
                html! {

                    { self.view_node(left) }
                    { &v.operator }
                    { self.view_node(right) }

                }
            }
        }
    }
}
<commit_msg>Actions<commit_after>#![recursion_limit = "256"]

use serde::{Deserialize, Serialize};
use yew::services::storage::{Area, StorageService};
use yew::{html, Component, ComponentLink, Html, Renderable, ShouldRender};

type Ref = i32;

pub struct Model {
    file: File,
    store: StorageService,
    selected: Option<Ref>,
    cursor: Option<Cursor>,
}

#[derive(Debug)]
pub struct Cursor {
    node: Ref,
    offset: usize,
}

impl Model {
    fn lookup(&self, reference: Ref) -> Option<&Node> {
        self.file.lookup(reference)
    }
    fn lookup_mut(&mut self, reference: Ref) -> Option<&mut Node> {
        self.file.lookup_mut(reference)
    }

    fn selected_node(&self) -> Option<&Node> {
        self.selected.and_then(|reference| self.lookup(reference))
    }
}

#[derive(Clone)]
pub enum Msg {
    Select(Ref),
    Rename(Ref, String),

    Store,
    Load,

    AddArgument,
    NewFn,

    SetValue(Value),
}

#[derive(Serialize, Deserialize)]
struct File {
    bindings: Vec<Ref>,
    nodes: Vec<Node>,
    next_reference: Ref,
}

impl File {
    fn lookup(&self, reference: Ref) -> Option<&Node> {
        self.nodes
            .iter()
            .filter(|v| v.reference == reference)
            .next()
    }

    fn lookup_mut(&mut self, reference: Ref) -> Option<&mut Node> {
        self.nodes
            .iter_mut()
            .filter(|v| v.reference == reference)
            .next()
    }

    fn add_node(&mut self, value: Value) -> Ref {
        let reference = self.next_reference();
        let node = Node {
            reference: reference,
            value: value,
        };
        self.nodes.push(node);
        reference
    }

    fn next_reference(&mut self) -> Ref {
        let reference = self.next_reference;
        self.next_reference += 1;
        reference
    }
}

#[derive(Serialize, Deserialize)]
struct Node {
    reference: Ref,
    value: Value,
}

const ERROR_NODE: Node = Node {
    reference: 1111111111,
    value: Value::Hole,
};

#[derive(Serialize, Deserialize, Clone)]
pub enum Value {
    Hole,

    Bool(bool),
    Int(i32),
    Float(f32),
    String(String),

    Ref(Ref),
    Binding(BindingValue),
    Pattern(PatternValue),

    Block(BlockValue),
    List(ListValue),
    If(IfValue),
    FunctionDefinition(FunctionDefinitionValue),
    FunctionCall(FunctionCallValue),
    BinaryOperator(BinaryOperatorValue),
}

impl Node {
    fn label(&self) -> Option<&Label> {
        match &self.value {
            Value::Binding(ref v) => Some(&v.label),
            Value::Pattern(ref v) => Some(&v.label),
            Value::FunctionDefinition(ref v) => Some(&v.label),
            _ => None,
        }
    }
    fn rename(&mut self, name: String) {
        match &mut self.value {
            Value::Binding(ref mut v) => v.label.name = name,
            Value::Pattern(ref mut v) => v.label.name = name,
            Value::FunctionDefinition(ref mut v) => v.label.name = name,
            _ => {}
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub struct BindingValue {
    label: Label,
    value: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct PatternValue {
    label: Label,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct BlockValue {
    expressions: Vec<Ref>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct ListValue {
    items: Vec<Ref>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct IfValue {
    conditional: Ref,
    true_body: Ref,
    false_body: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct FunctionDefinitionValue {
    label: Label,
    arguments: Vec<Ref>,
    body: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct FunctionCallValue {
    function: Ref,
    arguments: Vec<Ref>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct BinaryOperatorValue {
    operator: String,
    left: Ref,
    right: Ref,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct Pattern {
    label: Label,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct Label {
    name: String,
    colour: String,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
        Model {
            store: StorageService::new(Area::Local),
            file: File {
                next_reference: 1000,
                nodes: vec![
                    Node {
                        reference: 111,
                        value: Value::FunctionDefinition(FunctionDefinitionValue {
                            label: Label {
                                name: "main".to_string(),
                                colour: "red".to_string(),
                            },
                            arguments: vec![],
                            body: 123,
                        }),
                    },
                    Node {
                        reference: 124,
                        value: Value::Int(123),
                    },
                    Node {
                        reference: 12,
                        value: Value::FunctionDefinition(FunctionDefinitionValue {
                            label: Label {
                                name: "factorial".to_string(),
                                colour: "red".to_string(),
                            },
                            arguments: vec![222],
                            body: 228,
                        }),
                    },
                    Node {
                        reference: 222,
                        value: Value::Pattern(PatternValue {
                            label: Label {
                                name: "x".to_string(),
                                colour: "".to_string(),
                            },
                        }),
                    },
                    Node {
                        reference: 228,
                        value: Value::BinaryOperator(BinaryOperatorValue {
                            operator: "*".to_string(),
                            left: 1231,
                            right: 1232,
                        }),
                    },
                    Node {
                        reference: 1231,
                        value: Value::Ref(222),
                    },
                    Node {
                        reference: 1232,
                        value: Value::FunctionCall(FunctionCallValue {
                            function: 12,
                            arguments: vec![229],
                        }),
                    },
                    Node {
                        reference: 229,
                        value: Value::BinaryOperator(BinaryOperatorValue {
                            operator: "-".to_string(),
                            left: 230,
                            right: 231,
                        }),
                    },
                    Node {
                        reference: 230,
                        value: Value::Ref(222),
                    },
                    Node {
                        reference: 231,
                        value: Value::Int(1),
                    },
                ],
                bindings: vec![111, 12],
            },
            selected: None,
            cursor: None,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        const KEY: &str = "linc_file";
        match msg {
            Msg::Select(reference) => {
                self.selected = Some(reference);
            }
            Msg::Rename(reference, name) => {
                if let Some(node) = self.lookup_mut(reference) {
                    node.rename(name);
                }
            }

            Msg::Store => {
                self.store.store(KEY, yew::format::Json(&self.file));
            }
            Msg::Load => {
                if let yew::format::Json(Ok(file)) = self.store.restore(KEY) {
                    self.file = file;
                }
            }

            Msg::AddArgument => {
                let reference = self.file.add_node(Value::Pattern(PatternValue {
                    label: Label {
                        name: "xxx".to_string(),
                        colour: "red".to_string(),
                    },
                }));
                if let Some(node) = self
                    .selected
                    .and_then(|reference| self.lookup_mut(reference))
                {
                    if let Value::FunctionDefinition(ref mut v) = node.value {
                        v.arguments.push(reference);
                    }
                }
            }
            Msg::NewFn => {
                let reference =
                    self.file
                        .add_node(Value::FunctionDefinition(FunctionDefinitionValue {
                            label: Label {
                                name: "xxx".to_string(),
                                colour: "red".to_string(),
                            },
                            arguments: vec![],
                            body: 11111,
                        }));
                self.file.bindings.push(reference);
            }

            Msg::SetValue(v) => {}
        };
        true
    }
}

impl Renderable<Model> for Model {
    fn view(&self) -> Html<Self> {
        let selected_node = self
            .selected
            .and_then(|reference| self.lookup(reference))
            .unwrap_or(&ERROR_NODE);
        let serialized_node =
            serde_json::to_string_pretty(selected_node).expect("could not serialize to JSON");
        html! {

{ "LINC" }

{ self.view_actions() }

{ self.view_file(&self.file) }

{ self.view_file_json(&self.file) }

{ format!("Cursor: {:?}", self.cursor) }

{ format!("Selected: {:?}", self.selected) }

{ serialized_node }

        }
    }
}

struct Action {
    text: String,
    msg: Msg,
}

impl Model {
    fn view_actions(&self) -> Html<Model> {
        let actions = vec![
            Action {
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                text: "+arg".to_string(),
                msg: Msg::AddArgument,
            },
            Action {
                text: "+fn".to_string(),
                msg: Msg::NewFn,
            },
            Action {
                text: "{}".to_string(),
                msg: Msg::SetValue(Value::Block(BlockValue {
                    expressions: vec![],
                })),
            },
            Action {
                text: "{☆}".to_string(),
                msg: Msg::SetValue(Value::Block(BlockValue {
                    expressions: vec![],
                })),
            },
            Action {
                text: "[]".to_string(),
                msg: Msg::SetValue(Value::List(ListValue { items: vec![] })),
            },
            Action {
                text: "[☆]".to_string(),
                msg: Msg::SetValue(Value::List(ListValue { items: vec![] })),
            },
            Action {
                text: "If (◆) then ◆".to_string(),
                msg: Msg::SetValue(Value::If(IfValue {
                    conditional: -1,
                    true_body: -1,
                    false_body: -1,
                })),
            },
            Action {
                text: "If (☆) then ◆".to_string(),
                msg: Msg::SetValue(Value::If(IfValue {
                    conditional: -1,
                    true_body: -1,
                    false_body: -1,
                })),
            },
            Action {
                text: "If (◆) then ☆".to_string(),
                msg: Msg::SetValue(Value::If(IfValue {
                    conditional: -1,
                    true_body: -1,
                    false_body: -1,
                })),
            },
            Action {
                text: "Int".to_string(),
                msg: Msg::SetValue(Value::Int(0)),
            },
        ];
        let mut actions = actions.iter().map(|a| self.view_action(a));
        html! {

            { for actions }

        }
    }

    fn view_action(&self, action: &Action) -> Html<Model> {
        let m = action.msg.clone();
        html! {

            { &action.text }

        }
    }

    fn view_file(&self, file: &File) -> Html<Model> {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ for file.bindings.iter().map(|v| self.view_binding(*v)) }

        }
    }

    fn view_file_json(&self, file: &File) -> Html<Model> {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ serialized }

        }
    }

    fn view_label(&self, label: &Label, reference: Ref) -> Html<Model> {
        html! {
            <input oninput=|e| Msg::Rename(reference, e.value)
                type="text"
                value=label.name/>
        }
    }

    fn view_binding(&self, reference: Ref) -> Html<Model> {
        let node = self.lookup(reference).unwrap_or(&ERROR_NODE);
        html! {

{ self.view_node(node) }

        }
    }

    fn view_node(&self, node: &Node) -> Html<Model> {
        let reference = node.reference;
        let selected = match self.selected {
            None => false,
            Some(selected_reference) => selected_reference == reference,
        };
        let target = match self.selected_node() {
            None => false,
            Some(n) => {
                if let Value::Ref(target_reference) = n.value {
                    target_reference == reference
                } else {
                    false
                }
            }
        };
        // TODO: Use Vec.
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        if target {
            classes.push("target".to_string());
        }
        html! {

                { self.view_value(&node.value, reference) }

        }
    }

    fn view_value(&self, value: &Value, reference: Ref) -> Html<Model> {
        match value {
            Value::Hole => {
                html! { { "@" } }
            }
            Value::Bool(v) => {
                let v = if *v { "true" } else { "false" };
                html! { { v } }
            }
            Value::Int(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::Float(v) => {
                let v = format!("{}", v);
                html! { { v } }
            }
            Value::String(v) => {
                html! { { v } }
            }
            Value::Ref(reference) => {
                let node = self.lookup(*reference);
                let text = node
                    .and_then(|n| n.label())
                    .map(|l| l.name.clone())
                    .unwrap_or("<UNKNOWN>".to_string());
                html! { { text } }
            }
            Value::Binding(v) => {
                let label = self.view_label(&v.label, reference);
                let value = self.lookup(v.value).unwrap_or(&ERROR_NODE);
                html! {

                    { label }{ "=" }{ self.view_node(value) }

                }
            }
            Value::Pattern(v) => {
                html! {

                    { self.view_label(&v.label, reference) }

                }
            }
            Value::Block(_) => {
                html! { { "xxx" } }
            }
            Value::List(_) => {
                html! { { "xxx" } }
            }
            Value::If(_) => {
                html! { { "xxx" } }
            }
            Value::FunctionDefinition(v) => {
                let label = self.view_label(&v.label, reference);
                let mut args = v
                    .arguments
                    .iter()
                    // TODO: We should not filter out invalid nodes.
                    .filter_map(|r| self.lookup(*r))
                    .map(|n| self.view_node(n));
                let body = self.lookup(v.body).unwrap_or(&ERROR_NODE);
                html! {

                    { "fn" }{ label }
                    { "(" }{ for args }{ ")" }
                    { self.view_node(body) }

                }
            }
            Value::FunctionCall(v) => {
                let node = self.file.lookup(v.function);
                let function_name = node
                    .and_then(|n| n.label())
                    .map(|l| l.name.clone())
                    .unwrap_or("<UNKNOWN>".to_string());
                let mut args = v
                    .arguments
                    .iter()
                    // TODO: We should not filter out invalid nodes.
                    .filter_map(|r| self.lookup(*r))
                    .map(|n| self.view_node(n));
                html! {

                    { function_name }
                    { "(" }{ for args }{ ")" }

                }
            }
            Value::BinaryOperator(v) => {
                let left = self.lookup(v.left).unwrap_or(&ERROR_NODE);
                let right = self.lookup(v.right).unwrap_or(&ERROR_NODE);
                html! {

                    { self.view_node(left) }
                    { &v.operator }
                    { self.view_node(right) }

                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Serenity is a Rust library for the Discord API.
//!
//! View the [examples] on how to make and structure a bot.
//!
//! Serenity supports bot user authentication via the use of [`Client::new`].
//!
//! Once logged in, you may add handlers to your client to dispatch [`Event`]s,
//! such as [`Client::on_message`]. This will cause your handler to be called
//! when a [`Event::MessageCreate`] is received. Each handler is given a
//! [`Context`], giving information about the event. See the
//! [client's module-level documentation].
//!
//! The [`Shard`] is transparently handled by the library, removing
//! unnecessary complexity. Sharded connections are automatically handled for
//! you. See the [gateway's documentation][gateway docs] for more information.
//!
//! A [`Cache`] is also provided for you. This will be updated automatically for
//! you as data is received from the Discord API via events. When calling a
//! method on a [`Context`], the cache will first be searched for relevant data
//! to avoid unnecessary HTTP requests to the Discord API. For more information,
//! see the [cache's module-level documentation][cache docs].
//!
//! Note that, although this documentation will try to be as up-to-date and
//! accurate as possible, Discord hosts [official documentation][docs]. If you
//! need to be sure that some information piece is sanctioned by Discord, refer
//! to their own documentation.
//!
//! # Example Bot
//!
//! A basic ping-pong bot looks like:
//!
//! ```rust,ignore
//! #[macro_use] extern crate serenity;
//!
//! use serenity::client::Client;
//! use serenity::framework::standard::StandardFramework;
//! use std::env;
//!
//! fn main() {
//!     // Login with a bot token from the environment
//!     let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token"));
//!     client.with_framework(StandardFramework::new()
//!         .configure(|c| c.prefix("~")) // set the bot's prefix to "~"
//!         .on("ping", ping));
//!
//!     // start listening for events by starting a single shard
//!     let _ = client.start();
//! }
//!
//! command!(ping(_context, message) {
//!     let _ = message.reply("Pong!");
//! });
//! ```
//!
//! ### Full Examples
//!
//! Full examples, detailing and explaining usage of the basic functionality of the
//! library, can be found in the [`examples`] directory.
//!
//! # Installation
//!
//! Add the following to your `Cargo.toml` file:
//!
//! ```toml
//! [dependencies]
//! serenity = "0.4"
//! ```
//!
//! and to the top of your `main.rs`:
//!
//! ```rs
//! #[macro_use] extern crate serenity;
//! ```
//!
//! [`Cache`]: cache/struct.Cache.html
//! [`Client::new`]: client/struct.Client.html#method.new
//! [`Client::on_message`]: client/struct.Client.html#method.on_message
//! [`Context`]: client/struct.Context.html
//! [`Event`]: model/event/enum.Event.html
//! [`Event::MessageCreate`]: model/event/enum.Event.html#variant.MessageCreate
//! [`Shard`]: gateway/struct.Shard.html
//! [`examples`]: https://github.com/zeyla/serenity/blob/master/examples
//! [cache docs]: cache/index.html
//! [client's module-level documentation]: client/index.html
//! [docs]: https://discordapp.com/developers/docs/intro
//! [examples]: https://github.com/zeyla/serenity/tree/master/examples
//! [gateway docs]: gateway/index.html
#![doc(html_root_url = "https://docs.rs/serenity/*")]
#![allow(unknown_lints)]
#![allow(doc_markdown, inline_always)]
#![warn(enum_glob_use, if_not_else)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

#[cfg(feature = "lazy_static")]
#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate serde;

#[cfg(feature = "utils")]
extern crate base64;
#[cfg(feature = "voice")]
extern crate byteorder;
#[cfg(feature = "gateway")]
extern crate flate2;
#[cfg(feature = "hyper")]
extern crate hyper;
#[cfg(feature = "hyper-native-tls")]
extern crate hyper_native_tls;
#[cfg(feature = "http")]
extern crate multipart;
#[cfg(feature = "native-tls")]
extern crate native_tls;
#[cfg(feature = "voice")]
extern crate opus;
#[cfg(feature = "client")]
extern crate parking_lot;
#[cfg(feature = "voice")]
extern crate sodiumoxide;
#[cfg(feature = "threadpool")]
extern crate threadpool;
#[cfg(feature = "client")]
extern crate typemap;
#[cfg(feature = "standard_framework")]
extern crate vec_shift;
#[cfg(feature = "gateway")]
extern crate evzht9h3nznqzwl as websocket;

#[macro_use]
mod internal;

pub mod constants;
pub mod model;
pub mod prelude;

#[cfg(feature = "builder")]
pub mod builder;
#[cfg(feature = "cache")]
pub mod cache;
#[cfg(feature = "client")]
pub mod client;
#[cfg(feature = "framework")]
pub mod framework;
#[cfg(feature = "gateway")]
pub mod gateway;
#[cfg(feature = "http")]
pub mod http;
#[cfg(feature = "utils")]
pub mod utils;
#[cfg(feature = "voice")]
pub mod voice;

mod error;

pub use error::{Error, Result};

#[cfg(feature = "client")]
pub use client::Client;

#[cfg(feature = "cache")]
use cache::Cache;
#[cfg(feature = "cache")]
use std::sync::RwLock;

#[cfg(feature = "cache")]
lazy_static! {
    /// A mutable and lazily-initialized static binding. It can be accessed
    /// across any function and in any context.
    ///
    /// This [`Cache`] instance is updated for every event received, so you do
    /// not need to maintain your own cache.
    ///
    /// See the [cache module documentation] for more details.
    ///
    /// The Cache itself is wrapped within an `RwLock`, which allows for
    /// multiple readers or at most one writer at a time across threads. This
    /// means that you may have multiple commands reading from the Cache
    /// concurrently.
    ///
    /// # Examples
    ///
    /// Retrieve the [current user][`CurrentUser`]'s Id, by opening a Read
    /// guard:
    ///
    /// ```rust,ignore
    /// use serenity::CACHE;
    ///
    /// println!("{}", CACHE.read().unwrap().user.id);
    /// ```
    ///
    /// By `unwrap()`ing, the thread managing an event dispatch will be blocked
    /// until the guard can be opened.
    ///
    /// If you do not want to block the current thread, you may instead use
    /// `RwLock::try_read`. Refer to `RwLock`'s documentation in the stdlib for
    /// more information.
    ///
    /// [`CurrentUser`]: model/struct.CurrentUser.html
    /// [`Cache`]: cache/struct.Cache.html
    /// [cache module documentation]: cache/index.html
    pub static ref CACHE: RwLock<Cache> = RwLock::new(Cache::default());
}
<commit_msg>Feature-flag extern crates behind their name<commit_after>//! Serenity is a Rust library for the Discord API.
//!
//! View the [examples] on how to make and structure a bot.
//!
//! Serenity supports bot user authentication via the use of [`Client::new`].
//!
//! Once logged in, you may add handlers to your client to dispatch [`Event`]s,
//! such as [`Client::on_message`]. This will cause your handler to be called
//! when a [`Event::MessageCreate`] is received. Each handler is given a
//! [`Context`], giving information about the event. See the
//! [client's module-level documentation].
//!
//! The [`Shard`] is transparently handled by the library, removing
//! unnecessary complexity. Sharded connections are automatically handled for
//! you. See the [gateway's documentation][gateway docs] for more information.
//!
//! A [`Cache`] is also provided for you. This will be updated automatically for
//! you as data is received from the Discord API via events. When calling a
//! method on a [`Context`], the cache will first be searched for relevant data
//! to avoid unnecessary HTTP requests to the Discord API. For more information,
//! see the [cache's module-level documentation][cache docs].
//!
//! Note that, although this documentation will try to be as up-to-date and
//! accurate as possible, Discord hosts [official documentation][docs]. If you
//! need to be sure that some information piece is sanctioned by Discord, refer
//! to their own documentation.
//!
//! # Example Bot
//!
//! A basic ping-pong bot looks like:
//!
//! ```rust,ignore
//! #[macro_use] extern crate serenity;
//!
//! use serenity::client::Client;
//! use serenity::framework::standard::StandardFramework;
//! use std::env;
//!
//! fn main() {
//!     // Login with a bot token from the environment
//!     let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token"));
//!     client.with_framework(StandardFramework::new()
//!         .configure(|c| c.prefix("~")) // set the bot's prefix to "~"
//!         .on("ping", ping));
//!
//!     // start listening for events by starting a single shard
//!     let _ = client.start();
//! }
//!
//! command!(ping(_context, message) {
//!     let _ = message.reply("Pong!");
//! });
//! ```
//!
//! ### Full Examples
//!
//! Full examples, detailing and explaining usage of the basic functionality of the
//! library, can be found in the [`examples`] directory.
//!
//! # Installation
//!
//! Add the following to your `Cargo.toml` file:
//!
//! ```toml
//! [dependencies]
//! serenity = "0.4"
//! ```
//!
//! and to the top of your `main.rs`:
//!
//! ```rs
//! #[macro_use] extern crate serenity;
//! ```
//!
//! [`Cache`]: cache/struct.Cache.html
//! [`Client::new`]: client/struct.Client.html#method.new
//! [`Client::on_message`]: client/struct.Client.html#method.on_message
//! [`Context`]: client/struct.Context.html
//! [`Event`]: model/event/enum.Event.html
//! [`Event::MessageCreate`]: model/event/enum.Event.html#variant.MessageCreate
//! [`Shard`]: gateway/struct.Shard.html
//! [`examples`]: https://github.com/zeyla/serenity/blob/master/examples
//! [cache docs]: cache/index.html
//! [client's module-level documentation]: client/index.html
//! [docs]: https://discordapp.com/developers/docs/intro
//! [examples]: https://github.com/zeyla/serenity/tree/master/examples
//! [gateway docs]: gateway/index.html
#![doc(html_root_url = "https://docs.rs/serenity/*")]
#![allow(unknown_lints)]
#![allow(doc_markdown, inline_always)]
#![warn(enum_glob_use, if_not_else)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

#[cfg(feature = "lazy_static")]
#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate serde;

#[cfg(feature = "base64")]
extern crate base64;
#[cfg(feature = "byteorder")]
extern crate byteorder;
#[cfg(feature = "flate2")]
extern crate flate2;
#[cfg(feature = "hyper")]
extern crate hyper;
#[cfg(feature = "hyper-native-tls")]
extern crate hyper_native_tls;
#[cfg(feature = "multipart")]
extern crate multipart;
#[cfg(feature = "native-tls")]
extern crate native_tls;
#[cfg(feature = "opus")]
extern crate opus;
#[cfg(feature = "parking_lot")]
extern crate parking_lot;
#[cfg(feature = "sodiumoxide")]
extern crate sodiumoxide;
#[cfg(feature = "threadpool")]
extern crate threadpool;
#[cfg(feature = "typemap")]
extern crate typemap;
#[cfg(feature = "vec_shift")]
extern crate vec_shift;
#[cfg(feature = "evzht9h3nznqzwl")]
extern crate evzht9h3nznqzwl as websocket;

#[macro_use]
mod internal;

pub mod constants;
pub mod model;
pub mod prelude;

#[cfg(feature = "builder")]
pub mod builder;
#[cfg(feature = "cache")]
pub mod cache;
#[cfg(feature = "client")]
pub mod client;
#[cfg(feature = "framework")]
pub mod framework;
#[cfg(feature = "gateway")]
pub mod gateway;
#[cfg(feature = "http")]
pub mod http;
#[cfg(feature = "utils")]
pub mod utils;
#[cfg(feature = "voice")]
pub mod voice;

mod error;

pub use error::{Error, Result};

#[cfg(feature = "client")]
pub use client::Client;

#[cfg(feature = "cache")]
use cache::Cache;
#[cfg(feature = "cache")]
use std::sync::RwLock;

#[cfg(feature = "cache")]
lazy_static! {
    /// A mutable and lazily-initialized static binding. It can be accessed
    /// across any function and in any context.
    ///
    /// This [`Cache`] instance is updated for every event received, so you do
    /// not need to maintain your own cache.
    ///
    /// See the [cache module documentation] for more details.
    ///
    /// The Cache itself is wrapped within an `RwLock`, which allows for
    /// multiple readers or at most one writer at a time across threads. This
    /// means that you may have multiple commands reading from the Cache
    /// concurrently.
    ///
    /// # Examples
    ///
    /// Retrieve the [current user][`CurrentUser`]'s Id, by opening a Read
    /// guard:
    ///
    /// ```rust,ignore
    /// use serenity::CACHE;
    ///
    /// println!("{}", CACHE.read().unwrap().user.id);
    /// ```
    ///
    /// By `unwrap()`ing, the thread managing an event dispatch will be blocked
    /// until the guard can be opened.
    ///
    /// If you do not want to block the current thread, you may instead use
    /// `RwLock::try_read`. Refer to `RwLock`'s documentation in the stdlib for
    /// more information.
    ///
    /// [`CurrentUser`]: model/struct.CurrentUser.html
    /// [`Cache`]: cache/struct.Cache.html
    /// [cache module documentation]: cache/index.html
    pub static ref CACHE: RwLock<Cache> = RwLock::new(Cache::default());
}
<|endoftext|>


<commit_before>// TODO: FIXME: It must be removed after code layout stabilization!
#![allow(dead_code)]
#![allow(unused_variables)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate serde_derive;

extern crate rustc_serialize;

// Not that to use macroses from util inside of other modules it must me loaded first!
#[macro_use]
mod utils;

pub mod api;
mod commands;
mod errors;
mod services;
mod types;

#[cfg(test)]
mod tests {
    //use super::*;

    #[test]
    fn dummy() {
        assert! (true, "Dummy check!");
    }
}<commit_msg>commit error<commit_after>// TODO: FIXME: It must be removed after code layout stabilization!
#![allow(dead_code)]
#![allow(unused_variables)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate lazy_static;

extern crate rustc_serialize;

// Not that to use macroses from util inside of other modules it must me loaded first!
#[macro_use]
mod utils;

pub mod api;
mod commands;
mod errors;
mod services;
mod types;

#[cfg(test)]
mod tests {
    //use super::*;

    #[test]
    fn dummy() {
        assert! (true, "Dummy check!");
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]
use std::io;
pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

pub struct AtomicFile {
    pub path: Path,
    pub overwrite: OverwriteBehavior,
    pub tmpdir: Path
}

impl AtomicFile {
    /// Open the given file in write-only mode, if not `allow_overwrite`, errors will be returned
    /// from `do(...)` if the file exists.
    ///
    /// The temporary directory defaults to `path`, and will be used for temporary files. It must
    /// reside on the same filesystem.
    pub fn new(path: &Path, overwrite: OverwriteBehavior, tmpdir: Option<&Path>) -> AtomicFile {
        AtomicFile {
            path: path.clone(),
            overwrite: overwrite,
            tmpdir: match tmpdir {
                Some(x) => x.clone(),
                None => path.dir_path()
            }
        }
    }

    pub fn write<F: FnMut(&mut io::File) -> io::IoResult<()>>(&self, mut f: F) -> io::IoResult<()> {
        let tmpdir = try!(io::TempDir::new_in(&self.tmpdir, ".atomicwrite"));
        let mut tmpfile = try!(io::File::create(&tmpdir.path().join(Path::new("tmpfile.tmp"))));

        try!(f(&mut tmpfile));
        try!(tmpfile.fsync());
        try!(self.commit(tmpfile.path()));

        Ok(())
    }

    fn commit(&self, tmppath: &Path) -> io::IoResult<()> {
        match self.overwrite {
            AllowOverwrite => {
                try!(io::fs::rename(tmppath, &self.path));  // atomic
            },
            DisallowOverwrite => {
                try!(io::fs::link(tmppath, &self.path)); // atomic
                try!(io::fs::unlink(&self.path)); // doesn't matter if atomic
            }
        };
        Ok(())
    }
}

#[derive(Copy)]
pub enum OverwriteBehavior {
    AllowOverwrite,
    DisallowOverwrite
}
<commit_msg>Avoid spaghetti code<commit_after>#![allow(unstable)]
use std::io;
pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

pub struct AtomicFile {
    pub path: Path,
    pub overwrite: OverwriteBehavior,
    pub tmpdir: Path
}

impl AtomicFile {
    /// Open the given file in write-only mode, if not `allow_overwrite`, errors will be returned
    /// from `do(...)` if the file exists.
    ///
    /// The temporary directory defaults to `path`, and will be used for temporary files. It must
    /// reside on the same filesystem.
    pub fn new(path: &Path, overwrite: OverwriteBehavior, tmpdir: Option<&Path>) -> AtomicFile {
        AtomicFile {
            path: path.clone(),
            overwrite: overwrite,
            tmpdir: match tmpdir {
                Some(x) => x.clone(),
                None => path.dir_path()
            }
        }
    }

    pub fn write<F: FnMut(&mut io::File) -> io::IoResult<()>>(&self, mut f: F) -> io::IoResult<()> {
        let tmpdir = try!(io::TempDir::new_in(&self.tmpdir, ".atomicwrite"));
        let tmppath = tmpdir.path().join(Path::new("tmpfile.tmp"));
        let mut tmpfile = try!(io::File::create(&tmppath));

        try!(f(&mut tmpfile));
        try!(tmpfile.fsync());
        try!(self.commit(tmpfile.path()));

        Ok(())
    }

    fn commit(&self, tmppath: &Path) -> io::IoResult<()> {
        match self.overwrite {
            AllowOverwrite => {
                try!(io::fs::rename(tmppath, &self.path));  // atomic
            },
            DisallowOverwrite => {
                try!(io::fs::link(tmppath, &self.path)); // atomic
                try!(io::fs::unlink(&self.path)); // doesn't matter if atomic
            }
        };
        Ok(())
    }
}

#[derive(Copy)]
pub enum OverwriteBehavior {
    AllowOverwrite,
    DisallowOverwrite
}
<|endoftext|>