<commit_before>use id_allocator::IdAllocator;
use nalgebra::{Pnt2, Pnt3, Vec3, normalize};
use ncollide::bounding_volume::AABB;
use rand::{Rng, SeedableRng, IsaacRng};
use state::EntityId;
use std::cmp::{partial_min, partial_max};
use std::collections::RingBuf;
use std::num::Float;
use terrain::terrain::LOD_QUALITY;
use terrain::terrain_block::{TerrainBlock, BLOCK_WIDTH};

const TREE_NODES: [f32; 4] = [1.0/16.0, 1.0/16.0, 1.0/64.0, 1.0/128.0];
const MAX_BRANCH_LENGTH: [f32; 4] = [4.0, 4.0, 8.0, 16.0];
const LEAF_RADIUS: [f32; 4] = [1.5, 1.5, 8.0, 16.0];

#[inline(always)]
fn fmod(mut dividend: f64, divisor: f64) -> f64 {
  dividend -= divisor * (dividend / divisor).floor();
  if dividend < 0.0 || dividend >= divisor{
    // clamp
    dividend = 0.0;
  }
  dividend
}

fn sqr_distance(p1: &Pnt3<f32>, p2: &Pnt3<f32>) -> f32 {
  let d = *p1 - *p2.as_vec();
  d.x*d.x + d.y*d.y + d.z*d.z
}

/// Use one-octave perlin noise local maxima to place trees.
pub struct TreePlacer {
  seed: u32,
}

impl TreePlacer {
  pub fn new(seed: u32) -> TreePlacer {
    TreePlacer {
      seed: seed,
    }
  }

  fn rng_at(&self, center: &Pnt3<f32>, mut seed: Vec<u32>) -> IsaacRng {
    let center = *center * (LOD_QUALITY[0] as f32) / (BLOCK_WIDTH as f32);
    seed.push_all(&[self.seed, center.x as u32, center.z as u32]);
    SeedableRng::from_seed(seed.as_slice())
  }

  pub fn should_place_tree(&self, center: &Pnt3<f32>) -> bool {
    let mut rng = self.rng_at(center, vec!(0));
    rng.next_u32() > 0xFF7FFFFF
  }

  pub fn place_tree(
    &self,
    mut center: Pnt3<f32>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    lod_index: u32,
  ) {
    let lod_index = lod_index as usize;
    let normals = [
      normalize(&Vec3::new(-1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0, -1.0)),
    ];

    let wood_coords = Pnt2::new(0.0, 3.0);
    let leaf_coords = Pnt2::new(0.0, 4.0);

    let mut place_side =
      |&mut:
        corners: &[Pnt3<f32>],
        coords: Pnt2<f32>,
        idx1: usize,
        idx2: usize,
        idx3: usize,
        idx4: usize,
      | {
        let n1 = normals[idx1];
        let n2 = normals[idx2];
        let n3 = normals[idx3];
        let n4 = normals[idx4];

        let v1 = corners[idx1];
        let v2 = corners[idx2];
        let v3 = corners[idx3];
        let v4 = corners[idx4];

        block.vertex_coordinates.push_all(&[[v1, v2, v4], [v1, v4, v3]]);
        block.normals.push_all(&[[n1, n2, n4], [n1, n4, n3]]);
        block.coords.push_all(&[[coords, coords, coords], [coords, coords, coords]]);

        let minx = partial_min(v1.x, v2.x).unwrap();
        let maxx = partial_max(v1.x, v2.x).unwrap();
        let minz = partial_min(v1.z, v2.z).unwrap();
        let maxz = partial_max(v1.z, v2.z).unwrap();

        let bounds =
          AABB::new(
            Pnt3::new(minx, v1.y, minz),
            Pnt3::new(maxx, v3.y, maxz),
          );

        let id1 = id_allocator.allocate();
        let id2 = id_allocator.allocate();
        block.ids.push_all(&[id1, id2]);

        block.bounds.push((id1, bounds.clone()));
        block.bounds.push((id2, bounds));
      };

    let mut place_block =
      |&mut:
        coords: Pnt2<f32>,
        low_center: &Pnt3<f32>, low_radius: f32,
        high_center: &Pnt3<f32>, high_radius: f32| {
        let corners = [
          *low_center + Vec3::new(-low_radius, 0.0, -low_radius),
          *low_center + Vec3::new(-low_radius, 0.0,  low_radius),
          *low_center + Vec3::new( low_radius, 0.0,  low_radius),
          *low_center + Vec3::new( low_radius, 0.0, -low_radius),
          *high_center + Vec3::new(-high_radius, 0.0, -high_radius),
          *high_center + Vec3::new(-high_radius, 0.0,  high_radius),
          *high_center + Vec3::new( high_radius, 0.0,  high_radius),
          *high_center + Vec3::new( high_radius, 0.0, -high_radius),
        ];

        place_side(&corners, coords, 0, 1, 4, 5);
        place_side(&corners, coords, 1, 2, 5, 6);
        place_side(&corners, coords, 2, 3, 6, 7);
        place_side(&corners, coords, 3, 0, 7, 4);
        place_side(&corners, coords, 1, 0, 2, 3);
        place_side(&corners, coords, 4, 5, 7, 6);
      };

    let mut rng = self.rng_at(&center, vec!(1));
    let mass = (rng.next_u32() as f32) / (0x10000 as f32) / (0x10000 as f32);
    let mass = 0.1 + mass * 0.9;
    let mass = partial_min(partial_max(0.0, mass).unwrap(), 1.0).unwrap();

    let sqr_mass = mass * mass;
    let trunk_radius = sqr_mass * 2.0;
    let trunk_height = sqr_mass * 16.0;

    {
      place_block(
        wood_coords,
        &center, trunk_radius,
        &(center + Vec3::new(0.0, trunk_height, 0.0)), trunk_radius,
      );
      center = center + Vec3::new(0.0, trunk_height, 0.0);
    }

    {
      let crown_radius = sqr_mass * 16.0;
      let crown_height = sqr_mass * 16.0;
      let crown_width = crown_radius * 2.0;

      let mut points: Vec<Pnt3<_>> = {
        let n_points =
          (crown_width * crown_width * crown_height * TREE_NODES[lod_index]) as u32;
        range(0, n_points)
        .map(|_| {
          let x = rng.next_u32();
          let y = rng.next_u32();
          let z = rng.next_u32();
          Pnt3::new(
            fmod(x as f64, crown_width as f64) as f32 - crown_radius,
            fmod(y as f64, crown_height as f64) as f32,
            fmod(z as f64, crown_width as f64) as f32 - crown_radius,
          )
        })
        .map(|p| p + *center.as_vec())
        .collect()
      };

      let mut fringe = RingBuf::new();
      fringe.push_back((center, trunk_radius));

      while let Some((center, thickness)) = fringe.pop_front() {
        let mut i = 0;
        let mut any_branches = false;

        let radius = MAX_BRANCH_LENGTH[lod_index];
        while i < points.len() {
          if sqr_distance(&center, &points[i]) <= radius * radius {
            let next_thickness = thickness * 0.6;
            if center.y < points[i].y {
              place_block(wood_coords, &center, thickness, &points[i], next_thickness);
            } else {
              place_block(wood_coords, &points[i], next_thickness, &center, thickness);
            }
            fringe.push_back((points[i], next_thickness));
            points.swap_remove(i);
            any_branches = true;
          } else {
            i += 1;
          }
        }

        if !any_branches {
          // A node with no branches gets leaves.

          let radius = LEAF_RADIUS[lod_index];
          let height = 2.0 * radius;

          place_block(
            leaf_coords,
            &center, radius,
            &(center + Vec3::new(0.0, height, 0.0)), radius,
          );
        }
      }
    }
  }
}
<commit_msg>Add thanks to terrain::tree_placer.<commit_after>// Thanks to http://procworld.blogspot.com/2011/02/space-colonization.html
// for the basic idea used to generate these trees!

use id_allocator::IdAllocator;
use nalgebra::{Pnt2, Pnt3, Vec3, normalize};
use ncollide::bounding_volume::AABB;
use rand::{Rng, SeedableRng, IsaacRng};
use state::EntityId;
use std::cmp::{partial_min, partial_max};
use std::collections::RingBuf;
use std::num::Float;
use terrain::terrain::LOD_QUALITY;
use terrain::terrain_block::{TerrainBlock, BLOCK_WIDTH};

const TREE_NODES: [f32; 4] = [1.0/16.0, 1.0/16.0, 1.0/64.0, 1.0/128.0];
const MAX_BRANCH_LENGTH: [f32; 4] = [4.0, 4.0, 8.0, 16.0];
const LEAF_RADIUS: [f32; 4] = [1.5, 1.5, 8.0, 16.0];

#[inline(always)]
fn fmod(mut dividend: f64, divisor: f64) -> f64 {
  dividend -= divisor * (dividend / divisor).floor();
  if dividend < 0.0 || dividend >= divisor{
    // clamp
    dividend = 0.0;
  }
  dividend
}

fn sqr_distance(p1: &Pnt3<f32>, p2: &Pnt3<f32>) -> f32 {
  let d = *p1 - *p2.as_vec();
  d.x*d.x + d.y*d.y + d.z*d.z
}

/// Use one-octave perlin noise local maxima to place trees.
pub struct TreePlacer {
  seed: u32,
}

