<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[allow(unused_imports)] use syntax::ast::TokenTree;
#[allow(unused_imports)] use syntax::codemap::{Span, mk_sp, BytePos};
#[allow(unused_imports)] use syntax::ext::base::ExtCtxt;
#[allow(unused_imports)] use syntax::parse::{token, ParseSess, lexer};
#[allow(unused_imports)] use syntax::ext::build::AstBuilder;
#[allow(unused_imports)] use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};

#[allow(unused_imports)] use std::collections::hashmap;

use node;
use std::gc::Gc;

#[allow(dead_code)]
pub struct Parser<'a> {
  pub sess: &'a ParseSess,
  reader: Box<lexer::Reader:>,
  token: token::Token,
  span: Span,

  last_token: Option<Box<token::Token>>,
  last_span: Span,
}

impl<'a> Parser<'a> {
  #[allow(dead_code)]
  pub fn new<'a>(cx: &'a ExtCtxt, tts: &[TokenTree]) -> Parser<'a> {
    let sess = cx.parse_sess();
    let ttsvec = tts.iter().map(|x| (*x).clone()).collect();
    let mut reader = box lexer::new_tt_reader(
        &sess.span_diagnostic, None, ttsvec) as Box<lexer::Reader>;

    let tok0 = reader.next_token();
    let token = tok0.tok;
    let span = tok0.sp;

    Parser {
      sess: sess,
      reader: reader,

      token: token,
      span: span,

      last_token: None,
      last_span: span,
    }
  }

  /// Parse the platform tree from passed in tokens.
  pub fn parse_platformtree(&mut self) -> Option<node::PlatformTree> {
    let mut nodes: Vec<Gc<node::Node>> = Vec::new();
    let mut failed = false;
    loop {
      if self.token == token::EOF {
        break
      }

      let node = match self.parse_node() {
        Some(node) => box(GC) node,
        None => {
          failed = true;
          self.bump();
          continue
        }
      };

      nodes.push(node);
    }

    if failed {
      None
    } else {
      Some(node::PlatformTree::new(nodes))
    }
  }

  fn parse_node(&mut self) -> Option<node::Node> {
    let node_span: Option<Span>;
    let node_name: Option<String>;

    //  we're here
    // /
    // v
    // NAME @ PATH { ... }
    //      ^-- peeking here
    if self.reader.peek().tok == token::AT {
      node_span = Some(self.span);
      node_name = match self.expect_ident() {
        Some(name) => Some(name),
        None => return None,
      };
      if !self.expect(&token::AT) {
        return None;
      }
    } else {
      node_name = None;
      node_span = None;
    }

    self.parse_node_from_at(node_span, node_name)
  }

  fn parse_node_from_at(&mut self, name_span: Option<Span>,
      node_name: Option<String>) -> Option<node::Node> {
    let node_span: Span;
    let node_path_span: Span;
    let attributes: hashmap::HashMap<String, node::Attribute>;
    let subnodes: Vec<Gc<node::Node>>;

    // NAME is resolved, if it was there anyway.
    //    we're here
    //          |
    //          v
    //   NAME @ PATH { ... }
    node_path_span = self.span;
    if node_name == None {
      node_span = self.span;
    } else {
      node_span = mk_sp(name_span.unwrap().lo, self.span.hi);
    }

    let node_path = match self.token {
      token::IDENT(_, _) => {
        token::to_str(&self.bump())
      },
      token::LIT_INT_UNSUFFIXED(u) => {
        self.bump();
        u.to_str()
      }
      ref other => {
        self.error(format!("expected node path but found `{}`",
            token::to_str(other)));
        return None;
      }
    };

    //    we're here
    //             |
    //             v
    // NAME @ PATH { ... }
    // it's either a body, or a semicolon (no body)
    match self.bump() {
      token::LBRACE => {
        let (a, s) = match self.parse_node_body() {
          Some((attrs, subnodes)) => (attrs, subnodes),
          // TODO(farcaller): eat everything up to '}' and continue if failed
          // we can still parse further nodes.
          None => return None,
        };
        attributes = a;
        subnodes = s;

        if !self.expect(&token::RBRACE) {
          return None;
        }
      },
      token::SEMI => {
        attributes = hashmap::HashMap::new();
        subnodes = Vec::new();
      },
      ref other => {
        self.error(format!("expected `\\{` or `;` but found `{}`",
            token::to_str(other)));
        return None;
      }
    }

    let mut node = node::Node::new(node_name, node_span, node_path, node_path_span);
    node.attributes = attributes;
    node.subnodes = subnodes;
    Some(node)
  }

  fn parse_node_body(&mut self)
      -> Option<(
          hashmap::HashMap<String, node::Attribute>,
          Vec<Gc<node::Node>>)> {
    let mut attrs = hashmap::HashMap::new();
    let mut subnodes = Vec::new();

    loop {
      // break early if at brace
      if self.token == token::RBRACE {
        break;
      }

      // we're here
      // |
      // v
      // ATTR = VAL ;
      // NAME @ PATH
      // PATH { ... }
      // PATH ;
      //      ^-- peeking here
      if self.reader.peek().tok == token::EQ {
        // we're here
        // |
        // v
        // ATTR = VAL ;
        let name_span = self.span;
        let some_name = match self.expect_ident() {
          Some(name) => name,
          None => return None,
        };

        if attrs.contains_key(&some_name) {
          self.error(format!("key `{}` is already defined", some_name));
          return None;
        }

        self.bump(); // bump token::EQ

        // we're here
        //        |
        //        v
        // ATTR = VAL ;
        let attr_value_span = self.span;
        let attr_value = match self.parse_attribute_value() {
          Some(value) => value,
          None => return None,
        };

        //   we're here
        //            |
        //            v
        // ATTR = VAL ;
        if !self.expect(&token::SEMI) {
          return None;
        }

        attrs.insert(some_name, node::Attribute::new(
            attr_value, name_span, attr_value_span));
      } else {
        // this should be a subnode
        let oldsp = self.span;
        let oldtok = self.token.clone();
        let node = match self.parse_node() {
          Some(node) => node,
          None => {
            self.span = oldsp;
            self.error(format!("expected `=` or node but found `{}`",
                token::to_str(&oldtok)));
            return None;
          },
        };

        subnodes.push(box(GC) node);
      }
    }

    Some((attrs, subnodes))
  }

  fn parse_attribute_value(&mut self) -> Option<node::AttributeValue> {
    match self.token {
      token::LIT_STR(string_val) => {
        self.bump();
        let string = token::get_ident(string_val).get().to_str();
        Some(node::StrValue(string))
      },
      token::LIT_INT_UNSUFFIXED(intval) => {
        self.bump();
        Some(node::UIntValue(intval as uint))
      },
      token::BINOP(token::AND) => {
        self.bump();
        let name = match self.expect_ident() {
          Some(name) => name,
          None => return None,
        };
        Some(node::RefValue(name))
      },
      ref other => {
        self.error(format!("expected string but found `{}`",
            token::to_str(other)));
        None
      }
    }
  }

  fn error(&self, m: String) {
    self.sess.span_diagnostic.span_err(self.span, m.as_slice());
  }

  /// Bumps a token.
  ///
  /// This moves current token to last token, pops a new token from backlog or
  /// reader and returns the last token (i.e. the 'current' token at the time of
  /// method call).
  fn bump(&mut self) -> token::Token {
    let tok = self.token.clone();
    self.last_span = self.span;
    self.last_token = Some(box tok.clone());

    let next = self.reader.next_token();

    self.span = next.sp;
    self.token = next.tok;

    tok
  }

  /// Expects that the current token is t. Bumps on success.
  fn expect(&mut self, t: &token::Token) -> bool {
    if self.token == *t {
      self.bump();
      true
    } else {
      let token_str = token::to_str(t);
      let this_token_str = token::to_str(&self.token);
      self.error(format!("expected `{}` but found `{}`", token_str,
          this_token_str));
      false
    }
  }

  /// Expects that the current token is IDENT, returns its string value. Bumps
  /// on success.
  fn expect_ident(&mut self) -> Option<String> {
    let tok_str = token::to_str(&self.token);
    match self.token {
      token::IDENT(_, _) => {
        self.bump();
        Some(tok_str)
      },
      _ => {
        self.error(format!("expected identifier but found `{}`", tok_str));
        None
      },
    }
  }
}
<commit_msg>Remove parse_node_from_at.<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[allow(unused_imports)] use syntax::ast::TokenTree;
#[allow(unused_imports)] use syntax::codemap::{Span, mk_sp, BytePos};
#[allow(unused_imports)] use syntax::ext::base::ExtCtxt;
#[allow(unused_imports)] use syntax::parse::{token, ParseSess, lexer};
#[allow(unused_imports)] use syntax::ext::build::AstBuilder;
#[allow(unused_imports)] use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};

#[allow(unused_imports)] use std::collections::hashmap;

use node;
use std::gc::Gc;

#[allow(dead_code)]
pub struct Parser<'a> {
  pub sess: &'a ParseSess,
  reader: Box<lexer::Reader:>,
  token: token::Token,
  span: Span,

  last_token: Option<Box<token::Token>>,
  last_span: Span,
}

