<commit_before>use crate::ramp_table::RampTable;
use crate::grammar::Grammar;
use crate::lalr::LALROutput;
use crate::lr0::LR0Output;
use crate::lr0::Reductions;
use crate::{Rule, State, Token};
use log::debug;
use log::warn;

#[derive(Clone, Copy, PartialEq)]
pub enum ActionCode {
    Shift(State),
    Reduce(Rule),
}
impl ActionCode {
    pub fn is_shift(&self) -> bool {
        if let ActionCode::Shift(_) = self {
            true
        } else {
            false
        }
    }

    #[allow(dead_code)]
    pub fn is_reduce(&self) -> bool {
        if let ActionCode::Reduce(_) = self {
            true
        } else {
            false
        }
    }
}

pub const LEFT: u8 = 1;
pub const RIGHT: u8 = 2;

pub struct ParserAction {
    /// is this symbol always a token?
    pub symbol: Token,
    pub prec: i16,
    pub action_code: ActionCode,
    pub assoc: u8,
    pub suppressed: u8,
}

pub struct YaccParser {
    /// State -> [ParserAction]
    pub actions: RampTable<ParserAction>,
    pub final_state: State,
}
impl YaccParser {
    pub fn nstates(&self) -> usize {
        self.actions.num_keys()
    }
}

pub fn make_parser(gram: &Grammar, lr0: &LR0Output, lalr: &LALROutput) -> YaccParser {
    let nstates = lr0.nstates();
    let mut parser: RampTable<ParserAction> = RampTable::new();
    for state in 0..nstates  {
        let state: State = state.into();
        get_shifts(gram, lr0, state, &mut parser);
        get_reductions(gram, &lr0.reductions, lalr, state, &mut parser);
        parser.finish_key();
    }

    let final_state = find_final_state(gram, lr0);
    remove_conflicts(final_state, &mut parser);
    report_unused_rules(gram, &parser);

    YaccParser {
        actions: parser,
        final_state: final_state,
    }
}

fn get_shifts(gram: &Grammar, lr0: &LR0Output, stateno: State, actions: &mut RampTable<ParserAction>) {
    for &k in lr0.shifts.values(stateno) {
        let symbol = lr0.accessing_symbol[k];
        if gram.is_token(symbol) {
            actions.push_value(ParserAction {
                symbol: gram.symbol_to_token(symbol),
                prec: gram.prec[symbol.index()],
                action_code: ActionCode::Shift(k),
                assoc: gram.assoc[symbol.index()],
                suppressed: 0,
            });
        }
    }
}

fn get_reductions(
    gram: &Grammar,
    reductions: &Reductions,
    lalr: &LALROutput,
    stateno: State,
    actions: &mut RampTable<ParserAction>,
) {
    let range = reductions.values_range(stateno);
    let state_rules = reductions.values(stateno);
    for (i, &rule) in range.zip(state_rules) {
        for j in (0..gram.ntokens).rev() {
            if lalr.LA.get(i, j) {
                add_reduce(gram, actions, rule, Token(j as i16));
            }
        }
    }
}

/// Inserts a new value into the 'actions' table, in a sorted position.
/// This inserts one new value into the 'values' of the 'actions' table, at the end.
/// It is careful to insert items in a sorted order.
fn add_reduce(gram: &Grammar, actions: &mut RampTable<ParserAction>, rule: Rule, symbol: Token) {
    // end: index of the values of the current (unfinished) key
    let end = *actions.index.last().unwrap();
    let actions = &mut actions.table;
    let mut next: usize = end;
    while next < actions.len() && actions[next].symbol < symbol {
        next += 1;
    }

    while next < actions.len()
        && actions[next].symbol == symbol
        && actions[next].action_code.is_shift()
    {
        next += 1;
    }

    // find insertion position for a Reduce action
    while next < actions.len() && actions[next].symbol == symbol {
        let action = &actions[next];
        if let ActionCode::Reduce(action_rule) = action.action_code {
            if action_rule < rule {
                next += 1;
                continue;
            }
        }
        break;
    }

    actions.insert(
        next,
        ParserAction {
            symbol: symbol,
            prec: gram.rprec[rule.index()],
            action_code: ActionCode::Reduce(rule),
            assoc: gram.rassoc[rule.index()],
            suppressed: 0,
        },
    );
}

fn find_final_state(gram: &Grammar, lr0: &LR0Output) -> State {
    let goal = gram.ritem[1].as_symbol();
    let mut final_state: State = State(0);
    for &ts in lr0.shifts.values(0usize).iter().rev() {
        final_state = ts;
        if lr0.accessing_symbol[final_state] == goal {
            return ts;
        }
    }
    // Is reaching here an error?
    final_state
}

fn report_unused_rules(gram: &Grammar, parser: &RampTable<ParserAction>) {
    let mut rules_used = vec![false; gram.nrules];
    for state_actions in parser.iter_entries() {
        for action in state_actions.iter() {
            if let ActionCode::Reduce(action_rule) = action.action_code {
                if action.suppressed == 0 {
                    rules_used[action_rule.index()] = true;
                }
            }
        }
    }

    let num_unused = rules_used[3..].iter().filter(|&&used| !used).count();
    if num_unused != 0 {
        warn!("{} rule(s) were never reduced", num_unused);
    }
}

/// Modifies ParserAction::suppressed. That field could potentially be moved to a
/// separate vector, which this function would produce.
fn remove_conflicts(final_state: State, parser: &mut RampTable<ParserAction>) {
    let mut srtotal = 0;
    let mut rrtotal = 0;
    for (state, pvec) in parser.iter_entries_mut().enumerate() {
        let state = State(state as i16);
        let is_final_state = state == final_state;
        let (srcount, rrcount) = remove_conflicts_for_state(pvec, is_final_state);
        srtotal += srcount;
        rrtotal += rrcount;
    }
    if srtotal + rrtotal > 0 {
        total_conflicts(srtotal, rrtotal);
    }
}

/// Modifies ParserAction::suppressed. That field could potentially be moved to a
/// separate vector, which this function would produce.
/// Returns (shift_reduce_conflict_count, reduce_reduce_conflict_count)
fn remove_conflicts_for_state(pvec: &mut [ParserAction], is_final_state: bool) -> (usize, usize) {
    let mut srcount: usize = 0;
    let mut rrcount: usize = 0;
    if !pvec.is_empty() {
        let mut symbol = pvec[0].symbol;
        let mut pref: usize = 0; // index into pvec
        for p in 1..pvec.len() {
            // p is index into pvec
            if pvec[p].symbol != symbol {
                pref = p;
                symbol = pvec[p].symbol;
            } else if is_final_state && symbol == Token(0) {
                srcount += 1;
                pvec[p].suppressed = 1;
            } else if let ActionCode::Shift(_) = pvec[pref].action_code {
                if pvec[pref].prec > 0 && pvec[p].prec > 0 {
                    if pvec[pref].prec < pvec[p].prec {
                        pvec[pref].suppressed = 2;
                        pref = p;
                    } else if pvec[pref].prec > pvec[p].prec {
                        pvec[p].suppressed = 2;
                    } else if pvec[pref].assoc == LEFT {
                        pvec[pref].suppressed = 2;
                        pref = p;
                    } else if pvec[pref].assoc == RIGHT {
                        pvec[p].suppressed = 2;
                    } else {
                        pvec[pref].suppressed = 2;
                        pvec[p].suppressed = 2;
                    }
                } else {
                    srcount += 1;
                    pvec[p].suppressed = 1;
                }
            } else {
                rrcount += 1;
                pvec[p].suppressed = 1;
            }
        }
    }
    (srcount, rrcount)
}

fn total_conflicts(srtotal: usize, rrtotal: usize) {
    if srtotal > 0 {
        warn!("{} shift/reduce conflict(s)", srtotal);
    }

    if rrtotal > 1 {
        warn!("{} reduce/reduce conflict(s)", rrtotal);
    }
}

// Computese the default reduction for a single state.
fn sole_reduction(parser: &[ParserAction]) -> Rule {
    let mut count: usize = 0;
    let mut ruleno = Rule(0);
    for p in parser.iter() {
        match &p.action_code {
            ActionCode::Shift(_) => {
                if p.suppressed == 0 {
                    debug!("    found unsuppressed shift, returning 0");
                    return Rule(0);
                }
            }
            ActionCode::Reduce(reduce_rule) => {
                if p.suppressed == 0 {
                    if ruleno > Rule(0) && *reduce_rule != ruleno {
                        debug!(
                            "    found unsuppressed reduce for rule {}, returning 0",
                            ruleno
                        );
                        return Rule(0);
                    }
                    debug!("    found unsuppressed reduce");
                    if p.symbol != Token(1) {
                        count += 1;
                        debug!("    count --> {}", count);
                    }
                    ruleno = *reduce_rule;
                    debug!("    selecting rule {}", ruleno);
                }
            }
        }
    }

    if count == 0 {
        debug!("    did not find any reductions");
        return Rule(0);
    }
    debug!("    selected default reduction {}", ruleno);
    ruleno
}

/// Computes the default reduction for each state.
/// State -> Rule
pub fn default_reductions(parser: &RampTable<ParserAction>) -> Vec<Rule> {
    parser.iter_entries().map(|actions| sole_reduction(actions)).collect()
}
<commit_msg>Use iterators smartly<commit_after>use crate::ramp_table::RampTable;
use crate::grammar::Grammar;
use crate::lalr::LALROutput;
use crate::lr0::LR0Output;
use crate::lr0::Reductions;
use crate::{Rule, State, Token};
use log::debug;
use log::warn;

#[derive(Clone, Copy, PartialEq)]
pub enum ActionCode {
    Shift(State),
    Reduce(Rule),
}
impl ActionCode {
    pub fn is_shift(&self) -> bool {
        if let ActionCode::Shift(_) = self {
            true
        } else {
            false
        }
    }

    #[allow(dead_code)]
    pub fn is_reduce(&self) -> bool {
        if let ActionCode::Reduce(_) = self {
            true
        } else {
            false
        }
    }
}

pub const LEFT: u8 = 1;
pub const RIGHT: u8 = 2;

pub struct ParserAction {
    /// is this symbol always a token?
    pub symbol: Token,
    pub prec: i16,
    pub action_code: ActionCode,
    pub assoc: u8,
    pub suppressed: u8,
}

pub struct YaccParser {
    /// State -> [ParserAction]
    pub actions: RampTable<ParserAction>,
    pub final_state: State,
}
impl YaccParser {
    pub fn nstates(&self) -> usize {
        self.actions.num_keys()
    }
}

pub fn make_parser(gram: &Grammar, lr0: &LR0Output, lalr: &LALROutput) -> YaccParser {
    let nstates = lr0.nstates();
    let mut parser: RampTable<ParserAction> = RampTable::new();
    for state in 0..nstates  {
        let state: State = state.into();
        get_shifts(gram, lr0, state, &mut parser);
        get_reductions(gram, &lr0.reductions, lalr, state, &mut parser);
        parser.finish_key();
    }

    let final_state = find_final_state(gram, lr0);
    remove_conflicts(final_state, &mut parser);
    report_unused_rules(gram, &parser);

    YaccParser {
        actions: parser,
        final_state: final_state,
    }
}

