<commit_before>//! Internal traits and functions used to implement parallel
//! iteration. These should be considered highly unstable: users of
//! parallel iterators should not need to interact with them directly.
//! See `README.md` for a high-level overview.

use join;
use super::IndexedParallelIterator;
use super::len::*;
use registry::global_registry;

pub trait ProducerCallback<ITEM> {
    type Output;
    fn callback
(self, producer: P) -> Self::Output where P: Producer<Item = ITEM>;
}

/// A producer which will produce a fixed number of items N. This is
/// not queryable through the API; the consumer is expected to track
/// it.
pub trait Producer: IntoIterator + Send + Sized {
    /// Reports whether the producer has explicit weights.
    fn weighted(&self) -> bool {
        false
    }

    /// Cost to produce `len` items, where `len` must be `N`.
    fn cost(&mut self, len: usize) -> f64;

    /// Split into two producers; one produces items `0..index`, the
    /// other `index..N`. Index must be less than `N`.
    fn split_at(self, index: usize) -> (Self, Self);

    /// Iterate the producer, feeding each element to `folder`, and
    /// stop when the folder is full (or all elements have been consumed).
    ///
    /// The provided implementation is sufficient for most iterables.
    fn fold_with<F>(self, mut folder: F) -> F
        where F: Folder<Self::Item>,
    {
        for item in self {
            folder = folder.consume(item);
            if folder.full() {
                break;
            }
        }
        folder
    }
}

/// A consumer which consumes items that are fed to it.
pub trait Consumer<Item>: Send + Sized {
    type Folder: Folder<Item, Result = Self::Result>;
    type Reducer: Reducer<Self::Result>;
    type Result: Send;

    /// Reports whether the consumer has explicit weights.
    fn weighted(&self) -> bool {
        false
    }

    /// If it costs `producer_cost` to produce the items we will
    /// consume, returns cost adjusted to account for consuming them.
    fn cost(&mut self, producer_cost: f64) -> f64;

    /// Divide the consumer into two consumers, one processing items
    /// `0..index` and one processing items from `index..`. Also
    /// produces a reducer that can be used to reduce the results at
    /// the end.
    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer);

    /// Convert the consumer into a folder that can consume items
    /// sequentially, eventually producing a final result.
    fn into_folder(self) -> Self::Folder;

    /// Hint whether this `Consumer` would like to stop processing
    /// further items, e.g. if a search has been completed.
    fn full(&self) -> bool {
        false
    }
}

pub trait Folder<Item> {
    type Result;

    /// Consume next item and return new sequential state.
    fn consume(self, item: Item) -> Self;

    /// Finish consuming items, produce final result.
    fn complete(self) -> Self::Result;

    /// Hint whether this `Folder` would like to stop processing
    /// further items, e.g. if a search has been completed.
    fn full(&self) -> bool {
        false
    }
}

pub trait Reducer<Result> {
    /// Reduce two final results into one; this is executed after a
    /// split.
    fn reduce(self, left: Result, right: Result) -> Result;
}

/// A stateless consumer can be freely copied.
pub trait UnindexedConsumer<ITEM>: Consumer<ITEM> {
    // The result of split_off_left should be used for the left side of the
    // data it consumes, and the remaining consumer for the right side
    // (this matters for methods like find_first).
    fn split_off_left(&self) -> Self;
    fn to_reducer(&self) -> Self::Reducer;
}

/// An unindexed producer that doesn't know its exact length.
/// (or can't represent its known length in a `usize`)
pub trait UnindexedProducer: IntoIterator + Send + Sized {
    /// Split midway into a new producer if possible, otherwise return `None`.
    fn split(&mut self) -> Option<Self>;

    /// Iterate the producer, feeding each element to `folder`, and
    /// stop when the folder is full (or all elements have been consumed).
    ///
    /// The provided implementation is sufficient for most iterables.
    fn fold_with<F>(self, mut folder: F) -> F
        where F: Folder<Self::Item>,
    {
        for item in self {
            folder = folder.consume(item);
            if folder.full() {
                break;
            }
        }
        folder
    }
}

/// A splitter controls the policy for splitting into smaller work items.
#[derive(Clone, Copy)]
enum Splitter {
    /// Classic cost-splitting uses weights to split until below a threshold.
    Cost(f64),

    /// Thief-splitting is an adaptive policy that starts by splitting into
    /// enough jobs for every worker thread, and then resets itself whenever a
    /// job is actually stolen into a different thread.
    Thief(usize, usize),
}

impl Splitter {
    #[inline]
    fn thief_id() -> usize {
        // The actual `ID` value is irrelevant.  We're just using its TLS
        // address as a unique thread key, faster than a real thread-id call.
        thread_local!{ static ID: bool = false }
        ID.with(|id| id as *const bool as usize)
    }

    #[inline]
    fn new_thief() -> Splitter {
        Splitter::Thief(Splitter::thief_id(), global_registry().num_threads())
    }

    #[inline]
    fn try(&mut self) -> bool {
        match *self {
            Splitter::Cost(ref mut cost) => {
                if *cost > THRESHOLD {
                    *cost /= 2.0;
                    true
                } else {
                    false
                }
            }

            Splitter::Thief(ref mut origin, ref mut splits) => {
                let id = Splitter::thief_id();
                if *origin != id {
                    *origin = id;
                    *splits = global_registry().num_threads();
                    true
                } else if *splits > 0 {
                    *splits /= 2;
                    true
                } else {
                    false
                }
            }
        }
    }

    #[inline]
    fn try_unindexed
(&mut self, producer: &mut P) -> Option

        where P: UnindexedProducer
    {
        if self.try() { producer.split() } else { None }
    }
}

pub fn bridge<PAR_ITER, C>(mut par_iter: PAR_ITER, consumer: C) -> C::Result
    where PAR_ITER: IndexedParallelIterator,
          C: Consumer<PAR_ITER::Item>
{
    let len = par_iter.len();
    return par_iter.with_producer(Callback {
        len: len,
        consumer: consumer,
    });

    struct Callback<C> {
        len: usize,
        consumer: C,
    }

    impl<C, ITEM> ProducerCallback<ITEM> for Callback<C>
        where C: Consumer<ITEM>
    {
        type Output = C::Result;
        fn callback
(self, producer: P) -> C::Result
            where P: Producer<Item = ITEM>
        {
            bridge_producer_consumer(self.len, producer, self.consumer)
        }
    }
}

pub fn bridge_producer_consumer
(len: usize, mut producer: P, mut consumer: C) -> C::Result
    where P: Producer,
          C: Consumer

{
    let splitter = if producer.weighted() || consumer.weighted() {
        let producer_cost = producer.cost(len);
        let cost = consumer.cost(producer_cost);
        Splitter::Cost(cost)
    } else {
        Splitter::new_thief()
    };
    return helper(len, splitter, producer, consumer);

    fn helper
(len: usize, mut splitter: Splitter, producer: P, consumer: C) -> C::Result
        where P: Producer,
              C: Consumer

    {
        if consumer.full() {
            consumer.into_folder().complete()
        } else if len > 1 && splitter.try() {
            let mid = len / 2;
            let (left_producer, right_producer) = producer.split_at(mid);
            let (left_consumer, right_consumer, reducer) = consumer.split_at(mid);
            let (left_result, right_result) =
                join(|| helper(mid, splitter, left_producer, left_consumer),
                     || helper(len - mid, splitter, right_producer, right_consumer));
            reducer.reduce(left_result, right_result)
        } else {
            producer.fold_with(consumer.into_folder()).complete()
        }
    }
}

pub fn bridge_unindexed
(producer: P, consumer: C) -> C::Result
    where P: UnindexedProducer,
          C: UnindexedConsumer

{
    let splitter = Splitter::new_thief();
    bridge_unindexed_producer_consumer(splitter, producer, consumer)
}

fn bridge_unindexed_producer_consumer
(mut splitter: Splitter,
                                            mut producer: P,
                                            consumer: C)
                                            -> C::Result
    where P: UnindexedProducer,
          C: UnindexedConsumer

{
    if consumer.full() {
        consumer.into_folder().complete()
    } else if let Some(right_producer) = splitter.try_unindexed(&mut producer) {
        let (reducer, left_consumer, right_consumer) =
            (consumer.to_reducer(), consumer.split_off_left(), consumer);
        let (left_result, right_result) =
            join(|| bridge_unindexed_producer_consumer(splitter, producer, left_consumer),
                 || bridge_unindexed_producer_consumer(splitter, right_producer, right_consumer));
        reducer.reduce(left_result, right_result)
    } else {
        producer.fold_with(consumer.into_folder()).complete()
    }
}
<commit_msg>Add Folder::consume_iter<commit_after>//! Internal traits and functions used to implement parallel
//! iteration. These should be considered highly unstable: users of
//! parallel iterators should not need to interact with them directly.
//! See `README.md` for a high-level overview.

use join;
use super::IndexedParallelIterator;
use super::len::*;
use registry::global_registry;

pub trait ProducerCallback<ITEM> {
    type Output;
    fn callback
(self, producer: P) -> Self::Output where P: Producer<Item = ITEM>;
}

/// A producer which will produce a fixed number of items N. This is
/// not queryable through the API; the consumer is expected to track
/// it.
pub trait Producer: IntoIterator + Send + Sized {
    /// Reports whether the producer has explicit weights.
    fn weighted(&self) -> bool {
        false
    }

    /// Cost to produce `len` items, where `len` must be `N`.
    fn cost(&mut self, len: usize) -> f64;

    /// Split into two producers; one produces items `0..index`, the
    /// other `index..N`. Index must be less than `N`.
    fn split_at(self, index: usize) -> (Self, Self);

    /// Iterate the producer, feeding each element to `folder`, and
    /// stop when the folder is full (or all elements have been consumed).
    ///
    /// The provided implementation is sufficient for most iterables.
    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>,
    {
        folder.consume_iter(self)
    }
}

/// A consumer which consumes items that are fed to it.
pub trait Consumer<Item>: Send + Sized {
    type Folder: Folder<Item, Result = Self::Result>;
    type Reducer: Reducer<Self::Result>;
    type Result: Send;

    /// Reports whether the consumer has explicit weights.
    fn weighted(&self) -> bool {
        false
    }