impl<'a> Parser<'a> {
  #[allow(dead_code)]
  pub fn new<'a>(cx: &'a ExtCtxt, tts: &[TokenTree]) -> Parser<'a> {
    let sess = cx.parse_sess();
    let ttsvec = tts.iter().map(|x| (*x).clone()).collect();
    let mut reader = box lexer::new_tt_reader(
        &sess.span_diagnostic, None, ttsvec) as Box<lexer::Reader>;

    let tok0 = reader.next_token();
    let token = tok0.tok;
    let span = tok0.sp;

    Parser {
      sess: sess,
      reader: reader,

      token: token,
      span: span,

      last_token: None,
      last_span: span,
    }
  }

  /// Parse the platform tree from passed in tokens.
  pub fn parse_platformtree(&mut self) -> Option<node::PlatformTree> {
    let mut nodes: Vec<Gc<node::Node>> = Vec::new();
    let mut failed = false;
    loop {
      if self.token == token::EOF {
        break
      }

      let node = match self.parse_node() {
        Some(node) => box(GC) node,
        None => {
          failed = true;
          self.bump();
          continue
        }
      };

      nodes.push(node);
    }

    if failed {
      None
    } else {
      Some(node::PlatformTree::new(nodes))
    }
  }

  fn parse_node(&mut self) -> Option<node::Node> {
    let name_span: Option<Span>;
    let node_name: Option<String>;

    //  we're here
    // /
    // v
    // NAME @ PATH { ... }
    //      ^-- peeking here
    if self.reader.peek().tok == token::AT {
      name_span = Some(self.span);
      node_name = match self.expect_ident() {
        Some(name) => Some(name),
        None => return None,
      };
      if !self.expect(&token::AT) {
        return None;
      }
    } else {
      node_name = None;
      name_span = None;
    }

    let node_span: Span;
    let node_path_span: Span;
    let attributes: hashmap::HashMap<String, node::Attribute>;
    let subnodes: Vec<Gc<node::Node>>;

    // NAME is resolved, if it was there anyway.
    //    we're here
    //          |
    //          v
    //   NAME @ PATH { ... }
    node_path_span = self.span;
    if node_name == None {
      node_span = self.span;
    } else {
      node_span = mk_sp(name_span.unwrap().lo, self.span.hi);
    }

    let node_path = match self.token {
      token::IDENT(_, _) => {
        token::to_str(&self.bump())
      },
      token::LIT_INT_UNSUFFIXED(u) => {
        self.bump();
        u.to_str()
      }
      ref other => {
        self.error(format!("expected node path but found `{}`",
            token::to_str(other)));
        return None;
      }
    };

    //    we're here
    //             |
    //             v
    // NAME @ PATH { ... }
    // it's either a body, or a semicolon (no body)
    match self.bump() {
      token::LBRACE => {
        let (a, s) = match self.parse_node_body() {
          Some((attrs, subnodes)) => (attrs, subnodes),
          // TODO(farcaller): eat everything up to '}' and continue if failed
          // we can still parse further nodes.
          None => return None,
        };
        attributes = a;
        subnodes = s;

        if !self.expect(&token::RBRACE) {
          return None;
        }
      },
      token::SEMI => {
        attributes = hashmap::HashMap::new();
        subnodes = Vec::new();
      },
      ref other => {
        self.error(format!("expected `\\{` or `;` but found `{}`",
            token::to_str(other)));
        return None;
      }
    }

    let mut node = node::Node::new(node_name, node_span, node_path, node_path_span);
    node.attributes = attributes;
    node.subnodes = subnodes;
    Some(node)
  }

  fn parse_node_body(&mut self)
      -> Option<(
          hashmap::HashMap<String, node::Attribute>,
          Vec<Gc<node::Node>>)> {
    let mut attrs = hashmap::HashMap::new();
    let mut subnodes = Vec::new();

    loop {
      // break early if at brace
      if self.token == token::RBRACE {
        break;
      }

      // we're here
      // |
      // v
      // ATTR = VAL ;
      // NAME @ PATH
      // PATH { ... }
      // PATH ;
      //      ^-- peeking here
      if self.reader.peek().tok == token::EQ {
        // we're here
        // |
        // v
        // ATTR = VAL ;
        let name_span = self.span;
        let some_name = match self.expect_ident() {
          Some(name) => name,
          None => return None,
        };

        if attrs.contains_key(&some_name) {
          self.error(format!("key `{}` is already defined", some_name));
          return None;
        }

        self.bump(); // bump token::EQ

        // we're here
        //        |
        //        v
        // ATTR = VAL ;
        let attr_value_span = self.span;
        let attr_value = match self.parse_attribute_value() {
          Some(value) => value,
          None => return None,
        };

        //   we're here
        //            |
        //            v
        // ATTR = VAL ;
        if !self.expect(&token::SEMI) {
          return None;
        }

        attrs.insert(some_name, node::Attribute::new(
            attr_value, name_span, attr_value_span));
      } else {
        // this should be a subnode
        let oldsp = self.span;
        let oldtok = self.token.clone();
        let node = match self.parse_node() {
          Some(node) => node,
          None => {
            self.span = oldsp;
            self.error(format!("expected `=` or node but found `{}`",
                token::to_str(&oldtok)));
            return None;
          },
        };

        subnodes.push(box(GC) node);
      }
    }

    Some((attrs, subnodes))
  }

  fn parse_attribute_value(&mut self) -> Option<node::AttributeValue> {
    match self.token {
      token::LIT_STR(string_val) => {
        self.bump();
        let string = token::get_ident(string_val).get().to_str();
        Some(node::StrValue(string))
      },
      token::LIT_INT_UNSUFFIXED(intval) => {
        self.bump();
        Some(node::UIntValue(intval as uint))
      },
      token::BINOP(token::AND) => {
        self.bump();
        let name = match self.expect_ident() {
          Some(name) => name,
          None => return None,
        };
        Some(node::RefValue(name))
      },
      ref other => {
        self.error(format!("expected string but found `{}`",
            token::to_str(other)));
        None
      }
    }
  }

  fn error(&self, m: String) {
    self.sess.span_diagnostic.span_err(self.span, m.as_slice());
  }

  /// Bumps a token.
  ///
  /// This moves current token to last token, pops a new token from backlog or
  /// reader and returns the last token (i.e. the 'current' token at the time of
  /// method call).
  fn bump(&mut self) -> token::Token {
    let tok = self.token.clone();
    self.last_span = self.span;
    self.last_token = Some(box tok.clone());

    let next = self.reader.next_token();

    self.span = next.sp;
    self.token = next.tok;

    tok
  }

  /// Expects that the current token is t. Bumps on success.
  fn expect(&mut self, t: &token::Token) -> bool {
    if self.token == *t {
      self.bump();
      true
    } else {
      let token_str = token::to_str(t);
      let this_token_str = token::to_str(&self.token);
      self.error(format!("expected `{}` but found `{}`", token_str,
          this_token_str));
      false
    }
  }

  /// Expects that the current token is IDENT, returns its string value. Bumps
  /// on success.
  fn expect_ident(&mut self) -> Option<String> {
    let tok_str = token::to_str(&self.token);
    match self.token {
      token::IDENT(_, _) => {
        self.bump();
        Some(tok_str)
      },
      _ => {
        self.error(format!("expected identifier but found `{}`", tok_str));
        None
      },
    }
  }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::iter::Fuse;
use std::fmt;

use super::adaptors::{PutBack, put_back};
use either_or_both::EitherOrBoth;

/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](trait.Itertools.html#method.merge_join_by) for more information.
pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
    -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
    where I: IntoIterator,
          J: IntoIterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    MergeJoinBy {
        left: put_back(left.into_iter().fuse()),
        right: put_back(right.into_iter().fuse()),
        cmp_fn: cmp_fn
    }
}

/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](../trait.Itertools.html#method.merge_join_by) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
    left: PutBack<Fuse<I>>,
    right: PutBack<Fuse<J>>,
    cmp_fn: F
}

impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
          J: Iterator + fmt::Debug,
          J::Item: fmt::Debug,
{
    debug_fmt_fields!(MergeJoinBy, left, right);
}

impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
    where I: Iterator,
          J: Iterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    type Item = EitherOrBoth<I::Item, J::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        match (self.left.next(), self.right.next()) {
            (None, None) => None,
            (Some(left), None) =>
                Some(EitherOrBoth::Left(left)),
            (None, Some(right)) =>
                Some(EitherOrBoth::Right(right)),
            (Some(left), Some(right)) => {
                match (self.cmp_fn)(&left, &right) {
                    Ordering::Equal =>
                        Some(EitherOrBoth::Both(left, right)),
                    Ordering::Less => {
                        self.right.put_back(right);
                        Some(EitherOrBoth::Left(left))
                    },
                    Ordering::Greater => {
                        self.left.put_back(left);
                        Some(EitherOrBoth::Right(right))
                    }
                }
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (a_lower, a_upper) = self.left.size_hint();
        let (b_lower, b_upper) = self.right.size_hint();

        let lower = ::std::cmp::max(a_lower, b_lower);

        let upper = match (a_upper, b_upper) {
            (Some(x), Some(y)) => Some(x + y),
            _ => None,
        };

        (lower, upper)
    }

    fn count(mut self) -> usize {
        let mut count = 0;
        loop {
            match (self.left.next(), self.right.next()) {
                (None, None) => break count,
                (Some(_left), None) => break count + 1 + self.left.count(),
                (None, Some(_right)) => break count + 1 + self.right.count(),
                (Some(left), Some(right)) => {
                    count += 1;
                    match (self.cmp_fn)(&left, &right) {
                        Ordering::Equal => {}
                        Ordering::Less => self.right.put_back(right),
                        Ordering::Greater => self.left.put_back(left),
                    }
                }
            }
        }
    }

    fn last(mut self) -> Option<Self::Item> {
        let mut previous_element = None;
        loop {
            match (self.left.next(), self.right.next()) {
                (None, None) => break previous_element,
                (Some(left), None) => {
                    break Some(EitherOrBoth::Left(self.left.last().unwrap_or(left)))
                }
                (None, Some(right)) => {
                    break Some(EitherOrBoth::Right(self.right.last().unwrap_or(right)))
                }
                (Some(left), Some(right)) => {
                    previous_element = match (self.cmp_fn)(&left, &right) {
                        Ordering::Equal => Some(EitherOrBoth::Both(left, right)),
                        Ordering::Less => {
                            self.right.put_back(right);
                            Some(EitherOrBoth::Left(left))
                        }
                        Ordering::Greater => {
                            self.left.put_back(left);
                            Some(EitherOrBoth::Right(right))
                        }
                    }
                }
            }
        }
    }

    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
        loop {
            if n == 0 {
                break self.next();
            }
            n -= 1;
            match (self.left.next(), self.right.next()) {
                (None, None) => break None,
                (Some(_left), None) => break self.left.nth(n).map(EitherOrBoth::Left),
                (None, Some(_right)) => break self.right.nth(n).map(EitherOrBoth::Right),
                (Some(left), Some(right)) => match (self.cmp_fn)(&left, &right) {
                    Ordering::Equal => {}
                    Ordering::Less => self.right.put_back(right),
                    Ordering::Greater => self.left.put_back(left),
                },
            }
        }
    }
}
<commit_msg>Bypass PutBack adaptor where possible because it doesn't specialize these methods either<commit_after>use std::cmp::Ordering;
use std::iter::Fuse;
use std::fmt;

