<commit_before>use std::fs::File;
use std::io::prelude::*;

#[derive(Debug)]
enum ParameterMode {
  Position,
  Immediate,
  Relative
}

#[derive(Debug)]
enum OperationType {
  Add,
  Multiply,
  Input,
  Output,
  JumpIfTrue,
  JumpIfFalse,
  LessThan,
  Equals,
  SetRelativeBase,
  Halt
}

#[derive(Debug)]
struct Instruction {
  operation: OperationType,
  inputs: Vec<(ParameterMode, i64)>
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("09.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_instruction(numbers: &[i64]) -> Instruction {
  let instruction_code = numbers[0];
  let op_code = instruction_code % 100;

  let (operation, inputs_count) = match op_code {
    1 => (OperationType::Add, 3),
    2 => (OperationType::Multiply, 3),
    3 => (OperationType::Input, 1),
    4 => (OperationType::Output, 1),
    5 => (OperationType::JumpIfTrue, 2),
    6 => (OperationType::JumpIfFalse, 2),
    7 => (OperationType::LessThan, 3),
    8 => (OperationType::Equals, 3),
    9 => (OperationType::SetRelativeBase, 1),
    99 => (OperationType::Halt, 0),
    _ => panic!()
  };

  let get_parameter_mode = |i| {
    match (instruction_code - op_code) / 10i64.pow(2 + i as u32) % 10 {
      0 => ParameterMode::Position,
      1 => ParameterMode::Immediate,
      2 => ParameterMode::Relative,
      _ => panic!()
    }
  };

  Instruction {
    operation,
    inputs: (0..inputs_count)
      .map(|i| (get_parameter_mode(i), numbers[i + 1]))
      .collect()
  }
}

fn run_program(program: &mut Vec<i64>, input: i64) -> Vec<i64> {
  let mut relative_base = 0;
  let mut result = vec![];
  let mut pointer = 0;

  fn extend_memory(program: &mut Vec<i64>, index: usize) {
    while index >= program.len() {
      program.push(0);
    }
  }

  fn get_input_index(program: &mut Vec<i64>, instruction: &Instruction, relative_base: usize, index: usize) -> usize {
    match instruction.inputs[index] {
      (ParameterMode::Relative, d) => {
        let j = (relative_base as i64 + d) as usize;
        extend_memory(program, j);
        j
      },
      (_, j) => {
        extend_memory(program, j as usize);
        j as usize
      }
    }
  }

  while pointer < program.len() {
    let init_pointer = pointer;
    let instruction = parse_instruction(&program[pointer..]);

    let (target_value, target_index) = {
      let mut get_input = |i| {
        match instruction.inputs[i] {
          (ParameterMode::Immediate, value) => value,
          _ => {
            let j = get_input_index(program, &instruction, relative_base, i);
            program[j]
          }
        }
      };

      let (target_value, output_index) = match instruction.operation {
        OperationType::Add => (Some(get_input(0) + get_input(1)), Some(2)),
        OperationType::Multiply => (Some(get_input(0) * get_input(1)), Some(2)),
        OperationType::Input => (Some(input), Some(0)),
        OperationType::Output => (Some(get_input(0)), None),
        OperationType::LessThan => (Some((get_input(0) < get_input(1)) as i64), Some(2)),
        OperationType::Equals => (Some((get_input(0) == get_input(1)) as i64), Some(2)),
        OperationType::JumpIfTrue => {
          if get_input(0) != 0 {
            pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::JumpIfFalse => {
          if get_input(0) == 0 {
            pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::SetRelativeBase => {
          relative_base = (relative_base as i64 + get_input(0)) as usize;
          (None, None)
        }
        OperationType::Halt => break
      };

      (
        target_value,
        output_index.map(|i| {
          get_input_index(program, &instruction, relative_base, i)
        })
      )
    };

    if let Some(target_value) = target_value {
      if let Some(target_index) = target_index {
        extend_memory(program, target_index);
        program[target_index] = target_value;
      } else {
        result.push(target_value);
      }
    }

    if pointer == init_pointer {
      pointer += instruction.inputs.len() + 1;
    }
  }

  result
}

fn main() {
  let input = get_input().unwrap();
  let numbers = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  let output = run_program(&mut numbers.clone(), 1);
  println!("Part 1: {}", output.last().unwrap());

  let output = run_program(&mut numbers.clone(), 2);
  println!("Part 2: {}", output.last().unwrap());
}
<commit_msg>Avoid closures where possible<commit_after>use std::fs::File;
use std::io::prelude::*;

#[derive(Debug)]
enum ParameterMode {
  Position,
  Immediate,
  Relative
}

#[derive(Debug)]
enum OperationType {
  Add,
  Multiply,
  Input,
  Output,
  JumpIfTrue,
  JumpIfFalse,
  LessThan,
  Equals,
  SetRelativeBase,
  Halt
}

#[derive(Debug)]
struct Instruction {
  operation: OperationType,
  inputs: Vec<(ParameterMode, i64)>
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("09.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_instruction(numbers: &[i64]) -> Instruction {
  let instruction_code = numbers[0];
  let op_code = instruction_code % 100;

  let (operation, inputs_count) = match op_code {
    1 => (OperationType::Add, 3),
    2 => (OperationType::Multiply, 3),
    3 => (OperationType::Input, 1),
    4 => (OperationType::Output, 1),
    5 => (OperationType::JumpIfTrue, 2),
    6 => (OperationType::JumpIfFalse, 2),
    7 => (OperationType::LessThan, 3),
    8 => (OperationType::Equals, 3),
    9 => (OperationType::SetRelativeBase, 1),
    99 => (OperationType::Halt, 0),
    _ => panic!()
  };

  let get_parameter_mode = |i| {
    match (instruction_code - op_code) / 10i64.pow(2 + i as u32) % 10 {
      0 => ParameterMode::Position,
      1 => ParameterMode::Immediate,
      2 => ParameterMode::Relative,
      _ => panic!()
    }
  };

  Instruction {
    operation,
    inputs: (0..inputs_count)
      .map(|i| (get_parameter_mode(i), numbers[i + 1]))
      .collect()
  }
}

fn run_program(program: &mut Vec<i64>, input: i64) -> Vec<i64> {
  let mut relative_base = 0;
  let mut result = vec![];
  let mut pointer = 0;

  fn extend_memory(program: &mut Vec<i64>, index: usize) {
    while index >= program.len() {
      program.push(0);
    }
  }

  fn get_instruction_input_index(
    program: &mut Vec<i64>,
    instruction: &Instruction,
    relative_base: usize,
    index: usize
  ) -> usize {
    match instruction.inputs[index] {
      (ParameterMode::Relative, d) => {
        let j = (relative_base as i64 + d) as usize;
        extend_memory(program, j);
        j
      },
      (_, j) => {
        extend_memory(program, j as usize);
        j as usize
      }
    }
  }

  fn get_instruction_input(
    program: &mut Vec<i64>,
    instruction: &Instruction,
    relative_base: usize,
    index: usize
  ) -> i64 {
    match instruction.inputs[index] {
      (ParameterMode::Immediate, value) => value,
      _ => {
        let j = get_instruction_input_index(program, instruction, relative_base, index);
        program[j]
      }
    }
  }

  while pointer < program.len() {
    let init_pointer = pointer;
    let instruction = parse_instruction(&program[pointer..]);

    let (target_value, target_index) = {
      let mut get_input = |i| {
        get_instruction_input(program, &instruction, relative_base, i)
      };

      let (target_value, output_index) = match instruction.operation {
        OperationType::Add => (Some(get_input(0) + get_input(1)), Some(2)),
        OperationType::Multiply => (Some(get_input(0) * get_input(1)), Some(2)),
        OperationType::Input => (Some(input), Some(0)),
        OperationType::Output => (Some(get_input(0)), None),
        OperationType::LessThan => (Some((get_input(0) < get_input(1)) as i64), Some(2)),
        OperationType::Equals => (Some((get_input(0) == get_input(1)) as i64), Some(2)),
        OperationType::JumpIfTrue => {
          if get_input(0) != 0 {
            pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::JumpIfFalse => {
          if get_input(0) == 0 {
            pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::SetRelativeBase => {
          relative_base = (relative_base as i64 + get_input(0)) as usize;
          (None, None)
        }
        OperationType::Halt => break
      };

      (
        target_value,
        output_index.map(|i| {
          get_instruction_input_index(program, &instruction, relative_base, i)
        })
      )
    };

    if let Some(target_value) = target_value {
      if let Some(target_index) = target_index {
        extend_memory(program, target_index);
        program[target_index] = target_value;
      } else {
        result.push(target_value);
      }
    }

    if pointer == init_pointer {
      pointer += instruction.inputs.len() + 1;
    }
  }

  result
}

fn main() {
  let input = get_input().unwrap();
  let numbers = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  let output = run_program(&mut numbers.clone(), 1);
  println!("Part 1: {}", output.last().unwrap());

  let output = run_program(&mut numbers.clone(), 2);
  println!("Part 2: {}", output.last().unwrap());
}
<|endoftext|>


<commit_before>//!
//! [Under construction](https://github.com/rayon-rs/rayon/issues/231)
//!
//! ## Restricting multiple versions
//!
//! In order to ensure proper coordination between threadpools, and especially
//! to make sure there's only one global threadpool, `rayon-core` is actively
//! restricted from building multiple versions of itself into a single target.
//! You may see a build error like this in violation:
//!
//! ```text
//! error: native library `rayon-core` is being linked to by more
//! than one package, and can only be linked to by one package
//! ```
//!
//! While we strive to keep `rayon-core` semver-compatible, it's still
//! possible to arrive at this situation if different crates have overly
//! restrictive tilde or inequality requirements for `rayon-core`.  The
//! conflicting requirements will need to be resolved before the build will
//! succeed.

#![doc(html_root_url = "https://docs.rs/rayon-core/1.3")]
#![allow(non_camel_case_types)] // I prefer to use ALL_CAPS for type parameters
#![deny(missing_debug_implementations)]
#![cfg_attr(test, feature(conservative_impl_trait))]

use std::any::Any;
use std::env;
use std::error::Error;
use std::marker::PhantomData;
use std::str::FromStr;
use std::fmt;

extern crate coco;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate num_cpus;
extern crate rand;

#[macro_use]
mod log;

mod latch;
mod join;
mod job;
mod registry;
mod scope;
mod sleep;
mod spawn;
mod test;
mod thread_pool;
mod unwind;
mod util;

#[cfg(rayon_unstable)]
pub mod internal;
pub use thread_pool::ThreadPool;
pub use thread_pool::current_thread_index;
pub use thread_pool::current_thread_has_pending_tasks;
pub use join::{join, join_context};
pub use scope::{scope, Scope};
pub use spawn::spawn;

/// Returns the number of threads in the current registry. If this
/// code is executing within a Rayon thread-pool, then this will be
/// the number of threads for the thread-pool of the current
/// thread. Otherwise, it will be the number of threads for the global
/// thread-pool.
///
/// This can be useful when trying to judge how many times to split
/// parallel work (the parallel iterator traits use this value
/// internally for this purpose).
///
/// ### Future compatibility note
///
/// Note that unless this thread-pool was created with a
/// configuration that specifies the number of threads, then this
/// number may vary over time in future versions (see [the
/// `num_threads()` method for details][snt]).
///
/// [snt]: struct.Configuration.html#method.num_threads
pub fn current_num_threads() -> usize {
    ::registry::Registry::current_num_threads()
}

/// Contains the rayon thread pool configuration.
#[derive(Default)]
pub struct Configuration {
    /// The number of threads in the rayon thread pool.
    /// If zero will use the RAYON_NUM_THREADS environment variable.
    /// If RAYON_NUM_THREADS is invalid or zero will use the default.
    num_threads: usize,

    /// Custom closure, if any, to handle a panic that we cannot propagate
    /// anywhere else.
    panic_handler: Option<Box<PanicHandler>>,

    /// Closure to compute the name of a thread.
    get_thread_name: Option<Box<FnMut(usize) -> String>>,

    /// The stack size for the created worker threads
    stack_size: Option<usize>,

    /// Closure invoked on worker thread start.
    start_handler: Option<Box<StartHandler>>,

    /// Closure invoked on worker thread exit.
    exit_handler: Option<Box<ExitHandler>>,

    /// If false, worker threads will execute spawned jobs in a
    /// "depth-first" fashion. If true, they will do a "breadth-first"
    /// fashion. Depth-first is the default.
    breadth_first: bool,
}

/// The type for a panic handling closure. Note that this same closure
/// may be invoked multiple times in parallel.
type PanicHandler = Fn(Box<Any + Send>) + Send + Sync;

/// The type for a closure that gets invoked when a thread starts. The
/// closure is passed the index of the thread on which it is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
type StartHandler = Fn(usize) + Send + Sync;

/// The type for a closure that gets invoked when a thread exits. The
/// closure is passed the index of the thread on which is is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
type ExitHandler = Fn(usize) + Send + Sync;

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration::default()
    }

    /// Create a new `ThreadPool` initialized using this configuration.
    pub fn build(self) -> Result<ThreadPool, Box<Error + 'static>> {
        ThreadPool::new(self)
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `num_threads()` for more information.
    fn get_num_threads(&self) -> usize {
        if self.num_threads > 0 {
            self.num_threads
        } else {
            match env::var("RAYON_NUM_THREADS").ok().and_then(|s| usize::from_str(&s).ok()) {
                Some(x) if x > 0 => return x,
                Some(x) if x == 0 => return num_cpus::get(),
                _ => {},
            }

            // Support for deprecated `RAYON_RS_NUM_CPUS`.
            match env::var("RAYON_RS_NUM_CPUS").ok().and_then(|s| usize::from_str(&s).ok()) {
                Some(x) if x > 0 => x,
                _ => num_cpus::get(),
            }
        }
    }

    /// Get the thread name for the thread with the given index.
    fn get_thread_name(&mut self, index: usize) -> Option<String> {
        self.get_thread_name.as_mut().map(|c| c(index))
    }

    /// Set a closure which takes a thread index and returns
    /// the thread's name.
    pub fn thread_name<F>(mut self, closure: F) -> Self
    where F: FnMut(usize) -> String + 'static {
        self.get_thread_name = Some(Box::new(closure));
        self
    }

    /// Set the number of threads to be used in the rayon threadpool.
    ///
    /// If you specify a non-zero number of threads using this
    /// function, then the resulting thread-pools are guaranteed to
    /// start at most this number of threads.
    ///
    /// If `num_threads` is 0, or you do not call this function, then
    /// the Rayon runtime will select the number of threads
    /// automatically. At present, this is based on the
    /// `RAYON_NUM_THREADS` environment variable (if set),
    /// or the number of logical CPUs (otherwise).
    /// In the future, however, the default behavior may
    /// change to dynamically add or remove threads as needed.
    ///
    /// **Future compatibility warning:** Given the default behavior
    /// may change in the future, if you wish to rely on a fixed
    /// number of threads, you should use this function to specify
    /// that number. To reproduce the current default behavior, you
    /// may wish to use the [`num_cpus`
    /// crate](https://crates.io/crates/num_cpus) to query the number
    /// of CPUs dynamically.
    ///
    /// **Old environment variable:** `RAYON_NUM_THREADS` is a one-to-one
    /// replacement of the now deprecated `RAYON_RS_NUM_CPUS` environment
    /// variable. If both variables are specified, `RAYON_NUM_THREADS` will
    /// be prefered.
    pub fn num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = num_threads;
        self
    }

    /// Returns a copy of the current panic handler.
    fn take_panic_handler(&mut self) -> Option<Box<PanicHandler>> {
        self.panic_handler.take()
    }

    /// Normally, whenever Rayon catches a panic, it tries to
    /// propagate it to someplace sensible, to try and reflect the
    /// semantics of sequential execution. But in some cases,
    /// particularly with the `spawn()` APIs, there is no
    /// obvious place where we should propagate the panic to.
    /// In that case, this panic handler is invoked.
    ///
    /// If no panic handler is set, the default is to abort the
    /// process, under the principle that panics should not go
    /// unobserved.
    ///
    /// If the panic handler itself panics, this will abort the
    /// process. To prevent this, wrap the body of your panic handler
    /// in a call to `std::panic::catch_unwind()`.
    pub fn panic_handler<H>(mut self, panic_handler: H) -> Configuration
        where H: Fn(Box<Any + Send>) + Send + Sync + 'static
    {
        self.panic_handler = Some(Box::new(panic_handler));
        self
    }

    /// Get the stack size of the worker threads
    fn get_stack_size(&self) -> Option<usize>{
        self.stack_size
    }

    /// Set the stack size of the worker threads
    pub fn stack_size(mut self, stack_size: usize) -> Self {
        self.stack_size = Some(stack_size);
        self
    }

    /// Suggest to worker threads that they execute spawned jobs in a
    /// "breadth-first" fashion. Typically, when a worker thread is
    /// idle or blocked, it will attempt to execute the job from the
    /// *top* of its local deque of work (i.e., the job most recently
    /// spawned). If this flag is set to true, however, workers will
    /// prefer to execute in a *breadth-first* fashion -- that is,
    /// they will search for jobs at the *bottom* of their local
    /// deque. (At present, workers *always* steal from the bottom of
    /// other worker's deques, regardless of the setting of this
    /// flag.)
    ///
    /// If you think of the tasks as a tree, where a parent task
    /// spawns its children in the tree, then this flag loosely
    /// corresponds to doing a breadth-first traversal of the tree,
    /// whereas the default would be to do a depth-first traversal.
    ///
    /// **Note that this is an "execution hint".** Rayon's task
    /// execution is highly dynamic and the precise order in which
    /// independent tasks are executed is not intended to be
    /// guaranteed.
    pub fn breadth_first(mut self) -> Self {
        self.breadth_first = true;
        self
    }

    fn get_breadth_first(&self) -> bool {
        self.breadth_first
    }

    /// Takes the current thread start callback, leaving `None`.
    fn take_start_handler(&mut self) -> Option<Box<StartHandler>> {
        self.start_handler.take()
    }

    /// Set a callback to be invoked on thread start.
    ///
    /// The closure is passed the index of the thread on which it is invoked.
    /// Note that this same closure may be invoked multiple times in parallel.
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then startup will continue normally.
    pub fn start_handler<H>(mut self, start_handler: H) -> Configuration
        where H: Fn(usize) + Send + Sync + 'static
    {
        self.start_handler = Some(Box::new(start_handler));
        self
    }

    /// Returns a current thread exit callback, leaving `None`.
    fn take_exit_handler(&mut self) -> Option<Box<ExitHandler>> {
        self.exit_handler.take()
    }

    /// Set a callback to be invoked on thread exit.
    ///
    /// The closure is passed the index of the thread on which it is invoked.
    /// Note that this same closure may be invoked multiple times in parallel.
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then the thread will exit normally.
    pub fn exit_handler<H>(mut self, exit_handler: H) -> Configuration
        where H: Fn(usize) + Send + Sync + 'static
    {
        self.exit_handler = Some(Box::new(exit_handler));
        self
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will return an error. An `Ok` result indicates that this
/// is the first initialization of the thread pool.
pub fn initialize(config: Configuration) -> Result<(), Box<Error>> {
    let registry = try!(registry::init_global_registry(config));
    registry.wait_until_primed();
    Ok(())
}

impl fmt::Debug for Configuration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Configuration { ref num_threads, ref get_thread_name,
                            ref panic_handler, ref stack_size,
                            ref start_handler, ref exit_handler,
                            ref breadth_first } = *self;

        // Just print `Some(<closure>)` or `None` to the debug
        // output.
        struct ClosurePlaceholder;
        impl fmt::Debug for ClosurePlaceholder {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str("<closure>")
            }
        }
        let get_thread_name = get_thread_name.as_ref().map(|_| ClosurePlaceholder);
        let panic_handler = panic_handler.as_ref().map(|_| ClosurePlaceholder);
        let start_handler = start_handler.as_ref().map(|_| ClosurePlaceholder);
        let exit_handler = exit_handler.as_ref().map(|_| ClosurePlaceholder);

        f.debug_struct("Configuration")
         .field("num_threads", num_threads)
         .field("get_thread_name", &get_thread_name)
         .field("panic_handler", &panic_handler)
         .field("stack_size", &stack_size)
         .field("start_handler", &start_handler)
         .field("exit_handler", &exit_handler)
         .field("breadth_first", &breadth_first)
         .finish()
    }
}

/// Provides the calling context to a closure called by `join_context`.
#[derive(Debug)]
pub struct FnContext {
    migrated: bool,

    /// disable `Send` and `Sync`, just for a little future-proofing.
    _marker: PhantomData<*mut ()>,
}

impl FnContext {
    #[inline]
    fn new(migrated: bool) -> Self {
        FnContext {
            migrated: migrated,
            _marker: PhantomData,
        }
    }
}

impl FnContext {
    /// Returns `true` if the closure was called from a different thread
    /// than it was provided from.
    #[inline]
    pub fn migrated(&self) -> bool {
        self.migrated
    }
}
<commit_msg>deny missing-docs and non-camel-case types in rayon-core<commit_after>//!
//! [Under construction](https://github.com/rayon-rs/rayon/issues/231)
//!
//! ## Restricting multiple versions
//!
//! In order to ensure proper coordination between threadpools, and especially
//! to make sure there's only one global threadpool, `rayon-core` is actively
//! restricted from building multiple versions of itself into a single target.
//! You may see a build error like this in violation:
//!
//! ```text
//! error: native library `rayon-core` is being linked to by more
//! than one package, and can only be linked to by one package
//! ```
//!
//! While we strive to keep `rayon-core` semver-compatible, it's still
//! possible to arrive at this situation if different crates have overly
//! restrictive tilde or inequality requirements for `rayon-core`.  The
//! conflicting requirements will need to be resolved before the build will
//! succeed.

#![doc(html_root_url = "https://docs.rs/rayon-core/1.3")]
#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![cfg_attr(test, feature(conservative_impl_trait))]

use std::any::Any;
use std::env;
use std::error::Error;
use std::marker::PhantomData;
use std::str::FromStr;
use std::fmt;

extern crate coco;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate num_cpus;
extern crate rand;

#[macro_use]
mod log;

mod latch;
mod join;
mod job;
mod registry;
mod scope;
mod sleep;
mod spawn;
mod test;
mod thread_pool;
mod unwind;
mod util;

#[cfg(rayon_unstable)]
pub mod internal;
pub use thread_pool::ThreadPool;
pub use thread_pool::current_thread_index;
pub use thread_pool::current_thread_has_pending_tasks;
pub use join::{join, join_context};
pub use scope::{scope, Scope};
pub use spawn::spawn;

/// Returns the number of threads in the current registry. If this
/// code is executing within a Rayon thread-pool, then this will be
/// the number of threads for the thread-pool of the current
/// thread. Otherwise, it will be the number of threads for the global
/// thread-pool.
///
/// This can be useful when trying to judge how many times to split
/// parallel work (the parallel iterator traits use this value
/// internally for this purpose).
///
/// ### Future compatibility note
///
/// Note that unless this thread-pool was created with a
/// configuration that specifies the number of threads, then this
/// number may vary over time in future versions (see [the
/// `num_threads()` method for details][snt]).
///
/// [snt]: struct.Configuration.html#method.num_threads
pub fn current_num_threads() -> usize {
    ::registry::Registry::current_num_threads()
}

/// Contains the rayon thread pool configuration.
#[derive(Default)]
pub struct Configuration {
    /// The number of threads in the rayon thread pool.
    /// If zero will use the RAYON_NUM_THREADS environment variable.
    /// If RAYON_NUM_THREADS is invalid or zero will use the default.
    num_threads: usize,

    /// Custom closure, if any, to handle a panic that we cannot propagate
    /// anywhere else.
    panic_handler: Option<Box<PanicHandler>>,

    /// Closure to compute the name of a thread.
    get_thread_name: Option<Box<FnMut(usize) -> String>>,

    /// The stack size for the created worker threads
    stack_size: Option<usize>,

    /// Closure invoked on worker thread start.
    start_handler: Option<Box<StartHandler>>,

    /// Closure invoked on worker thread exit.
    exit_handler: Option<Box<ExitHandler>>,

    /// If false, worker threads will execute spawned jobs in a
    /// "depth-first" fashion. If true, they will do a "breadth-first"
    /// fashion. Depth-first is the default.
    breadth_first: bool,
}

/// The type for a panic handling closure. Note that this same closure
/// may be invoked multiple times in parallel.
type PanicHandler = Fn(Box<Any + Send>) + Send + Sync;

/// The type for a closure that gets invoked when a thread starts. The
/// closure is passed the index of the thread on which it is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
type StartHandler = Fn(usize) + Send + Sync;

/// The type for a closure that gets invoked when a thread exits. The
/// closure is passed the index of the thread on which is is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
type ExitHandler = Fn(usize) + Send + Sync;

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration::default()
    }

    /// Create a new `ThreadPool` initialized using this configuration.
    pub fn build(self) -> Result<ThreadPool, Box<Error + 'static>> {
        ThreadPool::new(self)
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `num_threads()` for more information.
    fn get_num_threads(&self) -> usize {
        if self.num_threads > 0 {
            self.num_threads
        } else {
            match env::var("RAYON_NUM_THREADS").ok().and_then(|s| usize::from_str(&s).ok()) {
                Some(x) if x > 0 => return x,
                Some(x) if x == 0 => return num_cpus::get(),
                _ => {},
            }

            // Support for deprecated `RAYON_RS_NUM_CPUS`.
            match env::var("RAYON_RS_NUM_CPUS").ok().and_then(|s| usize::from_str(&s).ok()) {
                Some(x) if x > 0 => x,
                _ => num_cpus::get(),
            }
        }
    }

    /// Get the thread name for the thread with the given index.
    fn get_thread_name(&mut self, index: usize) -> Option<String> {
        self.get_thread_name.as_mut().map(|c| c(index))
    }

    /// Set a closure which takes a thread index and returns
    /// the thread's name.
    pub fn thread_name<F>(mut self, closure: F) -> Self
    where F: FnMut(usize) -> String + 'static {
        self.get_thread_name = Some(Box::new(closure));
        self
    }

    /// Set the number of threads to be used in the rayon threadpool.
    ///
    /// If you specify a non-zero number of threads using this
    /// function, then the resulting thread-pools are guaranteed to
    /// start at most this number of threads.
    ///
    /// If `num_threads` is 0, or you do not call this function, then
    /// the Rayon runtime will select the number of threads
    /// automatically. At present, this is based on the
    /// `RAYON_NUM_THREADS` environment variable (if set),
    /// or the number of logical CPUs (otherwise).
    /// In the future, however, the default behavior may
    /// change to dynamically add or remove threads as needed.
    ///
    /// **Future compatibility warning:** Given the default behavior
    /// may change in the future, if you wish to rely on a fixed
    /// number of threads, you should use this function to specify
    /// that number. To reproduce the current default behavior, you
    /// may wish to use the [`num_cpus`
    /// crate](https://crates.io/crates/num_cpus) to query the number
    /// of CPUs dynamically.
    ///
    /// **Old environment variable:** `RAYON_NUM_THREADS` is a one-to-one
    /// replacement of the now deprecated `RAYON_RS_NUM_CPUS` environment
    /// variable. If both variables are specified, `RAYON_NUM_THREADS` will
    /// be prefered.
    pub fn num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = num_threads;
        self
    }

    /// Returns a copy of the current panic handler.
    fn take_panic_handler(&mut self) -> Option<Box<PanicHandler>> {
        self.panic_handler.take()
    }

    /// Normally, whenever Rayon catches a panic, it tries to
    /// propagate it to someplace sensible, to try and reflect the
    /// semantics of sequential execution. But in some cases,
    /// particularly with the `spawn()` APIs, there is no
    /// obvious place where we should propagate the panic to.
    /// In that case, this panic handler is invoked.
    ///
    /// If no panic handler is set, the default is to abort the
    /// process, under the principle that panics should not go
    /// unobserved.
    ///
    /// If the panic handler itself panics, this will abort the
    /// process. To prevent this, wrap the body of your panic handler
    /// in a call to `std::panic::catch_unwind()`.
    pub fn panic_handler<H>(mut self, panic_handler: H) -> Configuration
        where H: Fn(Box<Any + Send>) + Send + Sync + 'static
    {
        self.panic_handler = Some(Box::new(panic_handler));
        self
    }

    /// Get the stack size of the worker threads
    fn get_stack_size(&self) -> Option<usize>{
        self.stack_size
    }

    /// Set the stack size of the worker threads
    pub fn stack_size(mut self, stack_size: usize) -> Self {
        self.stack_size = Some(stack_size);
        self
    }

    /// Suggest to worker threads that they execute spawned jobs in a
    /// "breadth-first" fashion. Typically, when a worker thread is
    /// idle or blocked, it will attempt to execute the job from the
    /// *top* of its local deque of work (i.e., the job most recently
    /// spawned). If this flag is set to true, however, workers will
    /// prefer to execute in a *breadth-first* fashion -- that is,
    /// they will search for jobs at the *bottom* of their local
    /// deque. (At present, workers *always* steal from the bottom of
    /// other worker's deques, regardless of the setting of this
    /// flag.)
    ///
    /// If you think of the tasks as a tree, where a parent task
    /// spawns its children in the tree, then this flag loosely
    /// corresponds to doing a breadth-first traversal of the tree,
    /// whereas the default would be to do a depth-first traversal.
    ///
    /// **Note that this is an "execution hint".** Rayon's task
    /// execution is highly dynamic and the precise order in which
    /// independent tasks are executed is not intended to be
    /// guaranteed.
    pub fn breadth_first(mut self) -> Self {
        self.breadth_first = true;
        self
    }

    fn get_breadth_first(&self) -> bool {
        self.breadth_first
    }

    /// Takes the current thread start callback, leaving `None`.
    fn take_start_handler(&mut self) -> Option<Box<StartHandler>> {
        self.start_handler.take()
    }

    /// Set a callback to be invoked on thread start.
    ///
    /// The closure is passed the index of the thread on which it is invoked.
    /// Note that this same closure may be invoked multiple times in parallel.
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then startup will continue normally.
    pub fn start_handler<H>(mut self, start_handler: H) -> Configuration
        where H: Fn(usize) + Send + Sync + 'static
    {
        self.start_handler = Some(Box::new(start_handler));
        self
    }

    /// Returns a current thread exit callback, leaving `None`.
    fn take_exit_handler(&mut self) -> Option<Box<ExitHandler>> {
        self.exit_handler.take()
    }

    /// Set a callback to be invoked on thread exit.
    ///
    /// The closure is passed the index of the thread on which it is invoked.
    /// Note that this same closure may be invoked multiple times in parallel.
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then the thread will exit normally.
    pub fn exit_handler<H>(mut self, exit_handler: H) -> Configuration
        where H: Fn(usize) + Send + Sync + 'static
    {
        self.exit_handler = Some(Box::new(exit_handler));
        self
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will return an error. An `Ok` result indicates that this
/// is the first initialization of the thread pool.
pub fn initialize(config: Configuration) -> Result<(), Box<Error>> {
    let registry = try!(registry::init_global_registry(config));
    registry.wait_until_primed();
    Ok(())
}

impl fmt::Debug for Configuration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Configuration { ref num_threads, ref get_thread_name,
                            ref panic_handler, ref stack_size,
                            ref start_handler, ref exit_handler,
                            ref breadth_first } = *self;

        // Just print `Some(<closure>)` or `None` to the debug
        // output.
        struct ClosurePlaceholder;
        impl fmt::Debug for ClosurePlaceholder {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str("<closure>")
            }
        }
        let get_thread_name = get_thread_name.as_ref().map(|_| ClosurePlaceholder);
        let panic_handler = panic_handler.as_ref().map(|_| ClosurePlaceholder);
        let start_handler = start_handler.as_ref().map(|_| ClosurePlaceholder);
        let exit_handler = exit_handler.as_ref().map(|_| ClosurePlaceholder);

        f.debug_struct("Configuration")
         .field("num_threads", num_threads)
         .field("get_thread_name", &get_thread_name)
         .field("panic_handler", &panic_handler)
         .field("stack_size", &stack_size)
         .field("start_handler", &start_handler)
         .field("exit_handler", &exit_handler)
         .field("breadth_first", &breadth_first)
         .finish()
    }
}