fn get_shifts(gram: &Grammar, lr0: &LR0Output, stateno: State, actions: &mut RampTable<ParserAction>) {
    for &k in lr0.shifts.values(stateno) {
        let symbol = lr0.accessing_symbol[k];
        if gram.is_token(symbol) {
            actions.push_value(ParserAction {
                symbol: gram.symbol_to_token(symbol),
                prec: gram.prec[symbol.index()],
                action_code: ActionCode::Shift(k),
                assoc: gram.assoc[symbol.index()],
                suppressed: 0,
            });
        }
    }
}

fn get_reductions(
    gram: &Grammar,
    reductions: &Reductions,
    lalr: &LALROutput,
    stateno: State,
    actions: &mut RampTable<ParserAction>,
) {
    let range = reductions.values_range(stateno);
    let state_rules = reductions.values(stateno);
    for (i, &rule) in range.zip(state_rules) {
        for j in (0..gram.ntokens).rev() {
            if lalr.LA.get(i, j) {
                add_reduce(gram, actions, rule, Token(j as i16));
            }
        }
    }
}

/// Inserts a new value into the 'actions' table, in a sorted position.
/// This inserts one new value into the 'values' of the 'actions' table, at the end.
/// It is careful to insert items in a sorted order.
fn add_reduce(gram: &Grammar, actions: &mut RampTable<ParserAction>, rule: Rule, symbol: Token) {
    // end: index of the values of the current (unfinished) key
    let end = *actions.index.last().unwrap();
    let actions = &mut actions.table;
    let mut next: usize = end;
    while next < actions.len() && actions[next].symbol < symbol {
        next += 1;
    }

    while next < actions.len()
        && actions[next].symbol == symbol
        && actions[next].action_code.is_shift()
    {
        next += 1;
    }

    // find insertion position for a Reduce action
    while next < actions.len() && actions[next].symbol == symbol {
        let action = &actions[next];
        if let ActionCode::Reduce(action_rule) = action.action_code {
            if action_rule < rule {
                next += 1;
                continue;
            }
        }
        break;
    }

    actions.insert(
        next,
        ParserAction {
            symbol: symbol,
            prec: gram.rprec[rule.index()],
            action_code: ActionCode::Reduce(rule),
            assoc: gram.rassoc[rule.index()],
            suppressed: 0,
        },
    );
}

fn find_final_state(gram: &Grammar, lr0: &LR0Output) -> State {
    let goal = gram.ritem[1].as_symbol();
    let mut final_state: State = State(0);
    for &ts in lr0.shifts.values(0usize).iter().rev() {
        final_state = ts;
        if lr0.accessing_symbol[final_state] == goal {
            return ts;
        }
    }
    // Is reaching here an error?
    final_state
}

fn report_unused_rules(gram: &Grammar, parser: &RampTable<ParserAction>) {
    let mut rules_used = vec![false; gram.nrules];
    for state_actions in parser.iter_entries() {
        for action in state_actions.iter() {
            if let ActionCode::Reduce(action_rule) = action.action_code {
                if action.suppressed == 0 {
                    rules_used[action_rule.index()] = true;
                }
            }
        }
    }

    let num_unused = rules_used[3..].iter().filter(|&&used| !used).count();
    if num_unused != 0 {
        warn!("{} rule(s) were never reduced", num_unused);
    }
}

/// Modifies ParserAction::suppressed. That field could potentially be moved to a
/// separate vector, which this function would produce.
fn remove_conflicts(final_state: State, parser: &mut RampTable<ParserAction>) {
    let mut srtotal = 0;
    let mut rrtotal = 0;
    for (state, actions) in parser.iter_entries_mut().enumerate() {
        let state = State(state as i16);
        let is_final_state = state == final_state;
        let (srcount, rrcount) = remove_conflicts_for_state(actions, is_final_state);
        srtotal += srcount;
        rrtotal += rrcount;
    }
    if srtotal + rrtotal > 0 {
        total_conflicts(srtotal, rrtotal);
    }
}

/// Modifies ParserAction::suppressed. That field could potentially be moved to a
/// separate vector, which this function would produce.
/// Returns (shift_reduce_conflict_count, reduce_reduce_conflict_count)
fn remove_conflicts_for_state(actions: &mut [ParserAction], is_final_state: bool) -> (usize, usize) {
    let mut srcount: usize = 0;
    let mut rrcount: usize = 0;
    let mut iter_actions = actions.iter_mut();
    if let Some(first) = iter_actions.next() {
        // preferred
        let mut pref = first;
        let mut symbol = pref.symbol;
        for p in iter_actions {
            if p.symbol != symbol {
                pref = p;
                symbol = pref.symbol;
            } else if is_final_state && symbol == Token(0) {
                srcount += 1;
                p.suppressed = 1;
            } else if let ActionCode::Shift(_) = pref.action_code {
                if pref.prec > 0 && p.prec > 0 {
                    if pref.prec < p.prec {
                        pref.suppressed = 2;
                        pref = p;
                    } else if pref.prec > p.prec {
                        p.suppressed = 2;
                    } else if pref.assoc == LEFT {
                        pref.suppressed = 2;
                        pref = p;
                    } else if pref.assoc == RIGHT {
                        p.suppressed = 2;
                    } else {
                        pref.suppressed = 2;
                        p.suppressed = 2;
                    }
                } else {
                    srcount += 1;
                    p.suppressed = 1;
                }
            } else {
                rrcount += 1;
                p.suppressed = 1;
            }
        }
    }
    (srcount, rrcount)
}

fn total_conflicts(srtotal: usize, rrtotal: usize) {
    if srtotal > 0 {
        warn!("{} shift/reduce conflict(s)", srtotal);
    }

    if rrtotal > 1 {
        warn!("{} reduce/reduce conflict(s)", rrtotal);
    }
}

// Computese the default reduction for a single state.
fn sole_reduction(parser: &[ParserAction]) -> Rule {
    let mut count: usize = 0;
    let mut ruleno = Rule(0);
    for p in parser.iter() {
        match &p.action_code {
            ActionCode::Shift(_) => {
                if p.suppressed == 0 {
                    debug!("    found unsuppressed shift, returning 0");
                    return Rule(0);
                }
            }
            ActionCode::Reduce(reduce_rule) => {
                if p.suppressed == 0 {
                    if ruleno > Rule(0) && *reduce_rule != ruleno {
                        debug!(
                            "    found unsuppressed reduce for rule {}, returning 0",
                            ruleno
                        );
                        return Rule(0);
                    }
                    debug!("    found unsuppressed reduce");
                    if p.symbol != Token(1) {
                        count += 1;
                        debug!("    count --> {}", count);
                    }
                    ruleno = *reduce_rule;
                    debug!("    selecting rule {}", ruleno);
                }
            }
        }
    }

    if count == 0 {
        debug!("    did not find any reductions");
        return Rule(0);
    }
    debug!("    selected default reduction {}", ruleno);
    ruleno
}

/// Computes the default reduction for each state.
/// State -> Rule
pub fn default_reductions(parser: &RampTable<ParserAction>) -> Vec<Rule> {
    parser.iter_entries().map(|actions| sole_reduction(actions)).collect()
}
<|endoftext|>


<commit_before>//! Types dealing with ranges of values
#![macro_escape]

use std::fmt;
use std::i32;
use std::i64;
use time::Timespec;

/// The `quote!` macro can make it easier to create ranges. It roughly mirrors
/// traditional mathematic range syntax.
///
/// # Note
///
/// The `Range`, `RangeBound`, `Inclusive`, and `Exclusive` types must be
/// directly usable at the location the macro is used.
///
/// # Example
///
/// ```rust
/// #[feature(phase)];
///
/// #[phase(syntax, link)]
/// extern crate postgres;
///
/// use postgres::types::range::{Range, RangeBound, Inclusive, Exclusive};
///
/// fn main() {
///     # let mut r: Range<i32>;
///     // a closed interval
///     r = range!('[' 5i32, 10i32 ']');
///     // an open interval
///     r = range!('(' 5i32, 10i32 ')');
///     // half-open intervals
///     r = range!('(' 5i32, 10i32 ']');
///     r = range!('[' 5i32, 10i32 ')');
///     // a closed lower-bounded interval
///     r = range!('[' 5i32, ')');
///     // an open lower-bounded interval
///     r = range!('(' 5i32, ')');
///     // a closed upper-bounded interval
///     r = range!('(', 10i32 ']');
///     // an open upper-bounded interval
///     r = range!('(', 10i32 ')');
///     // an unbounded interval
///     r = range!('(', ')');
///     // an empty interval
///     r = range!(empty);
/// }
#[macro_export]
macro_rules! range(
    (empty) => (Range::empty());
    ('(', ')') => (Range::new(None, None));
    ('(', $h:expr ')') => (
        Range::new(None, Some(RangeBound::new($h, Exclusive)))
    );
    ('(', $h:expr ']') => (
        Range::new(None, Some(RangeBound::new($h, Inclusive)))
    );
    ('(' $l:expr, ')') => (
        Range::new(Some(RangeBound::new($l, Exclusive)), None)
    );
    ('[' $l:expr, ')') => (
        Range::new(Some(RangeBound::new($l, Inclusive)), None)
    );
    ('(' $l:expr, $h:expr ')') => (
        Range::new(Some(RangeBound::new($l, Exclusive)),
                   Some(RangeBound::new($h, Exclusive)))
    );
    ('(' $l:expr, $h:expr ']') => (
        Range::new(Some(RangeBound::new($l, Exclusive)),
                   Some(RangeBound::new($h, Inclusive)))
    );
    ('[' $l:expr, $h:expr ')') => (
        Range::new(Some(RangeBound::new($l, Inclusive)),
                   Some(RangeBound::new($h, Exclusive)))
    );
    ('[' $l:expr, $h:expr ']') => (
        Range::new(Some(RangeBound::new($l, Inclusive)),
                   Some(RangeBound::new($h, Inclusive)))
    )
)

/// A trait that normalizes a range bound for a type
pub trait Normalizable {
    /// Given a range bound, returns the normalized version of that bound. For
    /// discrete types such as i32, the normalized lower bound is always
    /// inclusive and the normalized upper bound is always exclusive. Other
    /// types, such as Timespec, have no normalization process so their
    /// implementation is a no-op.
    ///
    /// The logic here should match the logic performed by the equivalent
    /// Postgres type.
    fn normalize<S: BoundSided>(bound: RangeBound<S, Self>)
            -> RangeBound<S, Self>;
}

macro_rules! bounded_normalizable(
    ($t:ident) => (
        impl Normalizable for $t {
            fn normalize<S: BoundSided>(bound: RangeBound<S, $t>)
                    -> RangeBound<S, $t> {
                match (BoundSided::side(None::<S>), bound.type_) {
                    (Upper, Inclusive) => {
                        assert!(bound.value != $t::MAX);
                        RangeBound::new(bound.value + 1, Exclusive)
                    }
                    (Lower, Exclusive) => {
                        assert!(bound.value != $t::MAX);
                        RangeBound::new(bound.value + 1, Inclusive)
                    }
                    _ => bound
                }
            }
        }
    )
)