use super::adaptors::{PutBack, put_back};
use either_or_both::EitherOrBoth;

/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](trait.Itertools.html#method.merge_join_by) for more information.
pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
    -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
    where I: IntoIterator,
          J: IntoIterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    MergeJoinBy {
        left: put_back(left.into_iter().fuse()),
        right: put_back(right.into_iter().fuse()),
        cmp_fn: cmp_fn
    }
}

/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](../trait.Itertools.html#method.merge_join_by) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
    left: PutBack<Fuse<I>>,
    right: PutBack<Fuse<J>>,
    cmp_fn: F
}

impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
          J: Iterator + fmt::Debug,
          J::Item: fmt::Debug,
{
    debug_fmt_fields!(MergeJoinBy, left, right);
}

impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
    where I: Iterator,
          J: Iterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    type Item = EitherOrBoth<I::Item, J::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        match (self.left.next(), self.right.next()) {
            (None, None) => None,
            (Some(left), None) =>
                Some(EitherOrBoth::Left(left)),
            (None, Some(right)) =>
                Some(EitherOrBoth::Right(right)),
            (Some(left), Some(right)) => {
                match (self.cmp_fn)(&left, &right) {
                    Ordering::Equal =>
                        Some(EitherOrBoth::Both(left, right)),
                    Ordering::Less => {
                        self.right.put_back(right);
                        Some(EitherOrBoth::Left(left))
                    },
                    Ordering::Greater => {
                        self.left.put_back(left);
                        Some(EitherOrBoth::Right(right))
                    }
                }
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (a_lower, a_upper) = self.left.size_hint();
        let (b_lower, b_upper) = self.right.size_hint();

        let lower = ::std::cmp::max(a_lower, b_lower);

        let upper = match (a_upper, b_upper) {
            (Some(x), Some(y)) => Some(x + y),
            _ => None,
        };

        (lower, upper)
    }

    fn count(mut self) -> usize {
        let mut count = 0;
        loop {
            match (self.left.next(), self.right.next()) {
                (None, None) => break count,
                (Some(_left), None) => break count + 1 + self.left.into_parts().1.count(),
                (None, Some(_right)) => break count + 1 + self.right.into_parts().1.count(),
                (Some(left), Some(right)) => {
                    count += 1;
                    match (self.cmp_fn)(&left, &right) {
                        Ordering::Equal => {}
                        Ordering::Less => self.right.put_back(right),
                        Ordering::Greater => self.left.put_back(left),
                    }
                }
            }
        }
    }

    fn last(mut self) -> Option<Self::Item> {
        let mut previous_element = None;
        loop {
            match (self.left.next(), self.right.next()) {
                (None, None) => break previous_element,
                (Some(left), None) => {
                    break Some(EitherOrBoth::Left(
                        self.left.into_parts().1.last().unwrap_or(left),
                    ))
                }
                (None, Some(right)) => {
                    break Some(EitherOrBoth::Right(
                        self.right.into_parts().1.last().unwrap_or(right),
                    ))
                }
                (Some(left), Some(right)) => {
                    previous_element = match (self.cmp_fn)(&left, &right) {
                        Ordering::Equal => Some(EitherOrBoth::Both(left, right)),
                        Ordering::Less => {
                            self.right.put_back(right);
                            Some(EitherOrBoth::Left(left))
                        }
                        Ordering::Greater => {
                            self.left.put_back(left);
                            Some(EitherOrBoth::Right(right))
                        }
                    }
                }
            }
        }
    }

    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
        loop {
            if n == 0 {
                break self.next();
            }
            n -= 1;
            match (self.left.next(), self.right.next()) {
                (None, None) => break None,
                (Some(_left), None) => break self.left.nth(n).map(EitherOrBoth::Left),
                (None, Some(_right)) => break self.right.nth(n).map(EitherOrBoth::Right),
                (Some(left), Some(right)) => match (self.cmp_fn)(&left, &right) {
                    Ordering::Equal => {}
                    Ordering::Less => self.right.put_back(right),
                    Ordering::Greater => self.left.put_back(left),
                },
            }
        }
    }
}
<|endoftext|>


<commit_before>// 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.

#![license = "MIT/ASL2"]
#![crate_name = "rust-crypto-util"]

extern crate getopts;
extern crate rust_crypto = "rust-crypto";

use std::io;
use std::os;

use getopts::{optopt, optflag, getopts, Matches};

use rust_crypto::scrypt;

fn print_usage() {
    println!("Usage: rust-crypto-util <algorithm> [options]");
    println!("-h, --help\tUsage");
    println!("");
    println!("Algorithms:");
    println!(" * Scrypt (scrypt)");
    println!("");
    println!("Scrypt options:");
    println!("--logn\t\tThe Log N parameter");
    println!("-r\t\tThe R parameter");
    println!("-p\t\tThe P parameter");
    println!("--dklen\t\tThe DkLen parameter");
    println!("--rawsalt\tThe salt parameter is supplied on STDIN");
    println!("--rawpassword\tThe password parameter is supplied on STDIN");
    println!("--rawoutput\tThe resulting value should be output directly to STDOUT");
}

fn run_scrypt(matches: &Matches) {
    if !matches.opt_present("logn") || !matches.opt_present("r") || !matches.opt_present("p") ||
       !matches.opt_present("dklen") {
        print_usage();
        return;
    }
    let logn = from_str::<u8>(matches.opt_str("logn").unwrap().as_slice()).unwrap();
    let r = from_str::<u32>(matches.opt_str("r").unwrap().as_slice()).unwrap();
    let p = from_str::<u32>(matches.opt_str("p").unwrap().as_slice()).unwrap();
    let dklen = from_str::<uint>(matches.opt_str("dklen").unwrap().as_slice()).unwrap();

    if !matches.opt_present("rawsalt") || !matches.opt_present("rawpassword") ||
       !matches.opt_present("rawoutput") {
        println!("Required options missing.");
        return;
    }

    let salt_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let salt = io::stdio::stdin_raw().read_exact(salt_len as uint).unwrap();
    let pass_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let pass = io::stdio::stdin_raw().read_exact(pass_len as uint).unwrap();

    let params = scrypt::ScryptParams::new(logn, r, p);
    let mut output = Vec::from_elem(dklen, 0u8);
    scrypt::scrypt(pass.as_slice(), salt.as_slice(), &params, output.as_mut_slice());

    match io::stdout().write(output.as_slice()) {
        Ok(_) => { },
        Err(_) => fail!("Error writing result")
    }
}

fn main() {
    let args: Vec<String> = os::args().iter().map(|x| x.to_string()).collect();

    let opts = vec![
        // General parameters:
        optflag("h", "help", "Print help"),

        // Scrypt parameters:
        optopt("", "logn", "Log-N parameter for Scrypt", ""),
        optopt("r", "", "R parameter for Scrypt", ""),
        optopt("p", "", "P parameter for Scrypt", ""),
        optopt("", "dklen", "Length of the derived key", ""),
        optflag("", "rawsalt", "Use a raw salt value"),
        optflag("", "rawpassword", "Use a raw password value"),
        optflag("", "rawoutput", "Use raw output mode"),
    ];

    let matches = match getopts(args.tail(), opts.as_slice()) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_string()) }
    };

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage();
        return;
    }

    if matches.free.is_empty() {
        print_usage();
        return;
    }
    let algorithm_name = matches.free.get(0).as_slice();

    match algorithm_name {
        "scrypt" => run_scrypt(&matches),
        _ => {
            print_usage();
            return;
        }
    }
}
<commit_msg>Use the index operator on Vec now that .get() has been deprecated<commit_after>// 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.

#![license = "MIT/ASL2"]
#![crate_name = "rust-crypto-util"]

extern crate getopts;
extern crate rust_crypto = "rust-crypto";

use std::io;
use std::os;

use getopts::{optopt, optflag, getopts, Matches};

use rust_crypto::scrypt;

fn print_usage() {
    println!("Usage: rust-crypto-util <algorithm> [options]");
    println!("-h, --help\tUsage");
    println!("");
    println!("Algorithms:");
    println!(" * Scrypt (scrypt)");
    println!("");
    println!("Scrypt options:");
    println!("--logn\t\tThe Log N parameter");
    println!("-r\t\tThe R parameter");
    println!("-p\t\tThe P parameter");
    println!("--dklen\t\tThe DkLen parameter");
    println!("--rawsalt\tThe salt parameter is supplied on STDIN");
    println!("--rawpassword\tThe password parameter is supplied on STDIN");
    println!("--rawoutput\tThe resulting value should be output directly to STDOUT");
}

