<commit_before>//! Experiments with parallel processing
//!
//! The provided functions focus on the possibility of
//! returning results while the parser proceeds. Sequences are processesd in
//! batches (`RecordSet`) because sending across channels has a performance
//! impact. FASTA/FASTQ records can be accessed in both the 'worker' function and
//! (after processing) a function running in the main thread.
//!
//! # Search first occurrence of a sequence pattern
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::read_parallel;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//!
//! read_parallel(reader, 4, 2, |record_set| {
//!     // this function does the heavy work
//!     for (i, record) in record_set.into_iter().enumerate() {
//!         // this is not very efficient code, just for demonstration
//!         if let Some(pos) = record.seq().windows(3).position(|s| s == b"AAA") {
//!             return Some((i, pos));
//!         }
//!     }
//!     None
//! }, |record_sets| {
//!     // This function runs in the main thread. It provides a streaming iterator over
//!     // record sets and the corresponding return values from the worker function
//!     // (not necessarily in the same order as in the file)
//!     while let Some(result) = record_sets.next() {
//!         let (record_set, found) = result.unwrap();
//!         if let Some((i, pos)) = found {
//!             let record = record_set.into_iter().nth(i).unwrap();
//!             println!("Found AAA in record {} at position {}", record.id().unwrap(), pos);
//!              // this will also stop the worker threads, although with some delay
//!             return;
//!         }
//!     }
//! });
//! ```
//!
//! # Per-record processsing
//! The `parallel_fasta` / `parallel_fastq` functions are designed to efficiently pass
//! results for **each record** to the main thread without having to care about record sets.
//! This example filters sequences by the occurrence of a pattern:
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use std::fs::File;
//! use std::io::BufWriter;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//! let mut writer = BufWriter::new(File::create("filtered.fastq").unwrap());
//!
//! seq_io::parallel::parallel_fastq(reader, 4, 2,
//!     |record, found| { // runs in worker
//!         *found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
//!     },
//!     |record, found| { // runs in main thread
//!         if *found {
//!             record.write(&mut writer).unwrap();
//!         }
//!         // `false` will stop the reader
//!         true
//! }).unwrap();
//! ```

use std::io;

extern crate crossbeam;
extern crate scoped_threadpool;

use std::sync::mpsc;
use std::marker::PhantomData;

pub trait Reader: Send {
    type DataSet: Default + Send;
    type Err: Send;
    fn fill_data(&mut self, record: &mut Self::DataSet) -> Option<Result<(), Self::Err>>;
}

pub fn read_parallel<P, O, W, F, Out>(mut reader: P, n_threads: u32, queue_len: usize, work: W, func: F) -> Out
    where P: Reader,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(&mut P::DataSet) -> O,
          F: FnOnce(&mut ParallelRecordsets<P::DataSet, P::Err, O>) -> Out,
{

    let (done_send, done_recv) = mpsc::sync_channel(queue_len);
    let (empty_send, empty_recv): (mpsc::SyncSender<Option<P::DataSet>>, _) = mpsc::sync_channel(queue_len);

    crossbeam::scope(|scope| {

        scope.spawn(move || {

            let mut pool = scoped_threadpool::Pool::new(n_threads);

            pool.scoped(|pool_scope| {

                let work = &work;

                loop {
                    // recycle an old DataSet sent back after use by the streaming iterator
                    let mut data =
                        if let Ok(Some(r)) = empty_recv.recv() {
                            r
                        } else {
                            // 'ParallelRecordsets::stop()' called
                            return;
                        };

                    // each time, we need a new reference
                    let done_send = done_send.clone();

                    if let Some(res) = reader.fill_data(&mut data) {
                        match res {
                            Ok(_) => {
                                // expensive work carried out by func()
                                pool_scope.execute(move || {

                                    let out = work(&mut data);

                                    done_send.send(Some(Ok((data, out)))).ok();
                                });
                            }
                            Err(e) => {
                                done_send.send(Some(Err(e))).ok();
                                break;
                            }
                        }
                    } else {
                        break;
                    }
                }

                // make sure that the 'done' signal is only sent after everything else is done
                pool_scope.join_all();

                done_send.send(None).ok();
            });
        });

        for _ in 0..queue_len  {
            empty_send.send(Some(P::DataSet::default())).unwrap();
        }

        let mut records = ParallelRecordsets {
            empty_send: empty_send,
            done_recv: done_recv,
            current_recordset: P::DataSet::default(),
        };

        let out = func(&mut records);

        records.stop();

        out
    })
}

pub struct ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
{
    empty_send: mpsc::SyncSender<Option<R>>,
    done_recv: mpsc::Receiver<Option<Result<(R, O), E>>>,
    current_recordset: R,
}

impl<R, E, O> ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
 {

    pub fn next<'b>(&'b mut self) -> Option<Result<(&'b R, O), E>> {
        if let Some(result) = self.done_recv.recv().unwrap() {
            match result {
                Ok((r, o)) => {
                     let prev_rset = ::std::mem::replace(&mut self.current_recordset, r);
                     self.empty_send.send(Some(prev_rset)).ok(); // error: channel closed is not a problem, happens after calling stop()
                    return Some(Ok((&self.current_recordset, o)));
                }
                Err(e) => return Some(Err(e))
            }
        } else {
            // 'done' signal received
            return None;
        }
    }

    // has to be called before object goes out of scope
    // currently, the signal is delayed (has to wait until it is popped from the
    // 'empty' queue)
    // TODO: should an AtomicBool be used?
    fn stop(self) {
        self.empty_send.send(None).ok();
    }
}

#[macro_export]
macro_rules! parallel_record_impl {
    ($name:ident, $io_r:tt, $rdr:ty, $record:ty, $err:ty) => {

        pub fn $name<$io_r, O, W, F>(parser: $rdr, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<(), $err>
            where $io_r: io::Read + Send,
                  O: Default + Send,
                  W: Send + Sync,
                  W: Fn($record, &mut O),
                  F: FnMut($record, &O) -> bool,
        {
            let reader = $crate::parallel::ReusableReader::new(parser);

            $crate::parallel::read_parallel(reader, n_threads, queue_len, |d| {
                let mut iter = d.0.into_iter();
                let out: &mut Vec<O> = &mut d.1;
                for mut x in out.iter_mut().zip(&mut iter) {
                    work(x.1, &mut x.0);
                }
                for i in iter {
                    out.push(O::default());
                    work(i, out.last_mut().unwrap())
                }

            }, |records| {
                while let Some(result) = records.next() {
                    let (r, _) = result?;
                    for x in r.0.into_iter().zip(&r.1) {
                        if ! func(x.0, x.1) {
                            break;
                        }
                    }
                }
                Ok(())
            })
        }
     };
}

parallel_record_impl!(parallel_fasta, R, fasta::Reader<R>, fasta::RefRecord, fasta::ParseError);

parallel_record_impl!(parallel_fastq, R, fastq::Reader<R>, fastq::RefRecord, fastq::ParseError);

pub struct ReusableReader<P, O>(P, PhantomData<O>);

impl<P, O> ReusableReader<P, O> {
    pub fn new(p: P) -> ReusableReader<P, O> {
        ReusableReader(p, PhantomData)
    }
}

impl<P, O> Reader for ReusableReader<P, O>
    where P: Reader,
          O: Default + Send {

    type DataSet = (P::DataSet, O);
    type Err = P::Err;
    fn fill_data(&mut self, data: &mut Self::DataSet) -> Option<Result<(), P::Err>> {
        self.0.fill_data(&mut data.0)
    }
}

// trait impls

use super::fasta;

impl<R, S> Reader for fasta::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fasta::RecordSet;
    type Err = fasta::ParseError;
    fn fill_data(&mut self, rset: &mut fasta::RecordSet) -> Option<Result<(), fasta::ParseError>> {
        self.read_record_set(rset)
    }
}

use super::fastq;