/// Provides the calling context to a closure called by `join_context`.
#[derive(Debug)]
pub struct FnContext {
    migrated: bool,

    /// disable `Send` and `Sync`, just for a little future-proofing.
    _marker: PhantomData<*mut ()>,
}

impl FnContext {
    #[inline]
    fn new(migrated: bool) -> Self {
        FnContext {
            migrated: migrated,
            _marker: PhantomData,
        }
    }
}

impl FnContext {
    /// Returns `true` if the closure was called from a different thread
    /// than it was provided from.
    #[inline]
    pub fn migrated(&self) -> bool {
        self.migrated
    }
}
<|endoftext|>


<commit_before>use std::rand::{task_rng, Rng};
use std::sync::Arc;
use raytracer::compositor::composite;
use raytracer::{Ray, Tile};
use scene::{Camera, Scene};
use vec3::Vec3;

pub struct Renderer {
    pub reflect_depth: int,  // Maximum reflection recursions.
    pub refract_depth: int,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub use_octree: bool,    // Unimplemented. Use octree/k-d tree?
    pub shadow_samples: int, // Number of samples for soft shadows and area lights.
    pub pixel_samples: int,  // The square of this is the number of samples per pixel.
    pub tasks: int           // Minimum number of tasks to spawn.
}

impl Renderer {
    pub fn render(&self, camera: Camera, scene: Scene) -> Vec<Vec3> {
        let mut tiles = Vec::with_capacity(self.tasks as uint);
        let tiles_per_side = (self.tasks as f64).sqrt().ceil() as int;
        let tile_width  = (camera.image_width  as f64 / tiles_per_side as f64) as int;
        let tile_height = (camera.image_height as f64 / tiles_per_side as f64) as int;

        let shared_scene = Arc::new(scene);
        let (tx, rx) = channel();

        for tile_x in range(0, tiles_per_side) {
            for tile_y in range(0, tiles_per_side) {
                let scene_local = shared_scene.clone();
                let child_tx = tx.clone();

                let shadow_samples_local = self.shadow_samples;
                let pixel_samples_local = self.pixel_samples;
                let reflect_depth_local = self.reflect_depth;
                let refract_depth_local = self.refract_depth;

                let start_x = tile_x * tile_width;
                let start_y = tile_y * tile_height;
                let end_x = start_x + tile_width;
                let end_y = start_y + tile_height;

                spawn(proc() {
                    child_tx.send(Renderer::render_tile(camera,
                                                        scene_local.deref(),
                                                        shadow_samples_local,
                                                        pixel_samples_local,
                                                        reflect_depth_local,
                                                        refract_depth_local,
                                                        start_x, start_y,
                                                        end_x, end_y));
                });

            }
        }

        for _ in range(0, tiles_per_side * tiles_per_side) {
            tiles.push(rx.recv())
        }

        composite(tiles, camera.image_width, camera.image_height)
    }