impl TreePlacer {
  pub fn new(seed: u32) -> TreePlacer {
    TreePlacer {
      seed: seed,
    }
  }

  fn rng_at(&self, center: &Pnt3<f32>, mut seed: Vec<u32>) -> IsaacRng {
    let center = *center * (LOD_QUALITY[0] as f32) / (BLOCK_WIDTH as f32);
    seed.push_all(&[self.seed, center.x as u32, center.z as u32]);
    SeedableRng::from_seed(seed.as_slice())
  }

  pub fn should_place_tree(&self, center: &Pnt3<f32>) -> bool {
    let mut rng = self.rng_at(center, vec!(0));
    rng.next_u32() > 0xFF7FFFFF
  }

  pub fn place_tree(
    &self,
    mut center: Pnt3<f32>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    lod_index: u32,
  ) {
    let lod_index = lod_index as usize;
    let normals = [
      normalize(&Vec3::new(-1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0,  1.0)),
      normalize(&Vec3::new( 1.0, -1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0, -1.0)),
      normalize(&Vec3::new(-1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0,  1.0)),
      normalize(&Vec3::new( 1.0,  1.0, -1.0)),
    ];

    let wood_coords = Pnt2::new(0.0, 3.0);
    let leaf_coords = Pnt2::new(0.0, 4.0);

    let mut place_side =
      |&mut:
        corners: &[Pnt3<f32>],
        coords: Pnt2<f32>,
        idx1: usize,
        idx2: usize,
        idx3: usize,
        idx4: usize,
      | {
        let n1 = normals[idx1];
        let n2 = normals[idx2];
        let n3 = normals[idx3];
        let n4 = normals[idx4];

        let v1 = corners[idx1];
        let v2 = corners[idx2];
        let v3 = corners[idx3];
        let v4 = corners[idx4];

        block.vertex_coordinates.push_all(&[[v1, v2, v4], [v1, v4, v3]]);
        block.normals.push_all(&[[n1, n2, n4], [n1, n4, n3]]);
        block.coords.push_all(&[[coords, coords, coords], [coords, coords, coords]]);

        let minx = partial_min(v1.x, v2.x).unwrap();
        let maxx = partial_max(v1.x, v2.x).unwrap();
        let minz = partial_min(v1.z, v2.z).unwrap();
        let maxz = partial_max(v1.z, v2.z).unwrap();

        let bounds =
          AABB::new(
            Pnt3::new(minx, v1.y, minz),
            Pnt3::new(maxx, v3.y, maxz),
          );

        let id1 = id_allocator.allocate();
        let id2 = id_allocator.allocate();
        block.ids.push_all(&[id1, id2]);

        block.bounds.push((id1, bounds.clone()));
        block.bounds.push((id2, bounds));
      };

    let mut place_block =
      |&mut:
        coords: Pnt2<f32>,
        low_center: &Pnt3<f32>, low_radius: f32,
        high_center: &Pnt3<f32>, high_radius: f32| {
        let corners = [
          *low_center + Vec3::new(-low_radius, 0.0, -low_radius),
          *low_center + Vec3::new(-low_radius, 0.0,  low_radius),
          *low_center + Vec3::new( low_radius, 0.0,  low_radius),
          *low_center + Vec3::new( low_radius, 0.0, -low_radius),
          *high_center + Vec3::new(-high_radius, 0.0, -high_radius),
          *high_center + Vec3::new(-high_radius, 0.0,  high_radius),
          *high_center + Vec3::new( high_radius, 0.0,  high_radius),
          *high_center + Vec3::new( high_radius, 0.0, -high_radius),
        ];

        place_side(&corners, coords, 0, 1, 4, 5);
        place_side(&corners, coords, 1, 2, 5, 6);
        place_side(&corners, coords, 2, 3, 6, 7);
        place_side(&corners, coords, 3, 0, 7, 4);
        place_side(&corners, coords, 1, 0, 2, 3);
        place_side(&corners, coords, 4, 5, 7, 6);
      };

    let mut rng = self.rng_at(&center, vec!(1));
    let mass = (rng.next_u32() as f32) / (0x10000 as f32) / (0x10000 as f32);
    let mass = 0.1 + mass * 0.9;
    let mass = partial_min(partial_max(0.0, mass).unwrap(), 1.0).unwrap();

    let sqr_mass = mass * mass;
    let trunk_radius = sqr_mass * 2.0;
    let trunk_height = sqr_mass * 16.0;

    {
      place_block(
        wood_coords,
        &center, trunk_radius,
        &(center + Vec3::new(0.0, trunk_height, 0.0)), trunk_radius,
      );
      center = center + Vec3::new(0.0, trunk_height, 0.0);
    }

    {
      let crown_radius = sqr_mass * 16.0;
      let crown_height = sqr_mass * 16.0;
      let crown_width = crown_radius * 2.0;

      let mut points: Vec<Pnt3<_>> = {
        let n_points =
          (crown_width * crown_width * crown_height * TREE_NODES[lod_index]) as u32;
        range(0, n_points)
        .map(|_| {
          let x = rng.next_u32();
          let y = rng.next_u32();
          let z = rng.next_u32();
          Pnt3::new(
            fmod(x as f64, crown_width as f64) as f32 - crown_radius,
            fmod(y as f64, crown_height as f64) as f32,
            fmod(z as f64, crown_width as f64) as f32 - crown_radius,
          )
        })
        .map(|p| p + *center.as_vec())
        .collect()
      };

      let mut fringe = RingBuf::new();
      fringe.push_back((center, trunk_radius));

      while let Some((center, thickness)) = fringe.pop_front() {
        let mut i = 0;
        let mut any_branches = false;

        let radius = MAX_BRANCH_LENGTH[lod_index];
        while i < points.len() {
          if sqr_distance(&center, &points[i]) <= radius * radius {
            let next_thickness = thickness * 0.6;
            if center.y < points[i].y {
              place_block(wood_coords, &center, thickness, &points[i], next_thickness);
            } else {
              place_block(wood_coords, &points[i], next_thickness, &center, thickness);
            }
            fringe.push_back((points[i], next_thickness));
            points.swap_remove(i);
            any_branches = true;
          } else {
            i += 1;
          }
        }

        if !any_branches {
          // A node with no branches gets leaves.

          let radius = LEAF_RADIUS[lod_index];
          let height = 2.0 * radius;

          place_block(
            leaf_coords,
            &center, radius,
            &(center + Vec3::new(0.0, height, 0.0)), radius,
          );
        }
      }
    }
  }
}
<|endoftext|>


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

struct Struct {
    a: usize,
}; //~ ERROR expected item, found ';'

fn main() {}
<commit_msg>Changed to correct quotes ` `<commit_after>// Copyright 2017 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.

struct Struct {
    a: usize,
}; //~ ERROR expected item, found `;`

fn main() {}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::VecDeque;
use std::env::{set_current_dir, current_dir, home_dir};
use std::path::PathBuf;
use super::variables::Variables;
use super::status::SUCCESS;

pub struct DirectoryStack {
    dirs: VecDeque<PathBuf>, // The top is always the current directory
}

impl DirectoryStack {
    /// Create a new `DirectoryStack` containing the current working directory, if available.
    pub fn new() -> DirectoryStack {
        let mut dirs: VecDeque<PathBuf> = VecDeque::new();
        match current_dir() {
            Ok(curr_dir) => {
                dirs.push_front(curr_dir);
                DirectoryStack { dirs: dirs }
            },
            Err(_) => {
                eprintln!("ion: failed to get current directory when building directory stack");
                DirectoryStack { dirs: dirs}
            }
        }
    }

    /// This function will take a map of variables as input and attempt to parse the value of the
    /// directory stack size variable. If it succeeds, it will return the value of that variable,
    /// else it will return a default value of 1000.
    fn get_size(variables: &Variables) -> usize {
        variables.get_var_or_empty("DIRECTORY_STACK_SIZE").parse::<usize>().unwrap_or(1000)
    }

    /// Attempts to set the current directory to the directory stack's previous directory,
    /// and then removes the front directory from the stack.
    pub fn popd<I: IntoIterator>(&mut self, args: I) -> Result<(), Cow<'static, str>>
        where I::Item: AsRef<str>
    {
	let mut keep_front = false; // whether the -n option is present
	let mut count_from_front = true; // <=> input number is positive
	let mut num: usize = 0;

	for arg in args.into_iter().skip(1) {
		let arg = arg.as_ref();
		if arg == "-n" {
			keep_front = true;
		} else {
			match parse_numeric_arg(arg) {
				Some((x, y)) => { count_from_front = x; num = y; }
				None => return Err(Cow::Owned(format!("ion: popd: {}: invalid argument\n", arg)))
			};
		}
	}

	let len: usize = self.dirs.len();
	if len <= 1 {
		return Err(Cow::Borrowed("ion: popd: directory stack empty\n"));
	}

	let mut index: usize = if count_from_front { num } else {
		(len - 1).checked_sub(num)
			.ok_or_else(|| Cow::Owned(format!("ion: popd: negative directory stack index out of range\n")))?
	};

	// apply -n
	if index == 0 && keep_front { index = 1; }

	// change to new directory, return if not possible
	if index == 0 {
		self.set_current_dir_by_index(1, "popd")?;
	}

	// pop element
	if self.dirs.remove(index).is_none() {
		return Err(Cow::Owned(format!("ion: popd: {}: directory stack index out of range\n", index)));
	}

	self.print_dirs();
	Ok(())
    }