impl<R, S> Reader for fastq::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fastq::RecordSet;
    type Err = fastq::ParseError;
    fn fill_data(&mut self, rset: &mut fastq::RecordSet) -> Option<Result<(), fastq::ParseError>> {
        self.read_record_set(rset)
    }
}
<commit_msg>Document ReusableReader<commit_after>//! Experiments with parallel processing
//!
//! The provided functions focus on the possibility of
//! returning results while the parser proceeds. Sequences are processesd in
//! batches (`RecordSet`) because sending across channels has a performance
//! impact. FASTA/FASTQ records can be accessed in both the 'worker' function and
//! (after processing) a function running in the main thread.
//!
//! # Search first occurrence of a sequence pattern
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use seq_io::parallel::read_parallel;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//!
//! read_parallel(reader, 4, 2, |record_set| {
//!     // this function does the heavy work
//!     for (i, record) in record_set.into_iter().enumerate() {
//!         // this is not very efficient code, just for demonstration
//!         if let Some(pos) = record.seq().windows(3).position(|s| s == b"AAA") {
//!             return Some((i, pos));
//!         }
//!     }
//!     None
//! }, |record_sets| {
//!     // This function runs in the main thread. It provides a streaming iterator over
//!     // record sets and the corresponding return values from the worker function
//!     // (not necessarily in the same order as in the file)
//!     while let Some(result) = record_sets.next() {
//!         let (record_set, found) = result.unwrap();
//!         if let Some((i, pos)) = found {
//!             let record = record_set.into_iter().nth(i).unwrap();
//!             println!("Found AAA in record {} at position {}", record.id().unwrap(), pos);
//!              // this will also stop the worker threads, although with some delay
//!             return;
//!         }
//!     }
//! });
//! ```
//!
//! # Per-record processsing
//! The `parallel_fasta` / `parallel_fastq` functions are designed to efficiently pass
//! results for **each record** to the main thread without having to care about record sets.
//! This example filters sequences by the occurrence of a pattern:
//!
//! ```no_run
//! use seq_io::fastq::{Reader,Record};
//! use std::fs::File;
//! use std::io::BufWriter;
//!
//! let reader = Reader::from_path("seqs.fastq").unwrap();
//! let mut writer = BufWriter::new(File::create("filtered.fastq").unwrap());
//!
//! seq_io::parallel::parallel_fastq(reader, 4, 2,
//!     |record, found| { // runs in worker
//!         *found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
//!     },
//!     |record, found| { // runs in main thread
//!         if *found {
//!             record.write(&mut writer).unwrap();
//!         }
//!         // `false` will stop the reader
//!         true
//! }).unwrap();
//! ```

use std::io;

extern crate crossbeam;
extern crate scoped_threadpool;

use std::sync::mpsc;
use std::marker::PhantomData;

pub trait Reader: Send {
    type DataSet: Default + Send;
    type Err: Send;
    fn fill_data(&mut self, record: &mut Self::DataSet) -> Option<Result<(), Self::Err>>;
}

pub fn read_parallel<P, O, W, F, Out>(mut reader: P, n_threads: u32, queue_len: usize, work: W, func: F) -> Out
    where P: Reader,
          O: Default + Send,
          W: Send + Sync,
          W: Fn(&mut P::DataSet) -> O,
          F: FnOnce(&mut ParallelRecordsets<P::DataSet, P::Err, O>) -> Out,
{

    let (done_send, done_recv) = mpsc::sync_channel(queue_len);
    let (empty_send, empty_recv): (mpsc::SyncSender<Option<P::DataSet>>, _) = mpsc::sync_channel(queue_len);

    crossbeam::scope(|scope| {

        scope.spawn(move || {

            let mut pool = scoped_threadpool::Pool::new(n_threads);

            pool.scoped(|pool_scope| {

                let work = &work;

                loop {
                    // recycle an old DataSet sent back after use by the streaming iterator
                    let mut data =
                        if let Ok(Some(r)) = empty_recv.recv() {
                            r
                        } else {
                            // 'ParallelRecordsets::stop()' called
                            return;
                        };

                    // each time, we need a new reference
                    let done_send = done_send.clone();

                    if let Some(res) = reader.fill_data(&mut data) {
                        match res {
                            Ok(_) => {
                                // expensive work carried out by func()
                                pool_scope.execute(move || {

                                    let out = work(&mut data);

                                    done_send.send(Some(Ok((data, out)))).ok();
                                });
                            }
                            Err(e) => {
                                done_send.send(Some(Err(e))).ok();
                                break;
                            }
                        }
                    } else {
                        break;
                    }
                }

                // make sure that the 'done' signal is only sent after everything else is done
                pool_scope.join_all();

                done_send.send(None).ok();
            });
        });

        for _ in 0..queue_len  {
            empty_send.send(Some(P::DataSet::default())).unwrap();
        }

        let mut records = ParallelRecordsets {
            empty_send: empty_send,
            done_recv: done_recv,
            current_recordset: P::DataSet::default(),
        };

        let out = func(&mut records);

        records.stop();

        out
    })
}

pub struct ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
{
    empty_send: mpsc::SyncSender<Option<R>>,
    done_recv: mpsc::Receiver<Option<Result<(R, O), E>>>,
    current_recordset: R,
}

impl<R, E, O> ParallelRecordsets<R, E, O>
    where R: Default + Send,
          E: Send,
          O: Send,
 {

    pub fn next<'b>(&'b mut self) -> Option<Result<(&'b R, O), E>> {
        if let Some(result) = self.done_recv.recv().unwrap() {
            match result {
                Ok((r, o)) => {
                     let prev_rset = ::std::mem::replace(&mut self.current_recordset, r);
                     self.empty_send.send(Some(prev_rset)).ok(); // error: channel closed is not a problem, happens after calling stop()
                    return Some(Ok((&self.current_recordset, o)));
                }
                Err(e) => return Some(Err(e))
            }
        } else {
            // 'done' signal received
            return None;
        }
    }

    // has to be called before object goes out of scope
    // currently, the signal is delayed (has to wait until it is popped from the
    // 'empty' queue)
    // TODO: should an AtomicBool be used?
    fn stop(self) {
        self.empty_send.send(None).ok();
    }
}

#[macro_export]
macro_rules! parallel_record_impl {
    ($name:ident, $io_r:tt, $rdr:ty, $record:ty, $err:ty) => {

        pub fn $name<$io_r, O, W, F>(parser: $rdr, n_threads: u32, queue_len: usize, work: W, mut func: F) -> Result<(), $err>
            where $io_r: io::Read + Send,
                  O: Default + Send,
                  W: Send + Sync,
                  W: Fn($record, &mut O),
                  F: FnMut($record, &O) -> bool,
        {
            let reader = $crate::parallel::ReusableReader::new(parser);

            $crate::parallel::read_parallel(reader, n_threads, queue_len, |d| {
                let mut iter = d.0.into_iter();
                let out: &mut Vec<O> = &mut d.1;
                for mut x in out.iter_mut().zip(&mut iter) {
                    work(x.1, &mut x.0);
                }
                for i in iter {
                    out.push(O::default());
                    work(i, out.last_mut().unwrap())
                }

            }, |records| {
                while let Some(result) = records.next() {
                    let (r, _) = result?;
                    for x in r.0.into_iter().zip(&r.1) {
                        if ! func(x.0, x.1) {
                            break;
                        }
                    }
                }
                Ok(())
            })
        }
     };
}

parallel_record_impl!(parallel_fasta, R, fasta::Reader<R>, fasta::RefRecord, fasta::ParseError);

parallel_record_impl!(parallel_fastq, R, fastq::Reader<R>, fastq::RefRecord, fastq::ParseError);

/// Wrapper for `parallel::Reader` instances allowing
/// the output to be reused in order to save allocations.
/// Used by `parallel_fasta`/`parallel_fastq`
///
/// ```no_run
/// use seq_io::fastq::{Reader,Record,RecordSet};
/// use seq_io::parallel::{read_parallel,ReusableReader};
///
/// let inner = Reader::from_path("seqs.fastq").unwrap();
/// let reader = ReusableReader::new(inner);
///
/// read_parallel(reader, 4, 2, |&mut (ref record_set, ref mut out): &mut (RecordSet, Vec<bool>)| {
///     out.clear();
///     for record in record_set {
///         let found = record.seq().windows(3).position(|s| s == b"AAA").is_some();
///         out.push(found);
///     }
/// }, |record_sets| {
///     while let Some(result) = record_sets.next() {
///         let &(ref record_set, ref out) = result.unwrap().0;
///         for (record, found) in record_set.into_iter().zip(out) {
///             // ...
///         }
///     }
/// });
/// ```
pub struct ReusableReader<P, O>(P, PhantomData<O>);

impl<P, O> ReusableReader<P, O> {
    pub fn new(p: P) -> ReusableReader<P, O> {
        ReusableReader(p, PhantomData)
    }
}