fn run_scrypt(matches: &Matches) {
    if !matches.opt_present("logn") || !matches.opt_present("r") || !matches.opt_present("p") ||
       !matches.opt_present("dklen") {
        print_usage();
        return;
    }
    let logn = from_str::<u8>(matches.opt_str("logn").unwrap().as_slice()).unwrap();
    let r = from_str::<u32>(matches.opt_str("r").unwrap().as_slice()).unwrap();
    let p = from_str::<u32>(matches.opt_str("p").unwrap().as_slice()).unwrap();
    let dklen = from_str::<uint>(matches.opt_str("dklen").unwrap().as_slice()).unwrap();

    if !matches.opt_present("rawsalt") || !matches.opt_present("rawpassword") ||
       !matches.opt_present("rawoutput") {
        println!("Required options missing.");
        return;
    }

    let salt_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let salt = io::stdio::stdin_raw().read_exact(salt_len as uint).unwrap();
    let pass_len = io::stdio::stdin_raw().read_be_u32().unwrap();
    let pass = io::stdio::stdin_raw().read_exact(pass_len as uint).unwrap();

    let params = scrypt::ScryptParams::new(logn, r, p);
    let mut output = Vec::from_elem(dklen, 0u8);
    scrypt::scrypt(pass.as_slice(), salt.as_slice(), &params, output.as_mut_slice());

    match io::stdout().write(output.as_slice()) {
        Ok(_) => { },
        Err(_) => fail!("Error writing result")
    }
}

fn main() {
    let args: Vec<String> = os::args().iter().map(|x| x.to_string()).collect();

    let opts = vec![
        // General parameters:
        optflag("h", "help", "Print help"),

        // Scrypt parameters:
        optopt("", "logn", "Log-N parameter for Scrypt", ""),
        optopt("r", "", "R parameter for Scrypt", ""),
        optopt("p", "", "P parameter for Scrypt", ""),
        optopt("", "dklen", "Length of the derived key", ""),
        optflag("", "rawsalt", "Use a raw salt value"),
        optflag("", "rawpassword", "Use a raw password value"),
        optflag("", "rawoutput", "Use raw output mode"),
    ];

    let matches = match getopts(args.tail(), opts.as_slice()) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_string()) }
    };

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage();
        return;
    }

    if matches.free.is_empty() {
        print_usage();
        return;
    }
    let algorithm_name = matches.free[0].as_slice();

    match algorithm_name {
        "scrypt" => run_scrypt(&matches),
        _ => {
            print_usage();
            return;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

use rustc::middle::const_val::ConstVal;
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use pretty;

use super::remove_dead_blocks::RemoveDeadBlocks;

pub struct SimplifyCfg;

impl SimplifyCfg {
    pub fn new() -> SimplifyCfg {
        SimplifyCfg
    }

    fn remove_goto_chains(&self, mir: &mut Mir) -> bool {
        // Find the target at the end of the jump chain, return None if there is a loop
        fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
            // Keep track of already seen blocks to detect loops
            let mut seen: Vec<BasicBlock> = Vec::with_capacity(8);

            while mir.basic_block_data(target).statements.is_empty() {
                // NB -- terminator may have been swapped with `None`
                // below, in which case we have a cycle and just want
                // to stop
                if let Some(ref terminator) = mir.basic_block_data(target).terminator {
                    match terminator.kind {
                        TerminatorKind::Goto { target: next } => {
                            if seen.contains(&next) {
                                return None;
                            }
                            seen.push(next);
                            target = next;
                        }
                        _ => break
                    }
                } else {
                    break
                }
            }

            Some(target)
        }

        let mut changed = false;
        for bb in mir.all_basic_blocks() {
            // Temporarily take ownership of the terminator we're modifying to keep borrowck happy
            let mut terminator = mir.basic_block_data_mut(bb).terminator.take()
                                    .expect("invalid terminator state");

            debug!("remove_goto_chains: bb={:?} terminator={:?}", bb, terminator);

            for target in terminator.successors_mut() {
                let new_target = match final_target(mir, *target) {
                    Some(new_target) => new_target,
                    None if mir.basic_block_data(bb).statements.is_empty() => bb,
                    None => continue
                };
                changed |= *target != new_target;
                *target = new_target;
            }
            mir.basic_block_data_mut(bb).terminator = Some(terminator);
        }
        changed
    }

    fn simplify_branches(&self, mir: &mut Mir) -> bool {
        let mut changed = false;

        for bb in mir.all_basic_blocks() {
            let basic_block = mir.basic_block_data_mut(bb);
            let mut terminator = basic_block.terminator_mut();
            terminator.kind = match terminator.kind {
                TerminatorKind::If { ref targets, .. } if targets.0 == targets.1 => {
                    changed = true;
                    TerminatorKind::Goto { target: targets.0 }
                }

                TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
                    literal: Literal::Value {
                        value: ConstVal::Bool(cond)
                    }, ..
                }) } => {
                    changed = true;
                    if cond {
                        TerminatorKind::Goto { target: targets.0 }
                    } else {
                        TerminatorKind::Goto { target: targets.1 }
                    }
                }

                TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => {
                    TerminatorKind::Goto { target: targets[0] }
                }
                _ => continue
            }
        }

        changed
    }
}

impl<'tcx> MirPass<'tcx> for SimplifyCfg {
    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    src: MirSource, mir: &mut Mir<'tcx>) {
        let mut counter = 0;
        let mut changed = true;
        while changed {
            pretty::dump_mir(tcx, "simplify_cfg", &counter, src, mir, None);
            counter += 1;
            changed = self.simplify_branches(mir);
            changed |= self.remove_goto_chains(mir);
            RemoveDeadBlocks.run_pass(tcx, src, mir);
        }
        // FIXME: Should probably be moved into some kind of pass manager
        mir.basic_blocks.shrink_to_fit();
    }
}

impl Pass for SimplifyCfg {}
<commit_msg>Rollup merge of #33552 - dotdash:scfg, r=luqmana<commit_after>// Copyright 2015 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.

use rustc_data_structures::bitvec::BitVector;
use rustc::middle::const_val::ConstVal;
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use pretty;
use std::mem;

use super::remove_dead_blocks::RemoveDeadBlocks;

use traversal;

pub struct SimplifyCfg;

impl SimplifyCfg {
    pub fn new() -> SimplifyCfg {
        SimplifyCfg
    }
}

impl<'tcx> MirPass<'tcx> for SimplifyCfg {
    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
        simplify_branches(mir);
        RemoveDeadBlocks.run_pass(tcx, src, mir);
        merge_consecutive_blocks(mir);
        RemoveDeadBlocks.run_pass(tcx, src, mir);
        pretty::dump_mir(tcx, "simplify_cfg", &0, src, mir, None);

        // FIXME: Should probably be moved into some kind of pass manager
        mir.basic_blocks.shrink_to_fit();
    }
}

impl Pass for SimplifyCfg {}

fn merge_consecutive_blocks(mir: &mut Mir) {
    // Build the precedecessor map for the MIR
    let mut pred_count = vec![0u32; mir.basic_blocks.len()];
    for (_, data) in traversal::preorder(mir) {
        if let Some(ref term) = data.terminator {
            for &tgt in term.successors().iter() {
                pred_count[tgt.index()] += 1;
            }
        }
    }

    loop {
        let mut changed = false;
        let mut seen = BitVector::new(mir.basic_blocks.len());
        let mut worklist = vec![START_BLOCK];
        while let Some(bb) = worklist.pop() {
            // Temporarily take ownership of the terminator we're modifying to keep borrowck happy
            let mut terminator = mir.basic_block_data_mut(bb).terminator.take()
                .expect("invalid terminator state");

            // See if we can merge the target block into this one
            loop {
                let mut inner_change = false;

                if let TerminatorKind::Goto { target } = terminator.kind {
                    // Don't bother trying to merge a block into itself
                    if target == bb {
                        break;
                    }

                    let num_insts = mir.basic_block_data(target).statements.len();
                    match mir.basic_block_data(target).terminator().kind {
                        TerminatorKind::Goto { target: new_target } if num_insts == 0 => {
                            inner_change = true;
                            terminator.kind = TerminatorKind::Goto { target: new_target };
                            pred_count[target.index()] -= 1;
                            pred_count[new_target.index()] += 1;
                        }
                        _ if pred_count[target.index()] == 1 => {
                            inner_change = true;
                            let mut stmts = Vec::new();
                            {
                                let target_data = mir.basic_block_data_mut(target);
                                mem::swap(&mut stmts, &mut target_data.statements);
                                mem::swap(&mut terminator, target_data.terminator_mut());
                            }

                            mir.basic_block_data_mut(bb).statements.append(&mut stmts);
                        }
                        _ => {}
                    };
                }

                for target in terminator.successors_mut() {
                    let new_target = match final_target(mir, *target) {
                        Some(new_target) => new_target,
                        None if mir.basic_block_data(bb).statements.is_empty() => bb,
                        None => continue
                    };
                    if *target != new_target {
                        inner_change = true;
                        pred_count[target.index()] -= 1;
                        pred_count[new_target.index()] += 1;
                        *target = new_target;
                    }
                }

                changed |= inner_change;
                if !inner_change {
                    break;
                }
            }

            mir.basic_block_data_mut(bb).terminator = Some(terminator);

            for succ in mir.basic_block_data(bb).terminator().successors().iter() {
                if seen.insert(succ.index()) {
                    worklist.push(*succ);
                }
            }
        }

        if !changed {
            break;
        }
    }
}