    fn render_tile(camera: Camera,
                   scene: &Scene,
                   shadow_samples: int,
                   pixel_samples: int,
                   reflect_depth: int,
                   refract_depth: int,
                   from_x: int,
                   from_y: int,
                   to_x: int,
                   to_y: int)
                   -> Tile {
        let width  = to_x - from_x;
        let height = to_y - from_y;
        let tile_size = width * height;
        let mut image_data: Vec<Vec3> = Vec::with_capacity(tile_size as uint);

        for y in range(from_y, to_y) {
            for x in range(from_x, to_x) {
                let mut color = Vec3::zero();

                // Supersampling, jitter algorithm
                let mut rng = task_rng();
                let pixel_width = 1.0 / pixel_samples as f64;

                for y_subpixel in range(0, pixel_samples) {
                    for x_subpixel in range(0, pixel_samples) {
                        let mut j_x = x as f64;
                        let mut j_y = y as f64;

                        // Don't jitter if not antialiasing
                        if pixel_samples > 1 {
                            j_x = j_x + x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                            j_y = j_y + y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                        }

                        let ray = camera.get_ray(j_x, j_y);
                        let result = Renderer::trace(scene, &ray, shadow_samples, reflect_depth, refract_depth, false);
                        color = color + result.scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }

                image_data.push(Vec3 {
                    x: color.x,
                    y: color.y,
                    z: color.z
                });
            }
        }

        Tile {
            from_x: from_x,
            from_y: from_y,
            to_x: to_x,
            to_y: to_y,
            data: image_data
        }
    }

    fn trace(scene: &Scene,
             ray: &Ray,
             shadow_samples: int,
             reflect_depth: int,
             refract_depth: int,
             inside: bool)
             -> Vec3 {
        if reflect_depth <= 0 || refract_depth <= 0 { return Vec3::zero() }
        let epsilon = ::std::f64::EPSILON * 10000.0;

        match ray.get_nearest_hit(scene) {
            Some(nearest_hit) => {
                let n = nearest_hit.n.unit();
                let i = (ray.direction.scale(-1.0)).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let mut shadow = Vec3::zero();

                    if shadow_samples > 0 {
                        // Point light speedup
                        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };

                        // Take average shadow color after jittering/sampling light position
                        for _ in range(0, shadow_sample_tries) {
                            // L has to be a unit vector for t_max 1:1 correspondence to
                            // distance to light to work. Shadow feelers only search up
                            // until light source.
                            let sampled_light_position = light.position();
                            let shadow_l = (sampled_light_position - nearest_hit.position).unit();
                            let shadow_ray = Ray {origin: nearest_hit.position, direction: shadow_l};
                            let distance_to_light = (sampled_light_position - nearest_hit.position).len();

                            // Check against candidate primitives in scene for occlusion
                            // and multiply shadow color by occluders' shadow colors
                            shadow = shadow + scene.prims.iter().fold(Vec3::one(), |shadow_acc, prim| {
                                let occlusion = prim.intersects(&shadow_ray, epsilon, distance_to_light);
                                match occlusion {
                                    Some(occulusion) => {shadow_acc * occulusion.material.transmission()}
                                    None => shadow_acc
                                }
                            });
                        }

                        shadow = shadow.scale(1.0 / shadow_sample_tries as f64);
                    } else {
                        shadow = Vec3::one();
                    }

                    let l = (light.center() - nearest_hit.position).unit();

                    color_acc + light.color() * nearest_hit.material.sample(n, i, l) * shadow
                });

                // Global reflection
                if nearest_hit.material.is_reflective() {
                    let r = Vec3::reflect(&i, &n);
                    let reflect_ray = Ray {origin: nearest_hit.position, direction: r};
                    let reflection = Renderer::trace(scene, &reflect_ray, shadow_samples, reflect_depth - 1, refract_depth, inside);

                    result = result + nearest_hit.material.global_specular(&reflection);
                }

                // Global refraction
                if nearest_hit.material.is_refractive() {
                    let t = Vec3::refract(&i, &n, nearest_hit.material.ior(), inside);
                    let refract_ray = Ray {origin: nearest_hit.position + t.scale(epsilon), direction: t};
                    let refraction = Renderer::trace(scene, &refract_ray, shadow_samples, reflect_depth, refract_depth, !inside);

                    result = result + nearest_hit.material.global_transmissive(&refraction);
                }

                result
            }