bounded_normalizable!(i32)
bounded_normalizable!(i64)

impl Normalizable for Timespec {
    fn normalize<S: BoundSided>(bound: RangeBound<S, Timespec>)
            -> RangeBound<S, Timespec> {
        bound
    }
}

#[deriving(PartialEq, Eq)]
enum BoundSide {
    Upper,
    Lower
}

#[doc(hidden)]
trait BoundSided {
    // param is a hack to get around lack of hints for self type
    fn side(_: Option<Self>) -> BoundSide;
}

/// A tag type representing an upper bound
pub enum UpperBound {}

/// A tag type representing a lower bound
pub enum LowerBound {}

impl BoundSided for UpperBound {
    fn side(_: Option<UpperBound>) -> BoundSide {
        Upper
    }
}

impl BoundSided for LowerBound {
    fn side(_: Option<LowerBound>) -> BoundSide {
        Lower
    }
}

/// The type of a range bound
#[deriving(PartialEq, Eq, Clone)]
pub enum BoundType {
    /// The bound includes its value
    Inclusive,
    /// The bound excludes its value
    Exclusive
}

/// Represents a one-sided bound.
///
/// The side is determined by the `S` phantom parameter.
pub struct RangeBound<S, T> {
    /// The value of the bound
    pub value: T,
    /// The type of the bound
    pub type_: BoundType
}

impl<S: BoundSided, T: Clone> Clone for RangeBound<S, T> {
    fn clone(&self) -> RangeBound<S, T> {
        RangeBound {
            value: self.value.clone(),
            type_: self.type_.clone(),
        }
    }
}

impl<S: BoundSided, T: fmt::Show> fmt::Show for RangeBound<S, T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let chars = match self.type_ {
            Inclusive => ['[', ']'],
            Exclusive => ['(', ')'],
        };

        match BoundSided::side(None::<S>) {
            Lower => write!(fmt, "{}{}", chars[0], self.value),
            Upper => write!(fmt, "{}{}", self.value, chars[1]),
        }
    }
}

impl<S: BoundSided, T: PartialEq> PartialEq for RangeBound<S, T> {
    fn eq(&self, other: &RangeBound<S, T>) -> bool {
        self.value == other.value && self.type_ == other.type_
    }

    fn ne(&self, other: &RangeBound<S, T>) -> bool {
        self.value != other.value || self.type_ != other.type_
    }
}

impl<S: BoundSided, T: Eq> Eq for RangeBound<S, T> {}

impl<S: BoundSided, T: PartialOrd> PartialOrd for RangeBound<S, T> {
    fn partial_cmp(&self, other: &RangeBound<S, T>) -> Option<Ordering> {
        match (BoundSided::side(None::<S>), self.type_, other.type_,
                self.value.partial_cmp(&other.value)) {
            (Upper, Exclusive, Inclusive, Some(Equal))
            | (Lower, Inclusive, Exclusive, Some(Equal)) => Some(Less),
            (Upper, Inclusive, Exclusive, Some(Equal))
            | (Lower, Exclusive, Inclusive, Some(Equal)) => Some(Greater),
            (_, _, _, cmp) => cmp,
        }
    }
}

impl<S: BoundSided, T: Ord> Ord for RangeBound<S, T> {
    fn cmp(&self, other: &RangeBound<S, T>) -> Ordering {
        match (BoundSided::side(None::<S>), self.type_, other.type_,
                self.value.cmp(&other.value)) {
            (Upper, Exclusive, Inclusive, Equal)
            | (Lower, Inclusive, Exclusive, Equal) => Less,
            (Upper, Inclusive, Exclusive, Equal)
            | (Lower, Exclusive, Inclusive, Equal) => Greater,
            (_, _, _, ord) => ord,
        }
    }
}

impl<S: BoundSided, T: PartialOrd> RangeBound<S, T> {
    /// Constructs a new range bound
    pub fn new(value: T, type_: BoundType) -> RangeBound<S, T> {
        RangeBound { value: value, type_: type_ }
    }

    /// Determines if a value lies within the range specified by this bound.
    pub fn in_bounds(&self, value: &T) -> bool {
        match (self.type_, BoundSided::side(None::<S>)) {
            (Inclusive, Upper) => value <= &self.value,
            (Exclusive, Upper) => value < &self.value,
            (Inclusive, Lower) => value >= &self.value,
            (Exclusive, Lower) => value > &self.value,
        }
    }
}

struct OptBound<'a, S, T>(Option<&'a RangeBound<S, T>>);

impl<'a, S: BoundSided, T: PartialEq> PartialEq for OptBound<'a, S, T> {
    fn eq(&self, &OptBound(ref other): &OptBound<'a, S, T>) -> bool {
        let &OptBound(ref self_) = self;
        self_ == other
    }

    fn ne(&self, &OptBound(ref other): &OptBound<'a, S, T>) -> bool {
        let &OptBound(ref self_) = self;
        self_ != other
    }
}

impl<'a, S: BoundSided, T: PartialOrd> PartialOrd for OptBound<'a, S, T> {
    fn partial_cmp(&self, other: &OptBound<'a, S, T>) -> Option<Ordering> {
        match (*self, *other, BoundSided::side(None::<S>)) {
            (OptBound(None), OptBound(None), _) => Some(Equal),
            (OptBound(None), _, Lower)
            | (_, OptBound(None), Upper) => Some(Less),
            (OptBound(None), _, Upper)
            | (_, OptBound(None), Lower) => Some(Greater),
            (OptBound(Some(a)), OptBound(Some(b)), _) => a.partial_cmp(b)
        }
    }
}

/// Represents a range of values.
#[deriving(PartialEq, Eq, Clone)]
pub struct Range<T> {
    inner: InnerRange<T>,
}

#[deriving(PartialEq, Eq, Clone)]
enum InnerRange<T> {
    Empty,
    Normal(Option<RangeBound<LowerBound, T>>,
           Option<RangeBound<UpperBound, T>>)
}

impl<T: fmt::Show> fmt::Show for Range<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.inner {
            Empty => write!(fmt, "empty"),
            Normal(ref lower, ref upper) => {
                match *lower {
                    Some(ref bound) => try!(write!(fmt, "{}", bound)),
                    None => try!(write!(fmt, "(")),
                }
                try!(write!(fmt, ","));
                match *upper {
                    Some(ref bound) => write!(fmt, "{}", bound),
                    None => write!(fmt, ")"),
                }
            }
        }
    }
}

impl<T: PartialOrd+Normalizable> Range<T> {
    /// Creates a new range.
    ///
    /// If a bound is `None`, the range is unbounded in that direction.
    pub fn new(lower: Option<RangeBound<LowerBound, T>>,
               upper: Option<RangeBound<UpperBound, T>>) -> Range<T> {
        let lower = lower.map(|bound| Normalizable::normalize(bound));
        let upper = upper.map(|bound| Normalizable::normalize(bound));

        match (&lower, &upper) {
            (&Some(ref lower), &Some(ref upper)) => {
                let empty = match (lower.type_, upper.type_) {
                    (Inclusive, Inclusive) => lower.value > upper.value,
                    _ => lower.value >= upper.value
                };
                if empty {
                    return Range { inner: Empty };
                }
            }
            _ => {}
        }

        Range { inner: Normal(lower, upper) }
    }

    /// Creates a new empty range.
    pub fn empty() -> Range<T> {
        Range { inner: Empty }
    }

    /// Determines if this range is the empty range.
    pub fn is_empty(&self) -> bool {
        match self.inner {
            Empty => true,
            Normal(..) => false
        }
    }

    /// Returns the lower bound if it exists.
    pub fn lower<'a>(&'a self) -> Option<&'a RangeBound<LowerBound, T>> {
        match self.inner {
            Normal(Some(ref lower), _) => Some(lower),
            _ => None
        }
    }

    /// Returns the upper bound if it exists.
    pub fn upper<'a>(&'a self) -> Option<&'a RangeBound<UpperBound, T>> {
        match self.inner {
            Normal(_, Some(ref upper)) => Some(upper),
            _ => None
        }
    }

    /// Determines if a value lies within this range.
    pub fn contains(&self, value: &T) -> bool {
        match self.inner {
            Empty => false,
            Normal(ref lower, ref upper) => {
                lower.as_ref().map_or(true, |b| b.in_bounds(value)) &&
                    upper.as_ref().map_or(true, |b| b.in_bounds(value))
            }
        }
    }

    /// Determines if a range lies completely within this range.
    pub fn contains_range(&self, other: &Range<T>) -> bool {
        if other.is_empty() {
            return true;
        }

        if self.is_empty() {
            return false;
        }

        OptBound(self.lower()) <= OptBound(other.lower()) &&
            OptBound(self.upper()) >= OptBound(other.upper())
    }
}

fn order<T:PartialOrd>(a: T, b: T) -> (T, T) {
    if a < b {
        (a, b)
    } else {
        (b, a)
    }
}

impl<T: PartialOrd+Normalizable+Clone> Range<T> {
    /// Returns the intersection of this range with another
    pub fn intersect(&self, other: &Range<T>) -> Range<T> {
        if self.is_empty() || other.is_empty() {
            return Range::empty();
        }

        let (_, OptBound(lower)) = order(OptBound(self.lower()),
                                         OptBound(other.lower()));
        let (OptBound(upper), _) = order(OptBound(self.upper()),
                                         OptBound(other.upper()));

        Range::new(lower.map(|v| v.clone()), upper.map(|v| v.clone()))
    }

    /// Returns the union of this range with another if it is contiguous
    pub fn union(&self, other: &Range<T>) -> Option<Range<T>> {
        if self.is_empty() {
            return Some(other.clone());
        }

        if other.is_empty() {
            return Some(self.clone());
        }

        let (OptBound(l_lower), OptBound(u_lower)) =
            order(OptBound(self.lower()), OptBound(other.lower()));
        let (OptBound(l_upper), OptBound(u_upper)) =
            order(OptBound(self.upper()), OptBound(other.upper()));

        let discontiguous = match (u_lower, l_upper) {
            (Some(&RangeBound { value: ref l, type_: Exclusive }),
             Some(&RangeBound { value: ref u, type_: Exclusive })) => l >= u,
            (Some(&RangeBound { value: ref l, .. }),
             Some(&RangeBound { value: ref u, .. })) => l > u,
            _ => false
        };

        if discontiguous {
            None
        } else {
            Some(Range::new(l_lower.map(|v| v.clone()),
                            u_upper.map(|v| v.clone())))
        }
    }
}
<commit_msg>Restructure range! internals a bit<commit_after>//! Types dealing with ranges of values
#![macro_escape]

use std::fmt;
use std::i32;
use std::i64;
use time::Timespec;

