<commit_before>//! Synchronized types that allow access to a `Histogram` from multiple threads.

use crate::errors::*;
use crate::{Counter, Histogram};
use std::borrow::Borrow;
use std::ops::{AddAssign, Deref, DerefMut};
use std::sync::{atomic, Arc, Condvar, Mutex};
use std::time;

/// A write-only handle to a [`SyncHistogram`].
///
/// This handle allows you to record samples from multiple threads, each with its own `Recorder`,
/// concurrently. Writes to a `Recorder` are wait-free and scalable except for when the
/// [`SyncHistogram`] initiates a _phase shift_. During a phase shift, the next write on each
/// associated `Recorder` merges its results into a shared [`Histogram`] that is then made
/// available to the [`SyncHistogram`] once the phase shift completes.
///
/// An idle `Recorder` will hold up a phase shift indefinitely, or until it times out (is using
/// [`SyncHistogram::phase_timeout`]. If a `Recorder` will remain idle for extended periods of
/// time, it should call [`Recorder::idle`], which will tell the reader not to wait for this
/// particular writer.
///
/// If a `Recorder` is dropped, any samples not seen by the latest call to [`SyncHistogram::phase`]
/// are lost. If you wish to ensure that _all_ samples are communicated to the reader, use
/// [`Recorder::synchronize`].
#[derive(Debug)]
pub struct Recorder<C: Counter> {
    local: Histogram<C>,
    shared: Arc<Shared<C>>,
    last_phase: usize,
}

// make it more ergonomic to record samples
impl<C: Counter> AddAssign<u64> for Recorder<C> {
    fn add_assign(&mut self, value: u64) {
        self.record(value).unwrap();
    }
}

impl<C: Counter> Clone for Recorder<C> {
    fn clone(&self) -> Self {
        // reader will have to wait for one more recorder
        {
            let mut truth = self.shared.truth.lock().unwrap();
            truth.recorders += 1;
        }

        // new recorder should start with an empty histogram
        let mut h = self.local.clone();
        h.clear();

        // new recorder starts at the same phase as we do
        Recorder {
            local: h,
            shared: self.shared.clone(),
            last_phase: self.last_phase,
        }
    }
}

impl<C: Counter> Drop for Recorder<C> {
    fn drop(&mut self) {
        // we'll need to decrement the # of recorders
        {
            let mut truth = self.shared.truth.lock().unwrap();
            truth.recorders -= 1;

            // we have to be careful; we _may_ already have incremented for the ongoing phase!
            if truth.phased != 0 {
                // note that we _have_ to do this load under the lock, otherwise a reader may
                // increment the phase after we read, and before we take the lock above!
                let phase = self.shared.phase.load(atomic::Ordering::Acquire);
                if phase == self.last_phase {
                    // we contributed to the current phased value -- undo that
                    truth.phased -= 1;
                }
            }

            // by decrementing, we _may_ also finish the phase
            if truth.recorders == truth.phased {
                self.shared.all_phased.notify_one();
            }
        }
    }
}

#[derive(Debug)]
struct Critical<C: Counter> {
    /// Will be Some whenever the Histogram is in the process of being phased.
    merged: Option<Histogram<C>>,
    recorders: usize,
    phased: usize,
}

#[derive(Debug)]
struct Shared<C: Counter> {
    truth: Mutex<Critical<C>>,
    all_phased: Condvar,
    phase_change: Condvar,
    phase: atomic::AtomicUsize,
}

/// This guard denotes that a [`Recorder`] is currently idle, and should not be waited on by a
/// [`SyncHistogram`] phase-shift.
pub struct IdleRecorderGuard<'a, C: Counter>(&'a mut Recorder<C>);

impl<'a, C: Counter> Drop for IdleRecorderGuard<'a, C> {
    fn drop(&mut self) {
        let mut phased = false;
        // the Recorder is no longer idle, so the reader has to wait for us again
        // this basically means re-incrementing .recorders
        {
            let mut crit = self.0.shared.truth.lock().unwrap();
            crit.recorders += 1;

            // if there's a phase shift ongoing, we need to take part in that
            if let Some(ref mut h) = crit.merged {
                if !self.0.local.is_empty() {
                    h.add(&self.0.local)
                        .expect("TODO: failed to merge histogram");
                    phased = true;
                }
                crit.phased += 1;
            }

            // we are now up-to-date with the current phase
            // NOTE: we have to load this during the lock so we don't read too early/late
            self.0.last_phase = self.0.shared.phase.load(atomic::Ordering::Acquire);

            // NOTE: we cannot have finished the phase, since it cannot have been waiting for us.
        }

        // if we phase shifted, clear the changes we just merged
        if phased {
            self.0.local.clear();
        }
    }
}

impl<C: Counter> Recorder<C> {
    fn with_hist<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Histogram<C>) -> R,
    {
        let r = f(&mut self.local);
        let phase = self.shared.phase.load(atomic::Ordering::Acquire);
        if phase != self.last_phase {
            {
                let mut crit = self.shared.truth.lock().unwrap();
                if !self.local.is_empty() {
                    // it could be that the reader timed out, in which case we'll have to wait
                    if let Some(ref mut m) = crit.merged {
                        m.add(&self.local).expect("TODO: failed to merge histogram");
                    }
                }
                crit.phased += 1;
                if crit.phased == crit.recorders {
                    self.shared.all_phased.notify_one();
                }
            }
            self.last_phase = phase;
            self.local.clear();
        }
        r
    }

    /// Call this method if the Recorder will be idle for a while.
    ///
    /// Until the returned guard is dropped, the associated [`SyncHistogram`] will not wait for
    /// this recorder on a phase shift.
    pub fn idle(&mut self) -> IdleRecorderGuard<C> {
        let phase;
        {
            let mut crit = self.shared.truth.lock().unwrap();
            phase = self.shared.phase.load(atomic::Ordering::Acquire);
            if phase != self.last_phase {
                // if we happen to be in a phase shift, sync our outstanding changes
                if !self.local.is_empty() {
                    if let Some(ref mut m) = crit.merged {
                        m.add(&self.local).expect("TODO: failed to merge histogram");
                    }
                }
            // NOTE; we do _not_ increment .phased, since we're about to decrement .recorders
            } else if crit.phased != 0 {
                // we must have already performed this phase shift, and so .phased includes our +1
                // since we're about to decrement .recorders, we need to also undo that
                crit.phased -= 1;
            }

            // make the reader no longer wait for us
            crit.recorders -= 1;

            // we may have just finished the phase!
            if crit.phased == crit.recorders {
                self.shared.all_phased.notify_one();
            }
        }

        // if we phase shifted, clear the changes we just merged
        if phase != self.last_phase {
            self.last_phase = phase;
            self.local.clear();
        }

        IdleRecorderGuard(self)
    }

    /// This blocking call will return only once any locally-held samples have been made visible to
    /// the reader (the associated [`SyncHistogram`]).
    ///
    /// You may wish to call this before a `Recorder` goes out of scope to ensure that none of its
    /// samples are lost.
    pub fn synchronize(&mut self) {
        if self.local.is_empty() {
            return;
        }

        {
            let mut crit = self.shared.truth.lock().unwrap();
            loop {
                if let Some(ref mut m) = crit.merged {
                    m.add(&self.local).expect("TODO: failed to merge histogram");

                    // NOTE: we _may_ still be in a phase we've already synchronized;
                    // we should only bump .phased if we haven't already!
                    let phase = self.shared.phase.load(atomic::Ordering::Acquire);
                    if phase != self.last_phase {
                        crit.phased += 1;
                        self.last_phase = phase;
                    }
                    break;
                }
                crit = self.shared.phase_change.wait(crit).unwrap();
            }
        }
        self.local.clear();
    }

    /// See [`Histogram::add`].
    pub fn add<B: Borrow<Histogram<C>>>(&mut self, source: B) -> Result<(), AdditionError> {
        self.with_hist(move |h| h.add(source))
    }

    /// See [`Histogram::add_correct`].
    pub fn add_correct<B: Borrow<Histogram<C>>>(
        &mut self,
        source: B,
        interval: u64,
    ) -> Result<(), RecordError> {
        self.with_hist(move |h| h.add_correct(source, interval))
    }

    /// See [`Histogram::subtract`].
    pub fn subtract<B: Borrow<Histogram<C>>>(
        &mut self,
        subtrahend: B,
    ) -> Result<(), SubtractionError> {
        self.with_hist(move |h| h.subtract(subtrahend))
    }

    /// See [`Histogram::record`].
    pub fn record(&mut self, value: u64) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record(value))
    }

    /// See [`Histogram::saturating_record`].
    pub fn saturating_record(&mut self, value: u64) {
        self.with_hist(move |h| h.saturating_record(value))
    }

    /// See [`Histogram::record_n`].
    pub fn record_n(&mut self, value: u64, count: C) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record_n(value, count))
    }

    /// See [`Histogram::saturating_record_n`].
    pub fn saturating_record_n(&mut self, value: u64, count: C) {
        self.with_hist(move |h| h.saturating_record_n(value, count))
    }

    /// See [`Histogram::record_correct`].
    pub fn record_correct(&mut self, value: u64, interval: u64) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record_correct(value, interval))
    }

    /// See [`Histogram::record_n_correct`].
    pub fn record_n_correct(
        &mut self,
        value: u64,
        count: C,
        interval: u64,
    ) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record_n_correct(value, count, interval))
    }
}