            None => {scene.background}
        }
    }
}
<commit_msg>Faster Rng for Renderer<commit_after>use std::rand::{task_rng, Rng, SeedableRng, Isaac64Rng};
use std::sync::Arc;
use raytracer::compositor::composite;
use raytracer::{Ray, Tile};
use scene::{Camera, Scene};
use vec3::Vec3;

pub struct Renderer {
    pub reflect_depth: int,  // Maximum reflection recursions.
    pub refract_depth: int,  // Maximum refraction recursions. A sphere takes up 2 recursions.
    pub use_octree: bool,    // Unimplemented. Use octree/k-d tree?
    pub shadow_samples: int, // Number of samples for soft shadows and area lights.
    pub pixel_samples: int,  // The square of this is the number of samples per pixel.
    pub tasks: int           // Minimum number of tasks to spawn.
}

impl Renderer {
    pub fn render(&self, camera: Camera, scene: Scene) -> Vec<Vec3> {
        let mut tiles = Vec::with_capacity(self.tasks as uint);
        let tiles_per_side = (self.tasks as f64).sqrt().ceil() as int;
        let tile_width  = (camera.image_width  as f64 / tiles_per_side as f64) as int;
        let tile_height = (camera.image_height as f64 / tiles_per_side as f64) as int;

        let shared_scene = Arc::new(scene);
        let (tx, rx) = channel();

        for tile_x in range(0, tiles_per_side) {
            for tile_y in range(0, tiles_per_side) {
                let scene_local = shared_scene.clone();
                let child_tx = tx.clone();

                let shadow_samples_local = self.shadow_samples;
                let pixel_samples_local = self.pixel_samples;
                let reflect_depth_local = self.reflect_depth;
                let refract_depth_local = self.refract_depth;

                let start_x = tile_x * tile_width;
                let start_y = tile_y * tile_height;
                let end_x = start_x + tile_width;
                let end_y = start_y + tile_height;

                spawn(proc() {
                    child_tx.send(Renderer::render_tile(camera,
                                                        scene_local.deref(),
                                                        shadow_samples_local,
                                                        pixel_samples_local,
                                                        reflect_depth_local,
                                                        refract_depth_local,
                                                        start_x, start_y,
                                                        end_x, end_y));
                });

            }
        }

        for _ in range(0, tiles_per_side * tiles_per_side) {
            tiles.push(rx.recv())
        }

        composite(tiles, camera.image_width, camera.image_height)
    }