    pub fn pushd<I: IntoIterator>(&mut self, args: I, variables: &Variables) -> Result<(), Cow<'static, str>>
        where I::Item: AsRef<str>
    {
	enum Action {
		Switch, // <no arguments>
		RotLeft(usize), // +[num]
		RotRight(usize), // -[num]
		Push(PathBuf) // [dir]
	}

	let mut keep_front = false; // whether the -n option is present
	let mut action : Action = Action::Switch;

	for arg in args.into_iter().skip(1) {
		let arg = arg.as_ref();
		if arg == "-n" {
			keep_front = true;
		} else if let Action::Switch = action { // if action is not yet defined
			action = match parse_numeric_arg(arg) {
				Some((true, num)) => Action::RotLeft(num),
				Some((false, num)) => Action::RotRight(num),
				None => Action::Push(PathBuf::from(arg)) // no numeric arg => `dir`-parameter
			};
		} else {
			return Err(Cow::Borrowed("ion: pushd: too many arguments\n"));
		}
	}

	let len = self.dirs.len();
	match action {
		Action::Switch => {
			if len < 2 {
				return Err(Cow::Borrowed("ion: pushd: no other directory\n"));
			}
			if !keep_front {
				self.set_current_dir_by_index(1, "pushd")?;
				self.dirs.swap(0, 1);
			}
		},
		Action::RotLeft(num) => {
			if !keep_front {
				self.set_current_dir_by_index(num, "pushd")?;
				self.rotate_left(num);
			}
		},
		Action::RotRight(num) => {
			if !keep_front {
				self.set_current_dir_by_index(len - (num % len), "pushd")?;
				self.rotate_right(num);
			}
		},
		Action::Push(dir) => {
			let index = if keep_front { 1 } else { 0 };
			self.insert_dir(index, dir, variables);
		}
	};

	self.print_dirs();

	Ok(())
    }

    pub fn cd<I: IntoIterator>(&mut self, args: I, variables: &Variables) -> Result<(), Cow<'static, str>>
        where I::Item: AsRef<str>
    {
            match args.into_iter().nth(1) {
                Some(dir) => {
                    let dir = dir.as_ref();
                    if dir == "-" {
                        self.switch_to_previous_directory(variables)
                    } else {
                        self.change_and_push_dir(dir, variables)
                    }
                }
                None => self.switch_to_home_directory(variables)
            }
    }

    fn switch_to_home_directory(&mut self, variables: &Variables) -> Result<(), Cow<'static, str>> {
        home_dir()
            .map_or(Err(Cow::Borrowed("ion: failed to get home directory")), |home| {
                home.to_str().map_or(Err(Cow::Borrowed("ion: failed to convert home directory to str")), |home| {
                    self.change_and_push_dir(home, variables)
                })
            })
    }

    fn switch_to_previous_directory(&mut self, variables: &Variables) -> Result<(), Cow<'static, str>> {
        self.get_previous_dir().cloned()
            .map_or_else(|| Err(Cow::Borrowed("ion: no previous directory to switch to")), |prev| {
                self.dirs.remove(1);
                let prev = prev.to_string_lossy().to_string();
                println!("{}", prev);
                self.change_and_push_dir(&prev, variables)
            })
    }

    fn get_previous_dir(&self) -> Option<&PathBuf> {
        if self.dirs.len() < 2 {
            None
        } else {
            self.dirs.get(1)
        }
    }

    pub fn change_and_push_dir(&mut self, dir: &str, variables: &Variables) -> Result<(), Cow<'static, str>> {
        match (set_current_dir(dir), current_dir()) {
            (Ok(()), Ok(cur_dir)) => {
                self.push_dir(cur_dir, variables);
                Ok(())
            }
            (Err(err), _) => {
                Err(Cow::Owned(format!("ion: failed to set current dir to {}: {}\n", dir, err)))
            }
            (_, _) => Err(Cow::Borrowed("ion: change_and_push_dir(): error occurred that should never happen\n")), // This should not happen
        }
    }

    fn push_dir(&mut self, path: PathBuf, variables: &Variables) {
        self.dirs.push_front(path);

        self.dirs.truncate(DirectoryStack::get_size(variables));
    }

    fn insert_dir(&mut self, index: usize, path: PathBuf, variables: &Variables) {
        self.dirs.insert(index, path);
        self.dirs.truncate(DirectoryStack::get_size(variables));
    }

    pub fn dirs<I: IntoIterator>(&self, _: I) -> i32
        where I::Item: AsRef<str>
    {
        self.print_dirs();
        SUCCESS
    }

    pub fn dir_from_top(&self, num: usize) -> Option<&PathBuf> {
        self.dirs.get(num)
    }

    pub fn dir_from_bottom(&self, num: usize) -> Option<&PathBuf> {
        self.dirs.iter().rev().nth(num)
    }

    fn print_dirs(&self) {
        let dir = self.dirs.iter().fold(String::new(), |acc, dir| {
            acc + " " + dir.to_str().unwrap_or("ion: no directory found")
        });
        println!("{}", dir.trim_left());
    }

    // sets current_dir to the element referred by index
    fn set_current_dir_by_index(&self, index: usize, caller: &str) -> Result<(), Cow<'static, str>> {
	let dir = self.dirs.iter().nth(index)
		.ok_or_else(|| Cow::Owned(format!("ion: {}: {}: directory stack out of range\n", caller, index)))?;

	set_current_dir(dir)
		.map_err(|_| Cow::Owned(format!("ion: {}: Failed setting current dir\n", caller)))
    }

    // pushd +<num>
    fn rotate_left(&mut self, num: usize) {
	let cloned = self.dirs.clone();
	for (dest, src) in self.dirs.iter_mut().zip(
		cloned.iter().cycle().skip(num)
	) {
		*dest = src.clone();
	}
    }

    // pushd -<num>
    fn rotate_right(&mut self, num: usize) {
	let len = self.dirs.len();
	self.rotate_left(len - (num % len));
    }
}

// parses -N or +N patterns
// required for popd, pushd, dirs
fn parse_numeric_arg(arg: &str) -> Option<(bool, usize)> {
	match arg.chars().nth(0) {
		Some('+') => Some(true),
		Some('-') => Some(false),
		_ => None
	}.and_then(|b| {
		arg[1..].parse::<usize>()
			.ok()
			.map(|num| (b, num))
	})
}
<commit_msg>implemented dirs command line options<commit_after>use std::borrow::Cow;
use std::collections::VecDeque;
use std::env::{set_current_dir, current_dir, home_dir};
use std::path::PathBuf;
use super::variables::Variables;
use super::status::{SUCCESS, FAILURE};

pub struct DirectoryStack {
    dirs: VecDeque<PathBuf>, // The top is always the current directory
}

impl DirectoryStack {
    /// Create a new `DirectoryStack` containing the current working directory, if available.
    pub fn new() -> DirectoryStack {
        let mut dirs: VecDeque<PathBuf> = VecDeque::new();
        match current_dir() {
            Ok(curr_dir) => {
                dirs.push_front(curr_dir);
                DirectoryStack { dirs: dirs }
            },
            Err(_) => {
                eprintln!("ion: failed to get current directory when building directory stack");
                DirectoryStack { dirs: dirs}
            }
        }
    }

    /// This function will take a map of variables as input and attempt to parse the value of the
    /// directory stack size variable. If it succeeds, it will return the value of that variable,
    /// else it will return a default value of 1000.
    fn get_size(variables: &Variables) -> usize {
        variables.get_var_or_empty("DIRECTORY_STACK_SIZE").parse::<usize>().unwrap_or(1000)
    }

    /// Attempts to set the current directory to the directory stack's previous directory,
    /// and then removes the front directory from the stack.
    pub fn popd<I: IntoIterator>(&mut self, args: I) -> Result<(), Cow<'static, str>>
        where I::Item: AsRef<str>
    {
	let mut keep_front = false; // whether the -n option is present
	let mut count_from_front = true; // <=> input number is positive
	let mut num: usize = 0;

	for arg in args.into_iter().skip(1) {
		let arg = arg.as_ref();
		if arg == "-n" {
			keep_front = true;
		} else {
			match parse_numeric_arg(arg) {
				Some((x, y)) => { count_from_front = x; num = y; }
				None => return Err(Cow::Owned(format!("ion: popd: {}: invalid argument\n", arg)))
			};
		}
	}

	let len: usize = self.dirs.len();
	if len <= 1 {
		return Err(Cow::Borrowed("ion: popd: directory stack empty\n"));
	}

	let mut index: usize = if count_from_front { num } else {
		(len - 1).checked_sub(num)
			.ok_or_else(|| Cow::Owned(format!("ion: popd: negative directory stack index out of range\n")))?
	};

	// apply -n
	if index == 0 && keep_front { index = 1; }

	// change to new directory, return if not possible
	if index == 0 {
		self.set_current_dir_by_index(1, "popd")?;
	}

	// pop element
	if self.dirs.remove(index).is_none() {
		return Err(Cow::Owned(format!("ion: popd: {}: directory stack index out of range\n", index)));
	}

	self.print_dirs();
	Ok(())
    }