    /// If it costs `producer_cost` to produce the items we will
    /// consume, returns cost adjusted to account for consuming them.
    fn cost(&mut self, producer_cost: f64) -> f64;

    /// Divide the consumer into two consumers, one processing items
    /// `0..index` and one processing items from `index..`. Also
    /// produces a reducer that can be used to reduce the results at
    /// the end.
    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer);

    /// Convert the consumer into a folder that can consume items
    /// sequentially, eventually producing a final result.
    fn into_folder(self) -> Self::Folder;

    /// Hint whether this `Consumer` would like to stop processing
    /// further items, e.g. if a search has been completed.
    fn full(&self) -> bool {
        false
    }
}

pub trait Folder<Item>: Sized {
    type Result;

    /// Consume next item and return new sequential state.
    fn consume(self, item: Item) -> Self;

    /// Consume items from the iterator until full, and return new sequential state.
    fn consume_iter(mut self, iter: I) -> Self
        where I: IntoIterator<Item=Item>
    {
        for item in iter {
            self = self.consume(item);
            if self.full() {
                break;
            }
        }
        self
    }

    /// Finish consuming items, produce final result.
    fn complete(self) -> Self::Result;

    /// Hint whether this `Folder` would like to stop processing
    /// further items, e.g. if a search has been completed.
    fn full(&self) -> bool {
        false
    }
}

pub trait Reducer<Result> {
    /// Reduce two final results into one; this is executed after a
    /// split.
    fn reduce(self, left: Result, right: Result) -> Result;
}

/// A stateless consumer can be freely copied.
pub trait UnindexedConsumer<ITEM>: Consumer<ITEM> {
    // The result of split_off_left should be used for the left side of the
    // data it consumes, and the remaining consumer for the right side
    // (this matters for methods like find_first).
    fn split_off_left(&self) -> Self;
    fn to_reducer(&self) -> Self::Reducer;
}

/// An unindexed producer that doesn't know its exact length.
/// (or can't represent its known length in a `usize`)
pub trait UnindexedProducer: IntoIterator + Send + Sized {
    /// Split midway into a new producer if possible, otherwise return `None`.
    fn split(&mut self) -> Option<Self>;

    /// Iterate the producer, feeding each element to `folder`, and
    /// stop when the folder is full (or all elements have been consumed).
    ///
    /// The provided implementation is sufficient for most iterables.
    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>,
    {
        folder.consume_iter(self)
    }
}

/// A splitter controls the policy for splitting into smaller work items.
#[derive(Clone, Copy)]
enum Splitter {
    /// Classic cost-splitting uses weights to split until below a threshold.
    Cost(f64),

    /// Thief-splitting is an adaptive policy that starts by splitting into
    /// enough jobs for every worker thread, and then resets itself whenever a
    /// job is actually stolen into a different thread.
    Thief(usize, usize),
}

impl Splitter {
    #[inline]
    fn thief_id() -> usize {
        // The actual `ID` value is irrelevant.  We're just using its TLS
        // address as a unique thread key, faster than a real thread-id call.
        thread_local!{ static ID: bool = false }
        ID.with(|id| id as *const bool as usize)
    }

    #[inline]
    fn new_thief() -> Splitter {
        Splitter::Thief(Splitter::thief_id(), global_registry().num_threads())
    }

    #[inline]
    fn try(&mut self) -> bool {
        match *self {
            Splitter::Cost(ref mut cost) => {
                if *cost > THRESHOLD {
                    *cost /= 2.0;
                    true
                } else {
                    false
                }
            }

            Splitter::Thief(ref mut origin, ref mut splits) => {
                let id = Splitter::thief_id();
                if *origin != id {
                    *origin = id;
                    *splits = global_registry().num_threads();
                    true
                } else if *splits > 0 {
                    *splits /= 2;
                    true
                } else {
                    false
                }
            }
        }
    }

    #[inline]
    fn try_unindexed
(&mut self, producer: &mut P) -> Option

        where P: UnindexedProducer
    {
        if self.try() { producer.split() } else { None }
    }
}

pub fn bridge<PAR_ITER, C>(mut par_iter: PAR_ITER, consumer: C) -> C::Result
    where PAR_ITER: IndexedParallelIterator,
          C: Consumer<PAR_ITER::Item>
{
    let len = par_iter.len();
    return par_iter.with_producer(Callback {
        len: len,
        consumer: consumer,
    });

    struct Callback<C> {
        len: usize,
        consumer: C,
    }

    impl<C, ITEM> ProducerCallback<ITEM> for Callback<C>
        where C: Consumer<ITEM>
    {
        type Output = C::Result;
        fn callback
(self, producer: P) -> C::Result
            where P: Producer<Item = ITEM>
        {
            bridge_producer_consumer(self.len, producer, self.consumer)
        }
    }
}

pub fn bridge_producer_consumer
(len: usize, mut producer: P, mut consumer: C) -> C::Result
    where P: Producer,
          C: Consumer

{
    let splitter = if producer.weighted() || consumer.weighted() {
        let producer_cost = producer.cost(len);
        let cost = consumer.cost(producer_cost);
        Splitter::Cost(cost)
    } else {
        Splitter::new_thief()
    };
    return helper(len, splitter, producer, consumer);

    fn helper
(len: usize, mut splitter: Splitter, producer: P, consumer: C) -> C::Result
        where P: Producer,
              C: Consumer

    {
        if consumer.full() {
            consumer.into_folder().complete()
        } else if len > 1 && splitter.try() {
            let mid = len / 2;
            let (left_producer, right_producer) = producer.split_at(mid);
            let (left_consumer, right_consumer, reducer) = consumer.split_at(mid);
            let (left_result, right_result) =
                join(|| helper(mid, splitter, left_producer, left_consumer),
                     || helper(len - mid, splitter, right_producer, right_consumer));
            reducer.reduce(left_result, right_result)
        } else {
            producer.fold_with(consumer.into_folder()).complete()
        }
    }
}

pub fn bridge_unindexed
(producer: P, consumer: C) -> C::Result
    where P: UnindexedProducer,
          C: UnindexedConsumer

{
    let splitter = Splitter::new_thief();
    bridge_unindexed_producer_consumer(splitter, producer, consumer)
}

fn bridge_unindexed_producer_consumer
(mut splitter: Splitter,
                                            mut producer: P,
                                            consumer: C)
                                            -> C::Result
    where P: UnindexedProducer,
          C: UnindexedConsumer

{
    if consumer.full() {
        consumer.into_folder().complete()
    } else if let Some(right_producer) = splitter.try_unindexed(&mut producer) {
        let (reducer, left_consumer, right_consumer) =
            (consumer.to_reducer(), consumer.split_off_left(), consumer);
        let (left_result, right_result) =
            join(|| bridge_unindexed_producer_consumer(splitter, producer, left_consumer),
                 || bridge_unindexed_producer_consumer(splitter, right_producer, right_consumer));
        reducer.reduce(left_result, right_result)
    } else {
        producer.fold_with(consumer.into_folder()).complete()
    }
}
<|endoftext|>


<commit_before>// Std
use std::{collections::HashMap, ffi::OsString, mem, ops::Deref};

// Internal
use crate::{
    build::{Arg, ArgSettings},
    parse::{ArgMatches, MatchedArg, SubCommand, ValueType},
    util::Id,
};

#[derive(Debug)]
pub(crate) struct ArgMatcher(pub(crate) ArgMatches);

impl Default for ArgMatcher {
    fn default() -> Self {
        ArgMatcher(ArgMatches::default())
    }
}

impl Deref for ArgMatcher {
    type Target = ArgMatches;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl ArgMatcher {
    pub(crate) fn into_inner(self) -> ArgMatches {
        self.0
    }

    pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
        debug!(
            "ArgMatcher::get_global_values: global_arg_vec={:?}",
            global_arg_vec
        );
        let mut vals_map = HashMap::new();
        self.fill_in_global_values(global_arg_vec, &mut vals_map);
    }

    fn fill_in_global_values(
        &mut self,
        global_arg_vec: &[Id],
        vals_map: &mut HashMap<Id, MatchedArg>,
    ) {
        for global_arg in global_arg_vec {
            if let Some(ma) = self.get(global_arg) {
                // We have to check if the parent's global arg wasn't used but still exists
                // such as from a default value.
                //
                // For example, `myprog subcommand --global-arg=value` where --global-arg defines
                // a default value of `other` myprog would have an existing MatchedArg for
                // --global-arg where the value is `other`, however the occurs will be 0.
                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
                    if parent_ma.occurs > 0 && ma.occurs == 0 {
                        parent_ma.clone()
                    } else {
                        ma.clone()
                    }
                } else {
                    ma.clone()
                };
                vals_map.insert(global_arg.clone(), to_update);
            }
        }
        if let Some(ref mut sc) = self.0.subcommand {
            let mut am = ArgMatcher(mem::take(&mut sc.matches));
            am.fill_in_global_values(global_arg_vec, vals_map);
            mem::swap(&mut am.0, &mut sc.matches);
        }