/// The `quote!` macro can make it easier to create ranges. It roughly mirrors
/// traditional mathematic range syntax.
///
/// # Example
///
/// ```rust
/// #[feature(phase)];
///
/// #[phase(syntax, link)]
/// extern crate postgres;
///
/// use postgres::types::range::Range;
///
/// fn main() {
///     let mut r: Range<i32>;
///     // a closed interval
///     r = range!('[' 5i32, 10i32 ']');
///     // an open interval
///     r = range!('(' 5i32, 10i32 ')');
///     // half-open intervals
///     r = range!('(' 5i32, 10i32 ']');
///     r = range!('[' 5i32, 10i32 ')');
///     // a closed lower-bounded interval
///     r = range!('[' 5i32, ')');
///     // an open lower-bounded interval
///     r = range!('(' 5i32, ')');
///     // a closed upper-bounded interval
///     r = range!('(', 10i32 ']');
///     // an open upper-bounded interval
///     r = range!('(', 10i32 ')');
///     // an unbounded interval
///     r = range!('(', ')');
///     // an empty interval
///     r = range!(empty);
/// }
#[macro_export]
macro_rules! range(
    (empty) => (::postgres::types::range::Range::empty());
    ('(', ')') => (::postgres::types::range::Range::new(None, None));
    ('(', $h:expr ')') => (
        ::postgres::types::range::Range::new(None,
            Some(::postgres::types::range::RangeBound::new($h,
                ::postgres::types::range::Exclusive)))
    );
    ('(', $h:expr ']') => (
        ::postgres::types::range::Range::new(None,
            Some(::postgres::types::range::RangeBound::new($h,
                ::postgres::types::range::Inclusive)))
    );
    ('(' $l:expr, ')') => (
        ::postgres::types::range::Range::new(
            Some(::postgres::types::range::RangeBound::new($l,
                ::postgres::types::range::Exclusive)), None)
    );
    ('[' $l:expr, ')') => (
        ::postgres::types::range::Range::new(
            Some(::postgres::types::range::RangeBound::new($l,
                ::postgres::types::range::Inclusive)), None)
    );
    ('(' $l:expr, $h:expr ')') => (
        ::postgres::types::range::Range::new(
            Some(::postgres::types::range::RangeBound::new($l,
                ::postgres::types::range::Exclusive)),
            Some(::postgres::types::range::RangeBound::new($h,
                ::postgres::types::range::Exclusive)))
    );
    ('(' $l:expr, $h:expr ']') => (
        ::postgres::types::range::Range::new(
            Some(::postgres::types::range::RangeBound::new($l,
                ::postgres::types::range::Exclusive)),
            Some(::postgres::types::range::RangeBound::new($h,
                ::postgres::types::range::Inclusive)))
    );
    ('[' $l:expr, $h:expr ')') => (
        ::postgres::types::range::Range::new(
            Some(::postgres::types::range::RangeBound::new($l,
                ::postgres::types::range::Inclusive)),
            Some(::postgres::types::range::RangeBound::new($h,
                ::postgres::types::range::Exclusive)))
    );
    ('[' $l:expr, $h:expr ']') => (
        ::postgres::types::range::Range::new(
            Some(::postgres::types::range::RangeBound::new($l,
                ::postgres::types::range::Inclusive)),
            Some(::postgres::types::range::RangeBound::new($h,
                ::postgres::types::range::Inclusive)))
    )
)

/// A trait that normalizes a range bound for a type
pub trait Normalizable {
    /// Given a range bound, returns the normalized version of that bound. For
    /// discrete types such as i32, the normalized lower bound is always
    /// inclusive and the normalized upper bound is always exclusive. Other
    /// types, such as Timespec, have no normalization process so their
    /// implementation is a no-op.
    ///
    /// The logic here should match the logic performed by the equivalent
    /// Postgres type.
    fn normalize<S: BoundSided>(bound: RangeBound<S, Self>)
            -> RangeBound<S, Self>;
}

macro_rules! bounded_normalizable(
    ($t:ident) => (
        impl Normalizable for $t {
            fn normalize<S: BoundSided>(bound: RangeBound<S, $t>)
                    -> RangeBound<S, $t> {
                match (BoundSided::side(None::<S>), bound.type_) {
                    (Upper, Inclusive) => {
                        assert!(bound.value != $t::MAX);
                        RangeBound::new(bound.value + 1, Exclusive)
                    }
                    (Lower, Exclusive) => {
                        assert!(bound.value != $t::MAX);
                        RangeBound::new(bound.value + 1, Inclusive)
                    }
                    _ => bound
                }
            }
        }
    )
)

bounded_normalizable!(i32)
bounded_normalizable!(i64)

impl Normalizable for Timespec {
    fn normalize<S: BoundSided>(bound: RangeBound<S, Timespec>)
            -> RangeBound<S, Timespec> {
        bound
    }
}

#[deriving(PartialEq, Eq)]
enum BoundSide {
    Upper,
    Lower
}

#[doc(hidden)]
trait BoundSided {
    // param is a hack to get around lack of hints for self type
    fn side(_: Option<Self>) -> BoundSide;
}

/// A tag type representing an upper bound
pub enum UpperBound {}

/// A tag type representing a lower bound
pub enum LowerBound {}

impl BoundSided for UpperBound {
    fn side(_: Option<UpperBound>) -> BoundSide {
        Upper
    }
}

impl BoundSided for LowerBound {
    fn side(_: Option<LowerBound>) -> BoundSide {
        Lower
    }
}

/// The type of a range bound
#[deriving(PartialEq, Eq, Clone)]
pub enum BoundType {
    /// The bound includes its value
    Inclusive,
    /// The bound excludes its value
    Exclusive
}

/// Represents a one-sided bound.
///
/// The side is determined by the `S` phantom parameter.
pub struct RangeBound<S, T> {
    /// The value of the bound
    pub value: T,
    /// The type of the bound
    pub type_: BoundType
}

impl<S: BoundSided, T: Clone> Clone for RangeBound<S, T> {
    fn clone(&self) -> RangeBound<S, T> {
        RangeBound {
            value: self.value.clone(),
            type_: self.type_.clone(),
        }
    }
}

impl<S: BoundSided, T: fmt::Show> fmt::Show for RangeBound<S, T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let chars = match self.type_ {
            Inclusive => ['[', ']'],
            Exclusive => ['(', ')'],
        };

        match BoundSided::side(None::<S>) {
            Lower => write!(fmt, "{}{}", chars[0], self.value),
            Upper => write!(fmt, "{}{}", self.value, chars[1]),
        }
    }
}

impl<S: BoundSided, T: PartialEq> PartialEq for RangeBound<S, T> {
    fn eq(&self, other: &RangeBound<S, T>) -> bool {
        self.value == other.value && self.type_ == other.type_
    }

    fn ne(&self, other: &RangeBound<S, T>) -> bool {
        self.value != other.value || self.type_ != other.type_
    }
}

impl<S: BoundSided, T: Eq> Eq for RangeBound<S, T> {}

impl<S: BoundSided, T: PartialOrd> PartialOrd for RangeBound<S, T> {
    fn partial_cmp(&self, other: &RangeBound<S, T>) -> Option<Ordering> {
        match (BoundSided::side(None::<S>), self.type_, other.type_,
                self.value.partial_cmp(&other.value)) {
            (Upper, Exclusive, Inclusive, Some(Equal))
            | (Lower, Inclusive, Exclusive, Some(Equal)) => Some(Less),
            (Upper, Inclusive, Exclusive, Some(Equal))
            | (Lower, Exclusive, Inclusive, Some(Equal)) => Some(Greater),
            (_, _, _, cmp) => cmp,
        }
    }
}

impl<S: BoundSided, T: Ord> Ord for RangeBound<S, T> {
    fn cmp(&self, other: &RangeBound<S, T>) -> Ordering {
        match (BoundSided::side(None::<S>), self.type_, other.type_,
                self.value.cmp(&other.value)) {
            (Upper, Exclusive, Inclusive, Equal)
            | (Lower, Inclusive, Exclusive, Equal) => Less,
            (Upper, Inclusive, Exclusive, Equal)
            | (Lower, Exclusive, Inclusive, Equal) => Greater,
            (_, _, _, ord) => ord,
        }
    }
}

impl<S: BoundSided, T: PartialOrd> RangeBound<S, T> {
    /// Constructs a new range bound
    pub fn new(value: T, type_: BoundType) -> RangeBound<S, T> {
        RangeBound { value: value, type_: type_ }
    }

    /// Determines if a value lies within the range specified by this bound.
    pub fn in_bounds(&self, value: &T) -> bool {
        match (self.type_, BoundSided::side(None::<S>)) {
            (Inclusive, Upper) => value <= &self.value,
            (Exclusive, Upper) => value < &self.value,
            (Inclusive, Lower) => value >= &self.value,
            (Exclusive, Lower) => value > &self.value,
        }
    }
}

struct OptBound<'a, S, T>(Option<&'a RangeBound<S, T>>);

impl<'a, S: BoundSided, T: PartialEq> PartialEq for OptBound<'a, S, T> {
    fn eq(&self, &OptBound(ref other): &OptBound<'a, S, T>) -> bool {
        let &OptBound(ref self_) = self;
        self_ == other
    }

    fn ne(&self, &OptBound(ref other): &OptBound<'a, S, T>) -> bool {
        let &OptBound(ref self_) = self;
        self_ != other
    }
}

impl<'a, S: BoundSided, T: PartialOrd> PartialOrd for OptBound<'a, S, T> {
    fn partial_cmp(&self, other: &OptBound<'a, S, T>) -> Option<Ordering> {
        match (*self, *other, BoundSided::side(None::<S>)) {
            (OptBound(None), OptBound(None), _) => Some(Equal),
            (OptBound(None), _, Lower)
            | (_, OptBound(None), Upper) => Some(Less),
            (OptBound(None), _, Upper)
            | (_, OptBound(None), Lower) => Some(Greater),
            (OptBound(Some(a)), OptBound(Some(b)), _) => a.partial_cmp(b)
        }
    }
}

/// Represents a range of values.
#[deriving(PartialEq, Eq, Clone)]
pub struct Range<T> {
    inner: InnerRange<T>,
}

#[deriving(PartialEq, Eq, Clone)]
enum InnerRange<T> {
    Empty,
    Normal(Option<RangeBound<LowerBound, T>>,
           Option<RangeBound<UpperBound, T>>)
}

impl<T: fmt::Show> fmt::Show for Range<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.inner {
            Empty => write!(fmt, "empty"),
            Normal(ref lower, ref upper) => {
                match *lower {
                    Some(ref bound) => try!(write!(fmt, "{}", bound)),
                    None => try!(write!(fmt, "(")),
                }
                try!(write!(fmt, ","));
                match *upper {
                    Some(ref bound) => write!(fmt, "{}", bound),
                    None => write!(fmt, ")"),
                }
            }
        }
    }
}