impl<P, O> Reader for ReusableReader<P, O>
    where P: Reader,
          O: Default + Send {

    type DataSet = (P::DataSet, O);
    type Err = P::Err;
    fn fill_data(&mut self, data: &mut Self::DataSet) -> Option<Result<(), P::Err>> {
        self.0.fill_data(&mut data.0)
    }
}

// trait impls

use super::fasta;

impl<R, S> Reader for fasta::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fasta::RecordSet;
    type Err = fasta::ParseError;
    fn fill_data(&mut self, rset: &mut fasta::RecordSet) -> Option<Result<(), fasta::ParseError>> {
        self.read_record_set(rset)
    }
}

use super::fastq;

impl<R, S> Reader for fastq::Reader<R, S>
    where R: io::Read + Send,
          S: super::strategy::BufGrowStrategy + Send
{
    type DataSet = fastq::RecordSet;
    type Err = fastq::ParseError;
    fn fill_data(&mut self, rset: &mut fastq::RecordSet) -> Option<Result<(), fastq::ParseError>> {
        self.read_record_set(rset)
    }
}
<|endoftext|>


<commit_before>//! Operations on ASCII strings and characters.
//!
//! Most string operations in Rust act on UTF-8 strings. However, at times it
//! makes more sense to only consider the ASCII character set for a specific
//! operation.
//!
//! The [`escape_default`] function provides an iterator over the bytes of an
//! escaped version of the character given.
//!
//! [`escape_default`]: fn.escape_default.html

#![stable(feature = "core_ascii", since = "1.26.0")]

use crate::fmt;
use crate::ops::Range;
use crate::iter::FusedIterator;

/// An iterator over the escaped version of a byte.
///
/// This `struct` is created by the [`escape_default`] function. See its
/// documentation for more.
///
/// [`escape_default`]: fn.escape_default.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct EscapeDefault {
    range: Range<usize>,
    data: [u8; 4],
}

/// Returns an iterator that produces an escaped version of a `u8`.
///
/// The default is chosen with a bias toward producing literals that are
/// legal in a variety of languages, including C++11 and similar C-family
/// languages. The exact rules are:
///
/// * Tab is escaped as `\t`.
/// * Carriage return is escaped as `\r`.
/// * Line feed is escaped as `\n`.
/// * Single quote is escaped as `\'`.
/// * Double quote is escaped as `\"`.
/// * Backslash is escaped as `\\`.
/// * Any character in the 'printable ASCII' range `0x20` .. `0x7e`
///   inclusive is not escaped.
/// * Any other chars are given hex escapes of the form '\xNN'.
/// * Unicode escapes are never generated by this function.
///
/// # Examples
///
/// ```
/// use std::ascii;
///
/// let escaped = ascii::escape_default(b'0').next().unwrap();
/// assert_eq!(b'0', escaped);
///
/// let mut escaped = ascii::escape_default(b'\t');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b't', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\r');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'r', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\n');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'n', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\'');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'\'', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'"');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'"', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\\');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'\\', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\x9d');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'x', escaped.next().unwrap());
/// assert_eq!(b'9', escaped.next().unwrap());
/// assert_eq!(b'd', escaped.next().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn escape_default(c: u8) -> EscapeDefault {
    let (data, len) = match c {
        b'\t' => ([b'\\', b't', 0, 0], 2),
        b'\r' => ([b'\\', b'r', 0, 0], 2),
        b'\n' => ([b'\\', b'n', 0, 0], 2),
        b'\\' => ([b'\\', b'\\', 0, 0], 2),
        b'\'' => ([b'\\', b'\'', 0, 0], 2),
        b'"' => ([b'\\', b'"', 0, 0], 2),
        b'\x20' ..= b'\x7e' => ([c, 0, 0, 0], 1),
        _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
    };

    return EscapeDefault { range: 0..len, data };

    fn hexify(b: u8) -> u8 {
        match b {
            0 ..= 9 => b'0' + b,
            _ => b'a' + b - 10,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeDefault {
    type Item = u8;
    fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
    fn last(mut self) -> Option<u8> { self.next_back() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl DoubleEndedIterator for EscapeDefault {
    fn next_back(&mut self) -> Option<u8> {
        self.range.next_back().map(|i| self.data[i])
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExactSizeIterator for EscapeDefault {}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDefault {}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for EscapeDefault {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EscapeDefault { .. }")
    }
}
<commit_msg>Rollup merge of #63421 - clarfon:escape_default, r=dtolnay<commit_after>//! Operations on ASCII strings and characters.
//!
//! Most string operations in Rust act on UTF-8 strings. However, at times it
//! makes more sense to only consider the ASCII character set for a specific
//! operation.
//!
//! The [`escape_default`] function provides an iterator over the bytes of an
//! escaped version of the character given.
//!
//! [`escape_default`]: fn.escape_default.html

#![stable(feature = "core_ascii", since = "1.26.0")]

use crate::fmt;
use crate::ops::Range;
use crate::iter::FusedIterator;
use crate::str::from_utf8_unchecked;

/// An iterator over the escaped version of a byte.
///
/// This `struct` is created by the [`escape_default`] function. See its
/// documentation for more.
///
/// [`escape_default`]: fn.escape_default.html
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct EscapeDefault {
    range: Range<usize>,
    data: [u8; 4],
}

/// Returns an iterator that produces an escaped version of a `u8`.
///
/// The default is chosen with a bias toward producing literals that are
/// legal in a variety of languages, including C++11 and similar C-family
/// languages. The exact rules are:
///
/// * Tab is escaped as `\t`.
/// * Carriage return is escaped as `\r`.
/// * Line feed is escaped as `\n`.
/// * Single quote is escaped as `\'`.
/// * Double quote is escaped as `\"`.
/// * Backslash is escaped as `\\`.
/// * Any character in the 'printable ASCII' range `0x20` .. `0x7e`
///   inclusive is not escaped.
/// * Any other chars are given hex escapes of the form '\xNN'.
/// * Unicode escapes are never generated by this function.
///
/// # Examples
///
/// ```
/// use std::ascii;
///
/// let escaped = ascii::escape_default(b'0').next().unwrap();
/// assert_eq!(b'0', escaped);
///
/// let mut escaped = ascii::escape_default(b'\t');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b't', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\r');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'r', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\n');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'n', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\'');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'\'', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'"');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'"', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\\');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'\\', escaped.next().unwrap());
///
/// let mut escaped = ascii::escape_default(b'\x9d');
///
/// assert_eq!(b'\\', escaped.next().unwrap());
/// assert_eq!(b'x', escaped.next().unwrap());
/// assert_eq!(b'9', escaped.next().unwrap());
/// assert_eq!(b'd', escaped.next().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn escape_default(c: u8) -> EscapeDefault {
    let (data, len) = match c {
        b'\t' => ([b'\\', b't', 0, 0], 2),
        b'\r' => ([b'\\', b'r', 0, 0], 2),
        b'\n' => ([b'\\', b'n', 0, 0], 2),
        b'\\' => ([b'\\', b'\\', 0, 0], 2),
        b'\'' => ([b'\\', b'\'', 0, 0], 2),
        b'"' => ([b'\\', b'"', 0, 0], 2),
        b'\x20' ..= b'\x7e' => ([c, 0, 0, 0], 1),
        _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
    };

    return EscapeDefault { range: 0..len, data };

    fn hexify(b: u8) -> u8 {
        match b {
            0 ..= 9 => b'0' + b,
            _ => b'a' + b - 10,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeDefault {
    type Item = u8;
    fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
    fn last(mut self) -> Option<u8> { self.next_back() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl DoubleEndedIterator for EscapeDefault {
    fn next_back(&mut self) -> Option<u8> {
        self.range.next_back().map(|i| self.data[i])
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExactSizeIterator for EscapeDefault {}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDefault {}

#[stable(feature = "ascii_escape_display", since = "1.39.0")]
impl fmt::Display for EscapeDefault {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) })
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for EscapeDefault {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("EscapeDefault { .. }")
    }
}
<|endoftext|>


<commit_before>//! Panic support in the standard library.

#![unstable(feature = "core_panic_info",
            reason = "newly available in libcore",
            issue = "44489")]

use crate::any::Any;
use crate::fmt;

/// A struct providing information about a panic.
///
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
/// function.
///
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
///         println!("panic occurred: {:?}", s);
///     } else {
///         println!("panic occurred");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_info"]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
    payload: &'a (dyn Any + Send),
    message: Option<&'a fmt::Arguments<'a>>,
    location: &'a Location<'a>,
}

impl<'a> PanicInfo<'a> {
    #![unstable(feature = "panic_internals",
                reason = "internal details of the implementation of the `panic!` \
                          and related macros",
                issue = "0")]
    #[doc(hidden)]
    #[inline]
    pub fn internal_constructor(
        message: Option<&'a fmt::Arguments<'a>>,
        location: &'a Location<'a>,
    ) -> Self {
        struct NoPayload;
        PanicInfo {
            location,
            message,
            payload: &NoPayload,
        }
    }

    #[doc(hidden)]
    #[inline]
    pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
        self.payload = info;
    }

    /// Returns the payload associated with the panic.
    ///
    /// This will commonly, but not always, be a `&'static str` or [`String`].
    ///
    /// [`String`]: ../../std/string/struct.String.html
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn payload(&self) -> &(dyn Any + Send) {
        self.payload
    }

    /// If the `panic!` macro from the `core` crate (not from `std`)
    /// was used with a formatting string and some additional arguments,
    /// returns that message ready to be used for example with [`fmt::write`]
    ///
    /// [`fmt::write`]: ../fmt/fn.write.html
    #[unstable(feature = "panic_info_message", issue = "44489")]
    pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
        self.message
    }

    /// Returns information about the location from which the panic originated,
    /// if available.
    ///
    /// This method will currently always return [`Some`], but this may change
    /// in future versions.
    ///
    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}' at line {}", location.file(),
    ///             location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn location(&self) -> Option<&Location<'_>> {
        // NOTE: If this is changed to sometimes return None,
        // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
        Some(&self.location)
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for PanicInfo<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("panicked at ")?;
        if let Some(message) = self.message {
            write!(formatter, "'{}', ", message)?
        } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
            write!(formatter, "'{}', ", payload)?
        }
        // NOTE: we cannot use downcast_ref::<String>() here
        // since String is not available in libcore!
        // The payload is a String when `std::panic!` is called with multiple arguments,
        // but in that case the message is also available.

        self.location.fmt(formatter)
    }
}