        for (name, matched_arg) in vals_map.iter_mut() {
            self.0.args.insert(name.clone(), matched_arg.clone());
        }
    }

    pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
        self.0.args.get_mut(arg)
    }

    pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
        self.0.args.get(arg)
    }

    pub(crate) fn remove(&mut self, arg: &Id) {
        self.0.args.swap_remove(arg);
    }

    pub(crate) fn insert(&mut self, name: &Id) {
        self.0.args.insert(name.clone(), MatchedArg::new());
    }

    pub(crate) fn contains(&self, arg: &Id) -> bool {
        self.0.args.contains_key(arg)
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.0.args.is_empty()
    }

    pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
        self.0.args.keys()
    }

    pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
        self.0.args.entry(arg.clone())
    }

    pub(crate) fn subcommand(&mut self, sc: SubCommand) {
        self.0.subcommand = Some(Box::new(sc));
    }

    pub(crate) fn subcommand_name(&self) -> Option<&str> {
        self.0.subcommand_name()
    }

    pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
        self.0.args.iter()
    }

    pub(crate) fn inc_occurrence_of(&mut self, arg: &Id) {
        debug!("ArgMatcher::inc_occurrence_of: arg={:?}", arg);
        if let Some(a) = self.get_mut(arg) {
            a.occurs += 1;
            return;
        }
        debug!("ArgMatcher::inc_occurrence_of: first instance");
        self.insert(arg);
    }

    pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) {
        let ma = self.entry(arg).or_insert(MatchedArg {
            occurs: 0, // @TODO @question Shouldn't this be 1 if we're already adding a value to this arg?
            ty,
            indices: Vec::with_capacity(1),
            vals: Vec::with_capacity(1),
        });
        ma.vals.push(val);
    }

    pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueType) {
        let ma = self.entry(arg).or_insert(MatchedArg {
            occurs: 0,
            indices: Vec::with_capacity(1),
            vals: Vec::new(),
            ty,
        });
        ma.indices.push(idx);
    }

    pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
        debug!("ArgMatcher::needs_more_vals: o={}", o.name);
        if let Some(ma) = self.get(&o.id) {
            if let Some(num) = o.num_vals {
                debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
                return if o.is_set(ArgSettings::MultipleValues) {
                    ((ma.vals.len() as u64) % num) != 0
                } else {
                    num != (ma.vals.len() as u64)
                };
            } else if let Some(num) = o.max_vals {
                debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
                return (ma.vals.len() as u64) < num;
            } else if o.min_vals.is_some() {
                debug!("ArgMatcher::needs_more_vals: min_vals...true");
                return true;
            }
            return o.is_set(ArgSettings::MultipleValues);
        }
        true
    }
}
<commit_msg>Resolve a TODO<commit_after>// Std
use std::{collections::HashMap, ffi::OsString, mem, ops::Deref};

// Internal
use crate::{
    build::{Arg, ArgSettings},
    parse::{ArgMatches, MatchedArg, SubCommand, ValueType},
    util::Id,
};

#[derive(Debug)]
pub(crate) struct ArgMatcher(pub(crate) ArgMatches);

impl Default for ArgMatcher {
    fn default() -> Self {
        ArgMatcher(ArgMatches::default())
    }
}

impl Deref for ArgMatcher {
    type Target = ArgMatches;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl ArgMatcher {
    pub(crate) fn into_inner(self) -> ArgMatches {
        self.0
    }

    pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
        debug!(
            "ArgMatcher::get_global_values: global_arg_vec={:?}",
            global_arg_vec
        );
        let mut vals_map = HashMap::new();
        self.fill_in_global_values(global_arg_vec, &mut vals_map);
    }

    fn fill_in_global_values(
        &mut self,
        global_arg_vec: &[Id],
        vals_map: &mut HashMap<Id, MatchedArg>,
    ) {
        for global_arg in global_arg_vec {
            if let Some(ma) = self.get(global_arg) {
                // We have to check if the parent's global arg wasn't used but still exists
                // such as from a default value.
                //
                // For example, `myprog subcommand --global-arg=value` where --global-arg defines
                // a default value of `other` myprog would have an existing MatchedArg for
                // --global-arg where the value is `other`, however the occurs will be 0.
                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
                    if parent_ma.occurs > 0 && ma.occurs == 0 {
                        parent_ma.clone()
                    } else {
                        ma.clone()
                    }
                } else {
                    ma.clone()
                };
                vals_map.insert(global_arg.clone(), to_update);
            }
        }
        if let Some(ref mut sc) = self.0.subcommand {
            let mut am = ArgMatcher(mem::take(&mut sc.matches));
            am.fill_in_global_values(global_arg_vec, vals_map);
            mem::swap(&mut am.0, &mut sc.matches);
        }

        for (name, matched_arg) in vals_map.iter_mut() {
            self.0.args.insert(name.clone(), matched_arg.clone());
        }
    }

    pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
        self.0.args.get_mut(arg)
    }

    pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
        self.0.args.get(arg)
    }

    pub(crate) fn remove(&mut self, arg: &Id) {
        self.0.args.swap_remove(arg);
    }

    pub(crate) fn insert(&mut self, name: &Id) {
        self.0.args.insert(name.clone(), MatchedArg::new());
    }

    pub(crate) fn contains(&self, arg: &Id) -> bool {
        self.0.args.contains_key(arg)
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.0.args.is_empty()
    }

    pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
        self.0.args.keys()
    }

    pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
        self.0.args.entry(arg.clone())
    }

    pub(crate) fn subcommand(&mut self, sc: SubCommand) {
        self.0.subcommand = Some(Box::new(sc));
    }

    pub(crate) fn subcommand_name(&self) -> Option<&str> {
        self.0.subcommand_name()
    }

    pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
        self.0.args.iter()
    }

    pub(crate) fn inc_occurrence_of(&mut self, arg: &Id) {
        debug!("ArgMatcher::inc_occurrence_of: arg={:?}", arg);
        if let Some(a) = self.get_mut(arg) {
            a.occurs += 1;
            return;
        }
        debug!("ArgMatcher::inc_occurrence_of: first instance");
        self.insert(arg);
    }

    pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) {
        let ma = self.entry(arg).or_insert(MatchedArg {
            // We will manually inc occurrences later(for flexibility under
            // specific circumstances, like only add one occurrence for flag
            // when we met: `--flag=one,two`).
            occurs: 0,
            ty,
            indices: Vec::with_capacity(1),
            vals: Vec::with_capacity(1),
        });
        ma.vals.push(val);
    }

    pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueType) {
        let ma = self.entry(arg).or_insert(MatchedArg {
            occurs: 0,
            indices: Vec::with_capacity(1),
            vals: Vec::new(),
            ty,
        });
        ma.indices.push(idx);
    }

    pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
        debug!("ArgMatcher::needs_more_vals: o={}", o.name);
        if let Some(ma) = self.get(&o.id) {
            if let Some(num) = o.num_vals {
                debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
                return if o.is_set(ArgSettings::MultipleValues) {
                    ((ma.vals.len() as u64) % num) != 0
                } else {
                    num != (ma.vals.len() as u64)
                };
            } else if let Some(num) = o.max_vals {
                debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
                return (ma.vals.len() as u64) < num;
            } else if o.min_vals.is_some() {
                debug!("ArgMatcher::needs_more_vals: min_vals...true");
                return true;
            }
            return o.is_set(ArgSettings::MultipleValues);
        }
        true
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};
use std::fmt;

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
pub struct Au(i32);

// We don't use #[deriving] here for inlining.
impl Clone for Au {
    #[inline]
    fn clone(&self) -> Au {
        let Au(i) = *self;
        Au(i)
    }
}

impl fmt::Show for Au {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Au(n) = *self;
        write!(f.buf, "Au({})", n)
    }}

impl Eq for Au {
    #[inline]
    fn eq(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s == o
    }
    #[inline]
    fn ne(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s != o
    }
}

impl Add<Au,Au> for Au {
    #[inline]
    fn add(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s + o)
    }
}

impl Sub<Au,Au> for Au {
    #[inline]
    fn sub(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s - o)
    }

}

impl Mul<Au,Au> for Au {
    #[inline]
    fn mul(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s * o)
    }
}

impl Div<Au,Au> for Au {
    #[inline]
    fn div(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s / o)
    }
}

impl Rem<Au,Au> for Au {
    #[inline]
    fn rem(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s % o)
    }
}

impl Neg<Au> for Au {
    #[inline]
    fn neg(&self) -> Au {
        let Au(s) = *self;
        Au(-s)
    }
}

impl Ord for Au {
    #[inline]
    fn lt(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s < o
    }
    #[inline]
    fn le(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s <= o
    }
    #[inline]
    fn ge(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s >= o
    }
    #[inline]
    fn gt(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s > o
    }
}

impl One for Au {
    #[inline]
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au { Au(0) }
    #[inline]
    fn is_zero(&self) -> bool {
        let Au(s) = *self;
        s == 0
    }
}

impl Num for Au {}

#[inline]
pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
#[inline]
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    #[inline]
    fn from<T:ToPrimitive>(n: T) -> Option<Au> {
        Some(Au(n.to_i32().unwrap()))
    }
}

impl ToPrimitive for Au {
    #[inline]
    fn to_i64(&self) -> Option<i64> {
        let Au(s) = *self;
        Some(s as i64)
    }

    #[inline]
    fn to_u64(&self) -> Option<u64> {
        let Au(s) = *self;
        Some(s as u64)
    }

    #[inline]
    fn to_f32(&self) -> Option<f32> {
        let Au(s) = *self;
        s.to_f32()
    }

    #[inline]
    fn to_f64(&self) -> Option<f64> {
        let Au(s) = *self;
        s.to_f64()
    }
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f64) -> Au {
        let Au(s) = self;
        Au(((s as f64) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: int) -> Au {
        NumCast::from(px * 60).unwrap()
    }

    #[inline]
    pub fn to_nearest_px(&self) -> int {
        let Au(s) = *self;
        ((s as f64) / 60f64).round() as int
    }

    #[inline]
    pub fn to_snapped(&self) -> Au {
        let Au(s) = *self;
        let res = s % 60i32;
        return if res >= 30i32 { return Au(s - res + 60i32) }
                       else { return Au(s - res) };
    }

    #[inline]
    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    #[inline]
    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        from_px(pt_to_px(pt) as int)
    }

    #[inline]
    pub fn from_frac_px(px: f64) -> Au {
        Au((px * 60f64) as i32)
    }

    #[inline]
    pub fn min(x: Au, y: Au) -> Au {
        let Au(xi) = x;
        let Au(yi) = y;
        if xi < yi { x } else { y }
    }

    #[inline]
    pub fn max(x: Au, y: Au) -> Au {
        let Au(xi) = x;
        let Au(yi) = y;
        if xi > yi { x } else { y }
    }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72f64 * 96f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96f64 * 72f64
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(px: f64) -> Au {
    Au((px * 60f64) as i32)
}

pub fn from_px(px: int) -> Au {
    NumCast::from(px * 60).unwrap()
}

pub fn to_px(au: Au) -> int {
    let Au(a) = au;
    (a / 60) as int
}

pub fn to_frac_px(au: Au) -> f64 {
    let Au(a) = au;
    (a as f64) / 60f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(pt: f64) -> Au {
    from_px((pt / 72f64 * 96f64) as int)
}

// assumes 72 points per inch, and 96 px per inch
pub fn to_pt(au: Au) -> f64 {
    let Au(a) = au;
    (a as f64) / 60f64 * 72f64 / 96f64
}

<commit_msg>util: Add a `rect_contains_point` utility method<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};
use std::fmt;

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
pub struct Au(i32);

// We don't use #[deriving] here for inlining.
impl Clone for Au {
    #[inline]
    fn clone(&self) -> Au {
        let Au(i) = *self;
        Au(i)
    }
}

impl fmt::Show for Au {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Au(n) = *self;
        write!(f.buf, "Au({})", n)
    }}