impl<T: PartialOrd+Normalizable> Range<T> {
    /// Creates a new range.
    ///
    /// If a bound is `None`, the range is unbounded in that direction.
    pub fn new(lower: Option<RangeBound<LowerBound, T>>,
               upper: Option<RangeBound<UpperBound, T>>) -> Range<T> {
        let lower = lower.map(|bound| Normalizable::normalize(bound));
        let upper = upper.map(|bound| Normalizable::normalize(bound));

        match (&lower, &upper) {
            (&Some(ref lower), &Some(ref upper)) => {
                let empty = match (lower.type_, upper.type_) {
                    (Inclusive, Inclusive) => lower.value > upper.value,
                    _ => lower.value >= upper.value
                };
                if empty {
                    return Range { inner: Empty };
                }
            }
            _ => {}
        }

        Range { inner: Normal(lower, upper) }
    }

    /// Creates a new empty range.
    pub fn empty() -> Range<T> {
        Range { inner: Empty }
    }

    /// Determines if this range is the empty range.
    pub fn is_empty(&self) -> bool {
        match self.inner {
            Empty => true,
            Normal(..) => false
        }
    }

    /// Returns the lower bound if it exists.
    pub fn lower<'a>(&'a self) -> Option<&'a RangeBound<LowerBound, T>> {
        match self.inner {
            Normal(Some(ref lower), _) => Some(lower),
            _ => None
        }
    }

    /// Returns the upper bound if it exists.
    pub fn upper<'a>(&'a self) -> Option<&'a RangeBound<UpperBound, T>> {
        match self.inner {
            Normal(_, Some(ref upper)) => Some(upper),
            _ => None
        }
    }

    /// Determines if a value lies within this range.
    pub fn contains(&self, value: &T) -> bool {
        match self.inner {
            Empty => false,
            Normal(ref lower, ref upper) => {
                lower.as_ref().map_or(true, |b| b.in_bounds(value)) &&
                    upper.as_ref().map_or(true, |b| b.in_bounds(value))
            }
        }
    }

    /// Determines if a range lies completely within this range.
    pub fn contains_range(&self, other: &Range<T>) -> bool {
        if other.is_empty() {
            return true;
        }

        if self.is_empty() {
            return false;
        }

        OptBound(self.lower()) <= OptBound(other.lower()) &&
            OptBound(self.upper()) >= OptBound(other.upper())
    }
}

fn order<T:PartialOrd>(a: T, b: T) -> (T, T) {
    if a < b {
        (a, b)
    } else {
        (b, a)
    }
}

impl<T: PartialOrd+Normalizable+Clone> Range<T> {
    /// Returns the intersection of this range with another
    pub fn intersect(&self, other: &Range<T>) -> Range<T> {
        if self.is_empty() || other.is_empty() {
            return Range::empty();
        }

        let (_, OptBound(lower)) = order(OptBound(self.lower()),
                                         OptBound(other.lower()));
        let (OptBound(upper), _) = order(OptBound(self.upper()),
                                         OptBound(other.upper()));

        Range::new(lower.map(|v| v.clone()), upper.map(|v| v.clone()))
    }

    /// Returns the union of this range with another if it is contiguous
    pub fn union(&self, other: &Range<T>) -> Option<Range<T>> {
        if self.is_empty() {
            return Some(other.clone());
        }

        if other.is_empty() {
            return Some(self.clone());
        }

        let (OptBound(l_lower), OptBound(u_lower)) =
            order(OptBound(self.lower()), OptBound(other.lower()));
        let (OptBound(l_upper), OptBound(u_upper)) =
            order(OptBound(self.upper()), OptBound(other.upper()));

        let discontiguous = match (u_lower, l_upper) {
            (Some(&RangeBound { value: ref l, type_: Exclusive }),
             Some(&RangeBound { value: ref u, type_: Exclusive })) => l >= u,
            (Some(&RangeBound { value: ref l, .. }),
             Some(&RangeBound { value: ref u, .. })) => l > u,
            _ => false
        };

        if discontiguous {
            None
        } else {
            Some(Range::new(l_lower.map(|v| v.clone()),
                            u_upper.map(|v| v.clone())))
        }
    }
}
<|endoftext|>


<commit_before>/// Creates a [`Vec`] containing the arguments.
///
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
/// There are two forms of this macro:
///
/// - Create a [`Vec`] containing a given list of elements:
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
///
/// - Create a [`Vec`] from a given element and size:
///
/// ```
/// let v = vec![1; 3];
/// assert_eq!(v, [1, 1, 1]);
/// ```
///
/// Note that unlike array expressions this syntax supports all elements
/// which implement [`Clone`] and the number of elements doesn't have to be
/// a constant.
///
/// This will use `clone` to duplicate an expression, so one should be careful
/// using this with types having a nonstandard `Clone` implementation. For
/// example, `vec![Rc::new(1); 5]` will create a vector of five references
/// to the same boxed integer value, not five references pointing to independently
/// boxed integers.
///
/// [`Vec`]: ../std/vec/struct.Vec.html
/// [`Clone`]: ../std/clone/trait.Clone.html
#[cfg(not(test))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(box_syntax)]
macro_rules! vec {
    () => (
        $crate::vec::Vec::new()
    );
    ($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    );
    ($($x:expr),* $(,)?) => (
        <[_]>::into_vec(box [$($x),*])
    );
}

// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
// required for this macro definition, is not available. Instead use the
// `slice::into_vec`  function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
#[cfg(test)]
macro_rules! vec {
    () => (
        $crate::vec::Vec::new()
    );
    ($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    );
    ($($x:expr),*) => (
        $crate::slice::into_vec(box [$($x),*])
    );
    ($($x:expr,)*) => (vec![$($x),*])
}

/// Creates a `String` using interpolation of runtime expressions.
///
/// The first argument `format!` receives is a format string. This must be a string
/// literal. The power of the formatting string is in the `{}`s contained.
///
/// Additional parameters passed to `format!` replace the `{}`s within the
/// formatting string in the order given unless named or positional parameters
/// are used; see [`std::fmt`][fmt] for more information.
///
/// A common use for `format!` is concatenation and interpolation of strings.
/// The same convention is used with [`print!`] and [`write!`] macros,
/// depending on the intended destination of the string.
///
/// To convert a single value to a string, use the [`to_string`] method. This
/// will use the [`Display`] formatting trait.
///
/// [fmt]: ../std/fmt/index.html
/// [`print!`]: ../std/macro.print.html
/// [`write!`]: ../std/macro.write.html
/// [`to_string`]: ../std/string/trait.ToString.html
/// [`Display`]: ../std/fmt/trait.Display.html
///
/// # Panics
///
/// `format!` panics if a formatting trait implementation returns an error.
/// This indicates an incorrect implementation
/// since `fmt::Write for String` never returns an error itself.
///
/// # Examples
///
/// ```
/// format!("test");
/// format!("hello {}", "world!");
/// format!("x = {}, y = {y}", 10, y = 30);
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! format {
    ($($arg:tt)*) => {{
        let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
        res
    }}
}
<commit_msg>make `vec![,]` uncompilable<commit_after>/// Creates a [`Vec`] containing the arguments.
///
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
/// There are two forms of this macro:
///
/// - Create a [`Vec`] containing a given list of elements:
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
///
/// - Create a [`Vec`] from a given element and size:
///
/// ```
/// let v = vec![1; 3];
/// assert_eq!(v, [1, 1, 1]);
/// ```
///
/// Note that unlike array expressions this syntax supports all elements
/// which implement [`Clone`] and the number of elements doesn't have to be
/// a constant.
///
/// This will use `clone` to duplicate an expression, so one should be careful
/// using this with types having a nonstandard `Clone` implementation. For
/// example, `vec![Rc::new(1); 5]` will create a vector of five references
/// to the same boxed integer value, not five references pointing to independently
/// boxed integers.
///
/// [`Vec`]: ../std/vec/struct.Vec.html
/// [`Clone`]: ../std/clone/trait.Clone.html
#[cfg(not(test))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(box_syntax)]
macro_rules! vec {
    () => (
        $crate::vec::Vec::new()
    );
    ($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    );
    ($($x:expr),+ $(,)?) => (
        <[_]>::into_vec(box [$($x),+])
    );
}

// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
// required for this macro definition, is not available. Instead use the
// `slice::into_vec`  function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
#[cfg(test)]
macro_rules! vec {
    () => (
        $crate::vec::Vec::new()
    );
    ($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    );
    ($($x:expr),*) => (
        $crate::slice::into_vec(box [$($x),*])
    );
    ($($x:expr,)*) => (vec![$($x),*])
}

/// Creates a `String` using interpolation of runtime expressions.
///
/// The first argument `format!` receives is a format string. This must be a string
/// literal. The power of the formatting string is in the `{}`s contained.
///
/// Additional parameters passed to `format!` replace the `{}`s within the
/// formatting string in the order given unless named or positional parameters
/// are used; see [`std::fmt`][fmt] for more information.
///
/// A common use for `format!` is concatenation and interpolation of strings.
/// The same convention is used with [`print!`] and [`write!`] macros,
/// depending on the intended destination of the string.
///
/// To convert a single value to a string, use the [`to_string`] method. This
/// will use the [`Display`] formatting trait.
///
/// [fmt]: ../std/fmt/index.html
/// [`print!`]: ../std/macro.print.html
/// [`write!`]: ../std/macro.write.html
/// [`to_string`]: ../std/string/trait.ToString.html
/// [`Display`]: ../std/fmt/trait.Display.html
///
/// # Panics
///
/// `format!` panics if a formatting trait implementation returns an error.
/// This indicates an incorrect implementation
/// since `fmt::Write for String` never returns an error itself.
///
/// # Examples
///
/// ```
/// format!("test");
/// format!("hello {}", "world!");
/// format!("x = {}, y = {y}", 10, y = 30);
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! format {
    ($($arg:tt)*) => {{
        let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
        res
    }}
}
<|endoftext|>


<commit_before>//! A map from arena IDs to some other type. Space requirement is O(highest ID).

use std::marker::PhantomData;

use crate::Idx;

/// A map from arena IDs to some other type. Space requirement is O(highest ID).
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArenaMap<ID, V> {
    v: Vec<Option<V>>,
    _ty: PhantomData<ID>,
}

impl<T, V> ArenaMap<Idx<T>, V> {
    pub fn insert(&mut self, id: Idx<T>, t: V) {
        let idx = Self::to_idx(id);
        if self.v.capacity() <= idx {
            self.v.reserve(idx + 1 - self.v.capacity());
        }
        if self.v.len() <= idx {
            while self.v.len() <= idx {
                self.v.push(None);
            }
        }
        self.v[idx] = Some(t);
    }

    pub fn get(&self, id: Idx<T>) -> Option<&V> {
        self.v.get(Self::to_idx(id)).and_then(|it| it.as_ref())
    }

    pub fn get_mut(&mut self, id: Idx<T>) -> Option<&mut V> {
        self.v.get_mut(Self::to_idx(id)).and_then(|it| it.as_mut())
    }