/// A `Histogram` that can be written to by multiple threads concurrently.
///
/// Each writer thread should have a [`Recorder`], which allows it to record new samples without
/// synchronization. New recorded samples are made available through this histogram by calling
/// [`phase`], which blocks until it has synchronized with every recorder.
pub struct SyncHistogram<C: Counter> {
    /// Will be None during a phase shift.
    merged: Option<Histogram<C>>,
    shared: Arc<Shared<C>>,
}

impl<C: Counter> SyncHistogram<C> {
    fn phase_inner(&mut self, timeout: Option<time::Duration>) {
        let end = timeout.map(|dur| time::Instant::now() + dur);

        // time to start a phase change
        let mut truth = self.shared.truth.lock().unwrap();

        // provide histogram for writers to merge into
        truth.merged = self.merged.take();
        assert_eq!(truth.phased, 0);

        // tell writers to phase
        let _ = self.shared.phase.fetch_add(1, atomic::Ordering::AcqRel);

        // wait for writers to all have phased
        while truth.phased != truth.recorders {
            if let Some(end) = end {
                let now = time::Instant::now();
                if now > end {
                    truth = self.shared.truth.lock().unwrap();
                    break;
                }

                let (t, wtr) = self
                    .shared
                    .all_phased
                    .wait_timeout(truth, end - now)
                    .unwrap();
                truth = t;
                if wtr.timed_out() {
                    break;
                }
            } else {
                truth = self.shared.all_phased.wait(truth).unwrap();
            }
        }

        // take the merged histogram back out
        self.merged = truth.merged.take();

        // reset for next phase
        truth.phased = 0;

        self.shared.phase_change.notify_all();
    }

    /// Block until writes from all [`Recorder`] instances for this histogram have been
    /// incorporated.
    pub fn phase(&mut self) {
        self.phase_inner(None)
    }

    /// Block until writes from all [`Recorder`] instances for this histogram have been
    /// incorporated, or until the given amount of time has passed.
    pub fn phase_timeout(&mut self, timeout: time::Duration) {
        self.phase_inner(Some(timeout))
    }

    /// Obtain another multi-threaded writer for this histogram.
    ///
    /// Note that writes made to the `Recorder` will not be visible until the next call to
    /// [`phase`].
    pub fn recorder(&self) -> Recorder<C> {
        // we will have to wait for one more recorder
        {
            let mut truth = self.shared.truth.lock().unwrap();
            truth.recorders += 1;
        }

        // new recorder should start with an empty histogram
        let mut h = self
            .merged
            .as_ref()
            .expect("local histogram None outside phase shift")
            .clone();
        h.clear();

        // new recorder starts at the current phase
        Recorder {
            local: h,
            shared: self.shared.clone(),
            last_phase: self.shared.phase.load(atomic::Ordering::Acquire),
        }
    }
}

impl<C: Counter> From<Histogram<C>> for SyncHistogram<C> {
    fn from(h: Histogram<C>) -> Self {
        SyncHistogram {
            merged: Some(h),
            shared: Arc::new(Shared {
                truth: Mutex::new(Critical {
                    merged: None,
                    recorders: 0,
                    phased: 0,
                }),
                all_phased: Condvar::new(),
                phase_change: Condvar::new(),
                phase: atomic::AtomicUsize::new(0),
            }),
        }
    }
}

impl<C: Counter> Deref for SyncHistogram<C> {
    type Target = Histogram<C>;
    fn deref(&self) -> &Self::Target {
        self.merged
            .as_ref()
            .expect("local histogram None outside phase shift")
    }
}

impl<C: Counter> DerefMut for SyncHistogram<C> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.merged
            .as_mut()
            .expect("local histogram None outside phase shift")
    }
}
<commit_msg>Add missing notifys<commit_after>//! Synchronized types that allow access to a `Histogram` from multiple threads.

use crate::errors::*;
use crate::{Counter, Histogram};
use std::borrow::Borrow;
use std::ops::{AddAssign, Deref, DerefMut};
use std::sync::{atomic, Arc, Condvar, Mutex};
use std::time;

/// A write-only handle to a [`SyncHistogram`].
///
/// This handle allows you to record samples from multiple threads, each with its own `Recorder`,
/// concurrently. Writes to a `Recorder` are wait-free and scalable except for when the
/// [`SyncHistogram`] initiates a _phase shift_. During a phase shift, the next write on each
/// associated `Recorder` merges its results into a shared [`Histogram`] that is then made
/// available to the [`SyncHistogram`] once the phase shift completes.
///
/// An idle `Recorder` will hold up a phase shift indefinitely, or until it times out (is using
/// [`SyncHistogram::phase_timeout`]. If a `Recorder` will remain idle for extended periods of
/// time, it should call [`Recorder::idle`], which will tell the reader not to wait for this
/// particular writer.
///
/// If a `Recorder` is dropped, any samples not seen by the latest call to [`SyncHistogram::phase`]
/// are lost. If you wish to ensure that _all_ samples are communicated to the reader, use
/// [`Recorder::synchronize`].
#[derive(Debug)]
pub struct Recorder<C: Counter> {
    local: Histogram<C>,
    shared: Arc<Shared<C>>,
    last_phase: usize,
}

// make it more ergonomic to record samples
impl<C: Counter> AddAssign<u64> for Recorder<C> {
    fn add_assign(&mut self, value: u64) {
        self.record(value).unwrap();
    }
}