    fn render_tile(camera: Camera,
                   scene: &Scene,
                   shadow_samples: int,
                   pixel_samples: int,
                   reflect_depth: int,
                   refract_depth: int,
                   from_x: int,
                   from_y: int,
                   to_x: int,
                   to_y: int)
                   -> Tile {
        let width  = to_x - from_x;
        let height = to_y - from_y;
        let tile_size = width * height;
        let mut image_data: Vec<Vec3> = Vec::with_capacity(tile_size as uint);

		let mut random_data = [0u64, ..64];
		for i in range(0u, 64u) {
			random_data[i] = task_rng().next_u64();
		}
		let mut rng: Isaac64Rng = SeedableRng::from_seed(random_data.clone());

        for y in range(from_y, to_y) {
            for x in range(from_x, to_x) {
                let mut color = Vec3::zero();

                // Supersampling, jitter algorithm
                let pixel_width = 1.0 / pixel_samples as f64;

                for y_subpixel in range(0, pixel_samples) {
                    for x_subpixel in range(0, pixel_samples) {
                        let mut j_x = x as f64;
                        let mut j_y = y as f64;

                        // Don't jitter if not antialiasing
                        if pixel_samples > 1 {
                            j_x = j_x + x_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                            j_y = j_y + y_subpixel as f64 * pixel_width + rng.gen::<f64>() * pixel_width as f64;
                        }

                        let ray = camera.get_ray(j_x, j_y);
                        let result = Renderer::trace(scene, &ray, shadow_samples, reflect_depth, refract_depth, false);
                        color = color + result.scale(1.0 / (pixel_samples * pixel_samples) as f64);
                    }
                }

                image_data.push(Vec3 {
                    x: color.x,
                    y: color.y,
                    z: color.z
                });
            }
        }

        Tile {
            from_x: from_x,
            from_y: from_y,
            to_x: to_x,
            to_y: to_y,
            data: image_data
        }
    }

    fn trace(scene: &Scene,
             ray: &Ray,
             shadow_samples: int,
             reflect_depth: int,
             refract_depth: int,
             inside: bool)
             -> Vec3 {
        if reflect_depth <= 0 || refract_depth <= 0 { return Vec3::zero() }
        let epsilon = ::std::f64::EPSILON * 10000.0;

        match ray.get_nearest_hit(scene) {
            Some(nearest_hit) => {
                let n = nearest_hit.n.unit();
                let i = (ray.direction.scale(-1.0)).unit();

                // Local lighting computation: surface shading, shadows
                let mut result = scene.lights.iter().fold(Vec3::zero(), |color_acc, light| {
                    let mut shadow = Vec3::zero();

                    if shadow_samples > 0 {
                        // Point light speedup
                        let shadow_sample_tries = if light.is_point() { 1 } else { shadow_samples };

                        // Take average shadow color after jittering/sampling light position
                        for _ in range(0, shadow_sample_tries) {
                            // L has to be a unit vector for t_max 1:1 correspondence to
                            // distance to light to work. Shadow feelers only search up
                            // until light source.
                            let sampled_light_position = light.position();
                            let shadow_l = (sampled_light_position - nearest_hit.position).unit();
                            let shadow_ray = Ray {origin: nearest_hit.position, direction: shadow_l};
                            let distance_to_light = (sampled_light_position - nearest_hit.position).len();

                            // Check against candidate primitives in scene for occlusion
                            // and multiply shadow color by occluders' shadow colors
                            shadow = shadow + scene.prims.iter().fold(Vec3::one(), |shadow_acc, prim| {
                                let occlusion = prim.intersects(&shadow_ray, epsilon, distance_to_light);
                                match occlusion {
                                    Some(occulusion) => {shadow_acc * occulusion.material.transmission()}
                                    None => shadow_acc
                                }
                            });
                        }

                        shadow = shadow.scale(1.0 / shadow_sample_tries as f64);
                    } else {
                        shadow = Vec3::one();
                    }

                    let l = (light.center() - nearest_hit.position).unit();

                    color_acc + light.color() * nearest_hit.material.sample(n, i, l) * shadow
                });

                // Global reflection
                if nearest_hit.material.is_reflective() {
                    let r = Vec3::reflect(&i, &n);
                    let reflect_ray = Ray {origin: nearest_hit.position, direction: r};
                    let reflection = Renderer::trace(scene, &reflect_ray, shadow_samples, reflect_depth - 1, refract_depth, inside);

                    result = result + nearest_hit.material.global_specular(&reflection);
                }

                // Global refraction
                if nearest_hit.material.is_refractive() {
                    let t = Vec3::refract(&i, &n, nearest_hit.material.ior(), inside);
                    let refract_ray = Ray {origin: nearest_hit.position + t.scale(epsilon), direction: t};
                    let refraction = Renderer::trace(scene, &refract_ray, shadow_samples, reflect_depth, refract_depth, !inside);

                    result = result + nearest_hit.material.global_transmissive(&refraction);
                }

                result
            }

            None => {scene.background}
        }
    }
}
<|endoftext|>


<commit_before>//! Formatting helpers for a `Date`.

#![allow(non_snake_case)]