    pub fn values(&self) -> impl Iterator<Item = &V> {
        self.v.iter().filter_map(|o| o.as_ref())
    }

    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
        self.v.iter_mut().filter_map(|o| o.as_mut())
    }

    pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> {
        self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
    }

    fn to_idx(id: Idx<T>) -> usize {
        u32::from(id.into_raw()) as usize
    }

    fn from_idx(idx: usize) -> Idx<T> {
        Idx::from_raw((idx as u32).into())
    }
}

impl<T, V> std::ops::Index<Idx<V>> for ArenaMap<Idx<V>, T> {
    type Output = T;
    fn index(&self, id: Idx<V>) -> &T {
        self.v[Self::to_idx(id)].as_ref().unwrap()
    }
}

impl<T, V> Default for ArenaMap<Idx<V>, T> {
    fn default() -> Self {
        ArenaMap { v: Vec::new(), _ty: PhantomData }
    }
}
<commit_msg>Use more functional programming in ArenaMap::insert<commit_after>//! A map from arena IDs to some other type. Space requirement is O(highest ID).

use std::marker::PhantomData;

use crate::Idx;

/// A map from arena IDs to some other type. Space requirement is O(highest ID).
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArenaMap<ID, V> {
    v: Vec<Option<V>>,
    _ty: PhantomData<ID>,
}

impl<T, V> ArenaMap<Idx<T>, V> {
    pub fn insert(&mut self, id: Idx<T>, t: V) {
        let idx = Self::to_idx(id);
        if self.v.capacity() <= idx {
            self.v.reserve(idx + 1 - self.v.capacity());
        }

        let fill = (idx + 1).saturating_sub(self.v.len());
        self.v.extend(std::iter::repeat_with(|| None).take(fill));
        self.v[idx] = Some(t);
    }

    pub fn get(&self, id: Idx<T>) -> Option<&V> {
        self.v.get(Self::to_idx(id)).and_then(|it| it.as_ref())
    }

    pub fn get_mut(&mut self, id: Idx<T>) -> Option<&mut V> {
        self.v.get_mut(Self::to_idx(id)).and_then(|it| it.as_mut())
    }

    pub fn values(&self) -> impl Iterator<Item = &V> {
        self.v.iter().filter_map(|o| o.as_ref())
    }

    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
        self.v.iter_mut().filter_map(|o| o.as_mut())
    }

    pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> {
        self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
    }

    fn to_idx(id: Idx<T>) -> usize {
        u32::from(id.into_raw()) as usize
    }

    fn from_idx(idx: usize) -> Idx<T> {
        Idx::from_raw((idx as u32).into())
    }
}

impl<T, V> std::ops::Index<Idx<V>> for ArenaMap<Idx<V>, T> {
    type Output = T;
    fn index(&self, id: Idx<V>) -> &T {
        self.v[Self::to_idx(id)].as_ref().unwrap()
    }
}

impl<T, V> Default for ArenaMap<Idx<V>, T> {
    fn default() -> Self {
        ArenaMap { v: Vec::new(), _ty: PhantomData }
    }
}
<|endoftext|>


<commit_before>//! Module providing the TermLogger Implementation

use log::{
    set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record, SetLoggerError,
};
use std::error;
use std::fmt;
use std::io::{Error, Write};
use std::sync::Mutex;
use term;
use term::{color, StderrTerminal, StdoutTerminal, Terminal};

use self::TermLogError::{SetLogger, Term};
use super::logging::*;

use crate::{Config, SharedLogger};

/// TermLogger error type.
#[derive(Debug)]
pub enum TermLogError {
    ///The type returned by set_logger if set_logger has already been called.
    SetLogger(SetLoggerError),

    ///TermLogger initialization might also fail if stdout or stderr could not be opened,
    ///e.g. when no tty is attached to the process, it runs detached in the background, etc
    /// This is represented by the `Term` Kind
    Term,
}

impl fmt::Display for TermLogError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use std::error::Error as FmtError;

        write!(f, "{}", self.description())
    }
}

impl error::Error for TermLogError {
    fn description(&self) -> &str {
        match *self {
            SetLogger(ref err) => err.description(),
            Term => "A terminal could not be opened",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            SetLogger(ref err) => Some(err),
            Term => None,
        }
    }
}

impl From<SetLoggerError> for TermLogError {
    fn from(error: SetLoggerError) -> Self {
        SetLogger(error)
    }
}

enum StdTerminal {
    Stderr(Box<StderrTerminal>),
    Stdout(Box<StdoutTerminal>),
}

impl StdTerminal {
    fn flush(&mut self) -> Result<(), Error> {
        match self {
            StdTerminal::Stderr(term) => term.flush(),
            StdTerminal::Stdout(term) => term.flush(),
        }
    }
}

struct OutputStreams {
    err: StdTerminal,
    out: StdTerminal,
}

/// Specifies which streams should be used when logging
pub enum TerminalMode {
    /// Only use Stdout
    Stdout,
    /// Only use Stderr
    Stderr,
    /// Use Stderr for Errors and Stdout otherwise
    Mixed,
}

impl Default for TerminalMode {
    fn default() -> TerminalMode {
        TerminalMode::Mixed
    }
}

/// The TermLogger struct. Provides a stderr/out based Logger implementation
///
/// Supports colored output
pub struct TermLogger {
    level: LevelFilter,
    config: Config,
    streams: Mutex<OutputStreams>,
}

impl TermLogger {
    /// init function. Globally initializes the TermLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized or if a terminal couldn't be opened.
    ///
    /// Workaround the latter by either
    /// - panic'ing (not recommended). e.g. `TermLogger::init(LevelFilter::Warn, Config::default(), TerminalMode::Mixed).unwrap()`
    /// - silently ignoring (little better). e.g. `let _ = TermLogger::init(LevelFilter::Warn, Config::default(), TerminalMode::Mixed);`
    /// - falling back:
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// if let Err(_) = TermLogger::init(LevelFilter::Warn, Config::default(), TerminalMode::Mixed) {
    ///     SimpleLogger::init(LevelFilter::Warn, Config::default()).expect("No logger should be already set")
    /// }
    /// # }
    /// ```
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed).expect("No interactive terminal");
    /// # }
    /// ```
    pub fn init(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
    ) -> Result<(), TermLogError> {
        let logger = TermLogger::new(log_level, config, mode).ok_or(Term)?;
        set_max_level(log_level.clone());
        set_boxed_logger(logger)?;
        Ok(())
    }

    /// allows to create a new logger, that can be independently used, no matter whats globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// Returns a `Box`ed TermLogger, or None if a terminal couldn't be opened.
    /// Workaround this by either
    /// - panic'ing (not recommended). e.g. `TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed).unwrap()`
    /// - silently ignoring (little better). e.g. `if let Some(logger) = TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed) { /*...*/ }`
    /// - falling back:
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let mut multiple = vec![];
    /// match TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed) {
    ///     Some(logger) => multiple.push(logger as Box<dyn SharedLogger>),
    ///     None => multiple.push(SimpleLogger::new(LevelFilter::Warn, Config::default())),
    /// }
    /// // Add more ...
    /// # }
    /// ```
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let term_logger = TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed).expect("No interactive terminal");
    /// # }
    /// ```
    pub fn new(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
    ) -> Option<Box<TermLogger>> {
        let streams = match mode {
            TerminalMode::Stdout => term::stdout().and_then(|stdout| {
                term::stdout().map(|stdout2| {
                    Mutex::new(OutputStreams {
                        err: StdTerminal::Stdout(stdout),
                        out: StdTerminal::Stdout(stdout2),
                    })
                })
            }),
            TerminalMode::Stderr => term::stderr().and_then(|stderr| {
                term::stderr().map(|stderr2| {
                    Mutex::new(OutputStreams {
                        err: StdTerminal::Stderr(stderr),
                        out: StdTerminal::Stderr(stderr2),
                    })
                })
            }),
            TerminalMode::Mixed => term::stderr().and_then(|stderr| {
                term::stdout().map(|stdout| {
                    Mutex::new(OutputStreams {
                        err: StdTerminal::Stderr(stderr),
                        out: StdTerminal::Stdout(stdout),
                    })
                })
            }),
        };

        streams.map(|streams| {
            Box::new(TermLogger {
                level: log_level,
                config: config,
                streams: streams,
            })
        })
    }

    fn try_log_term<W>(
        &self,
        record: &Record<'_>,
        term_lock: &mut Box<dyn Terminal<Output = W> + Send>,
    ) -> Result<(), Error>
    where
        W: Write + Sized,
    {
        let color = match record.level() {
            Level::Error => color::RED,
            Level::Warn => color::YELLOW,
            Level::Info => color::BLUE,
            Level::Debug => color::CYAN,
            Level::Trace => color::WHITE,
        };

        if self.config.time <= record.level() {
            write_time(&mut *term_lock, &self.config)?;
        }

        if self.config.level <= record.level() {
            term_lock.fg(color)?;
            write_level(record, &mut *term_lock)?;
            term_lock.reset()?;
        }

        if self.config.thread <= record.level() {
            write_thread_id(&mut *term_lock)?;
        }

        if self.config.target <= record.level() {
            write_target(record, &mut *term_lock)?;
        }

        if self.config.location <= record.level() {
            write_location(record, &mut *term_lock)?;
        }

        write_args(record, &mut *term_lock)
    }

    fn try_log(&self, record: &Record<'_>) -> Result<(), Error> {
        if self.enabled(record.metadata()) {
            if should_skip(&self.config, record) {
                return Ok(());
            }

            let mut streams = self.streams.lock().unwrap();

            if record.level() == Level::Error {
                match streams.err {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            } else {
                match streams.out {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            }
        } else {
            Ok(())
        }
    }
}

impl Log for TermLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        let _ = self.try_log(record);
    }

    fn flush(&self) {
        let mut streams = self.streams.lock().unwrap();
        let _ = streams.out.flush();
        let _ = streams.err.flush();
    }
}

impl SharedLogger for TermLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}
<commit_msg>cargo fmt<commit_after>//! Module providing the TermLogger Implementation

use log::{
    set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record, SetLoggerError,
};
use std::error;
use std::fmt;
use std::io::{Error, Write};
use std::sync::Mutex;
use term;
use term::{color, StderrTerminal, StdoutTerminal, Terminal};

use self::TermLogError::{SetLogger, Term};
use super::logging::*;

use crate::{Config, SharedLogger};

/// TermLogger error type.
#[derive(Debug)]
pub enum TermLogError {
    ///The type returned by set_logger if set_logger has already been called.
    SetLogger(SetLoggerError),

    ///TermLogger initialization might also fail if stdout or stderr could not be opened,
    ///e.g. when no tty is attached to the process, it runs detached in the background, etc
    /// This is represented by the `Term` Kind
    Term,
}

impl fmt::Display for TermLogError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use std::error::Error as FmtError;

        write!(f, "{}", self.description())
    }
}

impl error::Error for TermLogError {
    fn description(&self) -> &str {
        match *self {
            SetLogger(ref err) => err.description(),
            Term => "A terminal could not be opened",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            SetLogger(ref err) => Some(err),
            Term => None,
        }
    }
}