    pub fn pushd<I: IntoIterator>(&mut self, args: I, variables: &Variables) -> Result<(), Cow<'static, str>>
        where I::Item: AsRef<str>
    {
	enum Action {
		Switch, // <no arguments>
		RotLeft(usize), // +[num]
		RotRight(usize), // -[num]
		Push(PathBuf) // [dir]
	}

	let mut keep_front = false; // whether the -n option is present
	let mut action : Action = Action::Switch;

	for arg in args.into_iter().skip(1) {
		let arg = arg.as_ref();
		if arg == "-n" {
			keep_front = true;
		} else if let Action::Switch = action { // if action is not yet defined
			action = match parse_numeric_arg(arg) {
				Some((true, num)) => Action::RotLeft(num),
				Some((false, num)) => Action::RotRight(num),
				None => Action::Push(PathBuf::from(arg)) // no numeric arg => `dir`-parameter
			};
		} else {
			return Err(Cow::Borrowed("ion: pushd: too many arguments\n"));
		}
	}

	let len = self.dirs.len();
	match action {
		Action::Switch => {
			if len < 2 {
				return Err(Cow::Borrowed("ion: pushd: no other directory\n"));
			}
			if !keep_front {
				self.set_current_dir_by_index(1, "pushd")?;
				self.dirs.swap(0, 1);
			}
		},
		Action::RotLeft(num) => {
			if !keep_front {
				self.set_current_dir_by_index(num, "pushd")?;
				self.rotate_left(num);
			}
		},
		Action::RotRight(num) => {
			if !keep_front {
				self.set_current_dir_by_index(len - (num % len), "pushd")?;
				self.rotate_right(num);
			}
		},
		Action::Push(dir) => {
			let index = if keep_front { 1 } else { 0 };
			self.insert_dir(index, dir, variables);
		}
	};

	self.print_dirs();

	Ok(())
    }

    pub fn cd<I: IntoIterator>(&mut self, args: I, variables: &Variables) -> Result<(), Cow<'static, str>>
        where I::Item: AsRef<str>
    {
            match args.into_iter().nth(1) {
                Some(dir) => {
                    let dir = dir.as_ref();
                    if dir == "-" {
                        self.switch_to_previous_directory(variables)
                    } else {
                        self.change_and_push_dir(dir, variables)
                    }
                }
                None => self.switch_to_home_directory(variables)
            }
    }

    fn switch_to_home_directory(&mut self, variables: &Variables) -> Result<(), Cow<'static, str>> {
        home_dir()
            .map_or(Err(Cow::Borrowed("ion: failed to get home directory")), |home| {
                home.to_str().map_or(Err(Cow::Borrowed("ion: failed to convert home directory to str")), |home| {
                    self.change_and_push_dir(home, variables)
                })
            })
    }

    fn switch_to_previous_directory(&mut self, variables: &Variables) -> Result<(), Cow<'static, str>> {
        self.get_previous_dir().cloned()
            .map_or_else(|| Err(Cow::Borrowed("ion: no previous directory to switch to")), |prev| {
                self.dirs.remove(1);
                let prev = prev.to_string_lossy().to_string();
                println!("{}", prev);
                self.change_and_push_dir(&prev, variables)
            })
    }

    fn get_previous_dir(&self) -> Option<&PathBuf> {
        if self.dirs.len() < 2 {
            None
        } else {
            self.dirs.get(1)
        }
    }

    pub fn change_and_push_dir(&mut self, dir: &str, variables: &Variables) -> Result<(), Cow<'static, str>> {
        match (set_current_dir(dir), current_dir()) {
            (Ok(()), Ok(cur_dir)) => {
                self.push_dir(cur_dir, variables);
                Ok(())
            }
            (Err(err), _) => {
                Err(Cow::Owned(format!("ion: failed to set current dir to {}: {}\n", dir, err)))
            }
            (_, _) => Err(Cow::Borrowed("ion: change_and_push_dir(): error occurred that should never happen\n")), // This should not happen
        }
    }

    fn push_dir(&mut self, path: PathBuf, variables: &Variables) {
        self.dirs.push_front(path);

        self.dirs.truncate(DirectoryStack::get_size(variables));
    }

    fn insert_dir(&mut self, index: usize, path: PathBuf, variables: &Variables) {
        self.dirs.insert(index, path);
        self.dirs.truncate(DirectoryStack::get_size(variables));
    }

    pub fn dirs<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
	const CLEAR: u8 = 1;		// -c
	const ABS_PATHNAMES: u8 = 2;	// -l
	const MULTILINE: u8 = 4;	// -p | -v
	const INDEX: u8 = 8;		// -v

	let mut dirs_args: u8 = 0;
	let mut num_arg: Option<usize> = None;

	for arg in args.into_iter().skip(1) {
		let arg = arg.as_ref();
		match arg {
			"-c" => dirs_args |= CLEAR,
			"-l" => dirs_args |= ABS_PATHNAMES,
			"-p" => dirs_args |= MULTILINE,
			"-v" => dirs_args |= INDEX | MULTILINE,
			arg => {
				num_arg = match parse_numeric_arg(arg) {
					Some((true, num)) => Some(num),
					Some((false, num)) if self.dirs.len() > num => Some(self.dirs.len() - num - 1),
					_ => return FAILURE // Err(Cow::Owned(format!("ion: dirs: {}: invalid argument\n", arg)))
				};
			}
		}
	}

	if dirs_args & CLEAR > 0 {
		self.dirs.truncate(1);
	}

	let mapper: fn((usize, &PathBuf)) -> Cow<str> =
		match (dirs_args & ABS_PATHNAMES > 0, dirs_args & INDEX > 0) {
			// ABS, INDEX
			(true, true) => |(num, x)| Cow::Owned(format!(" {}  {}", num, try_abs_path(x))),
			(true, false) => |(_, x)| try_abs_path(x),
			(false, true) => |(num, x)| Cow::Owned(format!(" {}  {}", num, x.to_string_lossy())),
			(false, false) => |(_, x)| x.to_string_lossy()
		};

	let mut iter = self.dirs.iter()
		.enumerate()
		.map(mapper);

	if let Some(num) = num_arg {
		match iter.nth(num) {
			Some(x) => println!("{}", x),
			None => return FAILURE
		};
	} else {
		let folder: fn(String, Cow<str>) -> String =
			match dirs_args & MULTILINE > 0 {
				true => |x, y| x + "\n" + &y,
				false => |x, y| x + " " + &y,
			};

		let first = match iter.next() {
			Some(x) => x.to_string(),
			None => return SUCCESS
		};

		println!("{}", iter.fold(first, folder));
	}
	SUCCESS
    }

    pub fn dir_from_top(&self, num: usize) -> Option<&PathBuf> {
        self.dirs.get(num)
    }

    pub fn dir_from_bottom(&self, num: usize) -> Option<&PathBuf> {
        self.dirs.iter().rev().nth(num)
    }

    fn print_dirs(&self) {
        let dir = self.dirs.iter().fold(String::new(), |acc, dir| {
            acc + " " + dir.to_str().unwrap_or("ion: no directory found")
        });
        println!("{}", dir.trim_left());
    }

    // sets current_dir to the element referred by index
    fn set_current_dir_by_index(&self, index: usize, caller: &str) -> Result<(), Cow<'static, str>> {
	let dir = self.dirs.iter().nth(index)
		.ok_or_else(|| Cow::Owned(format!("ion: {}: {}: directory stack out of range\n", caller, index)))?;

	set_current_dir(dir)
		.map_err(|_| Cow::Owned(format!("ion: {}: Failed setting current dir\n", caller)))
    }

    // pushd +<num>
    fn rotate_left(&mut self, num: usize) {
	let cloned = self.dirs.clone();
	for (dest, src) in self.dirs.iter_mut().zip(
		cloned.iter().cycle().skip(num)
	) {
		*dest = src.clone();
	}
    }

    // pushd -<num>
    fn rotate_right(&mut self, num: usize) {
	let len = self.dirs.len();
	self.rotate_left(len - (num % len));
    }
}

// parses -N or +N patterns
// required for popd, pushd, dirs
fn parse_numeric_arg(arg: &str) -> Option<(bool, usize)> {
	match arg.chars().nth(0) {
		Some('+') => Some(true),
		Some('-') => Some(false),
		_ => None
	}.and_then(|b| {
		arg[1..].parse::<usize>()
			.ok()
			.map(|num| (b, num))
	})
}

// converts pbuf to an absolute path if possible
fn try_abs_path(pbuf: &PathBuf) -> Cow<str> {
	Cow::Owned(
		pbuf.canonicalize()
			.unwrap_or_else(|_| pbuf.clone())
			.to_string_lossy()
			.to_string()
	)
}
<|endoftext|>


<commit_before>//! Abstractions for page tables and other paging related structures.

pub use self::page_table::*;
pub use self::recursive::*;

use addr::{PhysAddr, VirtAddr};
use core::ops::{Add, AddAssign, Sub, SubAssign};
use ux::*;

mod page_table;
mod recursive;

/// The default page size on x86_64.
pub const PAGE_SIZE: u16 = 4096;

/// A virtual 4kB page.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Page {
    number: u64,
}

impl Page {
    /// Returns the page that contains the given virtual address.
    pub fn containing_address(address: VirtAddr) -> Page {
        Page {
            number: address.as_u64() / u64::from(PAGE_SIZE),
        }
    }