impl<C: Counter> Clone for Recorder<C> {
    fn clone(&self) -> Self {
        // reader will have to wait for one more recorder
        {
            let mut truth = self.shared.truth.lock().unwrap();
            truth.recorders += 1;
        }

        // new recorder should start with an empty histogram
        let mut h = self.local.clone();
        h.clear();

        // new recorder starts at the same phase as we do
        Recorder {
            local: h,
            shared: self.shared.clone(),
            last_phase: self.last_phase,
        }
    }
}

impl<C: Counter> Drop for Recorder<C> {
    fn drop(&mut self) {
        // we'll need to decrement the # of recorders
        {
            let mut truth = self.shared.truth.lock().unwrap();
            truth.recorders -= 1;

            // we have to be careful; we _may_ already have incremented for the ongoing phase!
            if truth.phased != 0 {
                // note that we _have_ to do this load under the lock, otherwise a reader may
                // increment the phase after we read, and before we take the lock above!
                let phase = self.shared.phase.load(atomic::Ordering::Acquire);
                if phase == self.last_phase {
                    // we contributed to the current phased value -- undo that
                    truth.phased -= 1;
                }
            }

            // by decrementing, we _may_ also finish the phase
            if truth.recorders == truth.phased {
                self.shared.all_phased.notify_one();
            }
        }
    }
}

#[derive(Debug)]
struct Critical<C: Counter> {
    /// Will be Some whenever the Histogram is in the process of being phased.
    merged: Option<Histogram<C>>,
    recorders: usize,
    phased: usize,
}

#[derive(Debug)]
struct Shared<C: Counter> {
    truth: Mutex<Critical<C>>,
    all_phased: Condvar,
    phase_change: Condvar,
    phase: atomic::AtomicUsize,
}

/// This guard denotes that a [`Recorder`] is currently idle, and should not be waited on by a
/// [`SyncHistogram`] phase-shift.
pub struct IdleRecorderGuard<'a, C: Counter>(&'a mut Recorder<C>);

impl<'a, C: Counter> Drop for IdleRecorderGuard<'a, C> {
    fn drop(&mut self) {
        let mut phased = false;
        // the Recorder is no longer idle, so the reader has to wait for us again
        // this basically means re-incrementing .recorders
        {
            let mut crit = self.0.shared.truth.lock().unwrap();
            crit.recorders += 1;

            // if there's a phase shift ongoing, we need to take part in that
            if let Some(ref mut h) = crit.merged {
                if !self.0.local.is_empty() {
                    h.add(&self.0.local)
                        .expect("TODO: failed to merge histogram");
                    phased = true;
                }
                crit.phased += 1;
            }

            // we are now up-to-date with the current phase
            // NOTE: we have to load this during the lock so we don't read too early/late
            self.0.last_phase = self.0.shared.phase.load(atomic::Ordering::Acquire);

            // NOTE: we cannot have finished the phase, since it cannot have been waiting for us.
        }

        // if we phase shifted, clear the changes we just merged
        if phased {
            self.0.local.clear();
        }
    }
}

impl<C: Counter> Recorder<C> {
    fn with_hist<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Histogram<C>) -> R,
    {
        let r = f(&mut self.local);
        let phase = self.shared.phase.load(atomic::Ordering::Acquire);
        if phase != self.last_phase {
            {
                let mut crit = self.shared.truth.lock().unwrap();
                if !self.local.is_empty() {
                    // it could be that the reader timed out, in which case we'll have to wait
                    if let Some(ref mut m) = crit.merged {
                        m.add(&self.local).expect("TODO: failed to merge histogram");
                    }
                }
                crit.phased += 1;
                if crit.phased == crit.recorders {
                    self.shared.all_phased.notify_one();
                }
            }
            self.last_phase = phase;
            self.local.clear();
        }
        r
    }

    /// Call this method if the Recorder will be idle for a while.
    ///
    /// Until the returned guard is dropped, the associated [`SyncHistogram`] will not wait for
    /// this recorder on a phase shift.
    pub fn idle(&mut self) -> IdleRecorderGuard<C> {
        let phase;
        {
            let mut crit = self.shared.truth.lock().unwrap();
            phase = self.shared.phase.load(atomic::Ordering::Acquire);
            if phase != self.last_phase {
                // if we happen to be in a phase shift, sync our outstanding changes
                if !self.local.is_empty() {
                    if let Some(ref mut m) = crit.merged {
                        m.add(&self.local).expect("TODO: failed to merge histogram");
                    }
                }
            // NOTE; we do _not_ increment .phased, since we're about to decrement .recorders
            } else if crit.phased != 0 {
                // we must have already performed this phase shift, and so .phased includes our +1
                // since we're about to decrement .recorders, we need to also undo that
                crit.phased -= 1;
            }

            // make the reader no longer wait for us
            crit.recorders -= 1;

            // we may have just finished the phase!
            if crit.phased == crit.recorders {
                self.shared.all_phased.notify_one();
            }
        }

        // if we phase shifted, clear the changes we just merged
        if phase != self.last_phase {
            self.last_phase = phase;
            self.local.clear();
        }

        IdleRecorderGuard(self)
    }

    /// This blocking call will return only once any locally-held samples have been made visible to
    /// the reader (the associated [`SyncHistogram`]).
    ///
    /// You may wish to call this before a `Recorder` goes out of scope to ensure that none of its
    /// samples are lost.
    pub fn synchronize(&mut self) {
        if self.local.is_empty() {
            return;
        }

        {
            let mut crit = self.shared.truth.lock().unwrap();
            loop {
                if let Some(ref mut m) = crit.merged {
                    m.add(&self.local).expect("TODO: failed to merge histogram");

                    // NOTE: we _may_ still be in a phase we've already synchronized;
                    // we should only bump .phased if we haven't already!
                    let phase = self.shared.phase.load(atomic::Ordering::Acquire);
                    if phase != self.last_phase {
                        crit.phased += 1;
                        self.last_phase = phase;
                        if crit.phased == crit.recorders {
                            self.shared.all_phased.notify_one();
                        }
                    }
                    break;
                }
                crit = self.shared.phase_change.wait(crit).unwrap();
            }
        }
        self.local.clear();
    }

    /// See [`Histogram::add`].
    pub fn add<B: Borrow<Histogram<C>>>(&mut self, source: B) -> Result<(), AdditionError> {
        self.with_hist(move |h| h.add(source))
    }

    /// See [`Histogram::add_correct`].
    pub fn add_correct<B: Borrow<Histogram<C>>>(
        &mut self,
        source: B,
        interval: u64,
    ) -> Result<(), RecordError> {
        self.with_hist(move |h| h.add_correct(source, interval))
    }

    /// See [`Histogram::subtract`].
    pub fn subtract<B: Borrow<Histogram<C>>>(
        &mut self,
        subtrahend: B,
    ) -> Result<(), SubtractionError> {
        self.with_hist(move |h| h.subtract(subtrahend))
    }

    /// See [`Histogram::record`].
    pub fn record(&mut self, value: u64) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record(value))
    }

    /// See [`Histogram::saturating_record`].
    pub fn saturating_record(&mut self, value: u64) {
        self.with_hist(move |h| h.saturating_record(value))
    }

    /// See [`Histogram::record_n`].
    pub fn record_n(&mut self, value: u64, count: C) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record_n(value, count))
    }

    /// See [`Histogram::saturating_record_n`].
    pub fn saturating_record_n(&mut self, value: u64, count: C) {
        self.with_hist(move |h| h.saturating_record_n(value, count))
    }

    /// See [`Histogram::record_correct`].
    pub fn record_correct(&mut self, value: u64, interval: u64) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record_correct(value, interval))
    }

    /// See [`Histogram::record_n_correct`].
    pub fn record_n_correct(
        &mut self,
        value: u64,
        count: C,
        interval: u64,
    ) -> Result<(), RecordError> {
        self.with_hist(move |h| h.record_n_correct(value, count, interval))
    }
}