impl From<SetLoggerError> for TermLogError {
    fn from(error: SetLoggerError) -> Self {
        SetLogger(error)
    }
}

enum StdTerminal {
    Stderr(Box<StderrTerminal>),
    Stdout(Box<StdoutTerminal>),
}

impl StdTerminal {
    fn flush(&mut self) -> Result<(), Error> {
        match self {
            StdTerminal::Stderr(term) => term.flush(),
            StdTerminal::Stdout(term) => term.flush(),
        }
    }
}

struct OutputStreams {
    err: StdTerminal,
    out: StdTerminal,
}

/// Specifies which streams should be used when logging
pub enum TerminalMode {
    /// Only use Stdout
    Stdout,
    /// Only use Stderr
    Stderr,
    /// Use Stderr for Errors and Stdout otherwise
    Mixed,
}

impl Default for TerminalMode {
    fn default() -> TerminalMode {
        TerminalMode::Mixed
    }
}

/// The TermLogger struct. Provides a stderr/out based Logger implementation
///
/// Supports colored output
pub struct TermLogger {
    level: LevelFilter,
    config: Config,
    streams: Mutex<OutputStreams>,
}

impl TermLogger {
    /// init function. Globally initializes the TermLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized or if a terminal couldn't be opened.
    ///
    /// Workaround the latter by either
    /// - panic'ing (not recommended). e.g. `TermLogger::init(LevelFilter::Warn, Config::default(), TerminalMode::Mixed).unwrap()`
    /// - silently ignoring (little better). e.g. `let _ = TermLogger::init(LevelFilter::Warn, Config::default(), TerminalMode::Mixed);`
    /// - falling back:
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// if let Err(_) = TermLogger::init(LevelFilter::Warn, Config::default(), TerminalMode::Mixed) {
    ///     SimpleLogger::init(LevelFilter::Warn, Config::default()).expect("No logger should be already set")
    /// }
    /// # }
    /// ```
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed).expect("No interactive terminal");
    /// # }
    /// ```
    pub fn init(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
    ) -> Result<(), TermLogError> {
        let logger = TermLogger::new(log_level, config, mode).ok_or(Term)?;
        set_max_level(log_level.clone());
        set_boxed_logger(logger)?;
        Ok(())
    }

    /// allows to create a new logger, that can be independently used, no matter whats globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// Returns a `Box`ed TermLogger, or None if a terminal couldn't be opened.
    /// Workaround this by either
    /// - panic'ing (not recommended). e.g. `TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed).unwrap()`
    /// - silently ignoring (little better). e.g. `if let Some(logger) = TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed) { /*...*/ }`
    /// - falling back:
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let mut multiple = vec![];
    /// match TermLogger::new(LevelFilter::Warn, Config::default(), TerminalMode::Mixed) {
    ///     Some(logger) => multiple.push(logger as Box<dyn SharedLogger>),
    ///     None => multiple.push(SimpleLogger::new(LevelFilter::Warn, Config::default())),
    /// }
    /// // Add more ...
    /// # }
    /// ```
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let term_logger = TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed).expect("No interactive terminal");
    /// # }
    /// ```
    pub fn new(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
    ) -> Option<Box<TermLogger>> {
        let streams = match mode {
            TerminalMode::Stdout => term::stdout().and_then(|stdout| {
                term::stdout().map(|stdout2| {
                    Mutex::new(OutputStreams {
                        err: StdTerminal::Stdout(stdout),
                        out: StdTerminal::Stdout(stdout2),
                    })
                })
            }),
            TerminalMode::Stderr => term::stderr().and_then(|stderr| {
                term::stderr().map(|stderr2| {
                    Mutex::new(OutputStreams {
                        err: StdTerminal::Stderr(stderr),
                        out: StdTerminal::Stderr(stderr2),
                    })
                })
            }),
            TerminalMode::Mixed => term::stderr().and_then(|stderr| {
                term::stdout().map(|stdout| {
                    Mutex::new(OutputStreams {
                        err: StdTerminal::Stderr(stderr),
                        out: StdTerminal::Stdout(stdout),
                    })
                })
            }),
        };

        streams.map(|streams| {
            Box::new(TermLogger {
                level: log_level,
                config: config,
                streams: streams,
            })
        })
    }

    fn try_log_term<W>(
        &self,
        record: &Record<'_>,
        term_lock: &mut Box<dyn Terminal<Output = W> + Send>,
    ) -> Result<(), Error>
    where
        W: Write + Sized,
    {
        let color = match record.level() {
            Level::Error => color::RED,
            Level::Warn => color::YELLOW,
            Level::Info => color::BLUE,
            Level::Debug => color::CYAN,
            Level::Trace => color::WHITE,
        };

        if self.config.time <= record.level() {
            write_time(&mut *term_lock, &self.config)?;
        }

        if self.config.level <= record.level() {
            term_lock.fg(color)?;
            write_level(record, &mut *term_lock)?;
            term_lock.reset()?;
        }

        if self.config.thread <= record.level() {
            write_thread_id(&mut *term_lock)?;
        }

        if self.config.target <= record.level() {
            write_target(record, &mut *term_lock)?;
        }

        if self.config.location <= record.level() {
            write_location(record, &mut *term_lock)?;
        }

        write_args(record, &mut *term_lock)
    }

    fn try_log(&self, record: &Record<'_>) -> Result<(), Error> {
        if self.enabled(record.metadata()) {
            if should_skip(&self.config, record) {
                return Ok(());
            }

            let mut streams = self.streams.lock().unwrap();

            if record.level() == Level::Error {
                match streams.err {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            } else {
                match streams.out {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            }
        } else {
            Ok(())
        }
    }
}

impl Log for TermLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        let _ = self.try_log(record);
    }

    fn flush(&self) {
        let mut streams = self.streams.lock().unwrap();
        let _ = streams.out.flush();
        let _ = streams.err.flush();
    }
}

impl SharedLogger for TermLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}
<|endoftext|>


<commit_before>//! A filter for cross-site request forgery (CSRF).
//!
//! This middleware is stateless and [based on request
//! headers](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Verifying_Same_Origin_with_Standard_Headers).
//!
//! By default requests are allowed only if one of these is true:
//!
//! * The request method is safe (`GET`, `HEAD`, `OPTIONS`). It is the
//!   applications responsibility to ensure these methods cannot be used to
//!   execute unwanted actions. Note that upgrade requests for websockets are
//!   also considered safe.
//! * The `Origin` header (added automatically by the browser) matches one
//!   of the allowed origins.
//! * There is no `Origin` header but the `Referer` header matches one of
//!   the allowed origins.
//!
//! Use [`CsrfFilterBuilder::allow_xhr()`](struct.CsrfFilterBuilder.html#method.allow_xhr)
//! if you want to allow requests with unsafe methods via
//! [CORS](../cors/struct.Cors.html).
//!
//! # Example
//!
//! ```
//! # extern crate actix_web;
//! # use actix_web::*;
//!
//! use actix_web::middleware::csrf;
//!
//! fn handle_post(_req: HttpRequest) -> &'static str {
//!     "This action should only be triggered with requests from the same site"
//! }
//!
//! fn main() {
//!     let app = Application::new()
//!         .middleware(
//!             csrf::CsrfFilter::build()
//!                 .allowed_origin("https://www.example.com")
//!                 .finish())
//!         .resource("/", |r| {
//!             r.method(Method::GET).f(|_| httpcodes::HttpOk);
//!             r.method(Method::POST).f(handle_post);
//!         })
//!         .finish();
//! }
//! ```
//!
//! In this example the entire application is protected from CSRF.

use std::borrow::Cow;
use std::collections::HashSet;

use bytes::Bytes;
use error::{Result, ResponseError};
use http::{HeaderMap, HttpTryFrom, Uri, header};
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use httpmessage::HttpMessage;
use httpcodes::HttpForbidden;
use middleware::{Middleware, Started};

/// Potential cross-site request forgery detected.
#[derive(Debug, Fail)]
pub enum CsrfError {
    /// The HTTP request header `Origin` was required but not provided.
    #[fail(display="Origin header required")]
    MissingOrigin,
    /// The HTTP request header `Origin` could not be parsed correctly.
    #[fail(display="Could not parse Origin header")]
    BadOrigin,
    /// The cross-site request was denied.
    #[fail(display="Cross-site request denied")]
    CsrDenied,
}

impl ResponseError for CsrfError {
    fn error_response(&self) -> HttpResponse {
        HttpForbidden.build().body(self.to_string()).unwrap()
    }
}

fn uri_origin(uri: &Uri) -> Option<String> {
    match (uri.scheme_part(), uri.host(), uri.port()) {
        (Some(scheme), Some(host), Some(port)) => {
            Some(format!("{}://{}:{}", scheme, host, port))
        }
        (Some(scheme), Some(host), None) => {
            Some(format!("{}://{}", scheme, host))
        }
        _ => None
    }
}

fn origin(headers: &HeaderMap) -> Option<Result<Cow<str>, CsrfError>> {
    headers.get(header::ORIGIN)
        .map(|origin| {
            origin
                .to_str()
                .map_err(|_| CsrfError::BadOrigin)
                .map(|o| o.into())
        })
        .or_else(|| {
            headers.get(header::REFERER)
                .map(|referer| {
                    Uri::try_from(Bytes::from(referer.as_bytes()))
                        .ok()
                        .as_ref()
                        .and_then(uri_origin)
                        .ok_or(CsrfError::BadOrigin)
                        .map(|o| o.into())
                })
        })
}

/// A middleware that filters cross-site requests.
pub struct CsrfFilter {
    origins: HashSet<String>,
    allow_xhr: bool,
    allow_missing_origin: bool,
}

impl CsrfFilter {
    /// Start building a `CsrfFilter`.
    pub fn build() -> CsrfFilterBuilder {
        CsrfFilterBuilder {
            cors: CsrfFilter {
                origins: HashSet::new(),
                allow_xhr: false,
                allow_missing_origin: false,
            }
        }
    }

    fn validate<S>(&self, req: &mut HttpRequest<S>) -> Result<(), CsrfError> {
        if req.method().is_safe() || (self.allow_xhr && req.headers().contains_key("x-requested-with")) {
            Ok(())
        } else if let Some(header) = origin(req.headers()) {
            match header {
                Ok(ref origin) if self.origins.contains(origin.as_ref()) => Ok(()),
                Ok(_) => Err(CsrfError::CsrDenied),
                Err(err) => Err(err),
            }
        } else if self.allow_missing_origin {
            Ok(())
        } else {
            Err(CsrfError::MissingOrigin)
        }
    }
}

impl<S> Middleware<S> for CsrfFilter {
    fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
        self.validate(req)?;
        Ok(Started::Done)
    }
}