/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(location) = panic_info.location() {
///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
///     } else {
///         println!("panic occurred but can't get location information...");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_location"]
#[derive(Debug)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
    file: &'a str,
    line: u32,
    col: u32,
}

impl<'a> Location<'a> {
    /// Returns the source location of the caller of this function. If that function's caller is
    /// annotated then its call location will be returned, and so on up the stack to the first call
    /// within a non-tracked function body.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(track_caller)]
    /// use core::panic::Location;
    ///
    /// /// Returns the [`Location`] at which it is called.
    /// #[track_caller]
    /// fn get_caller_location() -> &'static Location<'static> {
    ///     Location::caller()
    /// }
    ///
    /// /// Returns a [`Location`] from within this function's definition.
    /// fn get_just_one_location() -> &'static Location<'static> {
    ///     get_caller_location()
    /// }
    ///
    /// let fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), file!());
    /// assert_eq!(fixed_location.line(), 15);
    /// assert_eq!(fixed_location.column(), 5);
    ///
    /// // running the same untracked function in a different location gives us the same result
    /// let second_fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), second_fixed_location.file());
    /// assert_eq!(fixed_location.line(), second_fixed_location.line());
    /// assert_eq!(fixed_location.column(), second_fixed_location.column());
    ///
    /// let this_location = get_caller_location();
    /// assert_eq!(this_location.file(), file!());
    /// assert_eq!(this_location.line(), 29);
    /// assert_eq!(this_location.column(), 21);
    ///
    /// // running the tracked function in a different location produces a different value
    /// let another_location = get_caller_location();
    /// assert_eq!(this_location.file(), another_location.file());
    /// assert_ne!(this_location.line(), another_location.line());
    /// assert_ne!(this_location.column(), another_location.column());
    /// ```
    #[cfg(not(bootstrap))]
    #[unstable(feature = "track_caller",
               reason = "uses #[track_caller] which is not yet stable",
               issue = "47809")]
    #[track_caller]
    pub const fn caller() -> &'static Location<'static> {
        crate::intrinsics::caller_location()
    }
}

impl<'a> Location<'a> {
    #![unstable(feature = "panic_internals",
                reason = "internal details of the implementation of the `panic!` \
                          and related macros",
                issue = "0")]
    #[doc(hidden)]
    pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
        Location { file, line, col }
    }

    /// Returns the name of the source file from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}'", location.file());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn file(&self) -> &str {
        self.file
    }

    /// Returns the line number from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at line {}", location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// Returns the column from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at column {}", location.column());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_col", since = "1.25.0")]
    pub fn column(&self) -> u32 {
        self.col
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for Location<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
    }
}

/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
/// and other panic runtimes. Not intended to be stabilized any time soon, do
/// not use.
#[unstable(feature = "std_internals", issue = "0")]
#[doc(hidden)]
pub unsafe trait BoxMeUp {
    /// Take full ownership of the contents.
    /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
    ///
    /// After this method got called, only some dummy default value is left in `self`.
    /// Calling this method twice, or calling `get` after calling this method, is an error.
    ///
    /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
    /// gets a borrowed `dyn BoxMeUp`.
    fn take_box(&mut self) -> *mut (dyn Any + Send);

    /// Just borrow the contents.
    fn get(&mut self) -> &(dyn Any + Send);
}
<commit_msg>Rollup merge of #66771 - SimonSapin:panic-stability, r=KodrAus<commit_after>//! Panic support in the standard library.

#![stable(feature = "core_panic_info", since = "1.41.0")]

use crate::any::Any;
use crate::fmt;

/// A struct providing information about a panic.
///
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
/// function.
///
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
///         println!("panic occurred: {:?}", s);
///     } else {
///         println!("panic occurred");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_info"]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
    payload: &'a (dyn Any + Send),
    message: Option<&'a fmt::Arguments<'a>>,
    location: &'a Location<'a>,
}

impl<'a> PanicInfo<'a> {
    #[unstable(feature = "panic_internals",
               reason = "internal details of the implementation of the `panic!` \
                         and related macros",
               issue = "0")]
    #[doc(hidden)]
    #[inline]
    pub fn internal_constructor(
        message: Option<&'a fmt::Arguments<'a>>,
        location: &'a Location<'a>,
    ) -> Self {
        struct NoPayload;
        PanicInfo {
            location,
            message,
            payload: &NoPayload,
        }
    }

    #[unstable(feature = "panic_internals",
               reason = "internal details of the implementation of the `panic!` \
                         and related macros",
               issue = "0")]
    #[doc(hidden)]
    #[inline]
    pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
        self.payload = info;
    }

    /// Returns the payload associated with the panic.
    ///
    /// This will commonly, but not always, be a `&'static str` or [`String`].
    ///
    /// [`String`]: ../../std/string/struct.String.html
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn payload(&self) -> &(dyn Any + Send) {
        self.payload
    }

    /// If the `panic!` macro from the `core` crate (not from `std`)
    /// was used with a formatting string and some additional arguments,
    /// returns that message ready to be used for example with [`fmt::write`]
    ///
    /// [`fmt::write`]: ../fmt/fn.write.html
    #[unstable(feature = "panic_info_message", issue = "66745")]
    pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
        self.message
    }

    /// Returns information about the location from which the panic originated,
    /// if available.
    ///
    /// This method will currently always return [`Some`], but this may change
    /// in future versions.
    ///
    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}' at line {}", location.file(),
    ///             location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn location(&self) -> Option<&Location<'_>> {
        // NOTE: If this is changed to sometimes return None,
        // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
        Some(&self.location)
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for PanicInfo<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("panicked at ")?;
        if let Some(message) = self.message {
            write!(formatter, "'{}', ", message)?
        } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
            write!(formatter, "'{}', ", payload)?
        }
        // NOTE: we cannot use downcast_ref::<String>() here
        // since String is not available in libcore!
        // The payload is a String when `std::panic!` is called with multiple arguments,
        // but in that case the message is also available.

        self.location.fmt(formatter)
    }
}

/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(location) = panic_info.location() {
///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
///     } else {
///         println!("panic occurred but can't get location information...");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_location"]
#[derive(Debug)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
    file: &'a str,
    line: u32,
    col: u32,
}