    pub fn from_page_table_indices(p4_index: u9, p3_index: u9, p2_index: u9, p1_index: u9) -> Page {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        addr.set_bits(12..21, u64::from(p1_index));
        Page::containing_address(VirtAddr::new(addr))
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> VirtAddr {
        VirtAddr::new(self.number * u64::from(PAGE_SIZE))
    }

    /// Returns the level 4 page table index of this page.
    pub fn p4_index(&self) -> u9 {
        self.start_address().p4_index()
    }

    /// Returns the level 3 page table index of this page.
    pub fn p3_index(&self) -> u9 {
        self.start_address().p3_index()
    }

    /// Returns the level 2 page table index of this page.
    pub fn p2_index(&self) -> u9 {
        self.start_address().p2_index()
    }

    /// Returns the level 1 page table index of this page.
    pub fn p1_index(&self) -> u9 {
        self.start_address().p1_index()
    }

    pub fn range(start: Page, end: Page) -> PageRange {
        PageRange { start, end }
    }

    pub fn range_inclusive(start: Page, end: Page) -> PageRangeInclusive {
        PageRangeInclusive { start, end }
    }
}

impl Add<u64> for Page {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}

impl AddAssign<u64> for Page {
    fn add_assign(&mut self, rhs: u64) {
        *self = self.clone() + rhs;
    }
}

impl Sub<u64> for Page {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() - rhs * u64::from(PAGE_SIZE))
    }
}

impl SubAssign<u64> for Page {
    fn sub_assign(&mut self, rhs: u64) {
        *self = self.clone() - rhs;
    }
}

pub struct PageRange {
    pub start: Page,
    pub end: Page,
}

impl Iterator for PageRange {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start < self.end {
            let page = self.start.clone();
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

pub struct PageRangeInclusive {
    pub start: Page,
    pub end: Page,
}

impl Iterator for PageRangeInclusive {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start <= self.end {
            let page = self.start.clone();
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

/// A physical 4kB frame.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct PhysFrame {
    number: u64,
}

impl PhysFrame {
    /// Returns the frame that contains the given physical address.
    pub fn containing_address(address: PhysAddr) -> PhysFrame {
        PhysFrame {
            number: address.as_u64() / u64::from(PAGE_SIZE),
        }
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> PhysAddr {
        PhysAddr::new(self.number * u64::from(PAGE_SIZE))
    }

    pub fn range(start: PhysFrame, end: PhysFrame) -> PhysFrameRange {
        PhysFrameRange { start, end }
    }

    pub fn range_inclusive(start: PhysFrame, end: PhysFrame) -> PhysFrameRangeInclusive {
        PhysFrameRangeInclusive { start, end }
    }
}

impl Add<u64> for PhysFrame {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysFrame::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}

impl AddAssign<u64> for PhysFrame {
    fn add_assign(&mut self, rhs: u64) {
        *self = self.clone() + rhs;
    }
}

impl Sub<u64> for PhysFrame {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        PhysFrame::containing_address(self.start_address() - rhs * u64::from(PAGE_SIZE))
    }
}

impl SubAssign<u64> for PhysFrame {
    fn sub_assign(&mut self, rhs: u64) {
        *self = self.clone() - rhs;
    }
}

pub struct PhysFrameRange {
    pub start: PhysFrame,
    pub end: PhysFrame,
}

impl Iterator for PhysFrameRange {
    type Item = PhysFrame;

    fn next(&mut self) -> Option<PhysFrame> {
        if self.start < self.end {
            let frame = self.start.clone();
            self.start += 1;
            Some(frame)
        } else {
            None
        }
    }
}

pub struct PhysFrameRangeInclusive {
    pub start: PhysFrame,
    pub end: PhysFrame,
}

impl Iterator for PhysFrameRangeInclusive {
    type Item = PhysFrame;

    fn next(&mut self) -> Option<PhysFrame> {
        if self.start <= self.end {
            let frame = self.start.clone();
            self.start += 1;
            Some(frame)
        } else {
            None
        }
    }
}

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

    #[test]
    pub fn test_page_ranges() {
        let page_size = u64::from(PAGE_SIZE);
        let number = 1000;

        let start_addr = VirtAddr::new(0xdeadbeaf);
        let start = Page::containing_address(start_addr);
        let end = start.clone() + number;

        let mut range = Page::range(start.clone(), end.clone());
        for i in 0..number {
            assert_eq!(
                range.next(),
                Some(Page::containing_address(
                    start_addr + u64::from(PAGE_SIZE) * i
                ))
            );
        }
        assert_eq!(range.next(), None);

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(
                    start_addr + u64::from(PAGE_SIZE) * i
                ))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }
}
<commit_msg>Implement Sub<Self> for PhysFrame and Page<commit_after>//! Abstractions for page tables and other paging related structures.

pub use self::page_table::*;
pub use self::recursive::*;

use addr::{PhysAddr, VirtAddr};
use core::ops::{Add, AddAssign, Sub, SubAssign};
use ux::*;

mod page_table;
mod recursive;

/// The default page size on x86_64.
pub const PAGE_SIZE: u16 = 4096;

/// A virtual 4kB page.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Page {
    number: u64,
}

impl Page {
    /// Returns the page that contains the given virtual address.
    pub fn containing_address(address: VirtAddr) -> Page {
        Page {
            number: address.as_u64() / u64::from(PAGE_SIZE),
        }
    }

    pub fn from_page_table_indices(p4_index: u9, p3_index: u9, p2_index: u9, p1_index: u9) -> Page {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        addr.set_bits(12..21, u64::from(p1_index));
        Page::containing_address(VirtAddr::new(addr))
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> VirtAddr {
        VirtAddr::new(self.number * u64::from(PAGE_SIZE))
    }

    /// Returns the level 4 page table index of this page.
    pub fn p4_index(&self) -> u9 {
        self.start_address().p4_index()
    }

    /// Returns the level 3 page table index of this page.
    pub fn p3_index(&self) -> u9 {
        self.start_address().p3_index()
    }

    /// Returns the level 2 page table index of this page.
    pub fn p2_index(&self) -> u9 {
        self.start_address().p2_index()
    }

    /// Returns the level 1 page table index of this page.
    pub fn p1_index(&self) -> u9 {
        self.start_address().p1_index()
    }

    pub fn range(start: Page, end: Page) -> PageRange {
        PageRange { start, end }
    }

    pub fn range_inclusive(start: Page, end: Page) -> PageRangeInclusive {
        PageRangeInclusive { start, end }
    }
}

impl Add<u64> for Page {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}

impl AddAssign<u64> for Page {
    fn add_assign(&mut self, rhs: u64) {
        *self = self.clone() + rhs;
    }
}

impl Sub<u64> for Page {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() - rhs * u64::from(PAGE_SIZE))
    }
}

impl SubAssign<u64> for Page {
    fn sub_assign(&mut self, rhs: u64) {
        *self = self.clone() - rhs;
    }
}

impl Sub<Page> for Page {
    type Output = u64;
    fn sub(self, rhs: Page) -> Self::Output {
        self.number - rhs.number
    }
}

pub struct PageRange {
    pub start: Page,
    pub end: Page,
}

impl Iterator for PageRange {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start < self.end {
            let page = self.start.clone();
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

pub struct PageRangeInclusive {
    pub start: Page,
    pub end: Page,
}

impl Iterator for PageRangeInclusive {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start <= self.end {
            let page = self.start.clone();
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

/// A physical 4kB frame.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct PhysFrame {
    number: u64,
}

impl PhysFrame {
    /// Returns the frame that contains the given physical address.
    pub fn containing_address(address: PhysAddr) -> PhysFrame {
        PhysFrame {
            number: address.as_u64() / u64::from(PAGE_SIZE),
        }
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> PhysAddr {
        PhysAddr::new(self.number * u64::from(PAGE_SIZE))
    }

    pub fn range(start: PhysFrame, end: PhysFrame) -> PhysFrameRange {
        PhysFrameRange { start, end }
    }

    pub fn range_inclusive(start: PhysFrame, end: PhysFrame) -> PhysFrameRangeInclusive {
        PhysFrameRangeInclusive { start, end }
    }
}

impl Add<u64> for PhysFrame {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysFrame::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}

impl AddAssign<u64> for PhysFrame {
    fn add_assign(&mut self, rhs: u64) {
        *self = self.clone() + rhs;
    }
}

impl Sub<u64> for PhysFrame {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        PhysFrame::containing_address(self.start_address() - rhs * u64::from(PAGE_SIZE))
    }
}

impl SubAssign<u64> for PhysFrame {
    fn sub_assign(&mut self, rhs: u64) {
        *self = self.clone() - rhs;
    }
}

impl Sub<PhysFrame> for PhysFrame {
    type Output = u64;
    fn sub(self, rhs: PhysFrame) -> Self::Output {
        self.number - rhs.number
    }
}

pub struct PhysFrameRange {
    pub start: PhysFrame,
    pub end: PhysFrame,
}

impl Iterator for PhysFrameRange {
    type Item = PhysFrame;