// Find the target at the end of the jump chain, return None if there is a loop
fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
    // Keep track of already seen blocks to detect loops
    let mut seen: Vec<BasicBlock> = Vec::with_capacity(8);

    while mir.basic_block_data(target).statements.is_empty() {
        // NB -- terminator may have been swapped with `None` in
        // merge_consecutive_blocks, in which case we have a cycle and just want
        // to stop
        match mir.basic_block_data(target).terminator {
            Some(Terminator { kind: TerminatorKind::Goto { target: next }, .. }) =>  {
                if seen.contains(&next) {
                    return None;
                }
                seen.push(next);
                target = next;
            }
            _ => break
        }
    }

    Some(target)
}

fn simplify_branches(mir: &mut Mir) {
    loop {
        let mut changed = false;

        for bb in mir.all_basic_blocks() {
            let basic_block = mir.basic_block_data_mut(bb);
            let mut terminator = basic_block.terminator_mut();
            terminator.kind = match terminator.kind {
                TerminatorKind::If { ref targets, .. } if targets.0 == targets.1 => {
                    changed = true;
                    TerminatorKind::Goto { target: targets.0 }
                }

                TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
                    literal: Literal::Value {
                        value: ConstVal::Bool(cond)
                    }, ..
                }) } => {
                    changed = true;
                    if cond {
                        TerminatorKind::Goto { target: targets.0 }
                    } else {
                        TerminatorKind::Goto { target: targets.1 }
                    }
                }

                TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => {
                    TerminatorKind::Goto { target: targets[0] }
                }
                _ => continue
            }
        }

        if !changed {
            break;
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains all the logic dealing with images:
//! Parsing the config file data, shuffling pixels of big images,
//! ordering pixels of small images and sorting the signatures to the end.

use crate::ascii_art::DEFAULT_IMAGES;
use crate::ascii_art::IMAGE_KNOWN_SIGNATURES;
use crate::dictionary::ConfigParseError;
use crate::game::Game;
use crate::LIVES;
use rand::seq::SliceRandom;
use rand::thread_rng;
use serde_derive::Deserialize;
use std::cmp::{Ord, Ordering};
use std::fmt;

/// Default game mode. Can be changed in the configuration file.
const DEFAULT_REWARDING_SCHEME: RewardingScheme = RewardingScheme::UnhideWhenGuessedChar;

/// Threshold to decide from how many characters on the images is considered to be "big".
/// Big images are disclosed with another algorithm.
/// This is just big enough that the gallow image stays small.
const BIG_IMAGE: usize = 60; // sort algorithm <-> random algorithm

/// A game mode defining how the ASCII-art image will be disclosed progressively.
#[derive(Clone, Debug, PartialEq)]
pub enum RewardingScheme {
    /// Game mode that is used together with the traditional gallows image (the gallows image
    /// is not build in, but can be added in the configuration file. The image is disclosed
    /// piecemeal after each wrong guess.
    UnhideWhenLostLife,
    /// Default game mode. The image is disclosed piecemeal after each right guess.
    UnhideWhenGuessedChar,
}
/// One character of the ASCII art image.
#[derive(Eq, PartialEq, Debug, Copy, Clone)] //omitting Ord
pub struct ImChar {
    pub point: (u8, u8),
    pub code: char,
}

/// Format an image character.
impl fmt::Display for ImChar {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.code)
    }
}

/// Delegate the comparison to `Ord`.
impl PartialOrd for ImChar {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

/// Ord enables us to v.sort() the image characters.
impl Ord for ImChar {
    /// Compares to ImChar.
    /// Points near the left lower corner are small.
    fn cmp(&self, other: &Self) -> Ordering {
        fn weight(ic: &ImChar) -> isize {
            let &ImChar { point: (x, y), .. } = ic;
            // points near the lower left corner are light
            x as isize - y as isize
        }
        weight(self).cmp(&weight(other))
    }
}

#[derive(Clone, Debug, PartialEq)]
/// An ASCII-art image.
pub struct Image {
    pub ichars: Vec<ImChar>,
    pub dimension: (u8, u8),
    pub visible_points: usize,
    pub rewarding_scheme: RewardingScheme,
}

/// Format an image.
impl fmt::Display for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let x_max = self.dimension.0 as usize;
        let y_max = self.dimension.1 as usize;

        let mut i = vec![' '; ((x_max + 1) * y_max) as usize];
        for y in 0..y_max {
            i[((x_max + 1) * y + x_max) as usize] = '\n';
        }

        for ic in self.ichars.iter().take(self.visible_points) {
            let &ImChar {
                point: (x, y),
                code,
            } = ic;
            i[(x as usize + y as usize * (x_max + 1))] = code;
        }

        write!(f, "{}", i.into_iter().collect::<String>())
    }
}

impl Image {
    /// Returns a random built-in image.
    pub fn new() -> Result<Self, ConfigParseError> {
        let mut rng = thread_rng();
        Self::from_yaml((DEFAULT_IMAGES).choose(&mut rng).unwrap())
    }

    /// Constructor reading image data from YAML configuration files.
    pub fn from_yaml(input: &str) -> Result<Self, ConfigParseError> {
        #[derive(Debug, PartialEq, Deserialize)]
        pub struct RawImage {
            image: Option<String>,
            traditional: Option<bool>,
        }

        let input = input.trim_start_matches('\u{feff}');

        let raw: RawImage = serde_yaml::from_str(input)?;

        let (image, rewarding_scheme) = match raw {
            RawImage { image: None, .. } => return Err(ConfigParseError::NoImageData),
            RawImage {
                image: Some(i),
                traditional: None,
            } => (i, DEFAULT_REWARDING_SCHEME),
            RawImage {
                image: Some(i),
                traditional: Some(r),
            } => (
                i,
                if r {
                    RewardingScheme::UnhideWhenLostLife
                } else {
                    RewardingScheme::UnhideWhenGuessedChar
                },
            ),
        };

        Self::from(&image, rewarding_scheme)
    }

    #[inline]
    /// This constructor takes a pure ASCII, non-escaped, multiline image string.
    pub fn from(image: &str, rewarding_scheme: RewardingScheme) -> Result<Self, ConfigParseError> {
        let mut ascii: Vec<ImChar> = Vec::new();
        let mut signature: Vec<ImChar> = Vec::new();

        // Create a string of `' '` with length of longest `IMAGE_KNOWN_SIGNATURES`.
        let mut spaces = String::new();
        let longest = IMAGE_KNOWN_SIGNATURES
            .iter()
            .map(|s| s.len())
            .max()
            .unwrap();
        for _ in 0..longest {
            spaces.push(' ');
        }

        for (y, line) in image.lines().enumerate() {
            let mut ascii_line = line.to_owned();
            for sig in IMAGE_KNOWN_SIGNATURES {
                // `spaces` has the same length than `sig`.
                let short_spaces = &spaces[..sig.len()];
                debug_assert_eq!(sig.len(), short_spaces.len());
                ascii_line = ascii_line.replace(sig, short_spaces);
            }
            debug_assert_eq!(line.len(), ascii_line.len());

            // Generate `ImChar` pixel from `ascii_line`.
            let mut ii: Vec<_> = ascii_line
                .char_indices()
                // consider only chars != ' '
                .filter(|&(_, c)| c != ' ')
                // save in ImChar object
                .map(|(x, c)| ImChar {
                    point: ((x) as u8, y as u8),
                    code: c,
                })
                .collect();
            ascii.append(&mut ii);

            // Check what we have changed and generate
            // `signature_line`.
            let mut signature_line = String::new();
            for (l, a) in line.chars().zip(ascii_line.chars()) {
                if l == a {
                    // Nothing changed here.
                    signature_line.push(' ');
                } else {
                    signature_line.push(l);
                }
            }
            debug_assert_eq!(signature_line.chars().count(), ascii_line.chars().count());

            // Generate `ImChar` pixel from `signature_line`.
            let mut ii: Vec<_> = signature_line
                .char_indices()
                // consider only chars != ' '
                .filter(|&(_, c)| c != ' ')
                // save in ImChar object
                .map(|(x, c)| ImChar {
                    point: ((x) as u8, y as u8),
                    code: c,
                })
                .collect();
            signature.append(&mut ii);
        }

        // Order or shuffle pixel in `ascii`
        if ascii.len() <= BIG_IMAGE {
            ascii.sort(); // Sort algorithm, see "impl Ord for ImageChar"
        } else {
            let mut rng = thread_rng();
            (&mut ascii).shuffle(&mut rng); // points appear randomly.
        }

        // Append `signatures` at the end of `ascii`.
        ascii.append(&mut signature);

        // Find the dimensions of the whole.
        let dimension = if !ascii.is_empty() {
            let mut x_max = 0;
            let mut y_max = 0;

            for i in &ascii {
                let &ImChar { point: (x, y), .. } = i;
                if x > x_max {
                    x_max = x
                };
                if y > y_max {
                    y_max = y
                };
            }
            // We know that there is at least one char.
            (x_max + 1, y_max + 1)
        } else {
            (0, 0)
        };

        // Find the number of pixels.
        let visible_points = ascii.len();

        if ascii.is_empty() {
            Err(ConfigParseError::NoImageData)
        } else {
            Ok(Self {
                ichars: ascii,
                dimension,
                visible_points,
                rewarding_scheme,
            })
        }
    }