/// A `Histogram` that can be written to by multiple threads concurrently.
///
/// Each writer thread should have a [`Recorder`], which allows it to record new samples without
/// synchronization. New recorded samples are made available through this histogram by calling
/// [`phase`], which blocks until it has synchronized with every recorder.
pub struct SyncHistogram<C: Counter> {
    /// Will be None during a phase shift.
    merged: Option<Histogram<C>>,
    shared: Arc<Shared<C>>,
}

impl<C: Counter> SyncHistogram<C> {
    fn phase_inner(&mut self, timeout: Option<time::Duration>) {
        let end = timeout.map(|dur| time::Instant::now() + dur);

        // time to start a phase change
        let mut truth = self.shared.truth.lock().unwrap();

        // provide histogram for writers to merge into
        truth.merged = self.merged.take();
        assert_eq!(truth.phased, 0);

        // tell writers to phase
        let _ = self.shared.phase.fetch_add(1, atomic::Ordering::AcqRel);

        // wait for writers to all have phased
        while truth.phased != truth.recorders {
            if let Some(end) = end {
                let now = time::Instant::now();
                if now > end {
                    truth = self.shared.truth.lock().unwrap();
                    break;
                }

                let (t, wtr) = self
                    .shared
                    .all_phased
                    .wait_timeout(truth, end - now)
                    .unwrap();
                truth = t;
                if wtr.timed_out() {
                    break;
                }
            } else {
                self.shared.phase_change.notify_all();
                truth = self.shared.all_phased.wait(truth).unwrap();
            }
        }

        // take the merged histogram back out
        self.merged = truth.merged.take();

        // reset for next phase
        truth.phased = 0;

        self.shared.phase_change.notify_all();
    }

    /// Block until writes from all [`Recorder`] instances for this histogram have been
    /// incorporated.
    pub fn phase(&mut self) {
        self.phase_inner(None)
    }

    /// Block until writes from all [`Recorder`] instances for this histogram have been
    /// incorporated, or until the given amount of time has passed.
    pub fn phase_timeout(&mut self, timeout: time::Duration) {
        self.phase_inner(Some(timeout))
    }

    /// Obtain another multi-threaded writer for this histogram.
    ///
    /// Note that writes made to the `Recorder` will not be visible until the next call to
    /// [`phase`].
    pub fn recorder(&self) -> Recorder<C> {
        // we will have to wait for one more recorder
        {
            let mut truth = self.shared.truth.lock().unwrap();
            truth.recorders += 1;
        }

        // new recorder should start with an empty histogram
        let mut h = self
            .merged
            .as_ref()
            .expect("local histogram None outside phase shift")
            .clone();
        h.clear();

        // new recorder starts at the current phase
        Recorder {
            local: h,
            shared: self.shared.clone(),
            last_phase: self.shared.phase.load(atomic::Ordering::Acquire),
        }
    }
}

impl<C: Counter> From<Histogram<C>> for SyncHistogram<C> {
    fn from(h: Histogram<C>) -> Self {
        SyncHistogram {
            merged: Some(h),
            shared: Arc::new(Shared {
                truth: Mutex::new(Critical {
                    merged: None,
                    recorders: 0,
                    phased: 0,
                }),
                all_phased: Condvar::new(),
                phase_change: Condvar::new(),
                phase: atomic::AtomicUsize::new(0),
            }),
        }
    }
}

impl<C: Counter> Deref for SyncHistogram<C> {
    type Target = Histogram<C>;
    fn deref(&self) -> &Self::Target {
        self.merged
            .as_ref()
            .expect("local histogram None outside phase shift")
    }
}