impl Eq for Au {
    #[inline]
    fn eq(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s == o
    }
    #[inline]
    fn ne(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s != o
    }
}

impl Add<Au,Au> for Au {
    #[inline]
    fn add(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s + o)
    }
}

impl Sub<Au,Au> for Au {
    #[inline]
    fn sub(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s - o)
    }

}

impl Mul<Au,Au> for Au {
    #[inline]
    fn mul(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s * o)
    }
}

impl Div<Au,Au> for Au {
    #[inline]
    fn div(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s / o)
    }
}

impl Rem<Au,Au> for Au {
    #[inline]
    fn rem(&self, other: &Au) -> Au {
        let Au(s) = *self;
        let Au(o) = *other;
        Au(s % o)
    }
}

impl Neg<Au> for Au {
    #[inline]
    fn neg(&self) -> Au {
        let Au(s) = *self;
        Au(-s)
    }
}

impl Ord for Au {
    #[inline]
    fn lt(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s < o
    }
    #[inline]
    fn le(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s <= o
    }
    #[inline]
    fn ge(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s >= o
    }
    #[inline]
    fn gt(&self, other: &Au) -> bool {
        let Au(s) = *self;
        let Au(o) = *other;
        s > o
    }
}

impl One for Au {
    #[inline]
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au { Au(0) }
    #[inline]
    fn is_zero(&self) -> bool {
        let Au(s) = *self;
        s == 0
    }
}

impl Num for Au {}

#[inline]
pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
#[inline]
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    #[inline]
    fn from<T:ToPrimitive>(n: T) -> Option<Au> {
        Some(Au(n.to_i32().unwrap()))
    }
}

impl ToPrimitive for Au {
    #[inline]
    fn to_i64(&self) -> Option<i64> {
        let Au(s) = *self;
        Some(s as i64)
    }

    #[inline]
    fn to_u64(&self) -> Option<u64> {
        let Au(s) = *self;
        Some(s as u64)
    }

    #[inline]
    fn to_f32(&self) -> Option<f32> {
        let Au(s) = *self;
        s.to_f32()
    }