impl<'a> Location<'a> {
    /// Returns the source location of the caller of this function. If that function's caller is
    /// annotated then its call location will be returned, and so on up the stack to the first call
    /// within a non-tracked function body.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(track_caller)]
    /// use core::panic::Location;
    ///
    /// /// Returns the [`Location`] at which it is called.
    /// #[track_caller]
    /// fn get_caller_location() -> &'static Location<'static> {
    ///     Location::caller()
    /// }
    ///
    /// /// Returns a [`Location`] from within this function's definition.
    /// fn get_just_one_location() -> &'static Location<'static> {
    ///     get_caller_location()
    /// }
    ///
    /// let fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), file!());
    /// assert_eq!(fixed_location.line(), 15);
    /// assert_eq!(fixed_location.column(), 5);
    ///
    /// // running the same untracked function in a different location gives us the same result
    /// let second_fixed_location = get_just_one_location();
    /// assert_eq!(fixed_location.file(), second_fixed_location.file());
    /// assert_eq!(fixed_location.line(), second_fixed_location.line());
    /// assert_eq!(fixed_location.column(), second_fixed_location.column());
    ///
    /// let this_location = get_caller_location();
    /// assert_eq!(this_location.file(), file!());
    /// assert_eq!(this_location.line(), 29);
    /// assert_eq!(this_location.column(), 21);
    ///
    /// // running the tracked function in a different location produces a different value
    /// let another_location = get_caller_location();
    /// assert_eq!(this_location.file(), another_location.file());
    /// assert_ne!(this_location.line(), another_location.line());
    /// assert_ne!(this_location.column(), another_location.column());
    /// ```
    #[cfg(not(bootstrap))]
    #[unstable(feature = "track_caller",
               reason = "uses #[track_caller] which is not yet stable",
               issue = "47809")]
    #[track_caller]
    pub const fn caller() -> &'static Location<'static> {
        crate::intrinsics::caller_location()
    }
}

impl<'a> Location<'a> {
    #![unstable(feature = "panic_internals",
                reason = "internal details of the implementation of the `panic!` \
                          and related macros",
                issue = "0")]
    #[doc(hidden)]
    pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
        Location { file, line, col }
    }

    /// Returns the name of the source file from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}'", location.file());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn file(&self) -> &str {
        self.file
    }

    /// Returns the line number from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at line {}", location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// Returns the column from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at column {}", location.column());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_col", since = "1.25.0")]
    pub fn column(&self) -> u32 {
        self.col
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for Location<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
    }
}

/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
/// and other panic runtimes. Not intended to be stabilized any time soon, do
/// not use.
#[unstable(feature = "std_internals", issue = "0")]
#[doc(hidden)]
pub unsafe trait BoxMeUp {
    /// Take full ownership of the contents.
    /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
    ///
    /// After this method got called, only some dummy default value is left in `self`.
    /// Calling this method twice, or calling `get` after calling this method, is an error.
    ///
    /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
    /// gets a borrowed `dyn BoxMeUp`.
    fn take_box(&mut self) -> *mut (dyn Any + Send);

    /// Just borrow the contents.
    fn get(&mut self) -> &(dyn Any + Send);
}
<|endoftext|>


<commit_before>use summary::Summary;

struct BoxWhiskerData {
    box_lo: f64,
    box_mid: f64,
    box_hi: f64,
    wh_lo: f64,
    wh_hi: f64,
}

impl BoxWhiskerData {
    fn from_summary(summary: &Summary) -> Self {
        BoxWhiskerData {
            box_lo: summary.percentile(0.25).unwrap(),
            box_mid: summary.median(),
            box_hi: summary.percentile(0.75).unwrap(),
            wh_lo: summary.min(),
            wh_hi: summary.max(),
        }
    }
}

struct BoxWhiskerCols {
    box_lo: usize,
    box_mid: usize,
    box_hi: usize,
    wh_lo: usize,
    wh_hi: usize,
}

impl BoxWhiskerCols {
    fn new(data: &BoxWhiskerData, width: usize) -> Self {
        let max_col = width - 1;
        let range = data.wh_hi - data.wh_lo;
        let normalize = |x| (x - data.wh_lo) / range;
        let scale = |x| (normalize(x) * (max_col as f64)) as f64;
        let to_col = |x| scale(x).floor() as usize;

        BoxWhiskerCols {
            box_lo: to_col(data.box_lo),
            box_mid: to_col(data.box_mid),
            box_hi: to_col(data.box_hi),
            wh_lo: to_col(data.wh_lo),
            wh_hi: to_col(data.wh_hi),
        }
    }
}

struct RowChars {
    wh_lo: &'static str,
    wh_lo_box_lo_fill: &'static str,
    box_lo: &'static str,
    box_lo_box_mid_fill: &'static str,
    box_mid: &'static str,
    box_mid_box_hi_fill: &'static str,
    box_hi: &'static str,
    box_hi_wh_hi_fill: &'static str,
    wh_hi: &'static str,
}

impl RowChars {
    pub fn render(&self, row: &mut Vec<String>, cols: &BoxWhiskerCols) {
        row[cols.wh_lo] = self.wh_lo.to_string();
        for i in (cols.wh_lo + 1)..cols.box_lo {
            row[i] = self.wh_lo_box_lo_fill.to_string();
        }
        row[cols.box_lo] = self.box_lo.to_string();
        for i in (cols.box_lo + 1)..cols.box_mid {
            row[i] = self.box_lo_box_mid_fill.to_string();
        }
        row[cols.box_mid] = self.box_mid.to_string();
        for i in (cols.box_mid + 1)..cols.box_hi {
            row[i] = self.box_mid_box_hi_fill.to_string();
        }
        row[cols.box_hi] = self.box_hi.to_string();
        for i in (cols.box_hi + 1)..cols.wh_hi {
            row[i] = self.box_hi_wh_hi_fill.to_string();
        }
        row[cols.wh_hi] = self.wh_hi.to_string();
    }
}

struct CharSet(RowChars, RowChars, RowChars);

impl CharSet {
    pub fn plot(&self, summary: &Summary, width: usize) -> String {
        let data = BoxWhiskerData::from_summary(summary);
        let cols = BoxWhiskerCols::new(&data, width);

        let mut plot = Plot::new(width);

        self.0.render(&mut plot.0, &cols);
        self.1.render(&mut plot.1, &cols);
        self.2.render(&mut plot.2, &cols);

        plot.render()
    }
}

static ASCII_CHARS: CharSet = CharSet(
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
    RowChars {
        wh_lo: "|",
        wh_lo_box_lo_fill: "-",
        box_lo: "|",
        box_lo_box_mid_fill: " ",
        box_mid: "|",
        box_mid_box_hi_fill: " ",
        box_hi: "|",
        box_hi_wh_hi_fill: "-",
        wh_hi: "|",
    },
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
);

static UNICODE_CHARS: CharSet = CharSet(
    RowChars {
        wh_lo: "┬",
        wh_lo_box_lo_fill: " ",
        box_lo: "┌",
        box_lo_box_mid_fill: "─",
        box_mid: "┬",
        box_mid_box_hi_fill: "─",
        box_hi: "┐",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┬",
    },
    RowChars {
        wh_lo: "├",
        wh_lo_box_lo_fill: "─",
        box_lo: "┤",
        box_lo_box_mid_fill: " ",
        box_mid: "│",
        box_mid_box_hi_fill: " ",
        box_hi: "├",
        box_hi_wh_hi_fill: "─",
        wh_hi: "┤",
    },
    RowChars {
        wh_lo: "┴",
        wh_lo_box_lo_fill: " ",
        box_lo: "└",
        box_lo_box_mid_fill: "─",
        box_mid: "┴",
        box_mid_box_hi_fill: "─",
        box_hi: "┘",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┴",
    },
);

fn make_row(width: usize) -> Vec<String> {
    use std::iter::repeat;

    let mut row = vec![];
    row.extend(repeat(String::from("")).take(width));

    row
}

struct Plot(Vec<String>, Vec<String>, Vec<String>);

impl Plot {
    fn new(width: usize) -> Self {
        Plot(make_row(width), make_row(width), make_row(width))
    }

    fn render(&self) -> String {
        let rows = vec![
            self.0.join(""),
            self.1.join(""),
            self.2.join(""),
        ];

        rows.join("\n")
    }
}

pub fn ascii_summary_plot(summary: &Summary, width: usize) -> String {
    ASCII_CHARS.plot(summary, width)
}

pub fn summary_plot(summary: &Summary, width: usize) -> String {
    UNICODE_CHARS.plot(summary, width)
}

fn make_padding(cols: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(String::from(" ")).take(cols))
}