    /// Discloses parts of the image according to the course of the play.
    pub fn update(&mut self, game: &Game) {
        match self.rewarding_scheme {
            RewardingScheme::UnhideWhenGuessedChar => {
                if game.lifes != 0 {
                    self.hide((game.secret.hidden_chars(), game.secret.chars_to_guess()));
                }
            }
            RewardingScheme::UnhideWhenLostLife => {
                self.hide((game.lifes as usize, LIVES as usize));
            }
        };
    }

    /// Sets how much of the image will be disclosed next time the image is rendered.
    fn hide(&mut self, fraction: (usize, usize)) {
        let l = self.ichars.len();

        let as_points = |(n, d)| (5 * l * (d - n) as usize / d as usize + l) / 6;

        // silently ignore division by zero
        if fraction.1 > 0 {
            self.visible_points = as_points(fraction);
        };
    }
}

// *******************************

#[cfg(test)]
mod tests {
    use super::DEFAULT_REWARDING_SCHEME;
    use super::{ImChar, Image};
    use crate::dictionary::ConfigParseError;

    #[test]
    fn test_image_from() {
        let config: &str = r#"
>o)
(_>   <o)
      (_>
"#;
        let expected: &str = "         \n>o)      \n(_>   <o)\n      (_>\n";
        let image = Image::from(
            &config,
            crate::image::RewardingScheme::UnhideWhenGuessedChar,
        )
        .unwrap();

        assert!(image.visible_points > 0);
        assert_eq!(format!("{}", image), expected);
    }

    #[test]
    fn test_image_yaml_error() {
        let config: &str = "this is no image";
        let image = Image::from_yaml(&config).unwrap_err();
        //println!("{:?}",image);

        assert!(matches!(image, ConfigParseError::NotInYamlFormat(_)));
    }

    /// Test image parsing of configuration file data
    #[test]
    fn test_image_parser_syntax() {
        let config: &str = r#"image: |1
 ab
 cd"#;
        let image = Image::from_yaml(&config);
        //println!("{:?}",image);
        let expected = Ok(Image {
            ichars: [
                ImChar {
                    point: (0, 1),
                    code: 'c',
                },
                ImChar {
                    point: (0, 0),
                    code: 'a',
                },
                ImChar {
                    point: (1, 1),
                    code: 'd',
                },
                ImChar {
                    point: (1, 0),
                    code: 'b',
                },
            ]
            .to_vec(),
            dimension: (2, 2),
            visible_points: 4,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        });

        assert_eq!(image, expected);
    }

    /// Is non image data ignored?
    #[test]
    fn test_image_parser_syntax_ignore() {
        let config: &str = r#"image: |1
 bc
 a
# Comment"#;
        let image = Image::from_yaml(&config).unwrap();
        //println!("{:?}",image);
        let expected = Image {
            ichars: [
                ImChar {
                    point: (0, 1),
                    code: 'a',
                },
                ImChar {
                    point: (0, 0),
                    code: 'b',
                },
                ImChar {
                    point: (1, 0),
                    code: 'c',
                },
            ]
            .to_vec(),
            dimension: (2, 2),
            visible_points: 3,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        };

        assert_eq!(image, expected);
    }

    #[test]
    fn test_image_from_yaml() {
        let config: &str = r#"image: |1
 >o)
 (_>   <o)
       (_>
"#;
        let expected: &str = ">o)      \n(_>   <o)\n      (_>\n";
        let image = Image::from_yaml(&config).unwrap();

        assert!(image.visible_points > 0);
        assert_eq!(format!("{}", image), expected);
    }

    #[test]
    fn test_yaml_image_parser_disclose() {
        //
        // Test yaml.
        let config: &str = "image: |1\n abcde\n f";
        let mut image = Image::from_yaml(&config).unwrap();
        //println!("{:?}",image);
        let expected = Image {
            ichars: [
                ImChar {
                    point: (0, 1),
                    code: 'f',
                },
                ImChar {
                    point: (0, 0),
                    code: 'a',
                },
                ImChar {
                    point: (1, 0),
                    code: 'b',
                },
                ImChar {
                    point: (2, 0),
                    code: 'c',
                },
                ImChar {
                    point: (3, 0),
                    code: 'd',
                },
                ImChar {
                    point: (4, 0),
                    code: 'e',
                },
            ]
            .to_vec(),
            dimension: (5, 2),
            visible_points: 6,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        };
        assert_eq!(image, expected);

        image.hide((6, 6));
        assert_eq!(image.visible_points, 1);

        image.hide((2, 6));
        assert_eq!(image.visible_points, 4);

        image.hide((0, 6));
        assert_eq!(image.visible_points, 6);
    }

    #[test]
    fn disclose_signature_last() {
        let image_str = "image: |1\n jensA\n BlisC";
        let image = Image::from_yaml(&image_str).unwrap();
        //println!("{:?}",image);
        let expected = Image {
            ichars: [
                // This is the ASCII part of the image.
                ImChar {
                    point: (0, 1),
                    code: 'B',
                },
                ImChar {
                    point: (4, 1),
                    code: 'C',
                },
                ImChar {
                    point: (4, 0),
                    code: 'A',
                },
                // From here on, we see only signatures.
                ImChar {
                    point: (0, 0),
                    code: 'j', // was `j`
                },
                ImChar {
                    point: (1, 0),
                    code: 'e', // was `j`
                },
                ImChar {
                    point: (2, 0),
                    code: 'n',
                },
                ImChar {
                    point: (3, 0),
                    code: 's',
                },
                ImChar {
                    point: (1, 1),
                    code: 'l',
                },
                ImChar {
                    point: (2, 1),
                    code: 'i',
                },
                ImChar {
                    point: (3, 1),
                    code: 's',
                },
            ]
            .to_vec(),
            dimension: (5, 2),
            visible_points: 10,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        };
        assert_eq!(image, expected);
    }
}
<commit_msg>Calculate distance from origin geometrically<commit_after>//! This module contains all the logic dealing with images:
//! Parsing the config file data, shuffling pixels of big images,
//! ordering pixels of small images and sorting the signatures to the end.

use crate::ascii_art::DEFAULT_IMAGES;
use crate::ascii_art::IMAGE_KNOWN_SIGNATURES;
use crate::dictionary::ConfigParseError;
use crate::game::Game;
use crate::LIVES;
use rand::seq::SliceRandom;
use rand::thread_rng;
use serde_derive::Deserialize;
use std::cmp::{Ord, Ordering};
use std::fmt;

/// Default game mode. Can be changed in the configuration file.
const DEFAULT_REWARDING_SCHEME: RewardingScheme = RewardingScheme::UnhideWhenGuessedChar;

/// Threshold to decide from how many characters on the images is considered to be "big".
/// Big images are disclosed with another algorithm.
/// This is just big enough that the gallow image stays small.
const BIG_IMAGE: usize = 60; // sort algorithm <-> random algorithm

/// A game mode defining how the ASCII-art image will be disclosed progressively.
#[derive(Clone, Debug, PartialEq)]
pub enum RewardingScheme {
    /// Game mode that is used together with the traditional gallows image (the gallows image
    /// is not build in, but can be added in the configuration file. The image is disclosed
    /// piecemeal after each wrong guess.
    UnhideWhenLostLife,
    /// Default game mode. The image is disclosed piecemeal after each right guess.
    UnhideWhenGuessedChar,
}
/// One character of the ASCII art image.
#[derive(Eq, PartialEq, Debug, Copy, Clone)] //omitting Ord
pub struct ImChar {
    pub point: (u8, u8),
    pub code: char,
}

/// Format an image character.
impl fmt::Display for ImChar {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.code)
    }
}

/// Delegate the comparison to `Ord`.
impl PartialOrd for ImChar {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

/// Ord enables us to v.sort() the image characters.
impl Ord for ImChar {
    /// Compares to ImChar.
    /// Points near the left lower corner are small.
    fn cmp(&self, other: &Self) -> Ordering {
        fn weight(ic: &ImChar) -> isize {
            let &ImChar { point: (x, y), .. } = ic;
            // points near the upper left corner are light
            (x as isize * x as isize) + (y as isize * y as isize)
        }
        weight(self).cmp(&weight(other))
    }
}

#[derive(Clone, Debug, PartialEq)]
/// An ASCII-art image.
pub struct Image {
    pub ichars: Vec<ImChar>,
    pub dimension: (u8, u8),
    pub visible_points: usize,
    pub rewarding_scheme: RewardingScheme,
}

/// Format an image.
impl fmt::Display for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let x_max = self.dimension.0 as usize;
        let y_max = self.dimension.1 as usize;

        let mut i = vec![' '; ((x_max + 1) * y_max) as usize];
        for y in 0..y_max {
            i[((x_max + 1) * y + x_max) as usize] = '\n';
        }

        for ic in self.ichars.iter().take(self.visible_points) {
            let &ImChar {
                point: (x, y),
                code,
            } = ic;
            i[(x as usize + y as usize * (x_max + 1))] = code;
        }

        write!(f, "{}", i.into_iter().collect::<String>())
    }
}

impl Image {
    /// Returns a random built-in image.
    pub fn new() -> Result<Self, ConfigParseError> {
        let mut rng = thread_rng();
        Self::from_yaml((DEFAULT_IMAGES).choose(&mut rng).unwrap())
    }

    /// Constructor reading image data from YAML configuration files.
    pub fn from_yaml(input: &str) -> Result<Self, ConfigParseError> {
        #[derive(Debug, PartialEq, Deserialize)]
        pub struct RawImage {
            image: Option<String>,
            traditional: Option<bool>,
        }

        let input = input.trim_start_matches('\u{feff}');

        let raw: RawImage = serde_yaml::from_str(input)?;

        let (image, rewarding_scheme) = match raw {
            RawImage { image: None, .. } => return Err(ConfigParseError::NoImageData),
            RawImage {
                image: Some(i),
                traditional: None,
            } => (i, DEFAULT_REWARDING_SCHEME),
            RawImage {
                image: Some(i),
                traditional: Some(r),
            } => (
                i,
                if r {
                    RewardingScheme::UnhideWhenLostLife
                } else {
                    RewardingScheme::UnhideWhenGuessedChar
                },
            ),
        };

        Self::from(&image, rewarding_scheme)
    }