use super::{
    parse::{
        consume_padding, try_consume_digits, try_consume_digits_in_range, try_consume_exact_digits,
        try_consume_exact_digits_in_range, try_consume_first_match,
    },
    Padding, ParseError, ParseResult, ParsedItems,
};
#[cfg(not(feature = "std"))]
use crate::no_std_prelude::*;
use crate::{Date, Sign, Weekday};
use core::{
    fmt::{self, Formatter},
    num::{NonZeroU16, NonZeroU8},
};

/// Array of weekdays that corresponds to the localized values. This can be
/// zipped via an iterator to perform parsing easily.
const WEEKDAYS: [Weekday; 7] = [
    Weekday::Monday,
    Weekday::Tuesday,
    Weekday::Wednesday,
    Weekday::Thursday,
    Weekday::Friday,
    Weekday::Saturday,
    Weekday::Sunday,
];

/// Full weekday names
const WEEKDAYS_FULL: [&str; 7] = [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
];

/// Abbreviated weekday names
const WEEKDAYS_ABBR: [&str; 7] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];

/// Full month names
const MONTHS_FULL: [&str; 12] = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
];

/// Abbreviated month names
const MONTHS_ABBR: [&str; 12] = [
    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];

/// Short day of the week
#[inline(always)]
pub(crate) fn fmt_a(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(WEEKDAYS_ABBR[date.weekday().number_days_from_monday() as usize])
}

/// Short day of the week
#[inline(always)]
pub(crate) fn parse_a(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.weekday = try_consume_first_match(s, WEEKDAYS_ABBR.iter().zip(WEEKDAYS.iter().cloned()))
        .ok_or(ParseError::InvalidDayOfWeek)?
        .into();

    Ok(())
}

/// Day of the week
#[inline(always)]
pub(crate) fn fmt_A(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(WEEKDAYS_FULL[date.weekday().number_days_from_monday() as usize])
}

/// Day of the week
#[inline(always)]
pub(crate) fn parse_A(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.weekday = try_consume_first_match(s, WEEKDAYS_FULL.iter().zip(WEEKDAYS.iter().cloned()))
        .ok_or(ParseError::InvalidDayOfWeek)?
        .into();

    Ok(())
}

/// Short month name
#[inline(always)]
pub(crate) fn fmt_b(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(MONTHS_ABBR[date.month() as usize - 1])
}

/// Short month name
#[inline(always)]
pub(crate) fn parse_b(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.month = try_consume_first_match(s, MONTHS_ABBR.iter().cloned().zip(1..))
        .map(NonZeroU8::new)
        .ok_or(ParseError::InvalidMonth)?;

    Ok(())
}

/// Month name
#[inline(always)]
pub(crate) fn fmt_B(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(MONTHS_FULL[date.month() as usize - 1])
}

/// Month name
#[inline(always)]
pub(crate) fn parse_B(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.month = try_consume_first_match(s, MONTHS_FULL.iter().cloned().zip(1..))
        .map(NonZeroU8::new)
        .ok_or(ParseError::InvalidMonth)?;

    Ok(())
}

/// Year divided by 100 and truncated to integer (`00`-`999`)
#[inline(always)]
pub(crate) fn fmt_C(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.year() / 100)
}

/// Year divided by 100 and truncated to integer (`00`-`999`)
#[inline(always)]
pub(crate) fn parse_C(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    let padding_length = consume_padding(s, padding.default_to(Padding::Zero), 1);
    items.year = (try_consume_digits::<i32, _>(s, (2 - padding_length)..=(3 - padding_length))
        .ok_or(ParseError::InvalidYear)?
        * 100
        + items.year.unwrap_or(0).rem_euclid(100))
    .into();

    Ok(())
}

/// Day of the month, zero-padded (`01`-`31`)
#[inline(always)]
pub(crate) fn fmt_d(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.day())
}

/// Day of the month, zero-padded (`01`-`31`)
#[inline(always)]
pub(crate) fn parse_d(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.day = try_consume_exact_digits::<u8>(s, 2, padding.default_to(Padding::Zero))
        .map(NonZeroU8::new)
        .ok_or(ParseError::InvalidDayOfMonth)?;

    Ok(())
}

/// Week-based year, last two digits (`00`-`99`)
#[inline(always)]
pub(crate) fn fmt_g(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.iso_year_week().0.rem_euclid(100))
}

/// Week-based year, last two digits (`00`-`99`)
#[inline(always)]
pub(crate) fn parse_g(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.week_based_year = (items.week_based_year.unwrap_or(0) / 100 * 100
        + try_consume_exact_digits::<i32>(s, 2, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidYear)?)
    .into();

    Ok(())
}

/// Week-based year
#[inline(always)]
pub(crate) fn fmt_G(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 4, date.iso_year_week().0)
}

/// Week-based year
#[inline(always)]
pub(crate) fn parse_G(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    let sign = try_consume_first_match(
        s,
        [("+", Sign::Positive), ("-", Sign::Negative)]
            .iter()
            .cloned(),
    )
    .unwrap_or(Sign::Positive);

    consume_padding(s, padding.default_to(Padding::Zero), 4);

    items.week_based_year = try_consume_digits_in_range(s, 1..=6, -100_000..=100_000)
        .map(|v: i32| sign * v)
        .ok_or(ParseError::InvalidYear)?
        .into();

    Ok(())
}

/// Day of the year, zero-padded to width 3 (`001`-`366`)
#[inline(always)]
pub(crate) fn fmt_j(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 3, date.ordinal())
}

/// Day of the year, zero-padded to width 3 (`001`-`366`)
#[inline(always)]
pub(crate) fn parse_j(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.ordinal_day =
        try_consume_exact_digits::<NonZeroU16>(s, 3, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidDayOfYear)?
            .into();

    Ok(())
}

/// Month of the year, zero-padded (`01`-`12`)
#[inline(always)]
pub(crate) fn fmt_m(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.month())
}

/// Month of the year, zero-padded (`01`-`12`)
#[inline(always)]
pub(crate) fn parse_m(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.month = try_consume_exact_digits::<NonZeroU8>(s, 2, padding.default_to(Padding::Zero))
        .ok_or(ParseError::InvalidMonth)?
        .into();

    Ok(())
}

/// ISO weekday (Monday = `1`, Sunday = `7`)
#[inline(always)]
pub(crate) fn fmt_u(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    write!(f, "{}", date.weekday().iso_weekday_number())
}

/// ISO weekday (Monday = `1`, Sunday = `7`)
#[inline(always)]
pub(crate) fn parse_u(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.weekday = try_consume_first_match(
        s,
        (1..).map(|d| d.to_string()).zip(WEEKDAYS.iter().cloned()),
    )
    .ok_or(ParseError::InvalidDayOfWeek)?
    .into();

    Ok(())
}

/// Sunday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn fmt_U(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.sunday_based_week())
}

/// Sunday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn parse_U(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.sunday_week =
        try_consume_exact_digits_in_range(s, 2, 0..=53, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidWeek)?
            .into();

    Ok(())
}

/// ISO week number, zero-padded (`01`-`53`)
#[inline(always)]
pub(crate) fn fmt_V(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.week())
}

/// ISO week number, zero-padded (`01`-`53`)
#[inline(always)]
pub(crate) fn parse_V(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.iso_week =
        try_consume_exact_digits_in_range(s, 2, 1..=53, padding.default_to(Padding::Zero))
            .map(NonZeroU8::new)
            .ok_or(ParseError::InvalidWeek)?;

    Ok(())
}

/// Weekday number (Sunday = `0`, Saturday = `6`)
#[inline(always)]
pub(crate) fn fmt_w(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    write!(f, "{}", date.weekday().number_days_from_sunday())
}

/// Weekday number (Sunday = `0`, Saturday = `6`)
#[inline(always)]
pub(crate) fn parse_w(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    let mut weekdays = WEEKDAYS;
    weekdays.rotate_left(1);

    items.weekday = try_consume_first_match(
        s,
        (0..)
            .map(|d: u8| d.to_string())
            .zip(weekdays.iter().cloned()),
    )
    .ok_or(ParseError::InvalidDayOfWeek)?
    .into();

    Ok(())
}

/// Monday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn fmt_W(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.monday_based_week())
}

/// Monday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn parse_W(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.monday_week =
        try_consume_exact_digits_in_range(s, 2, 0..=53, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidWeek)?
            .into();

    Ok(())
}

/// Last two digits of year (`00`-`99`)
#[inline(always)]
pub(crate) fn fmt_y(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.year().rem_euclid(100))
}

/// Last two digits of year (`00`-`99`)
#[inline(always)]
pub(crate) fn parse_y(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.year = (items.year.unwrap_or(0) / 100 * 100
        + try_consume_exact_digits::<i32>(s, 2, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidYear)?)
    .into();

    Ok(())
}

/// Full year
#[inline(always)]
pub(crate) fn fmt_Y(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    let year = date.year();

    if year >= 10_000 {
        f.write_str("+")?;
    }

    pad!(f, padding(Zero), 4, year)
}

/// Full year
#[inline(always)]
pub(crate) fn parse_Y(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    let sign = try_consume_first_match(
        s,
        [("+", Sign::Positive), ("-", Sign::Negative)]
            .iter()
            .cloned(),
    )
    .unwrap_or(Sign::Positive);

    consume_padding(s, padding.default_to(Padding::Zero), 4);

    items.year = try_consume_digits_in_range(s, 1..=6, -100_000..=100_000)
        .map(|v: i32| sign * v)
        .ok_or(ParseError::InvalidYear)?
        .into();

    Ok(())
}
<commit_msg>Display positive sign when necessary on "G"<commit_after>//! Formatting helpers for a `Date`.