    #[inline]
    fn to_f64(&self) -> Option<f64> {
        let Au(s) = *self;
        s.to_f64()
    }
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f64) -> Au {
        let Au(s) = self;
        Au(((s as f64) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: int) -> Au {
        NumCast::from(px * 60).unwrap()
    }

    #[inline]
    pub fn to_nearest_px(&self) -> int {
        let Au(s) = *self;
        ((s as f64) / 60f64).round() as int
    }

    #[inline]
    pub fn to_snapped(&self) -> Au {
        let Au(s) = *self;
        let res = s % 60i32;
        return if res >= 30i32 { return Au(s - res + 60i32) }
                       else { return Au(s - res) };
    }

    #[inline]
    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    #[inline]
    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        from_px(pt_to_px(pt) as int)
    }

    #[inline]
    pub fn from_frac_px(px: f64) -> Au {
        Au((px * 60f64) as i32)
    }

    #[inline]
    pub fn min(x: Au, y: Au) -> Au {
        let Au(xi) = x;
        let Au(yi) = y;
        if xi < yi { x } else { y }
    }

    #[inline]
    pub fn max(x: Au, y: Au) -> Au {
        let Au(xi) = x;
        let Au(yi) = y;
        if xi > yi { x } else { y }
    }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72f64 * 96f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96f64 * 72f64
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(px: f64) -> Au {
    Au((px * 60f64) as i32)
}

pub fn from_px(px: int) -> Au {
    NumCast::from(px * 60).unwrap()
}

pub fn to_px(au: Au) -> int {
    let Au(a) = au;
    (a / 60) as int
}

pub fn to_frac_px(au: Au) -> f64 {
    let Au(a) = au;
    (a as f64) / 60f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(pt: f64) -> Au {
    from_px((pt / 72f64 * 96f64) as int)
}

// assumes 72 points per inch, and 96 px per inch
pub fn to_pt(au: Au) -> f64 {
    let Au(a) = au;
    (a as f64) / 60f64 * 72f64 / 96f64
}

/// Returns true if the rect contains the given point. Points on the top or left sides of the rect
/// are considered inside the rectangle, while points on the right or bottom sides of the rect are
/// not considered inside the rectangle.
pub fn rect_contains_point<T:Ord + Add<T,T>>(rect: Rect<T>, point: Point2D<T>) -> bool {
    point.x >= rect.origin.x && point.x < rect.origin.x + rect.size.width &&
        point.y >= rect.origin.y && point.y < rect.origin.y + rect.size.height
}

<|endoftext|>


<commit_before>extern mod std;

use std::bitv;
use io::{ReaderUtil, WriterUtil};

// Computes a single solution to a given 9x9 sudoku
//
// Call with "-" to read input sudoku from stdin
//
// The expected line-based format is:
//
// 9,9
// <row>,<column>,<color>
// ...
//
// Row and column are 0-based (i.e. <= 8) and color is 1-based (>=1,<=9).
// A color of 0 indicates an empty field.
//
// If called without arguments, sudoku solves a built-in example sudoku
//

export grid_t, read_grid, solve_grid, write_grid;

// internal type of sudoku grids
type grid = ~[~[mut u8]];

// exported type of sudoku grids
enum grid_t { grid_ctor(grid), }

// read a sudoku problem from file f
fn read_grid(f: io::Reader) -> grid_t {
    assert f.read_line() == ~"9,9"; /* assert first line is exactly "9,9" */

    let g = vec::from_fn(10u, {|_i|
        vec::to_mut(vec::from_elem(10u, 0 as u8))
    });
    while !f.eof() {
        let comps = str::split_char(str::trim(f.read_line()), ',');
        if vec::len(comps) >= 3u {
            let row     = uint::from_str(comps[0]).get() as u8;
            let col     = uint::from_str(comps[1]).get() as u8;
            g[row][col] = uint::from_str(comps[2]).get() as u8;
        }
    }
    return grid_ctor(g);
}

// solve sudoku grid
fn solve_grid(g: grid_t) {
    fn next_color(g: grid, row: u8, col: u8, start_color: u8) -> bool {
        if start_color < 10u8 {
            // colors not yet used
            let avail = bitv::Bitv(10u, false);
            for u8::range(start_color, 10u8) |color| {
                avail.set(color as uint, true);
            }

            // drop colors already in use in neighbourhood
            drop_colors(g, avail, row, col);

            // find first remaining color that is available
            for uint::range(1u, 10u) |i| {
                if avail.get(i) {
                    g[row][col] = i as u8;
                    return true;
                }
            };
        }
        g[row][col] = 0u8;
        return false;
    }

    // find colors available in neighbourhood of (row, col)
    fn drop_colors(g: grid, avail: bitv::Bitv, row: u8, col: u8) {
        fn drop_color(g: grid, colors: bitv::Bitv, row: u8, col: u8) {
            let color = g[row][col];
            if color != 0u8 { colors.set(color as uint, false); }
        }

        let it = |a,b| drop_color(g, avail, a, b);

        for u8::range(0u8, 9u8) |idx| {
            it(idx, col); /* check same column fields */
            it(row, idx); /* check same row fields */
        }

        // check same block fields
        let row0 = (row / 3u8) * 3u8;
        let col0 = (col / 3u8) * 3u8;
        for u8::range(row0, row0 + 3u8) |alt_row| {
            for u8::range(col0, col0 + 3u8) |alt_col| { it(alt_row, alt_col); }
        }
    }

    let mut work: ~[(u8, u8)] = ~[]; /* queue of uncolored fields */
    for u8::range(0u8, 9u8) |row| {
        for u8::range(0u8, 9u8) |col| {
            let color = (*g)[row][col];
            if color == 0u8 { work += ~[(row, col)]; }
        }
    }

    let mut ptr = 0u;
    let end = vec::len(work);
    while (ptr < end) {
        let (row, col) = work[ptr];
        // is there another color to try?
        if next_color(*g, row, col, (*g)[row][col] + (1 as u8)) {
            //  yes: advance work list
            ptr = ptr + 1u;
        } else {
            // no: redo this field aft recoloring pred; unless there is none
            if ptr == 0u { fail ~"No solution found for this sudoku"; }
            ptr = ptr - 1u;
        }
    }
}

fn write_grid(f: io::Writer, g: grid_t) {
    for u8::range(0u8, 9u8) |row| {
        f.write_str(fmt!("%u", (*g)[row][0] as uint));
        for u8::range(1u8, 9u8) |col| {
            f.write_str(fmt!(" %u", (*g)[row][col] as uint));
        }
        f.write_char('\n');
     }
}

fn main() {
    let args = os::args();
    let grid = if vec::len(args) == 1u {
        // FIXME create sudoku inline since nested vec consts dont work yet
        // (#571)
        let g = vec::from_fn(10u, |_i| {
            vec::to_mut(vec::from_elem(10u, 0 as u8))
        });
        g[0][1] = 4u8;
        g[0][3] = 6u8;
        g[0][7] = 3u8;
        g[0][8] = 2u8;
        g[1][2] = 8u8;
        g[1][4] = 2u8;
        g[2][0] = 7u8;
        g[2][3] = 8u8;
        g[3][3] = 5u8;
        g[4][1] = 5u8;
        g[4][5] = 3u8;
        g[4][6] = 6u8;
        g[5][0] = 6u8;
        g[5][1] = 8u8;
        g[5][7] = 9u8;
        g[6][1] = 9u8;
        g[6][2] = 5u8;
        g[6][5] = 6u8;
        g[6][7] = 7u8;
        g[7][4] = 4u8;
        g[7][7] = 6u8;
        g[8][0] = 4u8;
        g[8][5] = 7u8;
        g[8][6] = 2u8;
        g[8][8] = 3u8;
        grid_ctor(g)
    } else {
        read_grid(io::stdin())
    };
    solve_grid(grid);
    write_grid(io::stdout(), grid);
}

<commit_msg>Change FIXME number<commit_after>extern mod std;

use std::bitv;
use io::{ReaderUtil, WriterUtil};

// Computes a single solution to a given 9x9 sudoku
//
// Call with "-" to read input sudoku from stdin
//
// The expected line-based format is:
//
// 9,9
// <row>,<column>,<color>
// ...
//
// Row and column are 0-based (i.e. <= 8) and color is 1-based (>=1,<=9).
// A color of 0 indicates an empty field.
//
// If called without arguments, sudoku solves a built-in example sudoku
//

export grid_t, read_grid, solve_grid, write_grid;

// internal type of sudoku grids
type grid = ~[~[mut u8]];

// exported type of sudoku grids
enum grid_t { grid_ctor(grid), }

// read a sudoku problem from file f
fn read_grid(f: io::Reader) -> grid_t {
    assert f.read_line() == ~"9,9"; /* assert first line is exactly "9,9" */

    let g = vec::from_fn(10u, {|_i|
        vec::to_mut(vec::from_elem(10u, 0 as u8))
    });
    while !f.eof() {
        let comps = str::split_char(str::trim(f.read_line()), ',');
        if vec::len(comps) >= 3u {
            let row     = uint::from_str(comps[0]).get() as u8;
            let col     = uint::from_str(comps[1]).get() as u8;
            g[row][col] = uint::from_str(comps[2]).get() as u8;
        }
    }
    return grid_ctor(g);
}

// solve sudoku grid
fn solve_grid(g: grid_t) {
    fn next_color(g: grid, row: u8, col: u8, start_color: u8) -> bool {
        if start_color < 10u8 {
            // colors not yet used
            let avail = bitv::Bitv(10u, false);
            for u8::range(start_color, 10u8) |color| {
                avail.set(color as uint, true);
            }

            // drop colors already in use in neighbourhood
            drop_colors(g, avail, row, col);

            // find first remaining color that is available
            for uint::range(1u, 10u) |i| {
                if avail.get(i) {
                    g[row][col] = i as u8;
                    return true;
                }
            };
        }
        g[row][col] = 0u8;
        return false;
    }

    // find colors available in neighbourhood of (row, col)
    fn drop_colors(g: grid, avail: bitv::Bitv, row: u8, col: u8) {
        fn drop_color(g: grid, colors: bitv::Bitv, row: u8, col: u8) {
            let color = g[row][col];
            if color != 0u8 { colors.set(color as uint, false); }
        }

        let it = |a,b| drop_color(g, avail, a, b);

        for u8::range(0u8, 9u8) |idx| {
            it(idx, col); /* check same column fields */
            it(row, idx); /* check same row fields */
        }

        // check same block fields
        let row0 = (row / 3u8) * 3u8;
        let col0 = (col / 3u8) * 3u8;
        for u8::range(row0, row0 + 3u8) |alt_row| {
            for u8::range(col0, col0 + 3u8) |alt_col| { it(alt_row, alt_col); }
        }
    }

    let mut work: ~[(u8, u8)] = ~[]; /* queue of uncolored fields */
    for u8::range(0u8, 9u8) |row| {
        for u8::range(0u8, 9u8) |col| {
            let color = (*g)[row][col];
            if color == 0u8 { work += ~[(row, col)]; }
        }
    }

    let mut ptr = 0u;
    let end = vec::len(work);
    while (ptr < end) {
        let (row, col) = work[ptr];
        // is there another color to try?
        if next_color(*g, row, col, (*g)[row][col] + (1 as u8)) {
            //  yes: advance work list
            ptr = ptr + 1u;
        } else {
            // no: redo this field aft recoloring pred; unless there is none
            if ptr == 0u { fail ~"No solution found for this sudoku"; }
            ptr = ptr - 1u;
        }
    }
}

fn write_grid(f: io::Writer, g: grid_t) {
    for u8::range(0u8, 9u8) |row| {
        f.write_str(fmt!("%u", (*g)[row][0] as uint));
        for u8::range(1u8, 9u8) |col| {
            f.write_str(fmt!(" %u", (*g)[row][col] as uint));
        }
        f.write_char('\n');
     }
}

fn main() {
    let args = os::args();
    let grid = if vec::len(args) == 1u {
        // FIXME create sudoku inline since nested vec consts dont work yet
        // (#3733)
        let g = vec::from_fn(10u, |_i| {
            vec::to_mut(vec::from_elem(10u, 0 as u8))
        });
        g[0][1] = 4u8;
        g[0][3] = 6u8;
        g[0][7] = 3u8;
        g[0][8] = 2u8;
        g[1][2] = 8u8;
        g[1][4] = 2u8;
        g[2][0] = 7u8;
        g[2][3] = 8u8;
        g[3][3] = 5u8;
        g[4][1] = 5u8;
        g[4][5] = 3u8;
        g[4][6] = 6u8;
        g[5][0] = 6u8;
        g[5][1] = 8u8;
        g[5][7] = 9u8;
        g[6][1] = 9u8;
        g[6][2] = 5u8;
        g[6][5] = 6u8;
        g[6][7] = 7u8;
        g[7][4] = 4u8;
        g[7][7] = 6u8;
        g[8][0] = 4u8;
        g[8][5] = 7u8;
        g[8][6] = 2u8;
        g[8][8] = 3u8;
        grid_ctor(g)
    } else {
        read_grid(io::stdin())
    };
    solve_grid(grid);
    write_grid(io::stdout(), grid);
}

<|endoftext|>


<commit_before>import core::*;

use std;
import std::list;
import std::list::{from_vec, head, is_not_empty, tail};
import option;

#[test]
fn test_from_vec() {
    let l = from_vec([0, 1, 2]);

    check is_not_empty(l);
    assert (head(l) == 0);

    let tail_l = tail(l);
    check is_not_empty(tail_l);
    assert (head(tail_l) == 1);

    let tail_tail_l = tail(tail_l);
    check is_not_empty(tail_tail_l);
    assert (head(tail_tail_l) == 2);
}

#[test]
fn test_from_vec_empty() {
    let empty : list::list<int> = from_vec([]);
    assert (empty == list::nil::<int>);
}

#[test]
fn test_from_vec_mut() {
    let l = from_vec([mutable 0, 1, 2]);

    check is_not_empty(l);
    assert (head(l) == 0);

    let tail_l = tail(l);
    check is_not_empty(tail_l);
    assert (head(tail_l) == 1);

    let tail_tail_l = tail(tail_l);
    check is_not_empty(tail_tail_l);
    assert (head(tail_tail_l) == 2);
}

#[test]
fn test_foldl() {
    fn add(&&a: uint, &&b: int) -> uint { ret a + (b as uint); }
    let l = from_vec([0, 1, 2, 3, 4]);
    let empty = list::nil::<int>;
    assert (list::foldl(l, 0u, add) == 10u);
    assert (list::foldl(empty, 0u, add) == 0u);
}

#[test]
fn test_foldl2() {
    fn sub(&&a: int, &&b: int) -> int {
        a - b
    }
    let l = from_vec([1, 2, 3, 4]);
    assert (list::foldl(l, 0, sub) == -10);
}

#[test]
fn test_find_success() {
    fn match(&&i: int) -> option::t<int> {
        ret if i == 2 { option::some(i) } else { option::none::<int> };
    }
    let l = from_vec([0, 1, 2]);
    assert (list::find(l, match) == option::some(2));
}

#[test]
fn test_find_fail() {
    fn match(&&_i: int) -> option::t<int> { ret option::none::<int>; }
    let l = from_vec([0, 1, 2]);
    let empty = list::nil::<int>;
    assert (list::find(l, match) == option::none::<int>);
    assert (list::find(empty, match) == option::none::<int>);
}

#[test]
fn test_has() {
    let l = from_vec([5, 8, 6]);
    let empty = list::nil::<int>;
    assert (list::has(l, 5));
    assert (!list::has(l, 7));
    assert (list::has(l, 8));
    assert (!list::has(empty, 5));
}

#[test]
fn test_len() {
    let l = from_vec([0, 1, 2]);
    let empty = list::nil::<int>;
    assert (list::len(l) == 3u);
    assert (list::len(empty) == 0u);
}

<commit_msg>add test for list:is_empty()<commit_after>import core::*;

use std;
import std::list;
import std::list::{from_vec, head, is_empty, is_not_empty, tail};
import option;

#[test]
fn test_is_empty() {
    let empty : list::list<int> = from_vec([]);
    let full1 = from_vec([1]);
    let full2 = from_vec(['r', 'u']);

    assert is_empty(empty);
    assert !is_empty(full1);
    assert !is_empty(full2);

    assert !is_not_empty(empty);
    assert is_not_empty(full1);
    assert is_not_empty(full2);
}

#[test]
fn test_from_vec() {
    let l = from_vec([0, 1, 2]);

    check is_not_empty(l);
    assert (head(l) == 0);

    let tail_l = tail(l);
    check is_not_empty(tail_l);
    assert (head(tail_l) == 1);

    let tail_tail_l = tail(tail_l);
    check is_not_empty(tail_tail_l);
    assert (head(tail_tail_l) == 2);
}

#[test]
fn test_from_vec_empty() {
    let empty : list::list<int> = from_vec([]);
    assert (empty == list::nil::<int>);
}

#[test]
fn test_from_vec_mut() {
    let l = from_vec([mutable 0, 1, 2]);

    check is_not_empty(l);
    assert (head(l) == 0);

    let tail_l = tail(l);
    check is_not_empty(tail_l);
    assert (head(tail_l) == 1);

    let tail_tail_l = tail(tail_l);
    check is_not_empty(tail_tail_l);
    assert (head(tail_tail_l) == 2);
}

#[test]
fn test_foldl() {
    fn add(&&a: uint, &&b: int) -> uint { ret a + (b as uint); }
    let l = from_vec([0, 1, 2, 3, 4]);
    let empty = list::nil::<int>;
    assert (list::foldl(l, 0u, add) == 10u);
    assert (list::foldl(empty, 0u, add) == 0u);
}

#[test]
fn test_foldl2() {
    fn sub(&&a: int, &&b: int) -> int {
        a - b
    }
    let l = from_vec([1, 2, 3, 4]);
    assert (list::foldl(l, 0, sub) == -10);
}

#[test]
fn test_find_success() {
    fn match(&&i: int) -> option::t<int> {
        ret if i == 2 { option::some(i) } else { option::none::<int> };
    }
    let l = from_vec([0, 1, 2]);
    assert (list::find(l, match) == option::some(2));
}

#[test]
fn test_find_fail() {
    fn match(&&_i: int) -> option::t<int> { ret option::none::<int>; }
    let l = from_vec([0, 1, 2]);
    let empty = list::nil::<int>;
    assert (list::find(l, match) == option::none::<int>);
    assert (list::find(empty, match) == option::none::<int>);
}

#[test]
fn test_has() {
    let l = from_vec([5, 8, 6]);
    let empty = list::nil::<int>;
    assert (list::has(l, 5));
    assert (!list::has(l, 7));
    assert (list::has(l, 8));
    assert (!list::has(empty, 5));
}

#[test]
fn test_len() {
    let l = from_vec([0, 1, 2]);
    let empty = list::nil::<int>;
    assert (list::len(l) == 3u);
    assert (list::len(empty) == 0u);
}

<|endoftext|>


<commit_before>/// Various testing of the reading of files in the pretty text format into
/// binary NBT files. This is only used for testing abnormally formatted but
/// otherwise valid text files, and for testing failure states of the string
/// reading.
///
/// Testing of valid and regularly formatted files are conducted in the main
/// file with its "loops".

use std::io::Cursor;

use error_chain::ChainedError;

use data::NBTFile;
use errors::Result;

/// Convenience method
fn try_parse_string(original: &str) -> Result<NBTFile> {
    let mut cursor = Cursor::new(original.as_bytes());
    ::string_read::read_file(&mut cursor)
}

fn try_parse_string_get_err_msg(original: &str) -> String {
    let err = match try_parse_string(original) {
        Ok(_) => panic!("try_parse_string_get_err_msg test expected the file to be Err but it was Ok"),
        Err(e) => e,
    };
    format!("{}", err.display_chain())
}

#[test]
fn empty_file() {
    let err_msg = try_parse_string_get_err_msg("   ");
    assert!(err_msg.contains("NBT file in text format does not contain any tags at all"));
}

#[test]
fn text_file_with_no_trailing_bytes() {
    /* I experienced an error with the new tokenizer where it would ignore the
     * last tag unless there was at least 1 byte following it */
    try_parse_string("None End").unwrap();
}

#[test]
fn incomplete_string() {
    let err_msg = try_parse_string_get_err_msg(r#"None Compound "A quotation mark at the end has been removed from this otherwise valid NBT file End End"#);
    assert!(err_msg.contains("EOF when trying to read the name of a Compound tag in a compound"));
}

#[test]
fn escaped_unescapable_char() {
    let err_msg = try_parse_string_get_err_msg(r#"None Compound "\k" End End"#);
    assert!(err_msg.contains("Invalid string, tried to escape the character"));
}

#[test]
fn eof_when_reading() {
    let err_msg = try_parse_string_get_err_msg(r#"None Compound "" Short """#);
    assert!(err_msg.contains("EOF when trying to read a short"));
}

#[test]
fn invalid_int() {
    let err_msg = try_parse_string_get_err_msg(r#"Zlib Compound "" Int "" NotAnInt End End"#);
    assert!(err_msg.contains("Invalid Int NotAnInt"));
}

#[test]
fn invalid_tag_type() {
    let err_msg = try_parse_string_get_err_msg(r#"Gzip Compound "" List "" NotATagType 1 9 End End"#);
    assert!(err_msg.contains("Unknown tag type NotATagType"));
}

#[test]
fn unquoted_string() {
    /* Since the rewrite of the tokenizer, strings without quotation marks have
     * become valid syntax. I'm not sure if I want to keep this valid or not,
     * so I'll leave it undocumented except for this test testing that they are
     * parsed */
    try_parse_string(r#"None Compound ForgotQuotationMarksAroundThisString End End"#).unwrap();
}
<commit_msg>fix unused results lint in string_read test<commit_after>/// Various testing of the reading of files in the pretty text format into
/// binary NBT files. This is only used for testing abnormally formatted but
/// otherwise valid text files, and for testing failure states of the string
/// reading.
///
/// Testing of valid and regularly formatted files are conducted in the main
/// file with its "loops".

use std::io::Cursor;

use error_chain::ChainedError;

use data::NBTFile;
use errors::Result;

/// Convenience method
fn try_parse_string(original: &str) -> Result<NBTFile> {
    let mut cursor = Cursor::new(original.as_bytes());
    ::string_read::read_file(&mut cursor)
}

fn try_parse_string_get_err_msg(original: &str) -> String {
    let err = match try_parse_string(original) {
        Ok(_) => panic!("try_parse_string_get_err_msg test expected the file to be Err but it was Ok"),
        Err(e) => e,
    };
    format!("{}", err.display_chain())
}

#[test]
fn empty_file() {
    let err_msg = try_parse_string_get_err_msg("   ");
    assert!(err_msg.contains("NBT file in text format does not contain any tags at all"));
}

#[test]
fn text_file_with_no_trailing_bytes() {
    /* I experienced an error with the new tokenizer where it would ignore the
     * last tag unless there was at least 1 byte following it */
    let _: NBTFile = try_parse_string("None End").unwrap();
}

#[test]
fn incomplete_string() {
    let err_msg = try_parse_string_get_err_msg(r#"None Compound "A quotation mark at the end has been removed from this otherwise valid NBT file End End"#);
    assert!(err_msg.contains("EOF when trying to read the name of a Compound tag in a compound"));
}

#[test]
fn escaped_unescapable_char() {
    let err_msg = try_parse_string_get_err_msg(r#"None Compound "\k" End End"#);
    assert!(err_msg.contains("Invalid string, tried to escape the character"));
}

#[test]
fn eof_when_reading() {
    let err_msg = try_parse_string_get_err_msg(r#"None Compound "" Short """#);
    assert!(err_msg.contains("EOF when trying to read a short"));
}

#[test]
fn invalid_int() {
    let err_msg = try_parse_string_get_err_msg(r#"Zlib Compound "" Int "" NotAnInt End End"#);
    assert!(err_msg.contains("Invalid Int NotAnInt"));
}

#[test]
fn invalid_tag_type() {
    let err_msg = try_parse_string_get_err_msg(r#"Gzip Compound "" List "" NotATagType 1 9 End End"#);
    assert!(err_msg.contains("Unknown tag type NotATagType"));
}

#[test]
fn unquoted_string() {
    /* Since the rewrite of the tokenizer, strings without quotation marks have
     * become valid syntax. I'm not sure if I want to keep this valid or not,
     * so I'll leave it undocumented except for this test testing that they are
     * parsed */
    let _: NBTFile = try_parse_string(r#"None Compound ForgotQuotationMarksAroundThisString End End"#).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z borrowck=mir

fn guard() -> bool {
    false
}

fn guard2(_:i32) -> bool {
    true
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        Some(y) => (2, y),
        None => (3, 3),
    };
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match2() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        None => (3, 3),
        Some(y) => (2, y),
    };
}

fn main() {
    let _ = match Some(1) {
        Some(_w) if guard() => 1,
        _x => 2,
        Some(y) if guard2(y) => 3,
        _z => 4,
    };
}

// END RUST SOURCE
//
// START rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _6 = discriminant(_2);
//      switchInt(move _6) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: {  // arm1
//      StorageLive(_8);
//      _8 = _4;
//      _1 = (const 1i32, move _8);
//      StorageDead(_8);
//      goto -> bb13;
//  }
//  bb3: { // binding3(empty) and arm3
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb4: {
//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
//  }
//  bb5: {
//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
//  }
//  bb6: {
//      falseEdges -> [real: bb3, imaginary: bb7]; //pre_binding3
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: {
//      unreachable;
//  }
//  bb9: { // binding1 and guard
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      StorageLive(_7);
//      _7 = const guard() -> [return: bb10, unwind: bb1];
//  }
//  bb10: { // end of guard
//      switchInt(move _7) -> [false: bb11, otherwise: bb2];
//  }
//  bb11: { // to pre_binding2
//      falseEdges -> [real: bb5, imaginary: bb5];
//  }
//  bb12: { // bindingNoLandingPads.before.mir2 and arm2
//      StorageLive(_5);
//      _5 = ((_2 as Some).0: i32);
//      StorageLive(_9);
//      _9 = _5;
//      _1 = (const 2i32, move _9);
//      StorageDead(_9);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//
// START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _6 = discriminant(_2);
//      switchInt(move _6) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: { // arm1
//      StorageLive(_8);
//      _8 = _4;
//      _1 = (const 1i32, move _8);
//      StorageDead(_8);
//      goto -> bb13;
//  }
//  bb3: { // binding3(empty) and arm3
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb4: {
//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
//  }
//  bb5: {
//      falseEdges -> [real: bb3, imaginary: bb6]; //pre_binding2
//  }
//  bb6: {
//      falseEdges -> [real: bb12, imaginary: bb7]; //pre_binding3
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: {
//      unreachable;
//  }
//  bb9: { // binding1 and guard
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      StorageLive(_7);
//      _7 = const guard() -> [return: bb10, unwind: bb1];
//  }
//  bb10: { // end of guard
//      switchInt(move _7) -> [false: bb11, otherwise: bb2];
//  }
//  bb11: { // to pre_binding2
//      falseEdges -> [real: bb6, imaginary: bb5];
//  }
//  bb12: { // binding2 and arm2
//      StorageLive(_5);
//      _5 = ((_2 as Some).0: i32);
//      StorageLive(_9);
//      _9 = _5;
//      _1 = (const 2i32, move _9);
//      StorageDead(_9);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//
// START rustc.main.QualifyAndPromoteConstants.before.mir
// bb0: {
//     ...
//     _2 = std::option::Option<i32>::Some(const 1i32,);
//     _3 = discriminant(_2);
//     _8 = discriminant(_2);
//     switchInt(move _8) -> [1isize: bb4, otherwise: bb5];
// }
// bb1: {
//     resume;
// }
// bb2: { // arm1
//     _1 = const 1i32;
//     goto -> bb17;
// }
// bb3: { // arm3
//     _1 = const 3i32;
//     goto -> bb17;
// }
//
// bb4: {
//     falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
// }
// bb5: {
//     falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
// }
// bb6: {
//     falseEdges -> [real: bb13, imaginary: bb7]; //pre_binding3
// }
// bb7: {
//     falseEdges -> [real: bb16, imaginary: bb8]; //pre_binding4
// }
// bb8: {
//     unreachable;
// }
// bb9: { // binding1: Some(w) if guard()
//     StorageLive(_4);
//     _4 = ((_2 as Some).0: i32);
//     StorageLive(_9);
//     _9 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { //end of guard
//    switchInt(move _9) -> [false: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
//     falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb12: { // binding2 & arm2
//     StorageLive(_5);
//     _5 = _2;
//     _1 = const 2i32;
//     goto -> bb17;
// }
// bb13: { // binding3: Some(y) if guard2(y)
//     StorageLive(_6);
//     _6 = ((_2 as Some).0: i32);
//     StorageLive(_11);
//     StorageLive(_12);
//     _12 = _6;
//     _11 = const guard2(move _12) -> [return: bb14, unwind: bb1];
// }
// bb14: { // end of guard2
//     StorageDead(_12);
//     switchInt(move _11) -> [false: bb15, otherwise: bb3];
// }
// bb15: { // to pre_binding4
//     falseEdges -> [real: bb7, imaginary: bb7];
// }
// bb16: { // binding4 & arm4
//     StorageLive(_7);
//     _7 = _2;
//     _1 = const 4i32;
//     goto -> bb17;
// }
// bb17: {
//     ...
//     return;
// }
// END rustc.main.QualifyAndPromoteConstants.before.mir
<commit_msg>Update mir-opt test to reflect change to MIR code-generation.<commit_after>// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z borrowck=mir

fn guard() -> bool {
    false
}

fn guard2(_:i32) -> bool {
    true
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        Some(y) => (2, y),
        None => (3, 3),
    };
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match2() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        None => (3, 3),
        Some(y) => (2, y),
    };
}

fn main() {
    let _ = match Some(1) {
        Some(_w) if guard() => 1,
        _x => 2,
        Some(y) if guard2(y) => 3,
        _z => 4,
    };
}

// END RUST SOURCE
//
// START rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _7 = discriminant(_2);
//      switchInt(move _7) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: {  // arm1
//      StorageLive(_9);
//      _9 = _4;
//      _1 = (const 1i32, move _9);
//      StorageDead(_9);
//      goto -> bb13;
//  }
//  bb3: { // binding3(empty) and arm3
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb4: {
//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
//  }
//  bb5: {
//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
//  }
//  bb6: {
//      falseEdges -> [real: bb3, imaginary: bb7]; //pre_binding3
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: {
//      unreachable;
//  }
//  bb9: { // binding1 and guard
//      StorageLive(_5);
//      _5 = &((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = const guard() -> [return: bb10, unwind: bb1];
//  }
//  bb10: { // end of guard
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      switchInt(move _8) -> [false: bb11, otherwise: bb2];
//  }
//  bb11: { // to pre_binding2
//      falseEdges -> [real: bb5, imaginary: bb5];
//  }
//  bb12: { // bindingNoLandingPads.before.mir2 and arm2
//      StorageLive(_6);
//      _6 = ((_2 as Some).0: i32);
//      StorageLive(_10);
//      _10 = _6;
//      _1 = (const 2i32, move _10);
//      StorageDead(_10);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//
// START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _7 = discriminant(_2);
//      switchInt(move _7) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: { // arm1
//      StorageLive(_9);
//      _9 = _4;
//      _1 = (const 1i32, move _9);
//      StorageDead(_9);
//      goto -> bb13;
//  }
//  bb3: { // binding3(empty) and arm3
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb4: {
//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
//  }
//  bb5: {
//      falseEdges -> [real: bb3, imaginary: bb6]; //pre_binding2
//  }
//  bb6: {
//      falseEdges -> [real: bb12, imaginary: bb7]; //pre_binding3
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: {
//      unreachable;
//  }
//  bb9: { // binding1 and guard
//      StorageLive(_5);
//      _5 = &((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = const guard() -> [return: bb10, unwind: bb1];
//  }
//  bb10: { // end of guard
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      switchInt(move _8) -> [false: bb11, otherwise: bb2];
//  }
//  bb11: { // to pre_binding2
//      falseEdges -> [real: bb6, imaginary: bb5];
//  }
//  bb12: { // binding2 and arm2
//      StorageLive(_6);
//      _6 = ((_2 as Some).0: i32);
//      StorageLive(_10);
//      _10 = _6;
//      _1 = (const 2i32, move _10);
//      StorageDead(_10);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//
// START rustc.main.QualifyAndPromoteConstants.before.mir
// bb0: {
//     ...
//     _2 = std::option::Option<i32>::Some(const 1i32,);
//     _3 = discriminant(_2);
//     _10 = discriminant(_2);
//     switchInt(move _10) -> [1isize: bb4, otherwise: bb5];
// }
// bb1: {
//     resume;
// }
// bb2: { // arm1
//     _1 = const 1i32;
//     goto -> bb17;
// }
// bb3: { // arm3
//     _1 = const 3i32;
//     goto -> bb17;
// }
//
// bb4: {
//     falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
// }
// bb5: {
//     falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
// }
// bb6: {
//     falseEdges -> [real: bb13, imaginary: bb7]; //pre_binding3
// }
// bb7: {
//     falseEdges -> [real: bb16, imaginary: bb8]; //pre_binding4
// }
// bb8: {
//     unreachable;
// }
// bb9: { // binding1: Some(w) if guard()
//     StorageLive(_5);
//     _5 = &((_2 as Some).0: i32);
//     StorageLive(_11);
//     _11 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { //end of guard
//    StorageLive(_4);
//    _4 = ((_2 as Some).0: i32);
//    switchInt(move _11) -> [false: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
//     falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb12: { // binding2 & arm2
//     StorageLive(_6);
//     _6 = _2;
//     _1 = const 2i32;
//     goto -> bb17;
// }
// bb13: { // binding3: Some(y) if guard2(y)
//     StorageLive(_8);
//     _8 = &((_2 as Some).0: i32);
//     StorageLive(_13);
//     StorageLive(_14);
//     _14 = (*_8);
//     _13 = const guard2(move _14) -> [return: bb14, unwind: bb1];
// }
// bb14: { // end of guard2
//     StorageDead(_14);
//     StorageLive(_7);
//     _7 = ((_2 as Some).0: i32);
//     switchInt(move _13) -> [false: bb15, otherwise: bb3];
// }
// bb15: { // to pre_binding4
//     falseEdges -> [real: bb7, imaginary: bb7];
// }
// bb16: { // binding4 & arm4
//     StorageLive(_9);
//     _9 = _2;
//     _1 = const 4i32;
//     goto -> bb17;
// }
// bb17: {
//     ...
//     return;
// }
// END rustc.main.QualifyAndPromoteConstants.before.mir
<|endoftext|>


<commit_before>//! IO facilities for TCP relay

use std::{
    io,
    marker::Unpin,
    pin::Pin,
    task::{Context, Poll},
};

use byte_string::ByteStr;
use bytes::Bytes;
use futures::ready;
use log::{debug, trace};
use tokio::{
    io::{ReadHalf, WriteHalf},
    prelude::*,
};

use crate::{
    config::ServerConfig,
    context::SharedContext,
    crypto::{CipherCategory, CipherType},
};

use super::{
    aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter},
    stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter},
};

enum DecryptedReader {
    Aead(AeadDecryptedReader),
    Stream(StreamDecryptedReader),
}

enum EncryptedWriter {
    Aead(AeadEncryptedWriter),
    Stream(StreamEncryptedWriter),
}

/// Steps for initializing a DecryptedReader
enum ReadStatus {
    /// Waiting for initializing vector (or nonce for AEAD ciphers)
    ///
    /// (context, Buffer, already_read_bytes, method, key)
    WaitIv(SharedContext, Vec<u8>, usize, CipherType, Bytes),

    /// Connection is established, DecryptedReader is initialized
    Established,
}

/// A bidirectional stream for communicating with ShadowSocks' server
pub struct CryptoStream<S> {
    stream: S,
    dec: Option<DecryptedReader>,
    enc: EncryptedWriter,
    read_status: ReadStatus,
}

impl<S: Unpin> Unpin for CryptoStream<S> {}

impl<S> CryptoStream<S> {
    /// Create a new CryptoStream with the underlying stream connection
    pub fn new(context: SharedContext, stream: S, svr_cfg: &ServerConfig) -> CryptoStream<S> {
        let method = svr_cfg.method();
        let prev_len = match method.category() {
            CipherCategory::Stream => method.iv_size(),
            CipherCategory::Aead => method.salt_size(),
        };

        let iv = match method.category() {
            CipherCategory::Stream => {
                let local_iv = loop {
                    let iv = method.gen_init_vec();
                    if context.check_nonce_and_set(&iv) {
                        // IV exist, generate another one
                        continue;
                    }
                    break iv;
                };
                trace!("generated Stream cipher IV {:?}", local_iv);
                local_iv
            }
            CipherCategory::Aead => {
                let local_salt = loop {
                    let salt = method.gen_salt();
                    if context.check_nonce_and_set(&salt) {
                        // Salt exist, generate another one
                        continue;
                    }
                    break salt;
                };
                trace!("generated AEAD cipher salt {:?}", local_salt);
                local_salt
            }
        };

        let method = svr_cfg.method();
        let enc = match method.category() {
            CipherCategory::Stream => EncryptedWriter::Stream(StreamEncryptedWriter::new(method, svr_cfg.key(), iv)),
            CipherCategory::Aead => EncryptedWriter::Aead(AeadEncryptedWriter::new(method, svr_cfg.key(), iv)),
        };

        CryptoStream {
            stream,
            dec: None,
            enc,
            read_status: ReadStatus::WaitIv(context, vec![0u8; prev_len], 0usize, method, svr_cfg.clone_key()),
        }
    }

    /// Return a reference to the underlying stream
    pub fn get_ref(&self) -> &S {
        &self.stream
    }
}

impl<S> CryptoStream<S>
where
    S: AsyncRead + Unpin,
{
    fn poll_read_handshake(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        if let ReadStatus::WaitIv(ref ctx, ref mut buf, ref mut pos, method, ref key) = self.read_status {
            while *pos < buf.len() {
                let n = ready!(Pin::new(&mut self.stream).poll_read(cx, &mut buf[*pos..]))?;
                if n == 0 {
                    use std::io::ErrorKind;
                    return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
                }
                *pos += n;
            }

            // Got iv/salt, check if it is repeated
            if ctx.check_nonce_and_set(buf) {
                use std::io::{Error, ErrorKind};

                debug!("detected repeated iv/salt {:?}", ByteStr::new(buf));

                let err = Error::new(ErrorKind::Other, "detected repeated iv/salt");
                return Poll::Ready(Err(err));
            }

            let dec = match method.category() {
                CipherCategory::Stream => {
                    trace!("got Stream cipher IV {:?}", ByteStr::new(&buf));
                    DecryptedReader::Stream(StreamDecryptedReader::new(method, key, &buf))
                }
                CipherCategory::Aead => {
                    trace!("got AEAD cipher salt {:?}", ByteStr::new(&buf));
                    DecryptedReader::Aead(AeadDecryptedReader::new(method, key, &buf))
                }
            };

            self.dec = Some(dec);
            self.read_status = ReadStatus::Established;
        }

        Poll::Ready(Ok(()))
    }

    fn priv_poll_read(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
        ready!(self.poll_read_handshake(ctx))?;

        let stream = unsafe { &mut *(&mut self.stream as *mut _) };
        match *self.dec.as_mut().unwrap() {
            DecryptedReader::Aead(ref mut r) => r.poll_read_decrypted(ctx, stream, buf),
            DecryptedReader::Stream(ref mut r) => r.poll_read_decrypted(ctx, stream, buf),
        }
    }
}

impl<S> CryptoStream<S>
where
    S: AsyncWrite + Unpin,
{
    fn priv_poll_write(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        let stream = unsafe { &mut *(&mut self.stream as *mut _) };
        match self.enc {
            EncryptedWriter::Aead(ref mut w) => w.poll_write_encrypted(ctx, stream, buf),
            EncryptedWriter::Stream(ref mut w) => w.poll_write_encrypted(ctx, stream, buf),
        }
    }

    fn priv_poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        AsyncWrite::poll_flush(Pin::new(&mut self.stream), ctx)
    }

    fn priv_poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        AsyncWrite::poll_shutdown(Pin::new(&mut self.stream), ctx)
    }
}

impl<S> CryptoStream<S>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    /// Split connection into reader and writer
    ///
    /// The two halfs share the same `CryptoStream<S>`
    pub fn split(self) -> (ReadHalf<CryptoStream<S>>, WriteHalf<CryptoStream<S>>) {
        use tokio::io::split;
        split(self)
    }
}

impl<S> AsyncRead for CryptoStream<S>
where
    S: AsyncRead + Unpin,
{
    fn poll_read(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
        self.priv_poll_read(ctx, buf)
    }
}

impl<S> AsyncWrite for CryptoStream<S>
where
    S: AsyncWrite + Unpin,
{
    fn poll_write(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        self.priv_poll_write(ctx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.priv_poll_flush(ctx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.priv_poll_shutdown(ctx)
    }
}
<commit_msg>Remove unnecessary unsafe<commit_after>//! IO facilities for TCP relay

use std::{
    io,
    marker::Unpin,
    pin::Pin,
    task::{Context, Poll},
};

use byte_string::ByteStr;
use bytes::Bytes;
use futures::ready;
use log::{debug, trace};
use tokio::{
    io::{ReadHalf, WriteHalf},
    prelude::*,
};

use crate::{
    config::ServerConfig,
    context::SharedContext,
    crypto::{CipherCategory, CipherType},
};

use super::{
    aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter},
    stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter},
};

enum DecryptedReader {
    Aead(AeadDecryptedReader),
    Stream(StreamDecryptedReader),
}

enum EncryptedWriter {
    Aead(AeadEncryptedWriter),
    Stream(StreamEncryptedWriter),
}

/// Steps for initializing a DecryptedReader
enum ReadStatus {
    /// Waiting for initializing vector (or nonce for AEAD ciphers)
    ///
    /// (context, Buffer, already_read_bytes, method, key)
    WaitIv(SharedContext, Vec<u8>, usize, CipherType, Bytes),

    /// Connection is established, DecryptedReader is initialized
    Established,
}

/// A bidirectional stream for communicating with ShadowSocks' server
pub struct CryptoStream<S> {
    stream: S,
    dec: Option<DecryptedReader>,
    enc: EncryptedWriter,
    read_status: ReadStatus,
}

impl<S: Unpin> Unpin for CryptoStream<S> {}

impl<S> CryptoStream<S> {
    /// Create a new CryptoStream with the underlying stream connection
    pub fn new(context: SharedContext, stream: S, svr_cfg: &ServerConfig) -> CryptoStream<S> {
        let method = svr_cfg.method();
        let prev_len = match method.category() {
            CipherCategory::Stream => method.iv_size(),
            CipherCategory::Aead => method.salt_size(),
        };

        let iv = match method.category() {
            CipherCategory::Stream => {
                let local_iv = loop {
                    let iv = method.gen_init_vec();
                    if context.check_nonce_and_set(&iv) {
                        // IV exist, generate another one
                        continue;
                    }
                    break iv;
                };
                trace!("generated Stream cipher IV {:?}", local_iv);
                local_iv
            }
            CipherCategory::Aead => {
                let local_salt = loop {
                    let salt = method.gen_salt();
                    if context.check_nonce_and_set(&salt) {
                        // Salt exist, generate another one
                        continue;
                    }
                    break salt;
                };
                trace!("generated AEAD cipher salt {:?}", local_salt);
                local_salt
            }
        };

        let method = svr_cfg.method();
        let enc = match method.category() {
            CipherCategory::Stream => EncryptedWriter::Stream(StreamEncryptedWriter::new(method, svr_cfg.key(), iv)),
            CipherCategory::Aead => EncryptedWriter::Aead(AeadEncryptedWriter::new(method, svr_cfg.key(), iv)),
        };

        CryptoStream {
            stream,
            dec: None,
            enc,
            read_status: ReadStatus::WaitIv(context, vec![0u8; prev_len], 0usize, method, svr_cfg.clone_key()),
        }
    }

    /// Return a reference to the underlying stream
    pub fn get_ref(&self) -> &S {
        &self.stream
    }
}

impl<S> CryptoStream<S>
where
    S: AsyncRead + Unpin,
{
    fn poll_read_handshake(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        if let ReadStatus::WaitIv(ref ctx, ref mut buf, ref mut pos, method, ref key) = self.read_status {
            while *pos < buf.len() {
                let n = ready!(Pin::new(&mut self.stream).poll_read(cx, &mut buf[*pos..]))?;
                if n == 0 {
                    use std::io::ErrorKind;
                    return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
                }
                *pos += n;
            }

            // Got iv/salt, check if it is repeated
            if ctx.check_nonce_and_set(buf) {
                use std::io::{Error, ErrorKind};

                debug!("detected repeated iv/salt {:?}", ByteStr::new(buf));

                let err = Error::new(ErrorKind::Other, "detected repeated iv/salt");
                return Poll::Ready(Err(err));
            }

            let dec = match method.category() {
                CipherCategory::Stream => {
                    trace!("got Stream cipher IV {:?}", ByteStr::new(&buf));
                    DecryptedReader::Stream(StreamDecryptedReader::new(method, key, &buf))
                }
                CipherCategory::Aead => {
                    trace!("got AEAD cipher salt {:?}", ByteStr::new(&buf));
                    DecryptedReader::Aead(AeadDecryptedReader::new(method, key, &buf))
                }
            };

            self.dec = Some(dec);
            self.read_status = ReadStatus::Established;
        }

        Poll::Ready(Ok(()))
    }

    fn priv_poll_read(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
        let this = self.get_mut();
        ready!(this.poll_read_handshake(ctx))?;

        match *this.dec.as_mut().unwrap() {
            DecryptedReader::Aead(ref mut r) => r.poll_read_decrypted(ctx, &mut this.stream, buf),
            DecryptedReader::Stream(ref mut r) => r.poll_read_decrypted(ctx, &mut this.stream, buf),
        }
    }
}

impl<S> CryptoStream<S>
where
    S: AsyncWrite + Unpin,
{
    fn priv_poll_write(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        let this = self.get_mut();
        match this.enc {
            EncryptedWriter::Aead(ref mut w) => w.poll_write_encrypted(ctx, &mut this.stream, buf),
            EncryptedWriter::Stream(ref mut w) => w.poll_write_encrypted(ctx, &mut this.stream, buf),
        }
    }

    fn priv_poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        AsyncWrite::poll_flush(Pin::new(&mut self.stream), ctx)
    }

    fn priv_poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        AsyncWrite::poll_shutdown(Pin::new(&mut self.stream), ctx)
    }
}

impl<S> CryptoStream<S>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    /// Split connection into reader and writer
    ///
    /// The two halfs share the same `CryptoStream<S>`
    pub fn split(self) -> (ReadHalf<CryptoStream<S>>, WriteHalf<CryptoStream<S>>) {
        use tokio::io::split;
        split(self)
    }
}

impl<S> AsyncRead for CryptoStream<S>
where
    S: AsyncRead + Unpin,
{
    fn poll_read(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
        self.priv_poll_read(ctx, buf)
    }
}

impl<S> AsyncWrite for CryptoStream<S>
where
    S: AsyncWrite + Unpin,
{
    fn poll_write(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        self.priv_poll_write(ctx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.priv_poll_flush(ctx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.priv_poll_shutdown(ctx)
    }
}
<|endoftext|>