    fn next(&mut self) -> Option<PhysFrame> {
        if self.start < self.end {
            let frame = self.start.clone();
            self.start += 1;
            Some(frame)
        } else {
            None
        }
    }
}

pub struct PhysFrameRangeInclusive {
    pub start: PhysFrame,
    pub end: PhysFrame,
}

impl Iterator for PhysFrameRangeInclusive {
    type Item = PhysFrame;

    fn next(&mut self) -> Option<PhysFrame> {
        if self.start <= self.end {
            let frame = self.start.clone();
            self.start += 1;
            Some(frame)
        } else {
            None
        }
    }
}

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

    #[test]
    pub fn test_page_ranges() {
        let page_size = u64::from(PAGE_SIZE);
        let number = 1000;

        let start_addr = VirtAddr::new(0xdeadbeaf);
        let start = Page::containing_address(start_addr);
        let end = start.clone() + number;

        let mut range = Page::range(start.clone(), end.clone());
        for i in 0..number {
            assert_eq!(
                range.next(),
                Some(Page::containing_address(
                    start_addr + u64::from(PAGE_SIZE) * i
                ))
            );
        }
        assert_eq!(range.next(), None);

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(
                    start_addr + u64::from(PAGE_SIZE) * i
                ))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }
}
<|endoftext|>


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

// A pass that annotates for each loops and functions with the free
// variables that they contain.

use middle::resolve;
use middle::ty;

use std::hashmap::HashMap;
use syntax::codemap::Span;
use syntax::{ast, ast_util};
use syntax::visit;
use syntax::visit::Visitor;
use syntax::ast::{item};

// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
#[deriving(Encodable, Decodable)]
pub struct freevar_entry {
    def: ast::Def, //< The variable being accessed free.
    span: Span     //< First span where it is accessed (there can be multiple)
}
pub type freevar_info = @~[@freevar_entry];
pub type freevar_map = @mut HashMap<ast::NodeId, freevar_info>;

struct CollectFreevarsVisitor {
    seen: @mut HashMap<ast::NodeId, ()>,
    refs: @mut ~[@freevar_entry],
    def_map: resolve::DefMap,
}

impl Visitor<int> for CollectFreevarsVisitor {

    fn visit_item(&mut self, _:@item, _:int) {
        // ignore_item
    }

    fn visit_expr(&mut self, expr:@ast::Expr, depth:int) {

            match expr.node {
              ast::ExprFnBlock(..) | ast::ExprProc(..) => {
                visit::walk_expr(self, expr, depth + 1)
              }
              ast::ExprPath(..) | ast::ExprSelf => {
                  let mut i = 0;
                  match self.def_map.find(&expr.id) {
                    None => fail!("path not found"),
                    Some(&df) => {
                      let mut def = df;
                      while i < depth {
                        match def {
                          ast::DefUpvar(_, inner, _, _) => { def = *inner; }
                          _ => break
                        }
                        i += 1;
                      }
                      if i == depth { // Made it to end of loop
                        let dnum = ast_util::def_id_of_def(def).node;
                        if !self.seen.contains_key(&dnum) {
                            self.refs.push(@freevar_entry {
                                def: def,
                                span: expr.span,
                            });
                            self.seen.insert(dnum, ());
                        }
                      }
                    }
                  }
              }
              _ => visit::walk_expr(self, expr, depth)
            }
    }

}

// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::DefMap, blk: ast::P<ast::Block>)
    -> freevar_info {
    let seen = @mut HashMap::new();
    let refs = @mut ~[];

    let mut v = CollectFreevarsVisitor {
        seen: seen,
        refs: refs,
        def_map: def_map,
    };

    v.visit_block(blk, 1);
    return @(*refs).clone();
}

struct AnnotateFreevarsVisitor {
    def_map: resolve::DefMap,
    freevars: freevar_map,
}

impl Visitor<()> for AnnotateFreevarsVisitor {
    fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
                blk:ast::P<ast::Block>, s:Span, nid:ast::NodeId, _:()) {
        let vars = collect_freevars(self.def_map, blk);
        self.freevars.insert(nid, vars);
        visit::walk_fn(self, fk, fd, blk, s, nid, ());
    }
}

// Build a map from every function and for-each body to a set of the
// freevars contained in it. The implementation is not particularly
// efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::Crate) ->
   freevar_map {
    let freevars = @mut HashMap::new();

    let mut visitor = AnnotateFreevarsVisitor {
        def_map: def_map,
        freevars: freevars,
    };
    visit::walk_crate(&mut visitor, crate, ());

    return freevars;
}

pub fn get_freevars(tcx: ty::ctxt, fid: ast::NodeId) -> freevar_info {
    match tcx.freevars.find(&fid) {
      None => fail!("get_freevars: {} has no freevars", fid),
      Some(&d) => return d
    }
}

pub fn has_freevars(tcx: ty::ctxt, fid: ast::NodeId) -> bool {
    !get_freevars(tcx, fid).is_empty()
}
<commit_msg>librustc: De-`@mut` the `CollectFreevarsVisitor`<commit_after>// Copyright 2012 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.

// A pass that annotates for each loops and functions with the free
// variables that they contain.

use middle::resolve;
use middle::ty;

use std::hashmap::HashMap;
use syntax::codemap::Span;
use syntax::{ast, ast_util};
use syntax::visit;
use syntax::visit::Visitor;
use syntax::ast::{item};

// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
#[deriving(Encodable, Decodable)]
pub struct freevar_entry {
    def: ast::Def, //< The variable being accessed free.
    span: Span     //< First span where it is accessed (there can be multiple)
}
pub type freevar_info = @~[@freevar_entry];
pub type freevar_map = @mut HashMap<ast::NodeId, freevar_info>;

struct CollectFreevarsVisitor {
    seen: HashMap<ast::NodeId, ()>,
    refs: ~[@freevar_entry],
    def_map: resolve::DefMap,
}

impl Visitor<int> for CollectFreevarsVisitor {

    fn visit_item(&mut self, _:@item, _:int) {
        // ignore_item
    }

    fn visit_expr(&mut self, expr:@ast::Expr, depth:int) {

            match expr.node {
              ast::ExprFnBlock(..) | ast::ExprProc(..) => {
                visit::walk_expr(self, expr, depth + 1)
              }
              ast::ExprPath(..) | ast::ExprSelf => {
                  let mut i = 0;
                  match self.def_map.find(&expr.id) {
                    None => fail!("path not found"),
                    Some(&df) => {
                      let mut def = df;
                      while i < depth {
                        match def {
                          ast::DefUpvar(_, inner, _, _) => { def = *inner; }
                          _ => break
                        }
                        i += 1;
                      }
                      if i == depth { // Made it to end of loop
                        let dnum = ast_util::def_id_of_def(def).node;
                        if !self.seen.contains_key(&dnum) {
                            self.refs.push(@freevar_entry {
                                def: def,
                                span: expr.span,
                            });
                            self.seen.insert(dnum, ());
                        }
                      }
                    }
                  }
              }
              _ => visit::walk_expr(self, expr, depth)
            }
    }

}

// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::DefMap, blk: ast::P<ast::Block>)
    -> freevar_info {
    let seen = HashMap::new();
    let refs = ~[];

    let mut v = CollectFreevarsVisitor {
        seen: seen,
        refs: refs,
        def_map: def_map,
    };

    v.visit_block(blk, 1);
    let CollectFreevarsVisitor {
        refs,
        ..
    } = v;
    return @refs;
}

struct AnnotateFreevarsVisitor {
    def_map: resolve::DefMap,
    freevars: freevar_map,
}

impl Visitor<()> for AnnotateFreevarsVisitor {
    fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
                blk:ast::P<ast::Block>, s:Span, nid:ast::NodeId, _:()) {
        let vars = collect_freevars(self.def_map, blk);
        self.freevars.insert(nid, vars);
        visit::walk_fn(self, fk, fd, blk, s, nid, ());
    }
}

// Build a map from every function and for-each body to a set of the
// freevars contained in it. The implementation is not particularly
// efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::Crate) ->
   freevar_map {
    let freevars = @mut HashMap::new();

    let mut visitor = AnnotateFreevarsVisitor {
        def_map: def_map,
        freevars: freevars,
    };
    visit::walk_crate(&mut visitor, crate, ());

    return freevars;
}

pub fn get_freevars(tcx: ty::ctxt, fid: ast::NodeId) -> freevar_info {
    match tcx.freevars.find(&fid) {
      None => fail!("get_freevars: {} has no freevars", fid),
      Some(&d) => return d
    }
}

pub fn has_freevars(tcx: ty::ctxt, fid: ast::NodeId) -> bool {
    !get_freevars(tcx, fid).is_empty()
}
<|endoftext|>


<commit_before>use rustc_data_structures::graph::iterate::{
    ControlFlow, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
use rustc_span::Span;

crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: LocalDefId) {
    let hir_id = tcx.hir().as_local_hir_id(def_id);

    if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
        if let FnKind::Closure(_) = fn_like_node.kind() {
            // closures can't recur, so they don't matter.
            return;
        }

        // If this is trait/impl method, extract the trait's substs.
        let trait_substs = match tcx.opt_associated_item(def_id.to_def_id()) {
            Some(AssocItem {
                container: AssocItemContainer::TraitContainer(trait_def_id), ..
            }) => {
                let trait_substs_count = tcx.generics_of(*trait_def_id).count();
                &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count]
            }
            _ => &[],
        };

        let mut vis = Search { tcx, body, def_id, reachable_recursive_calls: vec![], trait_substs };
        if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
            return;
        }

        vis.reachable_recursive_calls.sort();

        let hir_id = tcx.hir().as_local_hir_id(def_id);
        let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span(hir_id));
        tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
            let mut db = lint.build("function cannot return without recursing");
            db.span_label(sp, "cannot return without recursing");
            // offer some help to the programmer.
            for call_span in vis.reachable_recursive_calls {
                db.span_label(call_span, "recursive call site");
            }
            db.help("a `loop` may express intention better if this is on purpose");
            db.emit();
        });
    }
}