fn pad(s: &String, cols: usize) -> String {
    let padding = make_padding(cols);

    let padded: Vec<String> = s
        .split("\n")
        .map(|l| format!("{}{}", padding, l))
        .collect();

    padded.join("\n")
}

pub fn comparison_plot(
    summary1: &Summary,
    summary2: &Summary,
    width: usize,
    ascii: bool,
) -> String {
    let min = summary1.min().min(summary2.min());
    let max = summary1.max().max(summary2.max());

    let range = max - min;
    let range1 = summary1.max() - summary1.min();
    let range2 = summary2.max() - summary2.min();

    let proportion1 = range1 / range;
    let proportion2 = range2 / range;

    let width1 = (proportion1 * (width as f64)).floor() as usize;
    let width2 = (proportion2 * (width as f64)).floor() as usize;

    let offset1 = {
        let neg_proportion = (summary1.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };
    let offset2 = {
        let neg_proportion = (summary2.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };

    let (plot1, plot2) = if ascii {
        let plot1 = ascii_summary_plot(&summary1, width1);
        let plot2 = ascii_summary_plot(&summary2, width2);
        (plot1, plot2)
    } else {
        let plot1 = summary_plot(&summary1, width1);
        let plot2 = summary_plot(&summary2, width2);
        (plot1, plot2)
    };

    format!("{}\n{}", pad(&plot1, offset1), pad(&plot2, offset2))
}
<commit_msg>Rename structs for consistency<commit_after>use summary::Summary;

struct BoxplotData {
    box_lo: f64,
    box_mid: f64,
    box_hi: f64,
    wh_lo: f64,
    wh_hi: f64,
}

impl BoxplotData {
    fn from_summary(summary: &Summary) -> Self {
        BoxplotData {
            box_lo: summary.percentile(0.25).unwrap(),
            box_mid: summary.median(),
            box_hi: summary.percentile(0.75).unwrap(),
            wh_lo: summary.min(),
            wh_hi: summary.max(),
        }
    }
}

struct BoxplotCols {
    box_lo: usize,
    box_mid: usize,
    box_hi: usize,
    wh_lo: usize,
    wh_hi: usize,
}

impl BoxplotCols {
    fn new(data: &BoxplotData, width: usize) -> Self {
        let max_col = width - 1;
        let range = data.wh_hi - data.wh_lo;
        let normalize = |x| (x - data.wh_lo) / range;
        let scale = |x| (normalize(x) * (max_col as f64)) as f64;
        let to_col = |x| scale(x).floor() as usize;

        BoxplotCols {
            box_lo: to_col(data.box_lo),
            box_mid: to_col(data.box_mid),
            box_hi: to_col(data.box_hi),
            wh_lo: to_col(data.wh_lo),
            wh_hi: to_col(data.wh_hi),
        }
    }
}

struct RowChars {
    wh_lo: &'static str,
    wh_lo_box_lo_fill: &'static str,
    box_lo: &'static str,
    box_lo_box_mid_fill: &'static str,
    box_mid: &'static str,
    box_mid_box_hi_fill: &'static str,
    box_hi: &'static str,
    box_hi_wh_hi_fill: &'static str,
    wh_hi: &'static str,
}

impl RowChars {
    pub fn render(&self, row: &mut Vec<String>, cols: &BoxplotCols) {
        row[cols.wh_lo] = self.wh_lo.to_string();
        for i in (cols.wh_lo + 1)..cols.box_lo {
            row[i] = self.wh_lo_box_lo_fill.to_string();
        }
        row[cols.box_lo] = self.box_lo.to_string();
        for i in (cols.box_lo + 1)..cols.box_mid {
            row[i] = self.box_lo_box_mid_fill.to_string();
        }
        row[cols.box_mid] = self.box_mid.to_string();
        for i in (cols.box_mid + 1)..cols.box_hi {
            row[i] = self.box_mid_box_hi_fill.to_string();
        }
        row[cols.box_hi] = self.box_hi.to_string();
        for i in (cols.box_hi + 1)..cols.wh_hi {
            row[i] = self.box_hi_wh_hi_fill.to_string();
        }
        row[cols.wh_hi] = self.wh_hi.to_string();
    }
}

struct BoxplotChars(RowChars, RowChars, RowChars);

impl BoxplotChars {
    pub fn plot(&self, summary: &Summary, width: usize) -> String {
        let data = BoxplotData::from_summary(summary);
        let cols = BoxplotCols::new(&data, width);

        let mut plot = Plot::new(width);

        self.0.render(&mut plot.0, &cols);
        self.1.render(&mut plot.1, &cols);
        self.2.render(&mut plot.2, &cols);

        plot.render()
    }
}

static ASCII_CHARS: BoxplotChars = BoxplotChars(
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
    RowChars {
        wh_lo: "|",
        wh_lo_box_lo_fill: "-",
        box_lo: "|",
        box_lo_box_mid_fill: " ",
        box_mid: "|",
        box_mid_box_hi_fill: " ",
        box_hi: "|",
        box_hi_wh_hi_fill: "-",
        wh_hi: "|",
    },
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
);

static UNICODE_CHARS: BoxplotChars = BoxplotChars(
    RowChars {
        wh_lo: "┬",
        wh_lo_box_lo_fill: " ",
        box_lo: "┌",
        box_lo_box_mid_fill: "─",
        box_mid: "┬",
        box_mid_box_hi_fill: "─",
        box_hi: "┐",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┬",
    },
    RowChars {
        wh_lo: "├",
        wh_lo_box_lo_fill: "─",
        box_lo: "┤",
        box_lo_box_mid_fill: " ",
        box_mid: "│",
        box_mid_box_hi_fill: " ",
        box_hi: "├",
        box_hi_wh_hi_fill: "─",
        wh_hi: "┤",
    },
    RowChars {
        wh_lo: "┴",
        wh_lo_box_lo_fill: " ",
        box_lo: "└",
        box_lo_box_mid_fill: "─",
        box_mid: "┴",
        box_mid_box_hi_fill: "─",
        box_hi: "┘",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┴",
    },
);

fn make_row(width: usize) -> Vec<String> {
    use std::iter::repeat;

    let mut row = vec![];
    row.extend(repeat(String::from("")).take(width));

    row
}

struct Plot(Vec<String>, Vec<String>, Vec<String>);

impl Plot {
    fn new(width: usize) -> Self {
        Plot(make_row(width), make_row(width), make_row(width))
    }

    fn render(&self) -> String {
        let rows = vec![
            self.0.join(""),
            self.1.join(""),
            self.2.join(""),
        ];

        rows.join("\n")
    }
}

pub fn ascii_summary_plot(summary: &Summary, width: usize) -> String {
    ASCII_CHARS.plot(summary, width)
}

pub fn summary_plot(summary: &Summary, width: usize) -> String {
    UNICODE_CHARS.plot(summary, width)
}

fn make_padding(cols: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(String::from(" ")).take(cols))
}

fn pad(s: &String, cols: usize) -> String {
    let padding = make_padding(cols);

    let padded: Vec<String> = s
        .split("\n")
        .map(|l| format!("{}{}", padding, l))
        .collect();

    padded.join("\n")
}

pub fn comparison_plot(
    summary1: &Summary,
    summary2: &Summary,
    width: usize,
    ascii: bool,
) -> String {
    let min = summary1.min().min(summary2.min());
    let max = summary1.max().max(summary2.max());

    let range = max - min;
    let range1 = summary1.max() - summary1.min();
    let range2 = summary2.max() - summary2.min();

    let proportion1 = range1 / range;
    let proportion2 = range2 / range;

    let width1 = (proportion1 * (width as f64)).floor() as usize;
    let width2 = (proportion2 * (width as f64)).floor() as usize;

    let offset1 = {
        let neg_proportion = (summary1.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };
    let offset2 = {
        let neg_proportion = (summary2.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };

    let (plot1, plot2) = if ascii {
        let plot1 = ascii_summary_plot(&summary1, width1);
        let plot2 = ascii_summary_plot(&summary2, width2);
        (plot1, plot2)
    } else {
        let plot1 = summary_plot(&summary1, width1);
        let plot2 = summary_plot(&summary2, width2);
        (plot1, plot2)
    };

    format!("{}\n{}", pad(&plot1, offset1), pad(&plot2, offset2))
}
<|endoftext|>


<commit_before>use database::models::{ToU64, LogChannel};

use chrono::{Utc, Duration};

use diesel::prelude::*;

use serenity::prelude::{Mutex, Mentionable};
use serenity::client::{Context, EventHandler};
use serenity::model::channel::Message;
use serenity::model::event::MessageUpdateEvent;
use serenity::model::guild::Member;
use serenity::model::id::{GuildId, ChannelId, UserId};
use serenity::model::user::User;

use std::collections::HashMap;
use std::sync::atomic::{Ordering, AtomicUsize};

macro_rules! update_message {
  ($message:expr, $update:expr, $($field:ident),+) => {{
    $(
      if let Some(f) = $update.$field {
        $message.$field = f;
      }
    )+
  }}
}

#[derive(Default)]
pub struct Log {
  messages: Mutex<HashMap<UserId, HashMap<GuildId, Vec<Message>>>>,
  count: AtomicUsize
}

impl Log {
  fn get_log_channel<G: Into<GuildId>>(&self, guild: G) -> Option<ChannelId> {
    let log_channel: Option<LogChannel> = ::bot::CONNECTION.with(|c| {
      use database::schema::log_channels::dsl;
      dsl::log_channels.filter(dsl::server_id.eq(guild.into().to_u64()))
        .first(c)
        .ok()
    });
    log_channel.map(|x| ChannelId(*x.channel_id))
  }

  fn prune_messages(&self) {
    let now = Utc::now();
    let one_day = Duration::days(1);
    self.messages
      .lock()
      .values_mut()
      .flat_map(|x| x.values_mut())
      .for_each(|x| x.retain(|m| m.timestamp.signed_duration_since(now) < one_day));
  }
}

impl EventHandler for Log {
  fn guild_member_removal(&self, _: Context, guild: GuildId, user: User, member: Option<Member>) {
    let channel_id = some_or!(self.get_log_channel(guild), return);
    let mention = member.as_ref().map(|x| x.mention()).unwrap_or_else(|| user.mention());
    channel_id.send_message(|m| m.embed(|mut embed| {
      embed = embed
        .author(|a| a
          .name(&user.tag())
          .icon_url(&user.face()));
      if let Some(member) = member {
        embed = embed.field("Display name", member.display_name(), true);
      }
      embed = embed
        .field("Mention", mention, true)
        .field("Action", "Leave server", true)
        .timestamp(&Utc::now());
      embed
    })).ok();
  }

  fn guild_member_addition(&self, _: Context, guild: GuildId, member: Member) {
    let channel_id = some_or!(self.get_log_channel(guild), return);
    channel_id.send_message(|m| m.embed(|mut embed| {
      embed = embed
        .author(|a| a
          .name(&member.user.read().tag())
          .icon_url(&member.user.read().face()));
      embed = embed
        .field("Mention", member.mention(), true)
        .field("Action", "Join server", true)
        .timestamp(&Utc::now());
      embed
    })).ok();
  }

  fn message_update(&self, _: Context, update: MessageUpdateEvent) {
    let author = match update.author {
      Some(ref a) => a,
      None => return
    };
    let new_content = match update.content {
      Some(ref c) => c,
      None => return
    };

    let channel = match update.channel_id.get() {
      Ok(c) => c,
      Err(e) => {
        warn!("could not download channel {} for message history: {}", update.channel_id, e);
        return;
      }
    };

    let guild_channel = match channel.guild() {
      Some(g) => g,
      None => return
    };
    let reader = guild_channel.read();

    let channel_id = some_or!(self.get_log_channel(reader.guild_id), return);

    let guild = match reader.guild_id.find() {
      Some(g) => g,
      None => return
    };
    let guild_reader = guild.read();

    let member = match guild_reader.members.get(&author.id).cloned().or_else(|| guild_reader.member(author.id).ok()) {
      Some(m) => m,
      None => return
    };

    let mut messages = self.messages.lock();
    let message = messages
      .get_mut(&author.id)
      .and_then(|x| x.get_mut(&reader.guild_id))
      .and_then(|x| x.iter_mut().find(|m| m.id == update.id));
    let message = match message {
      Some(m) => m,
      None => return
    };

    let original_content = message.content.clone();
    let channel_mention = update.channel_id.mention();
    let message_id = update.id;

    update_message!(
      message,
      update,
      kind, content, tts, pinned, timestamp, author, mention_everyone, mentions, mention_roles,
      attachments
    );
    message.edited_timestamp = update.edited_timestamp;

    channel_id.send_message(|m| m.embed(|mut embed| {
      embed = embed
        .author(|a| a
          .name(&member.user.read().tag())
          .icon_url(&member.user.read().face()));
      embed = embed
        .field("Mention", member.mention(), true)
        .field("Action", "Edited message", true)
        .field("Channel", channel_mention, true)
        .field("Original message", original_content, false)
        .field("New message", new_content, false)
        .timestamp(&Utc::now())
        .footer(|f| f.text(message_id));
      embed
    })).ok();
  }

  fn message(&self, _: Context, message: Message) {
    if self.count.load(Ordering::SeqCst) == 100 {
      self.count.store(0, Ordering::SeqCst);

      self.prune_messages();
    }

    let channel = match message.channel_id.get() {
      Ok(c) => c,
      Err(e) => {
        warn!("could not download channel {} for message history: {}", message.channel_id, e);
        return;
      }
    };

    let guild_channel = match channel.guild() {
      Some(g) => g,
      None => return
    };

    let reader = guild_channel.read();

    self.messages
      .lock()
      .entry(message.author.id)
      .or_default()
      .entry(reader.guild_id)
      .or_default()
      .push(message);

    self.count.fetch_add(1, Ordering::SeqCst);
  }
}
<commit_msg>feat: include user IDs in footers<commit_after>use database::models::{ToU64, LogChannel};

use chrono::{Utc, Duration};

use diesel::prelude::*;

use serenity::prelude::{Mutex, Mentionable};
use serenity::client::{Context, EventHandler};
use serenity::model::channel::Message;
use serenity::model::event::MessageUpdateEvent;
use serenity::model::guild::Member;
use serenity::model::id::{GuildId, ChannelId, UserId};
use serenity::model::user::User;

use std::collections::HashMap;
use std::sync::atomic::{Ordering, AtomicUsize};

macro_rules! update_message {
  ($message:expr, $update:expr, $($field:ident),+) => {{
    $(
      if let Some(f) = $update.$field {
        $message.$field = f;
      }
    )+
  }}
}

#[derive(Default)]
pub struct Log {
  messages: Mutex<HashMap<UserId, HashMap<GuildId, Vec<Message>>>>,
  count: AtomicUsize
}

impl Log {
  fn get_log_channel<G: Into<GuildId>>(&self, guild: G) -> Option<ChannelId> {
    let log_channel: Option<LogChannel> = ::bot::CONNECTION.with(|c| {
      use database::schema::log_channels::dsl;
      dsl::log_channels.filter(dsl::server_id.eq(guild.into().to_u64()))
        .first(c)
        .ok()
    });
    log_channel.map(|x| ChannelId(*x.channel_id))
  }

  fn prune_messages(&self) {
    let now = Utc::now();
    let one_day = Duration::days(1);
    self.messages
      .lock()
      .values_mut()
      .flat_map(|x| x.values_mut())
      .for_each(|x| x.retain(|m| m.timestamp.signed_duration_since(now) < one_day));
  }
}

impl EventHandler for Log {
  fn guild_member_removal(&self, _: Context, guild: GuildId, user: User, member: Option<Member>) {
    let channel_id = some_or!(self.get_log_channel(guild), return);
    let mention = member.as_ref().map(|x| x.mention()).unwrap_or_else(|| user.mention());
    channel_id.send_message(|m| m.embed(|mut embed| {
      embed = embed
        .author(|a| a
          .name(&user.tag())
          .icon_url(&user.face()));
      if let Some(member) = member {
        embed = embed.field("Display name", member.display_name(), true);
      }
      embed = embed
        .field("Mention", mention, true)
        .field("Action", "Leave server", true)
        .timestamp(&Utc::now())
        .footer(|f| f.text(user.id));
      embed
    })).ok();
  }

  fn guild_member_addition(&self, _: Context, guild: GuildId, member: Member) {
    let channel_id = some_or!(self.get_log_channel(guild), return);
    channel_id.send_message(|m| m.embed(|mut embed| {
      embed = embed
        .author(|a| a
          .name(&member.user.read().tag())
          .icon_url(&member.user.read().face()));
      embed = embed
        .field("Mention", member.mention(), true)
        .field("Action", "Join server", true)
        .timestamp(&Utc::now())
        .footer(|f| f.text(member.user.read().id));
      embed
    })).ok();
  }

  fn message_update(&self, _: Context, update: MessageUpdateEvent) {
    let author = match update.author {
      Some(ref a) => a,
      None => return
    };
    let new_content = match update.content {
      Some(ref c) => c,
      None => return
    };

    let channel = match update.channel_id.get() {
      Ok(c) => c,
      Err(e) => {
        warn!("could not download channel {} for message history: {}", update.channel_id, e);
        return;
      }
    };

    let guild_channel = match channel.guild() {
      Some(g) => g,
      None => return
    };
    let reader = guild_channel.read();

    let channel_id = some_or!(self.get_log_channel(reader.guild_id), return);

    let guild = match reader.guild_id.find() {
      Some(g) => g,
      None => return
    };
    let guild_reader = guild.read();

    let member = match guild_reader.members.get(&author.id).cloned().or_else(|| guild_reader.member(author.id).ok()) {
      Some(m) => m,
      None => return
    };

    let mut messages = self.messages.lock();
    let message = messages
      .get_mut(&author.id)
      .and_then(|x| x.get_mut(&reader.guild_id))
      .and_then(|x| x.iter_mut().find(|m| m.id == update.id));
    let message = match message {
      Some(m) => m,
      None => return
    };

    let original_content = message.content.clone();
    let channel_mention = update.channel_id.mention();
    let message_id = update.id;

    update_message!(
      message,
      update,
      kind, content, tts, pinned, timestamp, author, mention_everyone, mentions, mention_roles,
      attachments
    );
    message.edited_timestamp = update.edited_timestamp;

    channel_id.send_message(|m| m.embed(|mut embed| {
      embed = embed
        .author(|a| a
          .name(&member.user.read().tag())
          .icon_url(&member.user.read().face()));
      embed = embed
        .field("Mention", member.mention(), true)
        .field("Action", "Edited message", true)
        .field("Channel", channel_mention, true)
        .field("Original message", original_content, false)
        .field("New message", new_content, false)
        .timestamp(&Utc::now())
        .footer(|f| f.text(message_id));
      embed
    })).ok();
  }

  fn message(&self, _: Context, message: Message) {
    if self.count.load(Ordering::SeqCst) == 100 {
      self.count.store(0, Ordering::SeqCst);

      self.prune_messages();
    }

    let channel = match message.channel_id.get() {
      Ok(c) => c,
      Err(e) => {
        warn!("could not download channel {} for message history: {}", message.channel_id, e);
        return;
      }
    };

    let guild_channel = match channel.guild() {
      Some(g) => g,
      None => return
    };

    let reader = guild_channel.read();

    self.messages
      .lock()
      .entry(message.author.id)
      .or_default()
      .entry(reader.guild_id)
      .or_default()
      .push(message);

    self.count.fetch_add(1, Ordering::SeqCst);
  }
}
<|endoftext|>


<commit_before>use bytes::{BytesMut, BufMut};
use futures::future;
use std::fmt::Write;

use ZapResult;

/// The result of an outgoing request
pub struct Response {
    headers: BytesMut,
    response: BytesMut,
    status: usize,
}

impl Response {
    // Create a new default response
    pub fn new() -> Response {
        Response {
            headers: BytesMut::new(),
            response: BytesMut::new(),
            status: 200,
        }
    }

    /// Set the status code
    pub fn status(&mut self, code: usize) -> &mut Response {
        self.status = code;
        self
    }

    /// Set a header with value
    pub fn header(&mut self, name: &str, val: &str) -> &mut Response {
        // Encode new header and write it to buffer
        push(&mut self.headers, name.as_bytes());
        push(&mut self.headers, b": ");
        push(&mut self.headers, val.as_bytes());
        push(&mut self.headers, b"\r\n");

        self
    }

    /// Set the response body
    pub fn body(&mut self, s: &str) -> &mut Response {
        self.response.write_str(s).unwrap();
        self
    }

    /// Write raw data to the body
    pub fn body_raw(&mut self, s: &[u8]) -> &mut Response {
        push(&mut self.response, s);
        self
    }

    // Finish the request
    pub fn ok(self) -> ZapResult {
        future::ok(self)
    }
}

/// Encode our response to a buffer
pub fn encode(msg: &Response, buf: &mut BytesMut) {
    // Get the content length
    let length = msg.response.len();

    // Encode the data
    push(buf, b"HTTP/1.1 ");
    push(buf, &usize_to_bytes(msg.status));
    push(buf, b"\r\nContent-Length: ");
    push(buf, &usize_to_bytes(length));
    push(buf, b"\r\n");
    push(buf, msg.headers.as_ref());

    push(buf, b"\r\n");
    push(buf, msg.response.as_ref());
}

// Push bytes to a buffer
fn push(buf: &mut BytesMut, data: &[u8]) {
    // Alloc new space
    buf.reserve(data.len());

    unsafe {
        // Put the data in the reserved space
        buf.bytes_mut()[..data.len()].copy_from_slice(data);
        buf.advance_mut(data.len());
    }
}

// Convert a usize to raw data without strings
fn usize_to_bytes(s : usize) -> [u8; 4] {
    // Define varibales we need
    let mut data : [u8; 4] = [0; 4];
    let mut length = s as u32;

    // Convert u16 to ASCII bytes
    for i in 1..5 {
        let base = (10u16.pow(4 - (i as u32))) as u32;
        data[i - 1] = 48 + (&length / &base) as u8;
        length = (&length % &base) as u32;
    }

    return data;
}
<commit_msg>Valid response<commit_after>use bytes::{BytesMut, BufMut};
use futures::future;
use std::fmt::Write;

use ZapResult;

/// The result of an outgoing request
pub struct Response {
    headers: BytesMut,
    response: BytesMut,
    status: usize,
}

impl Response {
    // Create a new default response
    pub fn new() -> Response {
        Response {
            headers: BytesMut::new(),
            response: BytesMut::new(),
            status: 200,
        }
    }

    /// Set the status code
    pub fn status(&mut self, code: usize) -> &mut Response {
        self.status = code;
        self
    }

    /// Set a header with value
    pub fn header(&mut self, name: &str, val: &str) -> &mut Response {
        // Encode new header and write it to buffer
        push(&mut self.headers, name.as_bytes());
        push(&mut self.headers, b": ");
        push(&mut self.headers, val.as_bytes());
        push(&mut self.headers, b"\r\n");

        self
    }

    /// Set the response body
    pub fn body(&mut self, s: &str) -> &mut Response {
        self.response.write_str(s).unwrap();
        self
    }

    /// Write raw data to the body
    pub fn body_raw(&mut self, s: &[u8]) -> &mut Response {
        push(&mut self.response, s);
        self
    }

    // Finish the request
    pub fn ok(self) -> ZapResult {
        future::ok(self)
    }
}

/// Encode our response to a buffer
pub fn encode(msg: &Response, buf: &mut BytesMut) {
    // Get the content length
    let length = msg.response.len();

    // Encode the data
    push(buf, b"HTTP/1.1 ");
    push(buf, usize_to_bytes(msg.status).as_ref());
    push(buf, b"\r\nContent-Length: ");
    push(buf, usize_to_bytes(length).as_ref());
    push(buf, b"\r\n");
    push(buf, msg.headers.as_ref());

    push(buf, b"\r\n");
    push(buf, msg.response.as_ref());
}

// Push bytes to a buffer
fn push(buf: &mut BytesMut, data: &[u8]) {
    // Alloc new space
    buf.reserve(data.len());

    unsafe {
        // Put the data in the reserved space
        buf.bytes_mut()[..data.len()].copy_from_slice(data);
        buf.advance_mut(data.len());
    }
}

// Convert a usize to raw data without strings
fn usize_to_bytes(s : usize) -> BytesMut {
    // Define varibales we need
    let mut data : BytesMut = BytesMut::new();
    let mut length = s as u32;

    // Convert u16 to ASCII bytes
    let mut addZero = false;
    for i in 1..5 {
        let base = (10u16.pow(4 - (i as u32))) as u32;

        // Calculate ascii decimal
        let c = 48 + (&length / &base) as u8;

        // Add byte
        if c == 48 && addZero {
            data.put_u8(c);
        } else if c != 48 {
            if !addZero {
                addZero = true;
            }

            data.put_u8(c);
        }

        // New length
        length = (&length % &base) as u32;
    }

    return data;
}
<|endoftext|>