#![allow(non_snake_case)]

use super::{
    parse::{
        consume_padding, try_consume_digits, try_consume_digits_in_range, try_consume_exact_digits,
        try_consume_exact_digits_in_range, try_consume_first_match,
    },
    Padding, ParseError, ParseResult, ParsedItems,
};
#[cfg(not(feature = "std"))]
use crate::no_std_prelude::*;
use crate::{Date, Sign, Weekday};
use core::{
    fmt::{self, Formatter},
    num::{NonZeroU16, NonZeroU8},
};

/// Array of weekdays that corresponds to the localized values. This can be
/// zipped via an iterator to perform parsing easily.
const WEEKDAYS: [Weekday; 7] = [
    Weekday::Monday,
    Weekday::Tuesday,
    Weekday::Wednesday,
    Weekday::Thursday,
    Weekday::Friday,
    Weekday::Saturday,
    Weekday::Sunday,
];

/// Full weekday names
const WEEKDAYS_FULL: [&str; 7] = [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
];

/// Abbreviated weekday names
const WEEKDAYS_ABBR: [&str; 7] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];

/// Full month names
const MONTHS_FULL: [&str; 12] = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
];

/// Abbreviated month names
const MONTHS_ABBR: [&str; 12] = [
    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];

/// Short day of the week
#[inline(always)]
pub(crate) fn fmt_a(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(WEEKDAYS_ABBR[date.weekday().number_days_from_monday() as usize])
}

/// Short day of the week
#[inline(always)]
pub(crate) fn parse_a(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.weekday = try_consume_first_match(s, WEEKDAYS_ABBR.iter().zip(WEEKDAYS.iter().cloned()))
        .ok_or(ParseError::InvalidDayOfWeek)?
        .into();

    Ok(())
}

/// Day of the week
#[inline(always)]
pub(crate) fn fmt_A(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(WEEKDAYS_FULL[date.weekday().number_days_from_monday() as usize])
}

/// Day of the week
#[inline(always)]
pub(crate) fn parse_A(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.weekday = try_consume_first_match(s, WEEKDAYS_FULL.iter().zip(WEEKDAYS.iter().cloned()))
        .ok_or(ParseError::InvalidDayOfWeek)?
        .into();

    Ok(())
}

/// Short month name
#[inline(always)]
pub(crate) fn fmt_b(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(MONTHS_ABBR[date.month() as usize - 1])
}

/// Short month name
#[inline(always)]
pub(crate) fn parse_b(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.month = try_consume_first_match(s, MONTHS_ABBR.iter().cloned().zip(1..))
        .map(NonZeroU8::new)
        .ok_or(ParseError::InvalidMonth)?;

    Ok(())
}

/// Month name
#[inline(always)]
pub(crate) fn fmt_B(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    f.write_str(MONTHS_FULL[date.month() as usize - 1])
}

/// Month name
#[inline(always)]
pub(crate) fn parse_B(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.month = try_consume_first_match(s, MONTHS_FULL.iter().cloned().zip(1..))
        .map(NonZeroU8::new)
        .ok_or(ParseError::InvalidMonth)?;

    Ok(())
}

/// Year divided by 100 and truncated to integer (`00`-`999`)
#[inline(always)]
pub(crate) fn fmt_C(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.year() / 100)
}

/// Year divided by 100 and truncated to integer (`00`-`999`)
#[inline(always)]
pub(crate) fn parse_C(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    let padding_length = consume_padding(s, padding.default_to(Padding::Zero), 1);
    items.year = (try_consume_digits::<i32, _>(s, (2 - padding_length)..=(3 - padding_length))
        .ok_or(ParseError::InvalidYear)?
        * 100
        + items.year.unwrap_or(0).rem_euclid(100))
    .into();

    Ok(())
}

/// Day of the month, zero-padded (`01`-`31`)
#[inline(always)]
pub(crate) fn fmt_d(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.day())
}

/// Day of the month, zero-padded (`01`-`31`)
#[inline(always)]
pub(crate) fn parse_d(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.day = try_consume_exact_digits::<u8>(s, 2, padding.default_to(Padding::Zero))
        .map(NonZeroU8::new)
        .ok_or(ParseError::InvalidDayOfMonth)?;

    Ok(())
}

/// Week-based year, last two digits (`00`-`99`)
#[inline(always)]
pub(crate) fn fmt_g(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.iso_year_week().0.rem_euclid(100))
}

/// Week-based year, last two digits (`00`-`99`)
#[inline(always)]
pub(crate) fn parse_g(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.week_based_year = (items.week_based_year.unwrap_or(0) / 100 * 100
        + try_consume_exact_digits::<i32>(s, 2, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidYear)?)
    .into();

    Ok(())
}

/// Week-based year
#[inline(always)]
pub(crate) fn fmt_G(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    let year = date.iso_year_week().0;

    if year >= 10_000 {
        f.write_str("+")?;
    }

    pad!(f, padding(Zero), 4, year)
}

/// Week-based year
#[inline(always)]
pub(crate) fn parse_G(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    let sign = try_consume_first_match(
        s,
        [("+", Sign::Positive), ("-", Sign::Negative)]
            .iter()
            .cloned(),
    )
    .unwrap_or(Sign::Positive);

    consume_padding(s, padding.default_to(Padding::Zero), 4);

    items.week_based_year = try_consume_digits_in_range(s, 1..=6, -100_000..=100_000)
        .map(|v: i32| sign * v)
        .ok_or(ParseError::InvalidYear)?
        .into();

    Ok(())
}

/// Day of the year, zero-padded to width 3 (`001`-`366`)
#[inline(always)]
pub(crate) fn fmt_j(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 3, date.ordinal())
}

/// Day of the year, zero-padded to width 3 (`001`-`366`)
#[inline(always)]
pub(crate) fn parse_j(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.ordinal_day =
        try_consume_exact_digits::<NonZeroU16>(s, 3, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidDayOfYear)?
            .into();

    Ok(())
}

/// Month of the year, zero-padded (`01`-`12`)
#[inline(always)]
pub(crate) fn fmt_m(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.month())
}

/// Month of the year, zero-padded (`01`-`12`)
#[inline(always)]
pub(crate) fn parse_m(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.month = try_consume_exact_digits::<NonZeroU8>(s, 2, padding.default_to(Padding::Zero))
        .ok_or(ParseError::InvalidMonth)?
        .into();

    Ok(())
}

/// ISO weekday (Monday = `1`, Sunday = `7`)
#[inline(always)]
pub(crate) fn fmt_u(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    write!(f, "{}", date.weekday().iso_weekday_number())
}

/// ISO weekday (Monday = `1`, Sunday = `7`)
#[inline(always)]
pub(crate) fn parse_u(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    items.weekday = try_consume_first_match(
        s,
        (1..).map(|d| d.to_string()).zip(WEEKDAYS.iter().cloned()),
    )
    .ok_or(ParseError::InvalidDayOfWeek)?
    .into();

    Ok(())
}

/// Sunday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn fmt_U(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.sunday_based_week())
}

/// Sunday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn parse_U(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.sunday_week =
        try_consume_exact_digits_in_range(s, 2, 0..=53, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidWeek)?
            .into();

    Ok(())
}

/// ISO week number, zero-padded (`01`-`53`)
#[inline(always)]
pub(crate) fn fmt_V(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.week())
}

/// ISO week number, zero-padded (`01`-`53`)
#[inline(always)]
pub(crate) fn parse_V(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.iso_week =
        try_consume_exact_digits_in_range(s, 2, 1..=53, padding.default_to(Padding::Zero))
            .map(NonZeroU8::new)
            .ok_or(ParseError::InvalidWeek)?;

    Ok(())
}

/// Weekday number (Sunday = `0`, Saturday = `6`)
#[inline(always)]
pub(crate) fn fmt_w(f: &mut Formatter<'_>, date: Date) -> fmt::Result {
    write!(f, "{}", date.weekday().number_days_from_sunday())
}

/// Weekday number (Sunday = `0`, Saturday = `6`)
#[inline(always)]
pub(crate) fn parse_w(items: &mut ParsedItems, s: &mut &str) -> ParseResult<()> {
    let mut weekdays = WEEKDAYS;
    weekdays.rotate_left(1);

    items.weekday = try_consume_first_match(
        s,
        (0..)
            .map(|d: u8| d.to_string())
            .zip(weekdays.iter().cloned()),
    )
    .ok_or(ParseError::InvalidDayOfWeek)?
    .into();

    Ok(())
}

/// Monday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn fmt_W(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.monday_based_week())
}

/// Monday-based week number (`00`-`53`)
#[inline(always)]
pub(crate) fn parse_W(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.monday_week =
        try_consume_exact_digits_in_range(s, 2, 0..=53, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidWeek)?
            .into();

    Ok(())
}

/// Last two digits of year (`00`-`99`)
#[inline(always)]
pub(crate) fn fmt_y(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    pad!(f, padding(Zero), 2, date.year().rem_euclid(100))
}

/// Last two digits of year (`00`-`99`)
#[inline(always)]
pub(crate) fn parse_y(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    items.year = (items.year.unwrap_or(0) / 100 * 100
        + try_consume_exact_digits::<i32>(s, 2, padding.default_to(Padding::Zero))
            .ok_or(ParseError::InvalidYear)?)
    .into();

    Ok(())
}