impl<C: Counter> DerefMut for SyncHistogram<C> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.merged
            .as_mut()
            .expect("local histogram None outside phase shift")
    }
}
<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line of the file we are editing in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y;// - 1;
                    if self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                    }
                    i -= 1;

                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    let curr = self.current_line() - 1;
                    self.set_current_line(curr);

                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Down => {
                if self.cursor.pos.y < self.term.rows() - 3 &&
                   self.cursor.pos.y < self.editor.contents.len() - 1
                {
                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let x = self.cursor.pos.x;
                let curr = self.current_line();
                let len = self.editor.contents[curr].len() - 1;

                if len > 0 && self.cursor.in_line < len - 1 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 0;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        let current_line = self.current_line();
        self.print_file(current_line);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<commit_msg>Sync work on file scrolling<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the line in the file that we are currently editing
    line: usize,
    /// Represents the line at the top of the UI
    top_line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            top_line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Prints our editor's contents to the UI from the bottom up
    fn print_file_bottom(&mut self, bottom: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut h = self.term.rows() - 3;
        let mut i = 0;
        let mut k = 0;
        let mut j = 0;

        loop {
            let line = &self.editor.contents[bottom - k];
            let len = line.len();
            let mut adv = len / w;
            if len > w && len % w > 0 {
                adv += 1;
            }
            i = adv;
            for &b in line {
                if b == b'\n' {
                    //continue;
                    break;
                }
                // TODO(nokaa): Handle cases where h - adv < 0
                self.term[(j, h - adv)].set_ch(b as char);
                j += 1;
                if j == w {
                    if adv == 0 {
                        break;
                    }

                    j = 0;
                    adv -= 1;
                }
            }
            while j < w {
                self.term[(j, h - adv)].set_ch(' ');
                j += 1;
            }

            if h == 0 {
                break;
            }
            h -= i;
            h -= 1;
            k += 1;
            j = 0;
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                let curr = self.current_line();

                if self.cursor.pos.y > 0 && curr > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y;// - 1;
                    if self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                    }
                    i -= 1;

                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    self.set_current_line(curr - 1);

                    let len = self.editor.contents[curr - 1].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                } else if curr > 0 {
                    self.set_current_line(curr - 1);
                    self.redraw_file();
                }
            }
            cursor::Direction::Down => {
                let curr = self.current_line();

                if self.cursor.pos.y < self.term.rows() - 3 &&
                   curr < self.editor.contents.len() - 1
                {
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                } else if curr < self.editor.contents.len() - 1  {
                    let len = self.editor.contents[curr + 1].len() - 1;
                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    self.redraw_file_bottom();
                    /*if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                    } else {
                    }*/
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let x = self.cursor.pos.x;
                let curr = self.current_line();
                let len = self.editor.contents[curr].len() - 1;

                if len > 0 && self.cursor.in_line < len - 1 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 0;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        self.top_line -= 1;
        let current_line = self.top_line;
        self.print_file(current_line);
    }

    pub fn redraw_file_bottom(&mut self) {
        self.top_line += 1;
        let bottom = self.current_line();
        self.print_file_bottom(bottom);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before>//! Interfaces for set-theoretic operations and relations on arbitrary types.
//!
//! These traits define interfaces for set-like operations on pre-defined
//! types, and when implemented for a type allow use of several
//! included algorithms.

use std::iter::Iterator;

/// Trait for checking if a set contains the given element.
pub trait Contains<E>
    where E: PartialEq
{
    /// Check if the set contains the given element.
    fn contains(&self, element: &E) -> bool;
}

/// Interface used to check if a set contains zero elements.
pub trait IsEmpty {
    /// Check if the set is empty.
    fn is_empty(&self) -> bool;
}

/// Trait for checking if a particular set's members are all contained in
/// another set.
pub trait IsSubsetOf<S> {
    /// Determine whether all elements in this are also elements of the
    /// given set.
    fn is_subset_of(&self, other: &S) -> bool;
}

/// Trait for checking if a particular set contains all members of another set.
///
/// `IsSupersetOf<S>` is automatically defined for all types `T` where
/// `S: [IsSubsetOf](trait.IsSubsetOf.html)<T>`; therefore you should prefer to
/// implement `IsSubsetOf` instead.
pub trait IsSupersetOf<S> {
    /// Check if this set contains all elements of the given set.
    fn is_superset_of(&self, other: &S) -> bool;
}

impl<T, S> IsSupersetOf<S> for T
    where S: IsSubsetOf<T>
{
    #[inline(always)]
    fn is_superset_of(&self, other: &S) -> bool {
        other.is_subset_of(self)
    }
}

/// Trait for set types whose elements can be accessed by iteration.
pub trait IterableSet<'a, E: 'a> {
    /// Iterator type used when iterating over the set's elements.
    type Iter: Iterator<Item=&'a E>;

    /// Fetch an iterator over (references to) the members of the set.
    fn iter(&self) -> Self::Iter;
}

/// Trait for set types that support the [absolute
/// complement][absolute-complement] operation.
///
/// [absolute-complement]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Absolute_complement
pub trait Complement {
    /// Type returned by an instance's `complement()` method.
    type Output;

    /// Calculate the absolute complement of the set.
    fn complement(&self) -> Self::Output;
}

/// Trait for set types that support the [set-theoretic difference][setdiff]
/// operation, which is also called the relative complement.
///
/// [setdiff]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
pub trait Difference<S> {
    /// Type of the result of computing this difference.
    type Output;
    /// Calculate the set-theoretic difference of this set with the one given.
    fn difference(&self, other: &S) -> Self::Output;
}

/// Trait for computing the [set-theoretic difference][setdiff] in-place, modifying
/// the receiver.
///
/// [setdiff]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
pub trait Subtract<S> {
    /// Remove the values in `other` from `self`, and return `self`.
    fn subtract(&mut self, other: &S) -> &Self;
}

/// Utility for working with multiple sets as an aggregate.
pub struct AggregateSet<'a, S: 'a> {
    sets: Vec<&'a S>
}

impl<'a, S: 'a, E> Contains<E> for AggregateSet<'a, S>
    where S: Contains<E>, E: PartialEq
{
    #[inline]
    fn contains(&self, e: &E) -> bool {
        self.sets.iter().any(|set| set.contains(e))
    }
}

impl<'a, S: 'a> IsSubsetOf<AggregateSet<'a, S>> for S
    where S: IsEmpty + IsSubsetOf<S> + Subtract<S> + Clone
{
    fn is_subset_of(&self, agg: &AggregateSet<'a, S>) -> bool {
        // If this set is empty, or is completely contained by any of the
        // aggregate's members, it's a subset.
        if self.is_empty() || agg.sets.iter().any(|set| self.is_subset_of(set)) {
            return true
        }

        // Otherwise we'll go the brute-force route: make a clone of `self`,
        // then subtract each member set from the clone until either the clone
        // is empty (=> this set is a subset of the aggregate) or we run out of
        // members (=> not a subset).
        let mut iter = agg.sets.iter();
        let mut diff = self.clone();

        while let Some(set) = iter.next() {
            if diff.subtract(set).is_empty() {
                return true;
            }
        }

        false
    }
}
<commit_msg>util/set: changed `Contains<E>` trait method to take `E` by value<commit_after>//! Interfaces for set-theoretic operations and relations on arbitrary types.
//!
//! These traits define interfaces for set-like operations on pre-defined
//! types, and when implemented for a type allow use of several
//! included algorithms.

use std::iter::Iterator;

/// Trait for checking if a set contains the given element.
pub trait Contains<E>
    where E: PartialEq
{
    /// Check if the set contains the given element.
    fn contains(&self, element: E) -> bool;
}

/// Interface used to check if a set contains zero elements.
pub trait IsEmpty {
    /// Check if the set is empty.
    fn is_empty(&self) -> bool;
}

/// Trait for checking if a particular set's members are all contained in
/// another set.
pub trait IsSubsetOf<S> {
    /// Determine whether all elements in this are also elements of the
    /// given set.
    fn is_subset_of(&self, other: &S) -> bool;
}

/// Trait for checking if a particular set contains all members of another set.
///
/// `IsSupersetOf<S>` is automatically defined for all types `T` where
/// `S: [IsSubsetOf](trait.IsSubsetOf.html)<T>`; therefore you should prefer to
/// implement `IsSubsetOf` instead.
pub trait IsSupersetOf<S> {
    /// Check if this set contains all elements of the given set.
    fn is_superset_of(&self, other: &S) -> bool;
}

impl<T, S> IsSupersetOf<S> for T
    where S: IsSubsetOf<T>
{
    #[inline(always)]
    fn is_superset_of(&self, other: &S) -> bool {
        other.is_subset_of(self)
    }
}

/// Trait for set types whose elements can be accessed by iteration.
pub trait IterableSet<'a, E: 'a> {
    /// Iterator type used when iterating over the set's elements.
    type Iter: Iterator<Item=&'a E>;

    /// Fetch an iterator over (references to) the members of the set.
    fn iter(&self) -> Self::Iter;
}

/// Trait for set types that support the [absolute
/// complement][absolute-complement] operation.
///
/// [absolute-complement]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Absolute_complement
pub trait Complement {
    /// Type returned by an instance's `complement()` method.
    type Output;

    /// Calculate the absolute complement of the set.
    fn complement(&self) -> Self::Output;
}

/// Trait for set types that support the [set-theoretic difference][setdiff]
/// operation, which is also called the relative complement.
///
/// [setdiff]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
pub trait Difference<S> {
    /// Type of the result of computing this difference.
    type Output;
    /// Calculate the set-theoretic difference of this set with the one given.
    fn difference(&self, other: &S) -> Self::Output;
}

/// Trait for computing the [set-theoretic difference][setdiff] in-place, modifying
/// the receiver.
///
/// [setdiff]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
pub trait Subtract<S> {
    /// Remove the values in `other` from `self`, and return `self`.
    fn subtract(&mut self, other: &S) -> &Self;
}

/// Utility for working with multiple sets as an aggregate.
pub struct AggregateSet<'a, S: 'a> {
    sets: Vec<&'a S>
}

impl<'a, S: 'a, E> Contains<E> for AggregateSet<'a, S>
    where S: Contains<E>, E: Copy + PartialEq
{
    #[inline]
    fn contains(&self, e: E) -> bool {
        self.sets.iter().any(|set| set.contains(e))
    }
}

impl<'a, S: 'a> IsSubsetOf<AggregateSet<'a, S>> for S
    where S: IsEmpty + IsSubsetOf<S> + Subtract<S> + Clone
{
    fn is_subset_of(&self, agg: &AggregateSet<'a, S>) -> bool {
        // If this set is empty, or is completely contained by any of the
        // aggregate's members, it's a subset.
        if self.is_empty() || agg.sets.iter().any(|set| self.is_subset_of(set)) {
            return true
        }

        // Otherwise we'll go the brute-force route: make a clone of `self`,
        // then subtract each member set from the clone until either the clone
        // is empty (=> this set is a subset of the aggregate) or we run out of
        // members (=> not a subset).
        let mut iter = agg.sets.iter();
        let mut diff = self.clone();

        while let Some(set) = iter.next() {
            if diff.subtract(set).is_empty() {
                return true;
            }
        }

        false
    }
}
<|endoftext|>


<commit_before>// This module implements simple request and response objects.

use std::fmt;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::io::{Read, Write};

use hyper;
use hyper::uri::RequestUri::{AbsolutePath, AbsoluteUri, Authority, Star};
use hyper::header::{Headers, ContentLength, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::method::Method;
use url;
use url::UrlParser;
use url::form_urlencoded::parse as form_urlencoded_parse;

use app::Pencil;
use datastructures::MultiDict;
use httputils::{get_name_by_http_code, get_content_type, get_host_value};
use httputils::get_status_from_code;
use routing::Rule;
use types::ViewArgs;
use http_errors::{HTTPError, NotFound};

/// Request type.
pub struct Request<'r, 'a, 'b: 'a> {
    pub app: &'r Pencil,
    /// The original hyper request object.
    pub request: hyper::server::request::Request<'a, 'b>,
    url: Option<url::Url>,
    /// The URL rule that matched the request.  This is
    /// going to be `None` if nothing matched.
    pub url_rule: Option<Rule>,
    /// A dict of view arguments that matched the request.
    pub view_args: ViewArgs,
    /// If matching the URL failed, this will be the error.
    pub routing_error: Option<HTTPError>,
    args: Option<MultiDict>,
    form: Option<MultiDict>,
}

impl<'r, 'a, 'b: 'a> Request<'r, 'a, 'b> {
    /// Create a `Request`.
    pub fn new(app: &'r Pencil, request: hyper::server::request::Request<'a, 'b>) -> Request<'r, 'a, 'b> {
        let url = match request.uri {
            AbsolutePath(ref url) => {
                let host: Option<&hyper::header::Host> = request.headers.get();
                match host {
                    Some(host) => {
                        let full_url = String::from("http://") + &get_host_value(host) +
                            "/" + &url.trim_left_matches('/');
                        match url::Url::parse(&full_url) {
                            Ok(url) => Some(url),
                            Err(_) => None,
                        }
                    },
                    None => None,
                }
            },
            _ => None,
        };
        Request {
            app: app,
            request: request,
            url: url,
            url_rule: None,
            view_args: HashMap::new(),
            routing_error: None,
            args: None,
            form: None,
        }
    }

    /// Match the request, set the `url_rule` and `view_args` field.
    pub fn match_request(&mut self) {
        match self.path() {
            Some(path) => {
                let url_adapter = self.app.url_map.bind(path, self.method());
                match url_adapter.matched() {
                    Ok(caps) => {
                        let (rule, view_args) = caps;
                        self.url_rule = Some(rule);
                        self.view_args = view_args;
                    },
                    Err(e) => {
                        self.routing_error = Some(e);
                    },
                }
            },
            None => {
                self.routing_error = Some(NotFound);
            }
        }
    }

    /// The endpoint that matched the request.
    pub fn endpoint(&self) -> Option<String> {
        match self.url_rule {
            Some(ref rule) => Some(rule.endpoint.clone()),
            None => None,
        }
    }

    /// The parsed URL parameters.
    pub fn args(&mut self) -> &MultiDict {
        if self.args.is_none() {
            let mut args = MultiDict::new();
            if self.url.is_some() {
                match self.url.as_ref().unwrap().query_pairs() {
                    Some(pairs) => {
                        for &(ref k, ref v) in pairs.iter() {
                            args.add(&k, &v);
                        }
                    },
                    None => (),
                }
            }
            self.args = Some(args);
        }
        return self.args.as_ref().unwrap();
    }

    /// Get content type.
    fn content_type(&self) -> Option<ContentType> {
        let content_type: Option<&ContentType> = self.request.headers.get();
        content_type.map(|c| c.clone())
    }

    /// This method is used internally to retrieve submitted data.
    fn load_form_data(&mut self) {
        if self.form.is_some() {
            return
        }
        let form = match self.content_type() {
            Some(ContentType(Mime(toplevel, sublevel, _))) => {
                if toplevel == TopLevel::Application && sublevel == SubLevel::WwwFormUrlEncoded {
                    let mut body: Vec<u8> = Vec::new();
                    self.request.read_to_end(&mut body).unwrap();
                    let mut form = MultiDict::new();
                    for &(ref k, ref v) in form_urlencoded_parse(&body).iter() {
                        form.add(&k, &v);
                    }
                    form
                } else {
                    MultiDict::new()
                }
            },
            None => {
                MultiDict::new()
            }
        };
        self.form = Some(form);
    }

    /// The form parameters.
    pub fn form(&mut self) -> &MultiDict {
        self.load_form_data();
        self.form.as_ref().unwrap()
    }

    /// The headers.
    pub fn headers(&self) -> &Headers {
        &self.request.headers
    }

    /// Requested path.
    pub fn path(&self) -> Option<String> {
        match self.request.uri {
            AbsolutePath(ref path) => {
                Some(path.splitn(2, '?').next().unwrap().to_string())
            },
            AbsoluteUri(ref url) => {
                url.serialize_path()
            },
            Authority(_) | Star => None
        }
    }

    /// Requested path including the query string.
    pub fn full_path(&self) -> Option<String> {
        let path = self.path();
        let query_string = self.query_string();
        if path.is_some() && query_string.is_some() {
            return Some(path.unwrap() + "?" + &query_string.unwrap());
        } else  {
            return path;
        }
    }

    /// The host including the port if available.
    pub fn host(&self) -> Option<String> {
        let host: Option<&hyper::header::Host> = self.request.headers.get();
        host.map(|host| get_host_value(host))
    }

    /// The URL parameters as raw String.
    pub fn query_string(&self) -> Option<String> {
        if self.url.is_some() {
            return self.url.as_ref().unwrap().query.clone();
        } else {
            return None;
        }
    }

    /// The requested method.
    pub fn method(&self) -> String {
        match self.request.method {
            Method::Options => "OPTIONS".to_string(),
            Method::Get => "GET".to_string(),
            Method::Post => "POST".to_string(),
            Method::Put => "PUT".to_string(),
            Method::Delete => "DELETE".to_string(),
            Method::Head => "HEAD".to_string(),
            Method::Trace => "TRACE".to_string(),
            Method::Connect => "CONNECT".to_string(),
            Method::Patch => "PATCH".to_string(),
            Method::Extension(ref method) => method.clone(),
        }
    }

    /// The remote address of the client.
    pub fn remote_addr(&self) -> SocketAddr {
        self.request.remote_addr.clone()
    }

    /// URL scheme (http or https), currently I do not know how to get
    /// this, the result will always be http.
    pub fn scheme(&self) -> String {
        String::from("http")
    }

    /// Just the host with scheme.
    pub fn host_url(&self) -> Option<String> {
        match self.host() {
            Some(host) => {
                Some(self.scheme() + "://" + &host + "/")
            },
            None => None,
        }
    }

    /// The current url.
    pub fn url(&self) -> Option<String> {
        let host_url = self.host_url();
        let full_path = self.full_path();
        if host_url.is_some() && full_path.is_some() {
            Some(host_url.unwrap() + &(full_path.unwrap()).trim_left_matches('/'))
        } else {
            None
        }
    }

    /// The current url without the query string.
    pub fn base_url(&self) -> Option<String> {
        let host_url = self.host_url();
        let path = self.path();
        if host_url.is_some() && path.is_some() {
            Some(host_url.unwrap() + &path.unwrap().trim_left_matches('/'))
        } else {
            None
        }
    }

    /// Whether the request is secure (https).
    pub fn is_secure(&self) -> bool {
        self.scheme() == "https".to_string()
    }
}

impl<'r, 'a, 'b: 'a> fmt::Debug for Request<'r, 'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.url() {
            Some(url) => {
                write!(f, "Pencil Request '{}' {}", url, self.method())
            },
            None => {
                write!(f, "Pencil Request")
            }
        }
    }
}

/// Response type.  It is just one container with a couple of parameters
/// (headers, body, status code etc).
#[derive(Clone)]
pub struct Response {
    pub status_code: isize,
    pub headers: Headers,
    pub body: String,
}

impl Response {
    /// Create a `Response`.
    pub fn new(body: String) -> Response {
        let mut response = Response {
            status_code: 200,
            headers: Headers::new(),
            body: body,
        };
        let mime: Mime = "text/html; charset=UTF-8".parse().unwrap();
        let content_type = ContentType(mime);
        let content_length = ContentLength(response.body.len() as u64);
        response.headers.set(content_type);
        response.headers.set(content_length);
        return response;
    }

    /// Get status name.
    pub fn status_name(&self) -> &str {
        match get_name_by_http_code(self.status_code) {
            Some(name) => name,
            None => "UNKNOWN",
        }
    }

    /// Sets a new string as response body.  The content length is set
    /// automatically.
    pub fn set_data(&mut self, value: String) {
        self.body = value;
        let content_length = self.body.len();
        self.set_content_length(content_length);
    }

    /// Returns the response content type if available.
    pub fn content_type(&self) -> Option<&ContentType> {
        self.headers.get()
    }

    /// Set response content type.
    pub fn set_content_type(&mut self, mimetype: &str) {
        let mimetype = get_content_type(mimetype, "UTF-8");
        let mime: Mime = (&mimetype).parse().unwrap();
        let content_type = ContentType(mime);
        self.headers.set(content_type);
    }

    /// Returns the response content length if available.
    pub fn content_length(&self) -> Option<usize> {
        let content_length: Option<&ContentLength> = self.headers.get();
        match content_length {
            Some(&ContentLength(length)) => Some(length as usize),
            None => None,
        }
    }

    /// Set content length.
    pub fn set_content_length(&mut self, value: usize) {
        let content_length = ContentLength(value as u64);
        self.headers.set(content_length);
    }

    /// Sets a cookie(TODO).
    pub fn set_cookie(&mut self) {
    }

    /// Delete a cookie(TODO).
    pub fn delete_cookie(&mut self) {
    }

    /// Return `true` if the response is streamed(currently we do not support
    /// streaming yet, always return `false`).
    pub fn is_streamed(&self) -> bool {
        false
    }

    /// Write the response out.  Mostly you shouldn't use this directly.
    pub fn write(self, request_method: String, mut res: hyper::server::Response) {
        // write status.
        let status_code = self.status_code;
        *res.status_mut() = get_status_from_code(status_code);

        // write headers.
        *res.headers_mut() = self.headers;

        // write data.
        if request_method == String::from("HEAD") ||
           (100 <= status_code && status_code < 200) ||
           status_code == 204 || status_code == 304 {
            res.headers_mut().set(ContentLength(0));
            try_return!(res.start().and_then(|w| w.end()));
        } else {
            let mut res = try_return!(res.start());
            try_return!(res.write_all(self.body.as_bytes()));
            try_return!(res.end());
        }
    }
}
<commit_msg>Added args for request wrapper<commit_after>// This module implements simple request and response objects.

use std::fmt;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::io::{Read, Write};

use hyper;
use hyper::uri::RequestUri::{AbsolutePath, AbsoluteUri, Authority, Star};
use hyper::header::{Headers, ContentLength, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::method::Method;
use url;
use url::UrlParser;
use url::form_urlencoded;

use app::Pencil;
use datastructures::MultiDict;
use httputils::{get_name_by_http_code, get_content_type, get_host_value};
use httputils::get_status_from_code;
use routing::Rule;
use types::ViewArgs;
use http_errors::{HTTPError, NotFound};

/// Request type.
pub struct Request<'r, 'a, 'b: 'a> {
    pub app: &'r Pencil,
    /// The original hyper request object.
    pub request: hyper::server::request::Request<'a, 'b>,
    url: Option<url::Url>,
    /// The URL rule that matched the request.  This is
    /// going to be `None` if nothing matched.
    pub url_rule: Option<Rule>,
    /// A dict of view arguments that matched the request.
    pub view_args: ViewArgs,
    /// If matching the URL failed, this will be the error.
    pub routing_error: Option<HTTPError>,
    args: Option<MultiDict>,
    form: Option<MultiDict>,
}

impl<'r, 'a, 'b: 'a> Request<'r, 'a, 'b> {
    /// Create a `Request`.
    pub fn new(app: &'r Pencil, request: hyper::server::request::Request<'a, 'b>) -> Request<'r, 'a, 'b> {
        let url = match request.uri {
            AbsolutePath(ref url) => {
                let host: Option<&hyper::header::Host> = request.headers.get();
                match host {
                    Some(host) => {
                        let full_url = String::from("http://") + &get_host_value(host) +
                            "/" + &url.trim_left_matches('/');
                        match url::Url::parse(&full_url) {
                            Ok(url) => Some(url),
                            Err(_) => None,
                        }
                    },
                    None => None,
                }
            },
            _ => None,
        };
        Request {
            app: app,
            request: request,
            url: url,
            url_rule: None,
            view_args: HashMap::new(),
            routing_error: None,
            args: None,
            form: None,
        }
    }

    /// Match the request, set the `url_rule` and `view_args` field.
    pub fn match_request(&mut self) {
        match self.path() {
            Some(path) => {
                let url_adapter = self.app.url_map.bind(path, self.method());
                match url_adapter.matched() {
                    Ok(caps) => {
                        let (rule, view_args) = caps;
                        self.url_rule = Some(rule);
                        self.view_args = view_args;
                    },
                    Err(e) => {
                        self.routing_error = Some(e);
                    },
                }
            },
            None => {
                self.routing_error = Some(NotFound);
            }
        }
    }

    /// The endpoint that matched the request.
    pub fn endpoint(&self) -> Option<String> {
        match self.url_rule {
            Some(ref rule) => Some(rule.endpoint.clone()),
            None => None,
        }
    }

    /// The parsed URL parameters.
    pub fn args(&mut self) -> &MultiDict {
        if self.args.is_none() {
            let mut args = MultiDict::new();
            let query_pairs = match self.request.uri {
                AbsolutePath(ref path) => {
                    match UrlParser::new().parse_path(path) {
                        Ok((_, query, _)) => {
                            query.map(|query| form_urlencoded::parse(query.as_bytes()))
                        },
                        Err(_) => None
                    }
                },
                AbsoluteUri(ref url) => {
                    url.query_pairs()
                },
                Authority(_) | Star => None
            };
            match query_pairs {
                Some(pairs) => {
                    for &(ref k, ref v) in pairs.iter() {
                        args.add(&k, &v);
                    }
                },
                None => {},
            }
            self.args = Some(args);
        }
        return self.args.as_ref().unwrap();
    }

    /// Get content type.
    fn content_type(&self) -> Option<ContentType> {
        let content_type: Option<&ContentType> = self.request.headers.get();
        content_type.map(|c| c.clone())
    }

    /// This method is used internally to retrieve submitted data.
    fn load_form_data(&mut self) {
        if self.form.is_some() {
            return
        }
        let form = match self.content_type() {
            Some(ContentType(Mime(toplevel, sublevel, _))) => {
                if toplevel == TopLevel::Application && sublevel == SubLevel::WwwFormUrlEncoded {
                    let mut body: Vec<u8> = Vec::new();
                    self.request.read_to_end(&mut body).unwrap();
                    let mut form = MultiDict::new();
                    for &(ref k, ref v) in form_urlencoded::parse(&body).iter() {
                        form.add(&k, &v);
                    }
                    form
                } else {
                    MultiDict::new()
                }
            },
            None => {
                MultiDict::new()
            }
        };
        self.form = Some(form);
    }

    /// The form parameters.
    pub fn form(&mut self) -> &MultiDict {
        self.load_form_data();
        self.form.as_ref().unwrap()
    }

    /// The headers.
    pub fn headers(&self) -> &Headers {
        &self.request.headers
    }

    /// Requested path.
    pub fn path(&self) -> Option<String> {
        match self.request.uri {
            AbsolutePath(ref path) => {
                Some(path.splitn(2, '?').next().unwrap().to_string())
            },
            AbsoluteUri(ref url) => {
                url.serialize_path()
            },
            Authority(_) | Star => None
        }
    }

    /// Requested path including the query string.
    pub fn full_path(&self) -> Option<String> {
        let path = self.path();
        let query_string = self.query_string();
        if path.is_some() && query_string.is_some() {
            return Some(path.unwrap() + "?" + &query_string.unwrap());
        } else  {
            return path;
        }
    }

    /// The host including the port if available.
    pub fn host(&self) -> Option<String> {
        let host: Option<&hyper::header::Host> = self.request.headers.get();
        host.map(|host| get_host_value(host))
    }

    /// The URL parameters as raw String.
    pub fn query_string(&self) -> Option<String> {
        if self.url.is_some() {
            return self.url.as_ref().unwrap().query.clone();
        } else {
            return None;
        }
    }

    /// The requested method.
    pub fn method(&self) -> String {
        match self.request.method {
            Method::Options => "OPTIONS".to_string(),
            Method::Get => "GET".to_string(),
            Method::Post => "POST".to_string(),
            Method::Put => "PUT".to_string(),
            Method::Delete => "DELETE".to_string(),
            Method::Head => "HEAD".to_string(),
            Method::Trace => "TRACE".to_string(),
            Method::Connect => "CONNECT".to_string(),
            Method::Patch => "PATCH".to_string(),
            Method::Extension(ref method) => method.clone(),
        }
    }

    /// The remote address of the client.
    pub fn remote_addr(&self) -> SocketAddr {
        self.request.remote_addr.clone()
    }

    /// URL scheme (http or https), currently I do not know how to get
    /// this, the result will always be http.
    pub fn scheme(&self) -> String {
        String::from("http")
    }

    /// Just the host with scheme.
    pub fn host_url(&self) -> Option<String> {
        match self.host() {
            Some(host) => {
                Some(self.scheme() + "://" + &host + "/")
            },
            None => None,
        }
    }

    /// The current url.
    pub fn url(&self) -> Option<String> {
        let host_url = self.host_url();
        let full_path = self.full_path();
        if host_url.is_some() && full_path.is_some() {
            Some(host_url.unwrap() + &(full_path.unwrap()).trim_left_matches('/'))
        } else {
            None
        }
    }

    /// The current url without the query string.
    pub fn base_url(&self) -> Option<String> {
        let host_url = self.host_url();
        let path = self.path();
        if host_url.is_some() && path.is_some() {
            Some(host_url.unwrap() + &path.unwrap().trim_left_matches('/'))
        } else {
            None
        }
    }

    /// Whether the request is secure (https).
    pub fn is_secure(&self) -> bool {
        self.scheme() == "https".to_string()
    }
}

impl<'r, 'a, 'b: 'a> fmt::Debug for Request<'r, 'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.url() {
            Some(url) => {
                write!(f, "Pencil Request '{}' {}", url, self.method())
            },
            None => {
                write!(f, "Pencil Request")
            }
        }
    }
}

/// Response type.  It is just one container with a couple of parameters
/// (headers, body, status code etc).
#[derive(Clone)]
pub struct Response {
    pub status_code: isize,
    pub headers: Headers,
    pub body: String,
}

impl Response {
    /// Create a `Response`.
    pub fn new(body: String) -> Response {
        let mut response = Response {
            status_code: 200,
            headers: Headers::new(),
            body: body,
        };
        let mime: Mime = "text/html; charset=UTF-8".parse().unwrap();
        let content_type = ContentType(mime);
        let content_length = ContentLength(response.body.len() as u64);
        response.headers.set(content_type);
        response.headers.set(content_length);
        return response;
    }

    /// Get status name.
    pub fn status_name(&self) -> &str {
        match get_name_by_http_code(self.status_code) {
            Some(name) => name,
            None => "UNKNOWN",
        }
    }

    /// Sets a new string as response body.  The content length is set
    /// automatically.
    pub fn set_data(&mut self, value: String) {
        self.body = value;
        let content_length = self.body.len();
        self.set_content_length(content_length);
    }

    /// Returns the response content type if available.
    pub fn content_type(&self) -> Option<&ContentType> {
        self.headers.get()
    }

    /// Set response content type.
    pub fn set_content_type(&mut self, mimetype: &str) {
        let mimetype = get_content_type(mimetype, "UTF-8");
        let mime: Mime = (&mimetype).parse().unwrap();
        let content_type = ContentType(mime);
        self.headers.set(content_type);
    }

    /// Returns the response content length if available.
    pub fn content_length(&self) -> Option<usize> {
        let content_length: Option<&ContentLength> = self.headers.get();
        match content_length {
            Some(&ContentLength(length)) => Some(length as usize),
            None => None,
        }
    }

    /// Set content length.
    pub fn set_content_length(&mut self, value: usize) {
        let content_length = ContentLength(value as u64);
        self.headers.set(content_length);
    }

    /// Sets a cookie(TODO).
    pub fn set_cookie(&mut self) {
    }

    /// Delete a cookie(TODO).
    pub fn delete_cookie(&mut self) {
    }

    /// Return `true` if the response is streamed(currently we do not support
    /// streaming yet, always return `false`).
    pub fn is_streamed(&self) -> bool {
        false
    }

    /// Write the response out.  Mostly you shouldn't use this directly.
    pub fn write(self, request_method: String, mut res: hyper::server::Response) {
        // write status.
        let status_code = self.status_code;
        *res.status_mut() = get_status_from_code(status_code);

        // write headers.
        *res.headers_mut() = self.headers;

        // write data.
        if request_method == String::from("HEAD") ||
           (100 <= status_code && status_code < 200) ||
           status_code == 204 || status_code == 304 {
            res.headers_mut().set(ContentLength(0));
            try_return!(res.start().and_then(|w| w.end()));
        } else {
            let mut res = try_return!(res.start());
            try_return!(res.write_all(self.body.as_bytes()));
            try_return!(res.end());
        }
    }
}
<|endoftext|>