    #[inline]
    /// This constructor takes a pure ASCII, non-escaped, multiline image string.
    pub fn from(image: &str, rewarding_scheme: RewardingScheme) -> Result<Self, ConfigParseError> {
        let mut ascii: Vec<ImChar> = Vec::new();
        let mut signature: Vec<ImChar> = Vec::new();

        // Create a string of `' '` with length of longest `IMAGE_KNOWN_SIGNATURES`.
        let mut spaces = String::new();
        let longest = IMAGE_KNOWN_SIGNATURES
            .iter()
            .map(|s| s.len())
            .max()
            .unwrap();
        for _ in 0..longest {
            spaces.push(' ');
        }

        for (y, line) in image.lines().enumerate() {
            let mut ascii_line = line.to_owned();
            for sig in IMAGE_KNOWN_SIGNATURES {
                // `spaces` has the same length than `sig`.
                let short_spaces = &spaces[..sig.len()];
                debug_assert_eq!(sig.len(), short_spaces.len());
                ascii_line = ascii_line.replace(sig, short_spaces);
            }
            debug_assert_eq!(line.len(), ascii_line.len());

            // Generate `ImChar` pixel from `ascii_line`.
            let mut ii: Vec<_> = ascii_line
                .char_indices()
                // consider only chars != ' '
                .filter(|&(_, c)| c != ' ')
                // save in ImChar object
                .map(|(x, c)| ImChar {
                    point: ((x) as u8, y as u8),
                    code: c,
                })
                .collect();
            ascii.append(&mut ii);

            // Check what we have changed and generate
            // `signature_line`.
            let mut signature_line = String::new();
            for (l, a) in line.chars().zip(ascii_line.chars()) {
                if l == a {
                    // Nothing changed here.
                    signature_line.push(' ');
                } else {
                    signature_line.push(l);
                }
            }
            debug_assert_eq!(signature_line.chars().count(), ascii_line.chars().count());

            // Generate `ImChar` pixel from `signature_line`.
            let mut ii: Vec<_> = signature_line
                .char_indices()
                // consider only chars != ' '
                .filter(|&(_, c)| c != ' ')
                // save in ImChar object
                .map(|(x, c)| ImChar {
                    point: ((x) as u8, y as u8),
                    code: c,
                })
                .collect();
            signature.append(&mut ii);
        }

        // Order or shuffle pixel in `ascii`
        if ascii.len() <= BIG_IMAGE {
            ascii.sort(); // Sort algorithm, see "impl Ord for ImageChar"
        } else {
            let mut rng = thread_rng();
            (&mut ascii).shuffle(&mut rng); // points appear randomly.
        }

        // Append `signatures` at the end of `ascii`.
        ascii.append(&mut signature);

        // Find the dimensions of the whole.
        let dimension = if !ascii.is_empty() {
            let mut x_max = 0;
            let mut y_max = 0;

            for i in &ascii {
                let &ImChar { point: (x, y), .. } = i;
                if x > x_max {
                    x_max = x
                };
                if y > y_max {
                    y_max = y
                };
            }
            // We know that there is at least one char.
            (x_max + 1, y_max + 1)
        } else {
            (0, 0)
        };

        // Find the number of pixels.
        let visible_points = ascii.len();

        if ascii.is_empty() {
            Err(ConfigParseError::NoImageData)
        } else {
            Ok(Self {
                ichars: ascii,
                dimension,
                visible_points,
                rewarding_scheme,
            })
        }
    }

    /// Discloses parts of the image according to the course of the play.
    pub fn update(&mut self, game: &Game) {
        match self.rewarding_scheme {
            RewardingScheme::UnhideWhenGuessedChar => {
                if game.lifes != 0 {
                    self.hide((game.secret.hidden_chars(), game.secret.chars_to_guess()));
                }
            }
            RewardingScheme::UnhideWhenLostLife => {
                self.hide((game.lifes as usize, LIVES as usize));
            }
        };
    }

    /// Sets how much of the image will be disclosed next time the image is rendered.
    fn hide(&mut self, fraction: (usize, usize)) {
        let l = self.ichars.len();

        let as_points = |(n, d)| (5 * l * (d - n) as usize / d as usize + l) / 6;

        // silently ignore division by zero
        if fraction.1 > 0 {
            self.visible_points = as_points(fraction);
        };
    }
}

// *******************************

#[cfg(test)]
mod tests {
    use super::DEFAULT_REWARDING_SCHEME;
    use super::{ImChar, Image};
    use crate::dictionary::ConfigParseError;

    #[test]
    fn test_image_from() {
        let config: &str = r#"
>o)
(_>   <o)
      (_>
"#;
        let expected: &str = "         \n>o)      \n(_>   <o)\n      (_>\n";
        let image = Image::from(
            &config,
            crate::image::RewardingScheme::UnhideWhenGuessedChar,
        )
        .unwrap();

        assert!(image.visible_points > 0);
        assert_eq!(format!("{}", image), expected);
    }

    #[test]
    fn test_image_yaml_error() {
        let config: &str = "this is no image";
        let image = Image::from_yaml(&config).unwrap_err();
        //println!("{:?}",image);

        assert!(matches!(image, ConfigParseError::NotInYamlFormat(_)));
    }

    /// Test image parsing of configuration file data
    #[test]
    fn test_image_parser_syntax() {
        let config: &str = r#"image: |1
 ab
 c e
 df"#;
        let image = Image::from_yaml(&config);
        //println!("{:?}",image);
        let expected = Ok(Image {
            ichars: [
                ImChar {
                    point: (0, 0),
                    code: 'a',
                },
                ImChar {
                    point: (1, 0),
                    code: 'b',
                },
                ImChar {
                    point: (0, 1),
                    code: 'c',
                },
                ImChar {
                    point: (0, 2),
                    code: 'd',
                },
                ImChar {
                    point: (2, 1),
                    code: 'e',
                },
                ImChar {
                    point: (1, 2),
                    code: 'f',
                },
            ]
            .to_vec(),
            dimension: (3, 3),
            visible_points: 6,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        });

        assert_eq!(image, expected);
    }

    /// Is non image data ignored?
    #[test]
    fn test_image_parser_syntax_ignore() {
        let config: &str = r#"image: |1
 ab
 c
# Comment"#;
        let image = Image::from_yaml(&config).unwrap();
        //println!("{:?}",image);
        let expected = Image {
            ichars: [
                ImChar {
                    point: (0, 0),
                    code: 'a',
                },
                ImChar {
                    point: (1, 0),
                    code: 'b',
                },
                ImChar {
                    point: (0, 1),
                    code: 'c',
                },
            ]
            .to_vec(),
            dimension: (2, 2),
            visible_points: 3,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        };

        assert_eq!(image, expected);
    }

    #[test]
    fn test_image_from_yaml() {
        let config: &str = r#"image: |1
 >o)
 (_>   <o)
       (_>
"#;
        let expected: &str = ">o)      \n(_>   <o)\n      (_>\n";
        let image = Image::from_yaml(&config).unwrap();

        assert!(image.visible_points > 0);
        assert_eq!(format!("{}", image), expected);
    }

    #[test]
    fn test_yaml_image_parser_disclose() {
        //
        // Test yaml.
        let config: &str = "image: |1\n abdef\n c";
        let mut image = Image::from_yaml(&config).unwrap();
        //println!("{:?}",image);
        let expected = Image {
            ichars: [
                ImChar {
                    point: (0, 0),
                    code: 'a',
                },
                ImChar {
                    point: (1, 0),
                    code: 'b',
                },
                ImChar {
                    point: (0, 1),
                    code: 'c',
                },
                ImChar {
                    point: (2, 0),
                    code: 'd',
                },
                ImChar {
                    point: (3, 0),
                    code: 'e',
                },
                ImChar {
                    point: (4, 0),
                    code: 'f',
                },
            ]
            .to_vec(),
            dimension: (5, 2),
            visible_points: 6,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        };
        assert_eq!(image, expected);

        image.hide((6, 6));
        assert_eq!(image.visible_points, 1);

        image.hide((2, 6));
        assert_eq!(image.visible_points, 4);

        image.hide((0, 6));
        assert_eq!(image.visible_points, 6);
    }

    #[test]
    fn disclose_signature_last() {
        let image_str = "image: |1\n jensB\n AlisC";
        let image = Image::from_yaml(&image_str).unwrap();
        //println!("{:?}",image);
        let expected = Image {
            ichars: [
                // These are regular image chars.
                ImChar {
                    point: (0, 1),
                    code: 'A',
                },
                ImChar {
                    point: (4, 0),
                    code: 'B',
                },
                ImChar {
                    point: (4, 1),
                    code: 'C',
                },
                // These chars are signature chars.
                ImChar {
                    point: (0, 0),
                    code: 'j',
                },
                ImChar {
                    point: (1, 0),
                    code: 'e',
                },
                ImChar {
                    point: (2, 0),
                    code: 'n',
                },
                ImChar {
                    point: (3, 0),
                    code: 's',
                },
                ImChar {
                    point: (1, 1),
                    code: 'l',
                },
                ImChar {
                    point: (2, 1),
                    code: 'i',
                },
                ImChar {
                    point: (3, 1),
                    code: 's',
                },
            ]
            .to_vec(),
            dimension: (5, 2),
            visible_points: 10,
            rewarding_scheme: DEFAULT_REWARDING_SCHEME,
        };
        assert_eq!(image, expected);
    }
}
<|endoftext|>