/// Full year
#[inline(always)]
pub(crate) fn fmt_Y(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
    let year = date.year();

    if year >= 10_000 {
        f.write_str("+")?;
    }

    pad!(f, padding(Zero), 4, year)
}

/// Full year
#[inline(always)]
pub(crate) fn parse_Y(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
    let sign = try_consume_first_match(
        s,
        [("+", Sign::Positive), ("-", Sign::Negative)]
            .iter()
            .cloned(),
    )
    .unwrap_or(Sign::Positive);

    consume_padding(s, padding.default_to(Padding::Zero), 4);

    items.year = try_consume_digits_in_range(s, 1..=6, -100_000..=100_000)
        .map(|v: i32| sign * v)
        .ok_or(ParseError::InvalidYear)?
        .into();

    Ok(())
}
<|endoftext|>


<commit_before>use preferences::{AppInfo, Preferences, PreferencesError, prefs_base_dir};
use notify::{Watcher, RecursiveMode, watcher};
use std::sync::mpsc::{channel, RecvError};
use std::time::Duration;

// Configuration level constants, location for configs is determined by this
const APP_INFO: AppInfo = AppInfo {
    name: "gemini",
    author: "holmgr",
};
const PREFS_KEY: &str = "conf/general";
const DEFAULT_SEED: u32 = 42;

// Deriving `Serialize` and `Deserialize` on a struct/enum automatically
// implements the `Preferences` trait.
/// Contains high level configuration parameters for the game such as constants
/// for generation.
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct GameConfig {
    map_seed: u32,
}

impl GameConfig {
    /// Attempts to load a GameConfig from disk at the default preference
    /// location.
    /// If the loading fails for any reason, for example, the file does not
    /// exist, a new default GameConfig object is created, stored and returned.
    pub fn retrieve() -> GameConfig {
        match GameConfig::load(&APP_INFO, PREFS_KEY) {
            Ok(config) => config,
            _ => {
                info!("Failed loading config, serving default");
                let config = GameConfig { map_seed: DEFAULT_SEED };
                let _ = config.store();
                config
            }
        }
    }

    /// Attempts to store the GameConfig on disk at the default preference
    /// location.
    /// # Failures
    /// If a serialization or file I/O error (e.g. permission denied) occurs.
    pub fn store(&self) -> Result<(), PreferencesError> {
        self.save(&APP_INFO, PREFS_KEY)
    }

    /// Setup a blocking Watcher listening for any file changes at the
    /// preferences location of the GameConfig.
    /// If some change is detected it will attempt to return the updated
    /// GameConfig.
    /// # Failures
    /// Channel error when attempting to read while watching for changes.
    pub fn await_update() -> Result<GameConfig, RecvError> {
        // Create a channel to receive the events.
        let (tx, rx) = channel();

        // Create a watcher object, delivering debounced events.
        // The notification back-end is selected based on the platform.
        let mut watcher = watcher(tx, Duration::from_secs(30)).unwrap();

        // Add a path to be watched. All files and directories at that path and
        // below will be monitored for changes.
        let mut config_path = prefs_base_dir().unwrap();
        config_path.push(APP_INFO.name);
        config_path.push(format!("{}.prefs.json", PREFS_KEY));
        watcher
            .watch(config_path, RecursiveMode::Recursive)
            .unwrap();

        match rx.recv() {
            Ok(_) => Ok(GameConfig::retrieve()),
            Err(e) => Err(e),
        }
    }
}
<commit_msg>Extend config with constants for generation, implment default trait<commit_after>use preferences::{AppInfo, Preferences, PreferencesError, prefs_base_dir};
use notify::{Watcher, RecursiveMode, watcher};
use std::sync::mpsc::{channel, RecvError};
use std::time::Duration;

// Configuration level constants, location for configs is determined by this
const APP_INFO: AppInfo = AppInfo {
    name: "gemini",
    author: "holmgr",
};
const PREFS_KEY: &str = "conf/general";

// Deriving `Serialize` and `Deserialize` on a struct/enum automatically
// implements the `Preferences` trait.
/// Contains high level configuration parameters for the game such as constants
/// for generation.
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct GameConfig {
    pub map_seed: u32,
    pub galaxy_size: f64,
    pub number_of_clusters: u64,
    pub cluster_spread: f64,
    pub cluster_size_mean: f64,
    pub cluster_size_std: f64,
}

impl GameConfig {
    /// Attempts to load a GameConfig from disk at the default preference
    /// location.
    /// If the loading fails for any reason, for example, the file does not
    /// exist, a new default GameConfig object is created, stored and returned.
    pub fn retrieve() -> GameConfig {
        match GameConfig::load(&APP_INFO, PREFS_KEY) {
            Ok(config) => config,
            _ => {
                info!("Failed loading config, serving default");
                let config: GameConfig = Default::default();
                let _ = config.store();
                config
            }
        }
    }

    /// Attempts to store the GameConfig on disk at the default preference
    /// location.
    /// # Failures
    /// If a serialization or file I/O error (e.g. permission denied) occurs.
    pub fn store(&self) -> Result<(), PreferencesError> {
        self.save(&APP_INFO, PREFS_KEY)
    }

    /// Setup a blocking Watcher listening for any file changes at the
    /// preferences location of the GameConfig.
    /// If some change is detected it will attempt to return the updated
    /// GameConfig.
    /// # Failures
    /// Channel error when attempting to read while watching for changes.
    pub fn await_update() -> Result<GameConfig, RecvError> {
        // Create a channel to receive the events.
        let (tx, rx) = channel();

        // Create a watcher object, delivering debounced events.
        // The notification back-end is selected based on the platform.
        let mut watcher = watcher(tx, Duration::from_secs(30)).unwrap();

        // Add a path to be watched. All files and directories at that path and
        // below will be monitored for changes.
        let mut config_path = prefs_base_dir().unwrap();
        config_path.push(APP_INFO.name);
        config_path.push(format!("{}.prefs.json", PREFS_KEY));
        watcher
            .watch(config_path, RecursiveMode::Recursive)
            .unwrap();

        match rx.recv() {
            Ok(_) => Ok(GameConfig::retrieve()),
            Err(e) => Err(e),
        }
    }
}

impl Default for GameConfig {
    fn default() -> GameConfig {
        GameConfig {
            map_seed: 42,
            galaxy_size: 100000.,
            number_of_clusters: 1000,
            cluster_spread: 1000.,
            cluster_size_mean: 1000.,
            cluster_size_std: 250.,
        }
    }
}
<|endoftext|>


<commit_before>use std::default::Default;

pub struct GameObject {
    pub pos: [f64; 2],
    pub vel: [f64; 2],
    pub size: [f64; 2],
}

impl GameObject {
    pub fn intersects(&self, other: &GameObject) -> bool {
        self.pos[0] - self.size[0]/2.0 < other.pos[0] + other.size[0]/2.0 &&
        self.pos[0] + self.size[0]/2.0 > other.pos[0] - other.size[0]/2.0 &&
        self.pos[1] - self.size[1]/2.0 < other.pos[1] + other.size[1]/2.0 &&
        self.pos[1] + self.size[1]/2.0 > other.pos[1] - other.size[1]/2.0
    }

    pub fn collision_normal(&self, other: &GameObject) -> Option<[f64; 2]> {
        if self.intersects(other) {
            let dx = (self.pos[0] - other.pos[0]).abs();
            let dy = (self.pos[0] - other.pos[0]).abs();

            if dx <= dy {
                if self.pos[0] <= other.pos[0] { Some([-1.0, 0.0]) }
                else { Some([1.0, 0.0]) }
            } else {
                if self.pos[1] <= other.pos[1] { Some([0.0, -1.0]) }
                else { Some([0.0, 1.0]) }
            }
        } else {
            None
        }
    }
}

impl Default for GameObject {
    fn default() -> GameObject {
        GameObject { pos: [0.0, 0.0], vel: [0.0, 0.0], size: [1.0, 1.0] }
    }
}
<commit_msg>Fixed GameObject.collision_normal() for dy<commit_after>use std::default::Default;

pub struct GameObject {
    pub pos: [f64; 2],
    pub vel: [f64; 2],
    pub size: [f64; 2],
}

impl GameObject {
    pub fn intersects(&self, other: &GameObject) -> bool {
        self.pos[0] - self.size[0]/2.0 < other.pos[0] + other.size[0]/2.0 &&
        self.pos[0] + self.size[0]/2.0 > other.pos[0] - other.size[0]/2.0 &&
        self.pos[1] - self.size[1]/2.0 < other.pos[1] + other.size[1]/2.0 &&
        self.pos[1] + self.size[1]/2.0 > other.pos[1] - other.size[1]/2.0
    }

    pub fn collision_normal(&self, other: &GameObject) -> Option<[f64; 2]> {
        if self.intersects(other) {
            let dx = (self.pos[0] - other.pos[0]).abs();
            let dy = (self.pos[1] - other.pos[1]).abs();

            if dx <= dy {
                if self.pos[0] <= other.pos[0] { Some([-1.0, 0.0]) }
                else { Some([1.0, 0.0]) }
            } else {
                if self.pos[1] <= other.pos[1] { Some([0.0, -1.0]) }
                else { Some([0.0, 1.0]) }
            }
        } else {
            None
        }
    }
}

impl Default for GameObject {
    fn default() -> GameObject {
        GameObject { pos: [0.0, 0.0], vel: [0.0, 0.0], size: [1.0, 1.0] }
    }
}
<|endoftext|>