struct NonRecursive;

struct Search<'mir, 'tcx> {
    tcx: TyCtxt<'tcx>,
    body: &'mir Body<'tcx>,
    def_id: LocalDefId,
    trait_substs: &'tcx [GenericArg<'tcx>],

    reachable_recursive_calls: Vec<Span>,
}

impl<'mir, 'tcx> Search<'mir, 'tcx> {
    /// Returns `true` if `func` refers to the function we are searching in.
    fn is_recursive_call(&self, func: &Operand<'tcx>) -> bool {
        let Search { tcx, body, def_id, trait_substs, .. } = *self;
        let param_env = tcx.param_env(def_id);

        let func_ty = func.ty(body, tcx);
        if let ty::FnDef(fn_def_id, substs) = func_ty.kind {
            let (call_fn_id, call_substs) =
                if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, fn_def_id, substs) {
                    (instance.def_id(), instance.substs)
                } else {
                    (fn_def_id, substs)
                };

            // FIXME(#57965): Make this work across function boundaries

            // If this is a trait fn, the substs on the trait have to match, or we might be
            // calling into an entirely different method (for example, a call from the default
            // method in the trait to `<A as Trait<B>>::method`, where `A` and/or `B` are
            // specific types).
            return call_fn_id == def_id.to_def_id()
                && &call_substs[..trait_substs.len()] == trait_substs;
        }

        false
    }
}

impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
    type BreakVal = NonRecursive;

    fn node_examined(
        &mut self,
        bb: BasicBlock,
        prior_status: Option<NodeStatus>,
    ) -> ControlFlow<Self::BreakVal> {
        // Back-edge in the CFG (loop).
        if let Some(NodeStatus::Visited) = prior_status {
            return ControlFlow::Break(NonRecursive);
        }

        match self.body[bb].terminator().kind {
            // These terminators return control flow to the caller.
            TerminatorKind::Abort
            | TerminatorKind::GeneratorDrop
            | TerminatorKind::Resume
            | TerminatorKind::Return
            | TerminatorKind::Unreachable
            | TerminatorKind::Yield { .. } => ControlFlow::Break(NonRecursive),

            // FIXME(Amanieu): I am not 100% sure about this, but it triggers
            // a spurious warning otherwise.
            TerminatorKind::InlineAsm { .. } => ControlFlow::Break(NonRecursive),

            // These do not.
            TerminatorKind::Assert { .. }
            | TerminatorKind::Call { .. }
            | TerminatorKind::Drop { .. }
            | TerminatorKind::DropAndReplace { .. }
            | TerminatorKind::FalseEdges { .. }
            | TerminatorKind::FalseUnwind { .. }
            | TerminatorKind::Goto { .. }
            | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue,
        }
    }

    fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
        // When we examine a node for the last time, remember it if it is a recursive call.
        let terminator = self.body[bb].terminator();
        if let TerminatorKind::Call { func, .. } = &terminator.kind {
            if self.is_recursive_call(func) {
                self.reachable_recursive_calls.push(terminator.source_info.span);
            }
        }

        ControlFlow::Continue
    }

    fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
        // Don't traverse successors of recursive calls or false CFG edges.
        match self.body[bb].terminator().kind {
            TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func),

            TerminatorKind::FalseUnwind { unwind: Some(imaginary_target), .. }
            | TerminatorKind::FalseEdges { imaginary_target, .. } => imaginary_target == target,

            _ => false,
        }
    }
}
<commit_msg>Fix handling on InlineAsm for the unconditional recursion lint.<commit_after>use rustc_data_structures::graph::iterate::{
    ControlFlow, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
use rustc_span::Span;

crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: LocalDefId) {
    let hir_id = tcx.hir().as_local_hir_id(def_id);

    if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
        if let FnKind::Closure(_) = fn_like_node.kind() {
            // closures can't recur, so they don't matter.
            return;
        }

        // If this is trait/impl method, extract the trait's substs.
        let trait_substs = match tcx.opt_associated_item(def_id.to_def_id()) {
            Some(AssocItem {
                container: AssocItemContainer::TraitContainer(trait_def_id), ..
            }) => {
                let trait_substs_count = tcx.generics_of(*trait_def_id).count();
                &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count]
            }
            _ => &[],
        };

        let mut vis = Search { tcx, body, def_id, reachable_recursive_calls: vec![], trait_substs };
        if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
            return;
        }

        vis.reachable_recursive_calls.sort();

        let hir_id = tcx.hir().as_local_hir_id(def_id);
        let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span(hir_id));
        tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
            let mut db = lint.build("function cannot return without recursing");
            db.span_label(sp, "cannot return without recursing");
            // offer some help to the programmer.
            for call_span in vis.reachable_recursive_calls {
                db.span_label(call_span, "recursive call site");
            }
            db.help("a `loop` may express intention better if this is on purpose");
            db.emit();
        });
    }
}

struct NonRecursive;

struct Search<'mir, 'tcx> {
    tcx: TyCtxt<'tcx>,
    body: &'mir Body<'tcx>,
    def_id: LocalDefId,
    trait_substs: &'tcx [GenericArg<'tcx>],

    reachable_recursive_calls: Vec<Span>,
}

impl<'mir, 'tcx> Search<'mir, 'tcx> {
    /// Returns `true` if `func` refers to the function we are searching in.
    fn is_recursive_call(&self, func: &Operand<'tcx>) -> bool {
        let Search { tcx, body, def_id, trait_substs, .. } = *self;
        let param_env = tcx.param_env(def_id);

        let func_ty = func.ty(body, tcx);
        if let ty::FnDef(fn_def_id, substs) = func_ty.kind {
            let (call_fn_id, call_substs) =
                if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, fn_def_id, substs) {
                    (instance.def_id(), instance.substs)
                } else {
                    (fn_def_id, substs)
                };

            // FIXME(#57965): Make this work across function boundaries

            // If this is a trait fn, the substs on the trait have to match, or we might be
            // calling into an entirely different method (for example, a call from the default
            // method in the trait to `<A as Trait<B>>::method`, where `A` and/or `B` are
            // specific types).
            return call_fn_id == def_id.to_def_id()
                && &call_substs[..trait_substs.len()] == trait_substs;
        }

        false
    }
}

impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
    type BreakVal = NonRecursive;

    fn node_examined(
        &mut self,
        bb: BasicBlock,
        prior_status: Option<NodeStatus>,
    ) -> ControlFlow<Self::BreakVal> {
        // Back-edge in the CFG (loop).
        if let Some(NodeStatus::Visited) = prior_status {
            return ControlFlow::Break(NonRecursive);
        }

        match self.body[bb].terminator().kind {
            // These terminators return control flow to the caller.
            TerminatorKind::Abort
            | TerminatorKind::GeneratorDrop
            | TerminatorKind::Resume
            | TerminatorKind::Return
            | TerminatorKind::Unreachable
            | TerminatorKind::Yield { .. } => ControlFlow::Break(NonRecursive),

            // A diverging InlineAsm is treated as non-recursing
            TerminatorKind::InlineAsm { destination, .. } => {
                if destination.is_some() {
                    ControlFlow::Continue
                } else {
                    ControlFlow::Break(NonRecursive)
                }
            }

            // These do not.
            TerminatorKind::Assert { .. }
            | TerminatorKind::Call { .. }
            | TerminatorKind::Drop { .. }
            | TerminatorKind::DropAndReplace { .. }
            | TerminatorKind::FalseEdges { .. }
            | TerminatorKind::FalseUnwind { .. }
            | TerminatorKind::Goto { .. }
            | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue,
        }
    }

    fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
        // When we examine a node for the last time, remember it if it is a recursive call.
        let terminator = self.body[bb].terminator();
        if let TerminatorKind::Call { func, .. } = &terminator.kind {
            if self.is_recursive_call(func) {
                self.reachable_recursive_calls.push(terminator.source_info.span);
            }
        }

        ControlFlow::Continue
    }

    fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
        // Don't traverse successors of recursive calls or false CFG edges.
        match self.body[bb].terminator().kind {
            TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func),

            TerminatorKind::FalseUnwind { unwind: Some(imaginary_target), .. }
            | TerminatorKind::FalseEdges { imaginary_target, .. } => imaginary_target == target,

            _ => false,
        }
    }
}
<|endoftext|>


<commit_before>//! Test runner.
//!
//! This module implements the `TestRunner` struct which manages executing tests as well as
//! scanning directories for tests.

use std::ffi::OsStr;
use std::path::PathBuf;
use std::error::Error;
use CommandResult;

pub struct TestRunner {
    // Directories that have not yet been scanned.
    dir_stack: Vec<PathBuf>,

    // Filenames of tests to run.
    test_list: Vec<PathBuf>,

    errors: usize,
}