/// Used to build a `CsrfFilter`.
///
/// To construct a CSRF filter:
///
/// 1. Call [`CsrfFilter::build`](struct.CsrfFilter.html#method.build) to
///    start building.
/// 2. [Add](struct.CsrfFilterBuilder.html#method.allowed_origin) allowed
///    origins.
/// 3. Call [finish](struct.CsrfFilterBuilder.html#method.finish) to retrieve
///    the constructed filter.
///
/// # Example
///
/// ```
/// use actix_web::middleware::csrf;
///
/// let csrf = csrf::CsrfFilter::build()
///     .allowed_origin("https://www.example.com")
///     .finish();
/// ```
pub struct CsrfFilterBuilder {
    cors: CsrfFilter,
}

impl CsrfFilterBuilder {
    /// Add an origin that is allowed to make requests. Will be verified
    /// against the `Origin` request header.
    pub fn allowed_origin(mut self, origin: &str) -> CsrfFilterBuilder {
        self.cors.origins.insert(origin.to_owned());
        self
    }

    /// Allow all requests with an `X-Requested-With` header.
    ///
    /// A cross-site attacker should not be able to send requests with custom
    /// headers unless a CORS policy whitelists them. Therefore it should be
    /// safe to allow requests with an `X-Requested-With` header (added
    /// automatically by many JavaScript libraries).
    ///
    /// This is disabled by default, because in Safari it is possible to
    /// circumvent this using redirects and Flash.
    ///
    /// Use this method to enable more lax filtering.
    pub fn allow_xhr(mut self) -> CsrfFilterBuilder {
        self.cors.allow_xhr = true;
        self
    }

    /// Allow requests if the expected `Origin` header is missing (and
    /// there is no `Referer` to fall back on).
    ///
    /// The filter is conservative by default, but it should be safe to allow
    /// missing `Origin` headers because a cross-site attacker cannot prevent
    /// the browser from sending `Origin` on unsafe requests.
    pub fn allow_missing_origin(mut self) -> CsrfFilterBuilder {
        self.cors.allow_missing_origin = true;
        self
    }

    /// Finishes building the `CsrfFilter` instance.
    pub fn finish(self) -> CsrfFilter {
        self.cors
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use http::Method;
    use test::TestRequest;

    #[test]
    fn test_safe() {
        let csrf = CsrfFilter::build()
            .allowed_origin("https://www.example.com")
            .finish();

        let mut req = TestRequest::with_header("Origin", "https://www.w3.org")
            .method(Method::HEAD)
            .finish();

        assert!(csrf.start(&mut req).is_ok());
    }

    #[test]
    fn test_csrf() {
        let csrf = CsrfFilter::build()
            .allowed_origin("https://www.example.com")
            .finish();

        let mut req = TestRequest::with_header("Origin", "https://www.w3.org")
            .method(Method::POST)
            .finish();

        assert!(csrf.start(&mut req).is_err());
    }

    #[test]
    fn test_referer() {
        let csrf = CsrfFilter::build()
            .allowed_origin("https://www.example.com")
            .finish();

        let mut req = TestRequest::with_header("Referer", "https://www.example.com/some/path?query=param")
            .method(Method::POST)
            .finish();

        assert!(csrf.start(&mut req).is_ok());
    }
}
<commit_msg>fix variable name: cors -> csrf<commit_after>//! A filter for cross-site request forgery (CSRF).
//!
//! This middleware is stateless and [based on request
//! headers](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Verifying_Same_Origin_with_Standard_Headers).
//!
//! By default requests are allowed only if one of these is true:
//!
//! * The request method is safe (`GET`, `HEAD`, `OPTIONS`). It is the
//!   applications responsibility to ensure these methods cannot be used to
//!   execute unwanted actions. Note that upgrade requests for websockets are
//!   also considered safe.
//! * The `Origin` header (added automatically by the browser) matches one
//!   of the allowed origins.
//! * There is no `Origin` header but the `Referer` header matches one of
//!   the allowed origins.
//!
//! Use [`CsrfFilterBuilder::allow_xhr()`](struct.CsrfFilterBuilder.html#method.allow_xhr)
//! if you want to allow requests with unsafe methods via
//! [CORS](../cors/struct.Cors.html).
//!
//! # Example
//!
//! ```
//! # extern crate actix_web;
//! # use actix_web::*;
//!
//! use actix_web::middleware::csrf;
//!
//! fn handle_post(_req: HttpRequest) -> &'static str {
//!     "This action should only be triggered with requests from the same site"
//! }
//!
//! fn main() {
//!     let app = Application::new()
//!         .middleware(
//!             csrf::CsrfFilter::build()
//!                 .allowed_origin("https://www.example.com")
//!                 .finish())
//!         .resource("/", |r| {
//!             r.method(Method::GET).f(|_| httpcodes::HttpOk);
//!             r.method(Method::POST).f(handle_post);
//!         })
//!         .finish();
//! }
//! ```
//!
//! In this example the entire application is protected from CSRF.

use std::borrow::Cow;
use std::collections::HashSet;

use bytes::Bytes;
use error::{Result, ResponseError};
use http::{HeaderMap, HttpTryFrom, Uri, header};
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use httpmessage::HttpMessage;
use httpcodes::HttpForbidden;
use middleware::{Middleware, Started};

/// Potential cross-site request forgery detected.
#[derive(Debug, Fail)]
pub enum CsrfError {
    /// The HTTP request header `Origin` was required but not provided.
    #[fail(display="Origin header required")]
    MissingOrigin,
    /// The HTTP request header `Origin` could not be parsed correctly.
    #[fail(display="Could not parse Origin header")]
    BadOrigin,
    /// The cross-site request was denied.
    #[fail(display="Cross-site request denied")]
    CsrDenied,
}

impl ResponseError for CsrfError {
    fn error_response(&self) -> HttpResponse {
        HttpForbidden.build().body(self.to_string()).unwrap()
    }
}

fn uri_origin(uri: &Uri) -> Option<String> {
    match (uri.scheme_part(), uri.host(), uri.port()) {
        (Some(scheme), Some(host), Some(port)) => {
            Some(format!("{}://{}:{}", scheme, host, port))
        }
        (Some(scheme), Some(host), None) => {
            Some(format!("{}://{}", scheme, host))
        }
        _ => None
    }
}

fn origin(headers: &HeaderMap) -> Option<Result<Cow<str>, CsrfError>> {
    headers.get(header::ORIGIN)
        .map(|origin| {
            origin
                .to_str()
                .map_err(|_| CsrfError::BadOrigin)
                .map(|o| o.into())
        })
        .or_else(|| {
            headers.get(header::REFERER)
                .map(|referer| {
                    Uri::try_from(Bytes::from(referer.as_bytes()))
                        .ok()
                        .as_ref()
                        .and_then(uri_origin)
                        .ok_or(CsrfError::BadOrigin)
                        .map(|o| o.into())
                })
        })
}

/// A middleware that filters cross-site requests.
pub struct CsrfFilter {
    origins: HashSet<String>,
    allow_xhr: bool,
    allow_missing_origin: bool,
}

impl CsrfFilter {
    /// Start building a `CsrfFilter`.
    pub fn build() -> CsrfFilterBuilder {
        CsrfFilterBuilder {
            csrf: CsrfFilter {
                origins: HashSet::new(),
                allow_xhr: false,
                allow_missing_origin: false,
            }
        }
    }

    fn validate<S>(&self, req: &mut HttpRequest<S>) -> Result<(), CsrfError> {
        if req.method().is_safe() || (self.allow_xhr && req.headers().contains_key("x-requested-with")) {
            Ok(())
        } else if let Some(header) = origin(req.headers()) {
            match header {
                Ok(ref origin) if self.origins.contains(origin.as_ref()) => Ok(()),
                Ok(_) => Err(CsrfError::CsrDenied),
                Err(err) => Err(err),
            }
        } else if self.allow_missing_origin {
            Ok(())
        } else {
            Err(CsrfError::MissingOrigin)
        }
    }
}

impl<S> Middleware<S> for CsrfFilter {
    fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
        self.validate(req)?;
        Ok(Started::Done)
    }
}

/// Used to build a `CsrfFilter`.
///
/// To construct a CSRF filter:
///
/// 1. Call [`CsrfFilter::build`](struct.CsrfFilter.html#method.build) to
///    start building.
/// 2. [Add](struct.CsrfFilterBuilder.html#method.allowed_origin) allowed
///    origins.
/// 3. Call [finish](struct.CsrfFilterBuilder.html#method.finish) to retrieve
///    the constructed filter.
///
/// # Example
///
/// ```
/// use actix_web::middleware::csrf;
///
/// let csrf = csrf::CsrfFilter::build()
///     .allowed_origin("https://www.example.com")
///     .finish();
/// ```
pub struct CsrfFilterBuilder {
    csrf: CsrfFilter,
}

impl CsrfFilterBuilder {
    /// Add an origin that is allowed to make requests. Will be verified
    /// against the `Origin` request header.
    pub fn allowed_origin(mut self, origin: &str) -> CsrfFilterBuilder {
        self.csrf.origins.insert(origin.to_owned());
        self
    }

    /// Allow all requests with an `X-Requested-With` header.
    ///
    /// A cross-site attacker should not be able to send requests with custom
    /// headers unless a CORS policy whitelists them. Therefore it should be
    /// safe to allow requests with an `X-Requested-With` header (added
    /// automatically by many JavaScript libraries).
    ///
    /// This is disabled by default, because in Safari it is possible to
    /// circumvent this using redirects and Flash.
    ///
    /// Use this method to enable more lax filtering.
    pub fn allow_xhr(mut self) -> CsrfFilterBuilder {
        self.csrf.allow_xhr = true;
        self
    }

    /// Allow requests if the expected `Origin` header is missing (and
    /// there is no `Referer` to fall back on).
    ///
    /// The filter is conservative by default, but it should be safe to allow
    /// missing `Origin` headers because a cross-site attacker cannot prevent
    /// the browser from sending `Origin` on unsafe requests.
    pub fn allow_missing_origin(mut self) -> CsrfFilterBuilder {
        self.csrf.allow_missing_origin = true;
        self
    }

    /// Finishes building the `CsrfFilter` instance.
    pub fn finish(self) -> CsrfFilter {
        self.csrf
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use http::Method;
    use test::TestRequest;

    #[test]
    fn test_safe() {
        let csrf = CsrfFilter::build()
            .allowed_origin("https://www.example.com")
            .finish();

        let mut req = TestRequest::with_header("Origin", "https://www.w3.org")
            .method(Method::HEAD)
            .finish();

        assert!(csrf.start(&mut req).is_ok());
    }

    #[test]
    fn test_csrf() {
        let csrf = CsrfFilter::build()
            .allowed_origin("https://www.example.com")
            .finish();

        let mut req = TestRequest::with_header("Origin", "https://www.w3.org")
            .method(Method::POST)
            .finish();

        assert!(csrf.start(&mut req).is_err());
    }

    #[test]
    fn test_referer() {
        let csrf = CsrfFilter::build()
            .allowed_origin("https://www.example.com")
            .finish();

        let mut req = TestRequest::with_header("Referer", "https://www.example.com/some/path?query=param")
            .method(Method::POST)
            .finish();

        assert!(csrf.start(&mut req).is_ok());
    }
}
<|endoftext|>