<commit_before>mod columnar;
mod linkedlist;
fn main() {
    println!("Hello, world!");
}
<commit_msg>Additional test for lifetime<commit_after>mod columnar;
mod linkedlist;
mod cell;

fn main() {
    println!("Hello, world!");
}

#[cfg(test)]
mod tests {
    use std::mem;
    #[test]
    fn test_intersection_lifetime() {
        fn x_or_y<'a>(x : &'a i32, y: &'a i32) -> &'a i32{
            if x < y {
                return x;
            }
            return y;
        }
        {
            let x = &3;
            {
                let y = &5;
                assert_eq!(*x_or_y(x, y), 3);
                assert_eq!(*x_or_y(y, x), 3);
            }
        }
    }
    #[test]
    fn test_different_lifetime() {
        struct XY<'a, 'b> {
            x: &'a i32,
            y: &'b i32,
        }
        {
            let x = &3;
            let mut z = &5;
            assert_eq!(*z, 5);
            {
                let y = &7;
                let tmp = XY{x, y};
                z = tmp.x; // this code would not work without x and y being in different lifetime.
                assert_eq!(*tmp.y, 7);
            }
            assert_eq!(*z, 3);
        }
    }

    #[test]
    #[allow(dead_code)]
    fn test_sizeof() {
        struct SingleField {
            x: i32
        }
        struct RefField<'a> {
            x: &'a i32
        }
        struct RefFieldMultiple<'a> {
            x: &'a i16,
            y: &'a i32,
            z: &'a i64,
        }
        assert_eq!(mem::size_of::<i64>(), 8);
        assert_eq!(mem::size_of::<i32>(), 4);
        assert_eq!(mem::size_of::<i16>(), 2);
        assert_eq!(mem::size_of::<i8>(), 1);

        assert_eq!(mem::size_of::<SingleField>(), 4);
        assert_eq!(mem::size_of::<RefField>(), 8); // pointer size.
        assert_eq!(mem::size_of::<RefFieldMultiple>(), 24); // pointer size.
    }
}<|endoftext|>


<commit_before>fn main() {

    let s: Vec<u64> = "
            08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
            49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
            81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
            52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
            22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
            24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
            32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
            67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
            24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
            21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
            78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
            16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
            86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
            19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
            04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
            88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
            04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
            20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
            20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
            01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48"
            .split(" ")
            .filter(|&x| !x.is_empty())
            .filter(|&x| x != "\n")
            .collect::<Vec<&str>>()
            .iter()
            .map(|&x| x.trim().parse().unwrap())
            .collect();

    fn get_slice(sb: &Vec<u64>, index: u64) -> &[u64] {
        &sb[index as usize..(index + 4) as usize]
    }

    fn get_v_slice(sb: &Vec<u64>, index: u64, vec: &mut Vec<u64>) {
        let mut curr_mut = 0;
        loop {
            let new_index = index + (curr_mut * 20);
            vec.push(sb[new_index as usize]);
            curr_mut = curr_mut + 1;
            if curr_mut == 4 {
                break;
            }
        }
    }

    fn get_fd_slice(sb: &Vec<u64>, index: u64, vec: &mut Vec<u64>) {
        let mut curr_mut = 0;
        loop {
            let new_index = index + (curr_mut * 20) + curr_mut;
            vec.push(sb[new_index as usize]);
            curr_mut = curr_mut + 1;
            if curr_mut == 4 {
                break;
            }
        }
    }

    fn get_bd_slice(sb: &Vec<u64>, index: u64, vec: &mut Vec<u64>) {
        let mut curr_mut = 0;
        loop {
            let new_index = index + 3 + (curr_mut * 20) - curr_mut;
            vec.push(sb[new_index as usize]);
            curr_mut = curr_mut + 1;
            if curr_mut == 4 {
                break;
            }
        }
    }

    fn calc_h(sb: &Vec<u64>, index: u64) -> u64 {
        let mut largest = 0;
        let mut curr_index = 0;
        loop {
            let new_index = index + (curr_index * 20);
            let slice = get_slice(sb, new_index);
            let calc = slice.iter().fold(1, |acc, item| acc * item);
            if calc > largest {
                largest = calc;
            }
            curr_index = curr_index + 1;
            if curr_index == 4 {
                break;
            }
        }
        largest
    }

    fn calc_v(sb: &Vec<u64>, index: u64) -> u64 {
        let mut largest = 0;
        let mut curr_index = 0;
        loop {
            let new_index = index + 1;
            let mut vec: Vec<u64> = Vec::new();
            get_v_slice(sb, new_index, &mut vec);
            let calc = vec.iter().fold(1, |acc, item| acc * item);
            if calc > largest {
                largest = calc;
            }
            curr_index = curr_index + 1;
            if curr_index == 4 {
                break;
            }
        }
        largest
    }

    fn calc_d(sb: &Vec<u64>, index: u64) -> u64 {

        let mut vec1: Vec<u64> = Vec::new();
        get_fd_slice(sb, index, &mut vec1);
        let calc1 = vec1.iter().fold(1, |acc, item| acc * item);

        let mut vec2: Vec<u64> = Vec::new();
        get_bd_slice(sb, index, &mut vec2);
        let calc2 = vec2.iter().fold(1, |acc, item| acc * item);

        if calc2 > calc1 {
            return calc2
        }
        calc1
    }

    fn get_largest_for_block(sb: &Vec<u64>, index: u64) -> u64 {
        let h = calc_h(sb, index);
        let v = calc_v(sb, index);
        let d = calc_d(sb, index);

        let vec = vec![h, v, d];

        *vec.iter().max().unwrap()
    }

    fn get_largest(sb: &Vec<u64>) -> u64 {
        let mut largest = 0;
        for scale in 1..17 {
            for xindex in 0..16 {
                let index = xindex + (scale * 20);
                let result = get_largest_for_block(sb, index);
                if result > largest {
                    // println!("{}", result);
                    largest = result;
                }
            }
        }
        largest
    }

    println!("{:?}", get_largest(&s));
}
<commit_msg>Refactoring problem_11<commit_after>macro_rules! timeit {
    ($func:expr) => ({
        let t1 = std::time::Instant::now();
        println!("{:?}", $func);
        let t2 = std::time::Instant::now().duration_since(t1);
        println!("{}", t2.as_secs() as f64 + t2.subsec_nanos() as f64 / 1000000000.00);
    })
}

fn main() {

    const SIZE: usize = 4;
    let s: Vec<usize> = "
            08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
            49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
            81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
            52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
            22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
            24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
            32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
            67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
            24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
            21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
            78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
            16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
            86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
            19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
            04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
            88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
            04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
            20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
            20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
            01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48"
        .split(" ")
        .filter(|&x| !x.is_empty() && x != "\n")
        .map(|x| x.trim().parse().unwrap())
        .collect();

    fn get_slice(sb: &Vec<usize>, index: usize) -> &[usize] {
        &sb[index as usize..(index + 4) as usize]
    }

    fn get_v_slice(sb: &Vec<usize>, index: usize, vec: &mut Vec<usize>) {
        (0..SIZE)
            .map(|x| vec.push(sb[(index + (x * 20)) as usize]))
            .collect::<Vec<_>>();
    }

    fn get_fd_slice(sb: &Vec<usize>, index: usize, vec: &mut Vec<usize>) {
        (0..SIZE)
            .map(|x| vec.push(sb[(index + (x * 20) + x) as usize]))
            .collect::<Vec<_>>();
    }

    fn get_bd_slice(sb: &Vec<usize>, index: usize, vec: &mut Vec<usize>) {
        (0..SIZE)
            .map(|x| vec.push(sb[(index + (x * 20) + SIZE - 1 - x) as usize]))
            .collect::<Vec<_>>();
    }

    fn calc_h(sb: &Vec<usize>, index: usize) -> usize {
        (0..SIZE)
            .map(|x| get_slice(sb, index + (x * 20)))
            .map(|s| s.iter().fold(1, |acc, item| acc * item))
            .max()
            .unwrap()
    }

    fn calc_v(sb: &Vec<usize>, index: usize) -> usize {
        (1..SIZE + 1)
            .map(|x| (x, Vec::new()))
            .map(|(x, mut v)| {
                get_v_slice(sb, index + x, &mut v);
                v
            })
            .map(|s| s.iter().fold(1, |acc, item| acc * item))
            .max()
            .unwrap()
    }

    fn calc_d(sb: &Vec<usize>, index: usize) -> usize {

        let mut vec1: Vec<usize> = Vec::new();
        get_fd_slice(sb, index, &mut vec1);
        let calc1 = vec1.iter().fold(1, |acc, item| acc * item);

        let mut vec2: Vec<usize> = Vec::new();
        get_bd_slice(sb, index, &mut vec2);
        let calc2 = vec2.iter().fold(1, |acc, item| acc * item);

        vec![calc1, calc2].into_iter().max().unwrap()
    }

    fn get_largest_for_block(sb: &Vec<usize>, index: usize) -> usize {
        vec![calc_h(sb, index), calc_v(sb, index), calc_d(sb, index)].into_iter().max().unwrap()
    }

    fn get_largest(sb: &Vec<usize>) -> usize {
        let mut largest = 0;
        for scale in 1..17 {
            for xindex in 0..16 {
                let index = xindex + (scale * 20);
                let result = get_largest_for_block(sb, index);
                if result > largest {
                    largest = result;
                }
            }
        }
        largest
    }

    timeit!(get_largest(&s));
}
<|endoftext|>