impl TestRunner {
    /// Create a new blank TrstRunner.
    pub fn new() -> TestRunner {
        TestRunner {
            dir_stack: Vec::new(),
            test_list: Vec::new(),
            errors: 0,
        }
    }

    /// Add a directory path to be scanned later.
    ///
    /// If `dir` turns out to be a regular file, it is silently ignored.
    /// Otherwise, any problems reading the directory are reported.
    pub fn push_dir<P: Into<PathBuf>>(&mut self, dir: P) {
        self.dir_stack.push(dir.into());
    }

    /// Add a test to be executed later.
    ///
    /// Any problems reading `file` as a test case file will be reported as a test failure.
    pub fn push_test<P: Into<PathBuf>>(&mut self, file: P) {
        self.test_list.push(file.into());
    }

    /// Scan any directories pushed so far.
    /// Push any potential test cases found.
    pub fn scan_dirs(&mut self) {
        // This recursive search tries to minimize statting in a directory hierarchy containing
        // mostly test cases.
        //
        // - Directory entries with a "cton" extension are presumed to be test case files.
        // - Directory entries with no extension are presumed to be subdirectories.
        // - Anything else is ignored.
        //
        while let Some(dir) = self.dir_stack.pop() {
            match dir.read_dir() {
                Err(err) => {
                    // Fail silently if `dir` was actually a regular file.
                    // This lets us skip spurious extensionless files without statting everything
                    // needlessly.
                    if !dir.is_file() {
                        self.path_error(dir, err);
                    }
                }
                Ok(entries) => {
                    // Read all directory entries. Avoid statting.
                    for entry_result in entries {
                        match entry_result {
                            Err(err) => {
                                // Not sure why this would happen. `read_dir` succeeds, but there's
                                // a problem with an entry. I/O error during a getdirentries
                                // syscall seems to be the reason. The implementation in
                                // libstd/sys/unix/fs.rs seems to suggest that breaking now would
                                // be a good idea, or the iterator could keep returning the same
                                // error forever.
                                self.path_error(dir, err);
                                break;
                            }
                            Ok(entry) => {
                                let path = entry.path();
                                // Recognize directories and tests by extension.
                                // Yes, this means we ignore directories with '.' in their name.
                                match path.extension().and_then(OsStr::to_str) {
                                    Some("cton") => self.push_test(path),
                                    Some(_) => {}
                                    None => self.push_dir(path),
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /// Report an error related to a path.
    fn path_error<E: Error>(&mut self, path: PathBuf, err: E) {
        self.errors += 1;
        println!("path-error {}: {}", path.to_string_lossy(), err);
    }

    /// Scan pushed directories for tests and run them.
    pub fn run(&mut self) -> CommandResult {
        self.scan_dirs();
        match self.errors {
            0 => Ok(()),
            1 => Err("1 failure".to_string()),
            n => Err(format!("{} failures", n)),
        }
    }
}
<commit_msg>Add a job queue and begin loading test files.<commit_after>//! Test runner.
//!
//! This module implements the `TestRunner` struct which manages executing tests as well as
//! scanning directories for tests.

use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::error::Error;
use std::mem;
use std::panic::catch_unwind;
use std::time;
use CommandResult;
use utils::read_to_string;
use cton_reader::parse_test;

type TestResult = Result<time::Duration, String>;

#[derive(PartialEq, Eq, Debug)]
enum QueueEntry {
    New(PathBuf),
    Running,
    Done(PathBuf, TestResult),
}

pub struct TestRunner {
    // Directories that have not yet been scanned.
    dir_stack: Vec<PathBuf>,

    // Filenames of tests to run.
    tests: Vec<QueueEntry>,

    // Pointer into `tests` where the `New` entries begin.
    new_tests: usize,

    // Number of contiguous finished tests at the front of `tests`.
    finished_tests: usize,

    errors: usize,
}

impl TestRunner {
    /// Create a new blank TrstRunner.
    pub fn new() -> TestRunner {
        TestRunner {
            dir_stack: Vec::new(),
            tests: Vec::new(),
            new_tests: 0,
            finished_tests: 0,
            errors: 0,
        }
    }

    /// Add a directory path to be scanned later.
    ///
    /// If `dir` turns out to be a regular file, it is silently ignored.
    /// Otherwise, any problems reading the directory are reported.
    pub fn push_dir<P: Into<PathBuf>>(&mut self, dir: P) {
        self.dir_stack.push(dir.into());
    }

    /// Add a test to be executed later.
    ///
    /// Any problems reading `file` as a test case file will be reported as a test failure.
    pub fn push_test<P: Into<PathBuf>>(&mut self, file: P) {
        self.tests.push(QueueEntry::New(file.into()));
    }

    /// Take a new test for running as a job.
    /// Leaves the queue entry marked as `Runnning`.
    fn take_job(&mut self) -> Option<Job> {
        let index = self.new_tests;
        if index == self.tests.len() {
            return None;
        }
        self.new_tests += 1;

        let entry = mem::replace(&mut self.tests[index], QueueEntry::Running);
        if let QueueEntry::New(path) = entry {
            Some(Job::new(index, path))
        } else {
            // Oh, sorry about that. Put the entry back.
            self.tests[index] = entry;
            None
        }
    }

    /// Report the end of a job.
    fn finish_job(&mut self, job: Job, result: TestResult) {
        assert_eq!(self.tests[job.index], QueueEntry::Running);
        if let Err(ref e) = result {
            self.job_error(&job.path, e);
        }
        self.tests[job.index] = QueueEntry::Done(job.path, result);
        if job.index == self.finished_tests {
            while let Some(&QueueEntry::Done(_, _)) = self.tests.get(self.finished_tests) {
                self.finished_tests += 1;
            }
        }
    }

    /// Scan any directories pushed so far.
    /// Push any potential test cases found.
    pub fn scan_dirs(&mut self) {
        // This recursive search tries to minimize statting in a directory hierarchy containing
        // mostly test cases.
        //
        // - Directory entries with a "cton" extension are presumed to be test case files.
        // - Directory entries with no extension are presumed to be subdirectories.
        // - Anything else is ignored.
        //
        while let Some(dir) = self.dir_stack.pop() {
            match dir.read_dir() {
                Err(err) => {
                    // Fail silently if `dir` was actually a regular file.
                    // This lets us skip spurious extensionless files without statting everything
                    // needlessly.
                    if !dir.is_file() {
                        self.path_error(dir, err);
                    }
                }
                Ok(entries) => {
                    // Read all directory entries. Avoid statting.
                    for entry_result in entries {
                        match entry_result {
                            Err(err) => {
                                // Not sure why this would happen. `read_dir` succeeds, but there's
                                // a problem with an entry. I/O error during a getdirentries
                                // syscall seems to be the reason. The implementation in
                                // libstd/sys/unix/fs.rs seems to suggest that breaking now would
                                // be a good idea, or the iterator could keep returning the same
                                // error forever.
                                self.path_error(dir, err);
                                break;
                            }
                            Ok(entry) => {
                                let path = entry.path();
                                // Recognize directories and tests by extension.
                                // Yes, this means we ignore directories with '.' in their name.
                                match path.extension().and_then(OsStr::to_str) {
                                    Some("cton") => self.push_test(path),
                                    Some(_) => {}
                                    None => self.push_dir(path),
                                }
                            }
                        }
                    }
                }
            }
            // Get the new jobs running before moving on to the next directory.
            self.schedule_jobs();
        }
    }

    /// Report an error related to a path.
    fn path_error<E: Error>(&mut self, path: PathBuf, err: E) {
        self.errors += 1;
        println!("{}: {}", path.to_string_lossy(), err);
    }

    /// Report an error related to a job.
    fn job_error(&mut self, path: &Path, err: &str) {
        self.errors += 1;
        println!("FAIL {}: {}", path.to_string_lossy(), err);
    }

    /// Schedule and new jobs to run.
    fn schedule_jobs(&mut self) {
        while let Some(job) = self.take_job() {
            let result = job.run();
            self.finish_job(job, result);
        }
    }

    /// Scan pushed directories for tests and run them.
    pub fn run(&mut self) -> CommandResult {
        self.scan_dirs();
        self.schedule_jobs();
        match self.errors {
            0 => Ok(()),
            1 => Err("1 failure".to_string()),
            n => Err(format!("{} failures", n)),
        }
    }
}

/// A test file waiting to be run.
struct Job {
    index: usize,
    path: PathBuf,
}

impl Job {
    pub fn new(index: usize, path: PathBuf) -> Job {
        Job {
            index: index,
            path: path,
        }
    }

    pub fn run(&self) -> TestResult {
        match catch_unwind(|| self.run_or_panic()) {
            Err(msg) => Err(format!("panic: {:?}", msg)),
            Ok(result) => result,
        }
    }

    fn run_or_panic(&self) -> TestResult {
        let started = time::Instant::now();
        let buffer = try!(read_to_string(&self.path).map_err(|e| e.to_string()));
        let testfile = try!(parse_test(&buffer).map_err(|e| e.to_string()));
        if testfile.commands.is_empty() {
            return Err("no test commands found".to_string());
        }
        if testfile.functions.is_empty() {
            return Err("no functions found".to_string());
        }
        // TODO: Actually run the tests.
        Ok(started.elapsed())
    }
}
<|endoftext|>