<commit_before>use prelude::*;
use super::{CheckpointFormat};
use rw::{ReadBuffer, WriteBuffer};

use csv::{Writer as CsvWriter};
use densearray::{Reshape, ReshapeMut};

use rand::{Rng, thread_rng};
use rustc_serialize::{Encodable};
use std::cmp::{max, min};
use std::fmt::{Debug};
use std::fs::{File, create_dir_all};
use std::io::{Write};
use std::path::{Path, PathBuf};
use std::thread::{sleep};
use std::time::{Duration, Instant};

//pub mod adagrad;
pub mod adagrad_new;
//pub mod adam;
pub mod adam_new;
//pub mod rmsprop;
//pub mod sgd;
pub mod sgd_new;
//pub mod shared_sgd;
pub mod shared_sgd_new;

#[derive(Clone, Debug)]
pub struct CheckpointConfig {
  pub prefix:   PathBuf,
  pub trace:    bool,
}

pub struct CheckpointState {
  pub cfg:          CheckpointConfig,
  pub config_file:  Option<File>,
  pub train_file:   Option<CsvWriter<File>>,
  pub valid_file:   Option<CsvWriter<File>>,
  start_time:   Instant,
  lap_time:     Instant,
  elapsed_s:    f64,
}

impl CheckpointState {
  pub fn new(cfg: CheckpointConfig) -> CheckpointState {
    Self::with_fields(cfg, "iter,loss,accuracy,elapsed")
  }

  pub fn with_fields(cfg: CheckpointConfig, fields: &str) -> CheckpointState {
    let delay_s = thread_rng().gen_range(0, 2);
    let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
    sleep(Duration::new(delay_s, delay_ns));
    create_dir_all(&cfg.prefix).ok();
    loop {
      let mut lo_idx = Some(0);
      let mut hi_idx = None;
      let mut idx = 0;
      while lo_idx != hi_idx {
        match (lo_idx, hi_idx) {
          (Some(lo), None) => {
            idx = lo;
          }
          (Some(lo), Some(hi)) => {
            idx = (lo + hi) / 2;
          }
          _ => unreachable!(),
        }
        let mut config_path = PathBuf::from(&cfg.prefix);
        let mut config_filename = format!("config.{}", idx);
        config_path.push(&config_filename);
        if config_path.exists() {
          match (lo_idx, hi_idx) {
            (Some(lo), None) => {
              lo_idx = Some(lo + max(1, lo));
            }
            (Some(lo), Some(hi)) => {
              lo_idx = Some(min(hi, max(lo + 1, idx)));
            }
            _ => unreachable!(),
          }
        } else {
          match (lo_idx, hi_idx) {
            (Some(_), None) => {
              lo_idx = Some(idx / 2);
              hi_idx = Some(idx);
            }
            (Some(_), Some(_)) => {
              hi_idx = Some(idx);
            }
            _ => unreachable!(),
          }
        }
      }
      idx = hi_idx.unwrap();

      let delay_s = thread_rng().gen_range(0, 2);
      let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
      sleep(Duration::new(delay_s, delay_ns));
      let mut cfg_f = None;
      let mut trace_f = None;
      let mut valid_f = None;
      let mut config_path = PathBuf::from(&cfg.prefix);
      let mut config_filename = format!("config.{}", idx);
      config_path.push(&config_filename);
      if config_path.exists() {
        continue;
      }
      match File::create(&config_path) {
        Err(_) => {
          continue;
        }
        Ok(f) => {
          cfg_f = Some(f);
        }
      }
      if cfg.trace {
        let mut train_path = PathBuf::from(&cfg.prefix);
        let mut train_filename = format!("train.log.{}", idx);
        train_path.push(&train_filename);
        assert!(!train_path.exists());
        let mut f = File::create(&train_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        trace_f = Some(f);

        let mut valid_path = PathBuf::from(&cfg.prefix);
        let mut valid_filename = format!("valid.log.{}", idx);
        valid_path.push(&valid_filename);
        assert!(!valid_path.exists());
        let mut f = File::create(&valid_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        valid_f = Some(f);
      }
      let init_time = Instant::now();
      return CheckpointState{
        cfg:          cfg,
        config_file:  cfg_f,
        train_file:   trace_f.map(|f| CsvWriter::from_writer(f)),
        valid_file:   valid_f.map(|f| CsvWriter::from_writer(f)),
        start_time:   init_time,
        lap_time:     init_time,
        elapsed_s:    0.0,
      };
    }
  }

  pub fn start_timing(&mut self) {
    self.start_time = Instant::now();
  }

  pub fn stop_timing(&mut self) {
    self.lap_time = Instant::now();
    let duration = self.lap_time - self.start_time;
    self.elapsed_s = duration.as_secs() as f64 + 1.0e-9 * duration.subsec_nanos() as f64;
  }

  pub fn elapsed(&self) -> f64 {
    self.elapsed_s
  }

  pub fn append_config_info<U>(&mut self, info: &U) where U: Debug {
    if let Some(ref mut config_file) = self.config_file {
      writeln!(config_file, "{:?}", info).unwrap();
    }
  }

  pub fn append_class_stats_train(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_train_info(&stats.to_record(elapsed));
  }

  pub fn append_train_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut train_file) = self.train_file {
      train_file.encode(rec).unwrap();
      train_file.flush().unwrap();
    }
  }

  pub fn append_class_stats_valid(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_valid_info(&stats.to_record(elapsed));
  }

  pub fn append_valid_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut valid_file) = self.valid_file {
      valid_file.encode(rec).unwrap();
      valid_file.flush().unwrap();
    }
  }
}

pub trait TraceRecord {
  fn loss(&self) -> f32;
  fn other(&self) -> f32;
}

#[derive(Clone, Debug)]
pub enum StepSize {
  Constant(f32),
  Custom{init_step: f32, steps: Vec<(usize, f32)>},
  Decay{init_step: f32, step_decay: f32, decay_iters: usize},
  Adaptive{init_step: f32, test_iters: usize, epoch_iters: usize, sched: AdaptiveStepSizeSchedule},
  BacktrackingLineSearch{decay: f32, c: f32},
  //WeakWolfeLineSearch,
}

#[derive(Clone, Copy, Debug)]
pub enum AdaptiveStepSizeSchedule {
  Pow10,
  Decimal,
}

pub fn adaptive_pow10_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 2] = [0.3,    0.1];
  const F2: [f32; 2] = [0.03,   0.01];
  const F3: [f32; 2] = [0.003,  0.001];
  const F4: [f32; 2] = [0.0003, 0.0001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 2 {
    F1[t-1]
  } else if t > 2 && t <= 4 {
    F2[t-2-1]
  } else if t > 4 && t <= 6 {
    F3[t-4-1]
  } else if t > 6 && t <= 8 {
    F4[t-6-1]
  } else {
    unimplemented!();
  }
}

pub fn adaptive_decimal_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 9] = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1];
  const F2: [f32; 9] = [0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01];
  const F3: [f32; 9] = [0.009, 0.008, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 9 {
    F1[t-1]
  } else if t > 9 && t <= 18 {
    F2[t-9-1]
  } else if t > 18 && t <= 27 {
    F3[t-18-1]
  } else {
    unimplemented!();
  }
}

#[derive(Clone, Copy, Debug)]
pub enum GradientMomentum {
  HeavyBall(f32),
  Nesterov(f32),
}

#[derive(Clone, Copy, Debug)]
pub enum NesterovParamState {
  Orig,
  PlusMomentum,
}

#[derive(Clone, Copy, Debug)]
pub struct StepStats {
  pub elapsed:  Option<f64>,
}

pub trait OptWorker<T, S> {
  type Rng: Rng;

  //fn init_param(&mut self, rng: &mut Xorshiftplus128Rng);
  fn init_param(&mut self, rng: &mut Self::Rng);
  /*fn load_local_param(&mut self, param_reader: &mut ReadBuffer<T>);
  fn store_local_param(&mut self, param_writer: &mut WriteBuffer<T>);
  fn store_global_param(&mut self, param_writer: &mut WriteBuffer<T>);*/

  fn step(&mut self, samples: &mut Iterator<Item=S>) /* -> StepStats*/;
  fn eval(&mut self, epoch_size: usize, samples: &mut Iterator<Item=S>);
}

pub trait OptCheckpoint<Format> where Format: CheckpointFormat {
  fn save_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
  fn restore_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
}

pub trait OptStats<Stats> {
  fn reset_opt_stats(&mut self);
  fn get_opt_stats(&self) -> &Stats;
}

pub trait OptUpdateStats<Stats> {
  fn update_stats(&mut self, stats: &mut Stats);
}

#[derive(Clone, Default, Debug)]
pub struct ClassOptStats {
  pub iter_count:       usize,
  pub sample_count:     usize,
  pub correct_count:    usize,
  pub avg_loss:         f32,
}

impl ClassOptStats {
  pub fn reset(&mut self) {
    self.iter_count = 0;
    self.sample_count = 0;
    self.correct_count = 0;
    self.avg_loss = 0.0;
  }

  pub fn accuracy(&self) -> f32 {
    self.correct_count as f32 / self.sample_count as f32
  }
}

#[derive(Clone, Default, Debug)]
pub struct RegressOptStats {
  pub avg_loss:         f32,
}
<commit_msg>Flush the config log for good measure.<commit_after>use prelude::*;
use super::{CheckpointFormat};
use rw::{ReadBuffer, WriteBuffer};

use csv::{Writer as CsvWriter};
use densearray::{Reshape, ReshapeMut};

use rand::{Rng, thread_rng};
use rustc_serialize::{Encodable};
use std::cmp::{max, min};
use std::fmt::{Debug};
use std::fs::{File, create_dir_all};
use std::io::{Write};
use std::path::{Path, PathBuf};
use std::thread::{sleep};
use std::time::{Duration, Instant};

//pub mod adagrad;
pub mod adagrad_new;
//pub mod adam;
pub mod adam_new;
//pub mod rmsprop;
//pub mod sgd;
pub mod sgd_new;
//pub mod shared_sgd;
pub mod shared_sgd_new;

#[derive(Clone, Debug)]
pub struct CheckpointConfig {
  pub prefix:   PathBuf,
  pub trace:    bool,
}

pub struct CheckpointState {
  pub cfg:          CheckpointConfig,
  pub config_file:  Option<File>,
  pub train_file:   Option<CsvWriter<File>>,
  pub valid_file:   Option<CsvWriter<File>>,
  start_time:   Instant,
  lap_time:     Instant,
  elapsed_s:    f64,
}

impl CheckpointState {
  pub fn new(cfg: CheckpointConfig) -> CheckpointState {
    Self::with_fields(cfg, "iter,loss,accuracy,elapsed")
  }

  pub fn with_fields(cfg: CheckpointConfig, fields: &str) -> CheckpointState {
    let delay_s = thread_rng().gen_range(0, 2);
    let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
    sleep(Duration::new(delay_s, delay_ns));
    create_dir_all(&cfg.prefix).ok();
    loop {
      let mut lo_idx = Some(0);
      let mut hi_idx = None;
      let mut idx = 0;
      while lo_idx != hi_idx {
        match (lo_idx, hi_idx) {
          (Some(lo), None) => {
            idx = lo;
          }
          (Some(lo), Some(hi)) => {
            idx = (lo + hi) / 2;
          }
          _ => unreachable!(),
        }
        let mut config_path = PathBuf::from(&cfg.prefix);
        let mut config_filename = format!("config.{}", idx);
        config_path.push(&config_filename);
        if config_path.exists() {
          match (lo_idx, hi_idx) {
            (Some(lo), None) => {
              lo_idx = Some(lo + max(1, lo));
            }
            (Some(lo), Some(hi)) => {
              lo_idx = Some(min(hi, max(lo + 1, idx)));
            }
            _ => unreachable!(),
          }
        } else {
          match (lo_idx, hi_idx) {
            (Some(_), None) => {
              lo_idx = Some(idx / 2);
              hi_idx = Some(idx);
            }
            (Some(_), Some(_)) => {
              hi_idx = Some(idx);
            }
            _ => unreachable!(),
          }
        }
      }
      idx = hi_idx.unwrap();

      let delay_s = thread_rng().gen_range(0, 2);
      let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
      sleep(Duration::new(delay_s, delay_ns));
      let mut cfg_f = None;
      let mut trace_f = None;
      let mut valid_f = None;
      let mut config_path = PathBuf::from(&cfg.prefix);
      let mut config_filename = format!("config.{}", idx);
      config_path.push(&config_filename);
      if config_path.exists() {
        continue;
      }
      match File::create(&config_path) {
        Err(_) => {
          continue;
        }
        Ok(f) => {
          cfg_f = Some(f);
        }
      }
      if cfg.trace {
        let mut train_path = PathBuf::from(&cfg.prefix);
        let mut train_filename = format!("train.log.{}", idx);
        train_path.push(&train_filename);
        assert!(!train_path.exists());
        let mut f = File::create(&train_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        trace_f = Some(f);

        let mut valid_path = PathBuf::from(&cfg.prefix);
        let mut valid_filename = format!("valid.log.{}", idx);
        valid_path.push(&valid_filename);
        assert!(!valid_path.exists());
        let mut f = File::create(&valid_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        valid_f = Some(f);
      }
      let init_time = Instant::now();
      return CheckpointState{
        cfg:          cfg,
        config_file:  cfg_f,
        train_file:   trace_f.map(|f| CsvWriter::from_writer(f)),
        valid_file:   valid_f.map(|f| CsvWriter::from_writer(f)),
        start_time:   init_time,
        lap_time:     init_time,
        elapsed_s:    0.0,
      };
    }
  }

  pub fn start_timing(&mut self) {
    self.start_time = Instant::now();
  }

  pub fn stop_timing(&mut self) {
    self.lap_time = Instant::now();
    let duration = self.lap_time - self.start_time;
    self.elapsed_s = duration.as_secs() as f64 + 1.0e-9 * duration.subsec_nanos() as f64;
  }

  pub fn elapsed(&self) -> f64 {
    self.elapsed_s
  }

  pub fn append_config_info<U>(&mut self, info: &U) where U: Debug {
    if let Some(ref mut config_file) = self.config_file {
      writeln!(config_file, "{:?}", info).unwrap();
      config_file.flush().unwrap();
    }
  }

  pub fn append_class_stats_train(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_train_info(&stats.to_record(elapsed));
  }

  pub fn append_train_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut train_file) = self.train_file {
      train_file.encode(rec).unwrap();
      train_file.flush().unwrap();
    }
  }

  pub fn append_class_stats_valid(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_valid_info(&stats.to_record(elapsed));
  }

  pub fn append_valid_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut valid_file) = self.valid_file {
      valid_file.encode(rec).unwrap();
      valid_file.flush().unwrap();
    }
  }
}

pub trait TraceRecord {
  fn loss(&self) -> f32;
  fn other(&self) -> f32;
}

#[derive(Clone, Debug)]
pub enum StepSize {
  Constant(f32),
  Custom{init_step: f32, steps: Vec<(usize, f32)>},
  Decay{init_step: f32, step_decay: f32, decay_iters: usize},
  Adaptive{init_step: f32, test_iters: usize, epoch_iters: usize, sched: AdaptiveStepSizeSchedule},
  BacktrackingLineSearch{decay: f32, c: f32},
  //WeakWolfeLineSearch,
}

#[derive(Clone, Copy, Debug)]
pub enum AdaptiveStepSizeSchedule {
  Pow10,
  Decimal,
}

pub fn adaptive_pow10_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 2] = [0.3,    0.1];
  const F2: [f32; 2] = [0.03,   0.01];
  const F3: [f32; 2] = [0.003,  0.001];
  const F4: [f32; 2] = [0.0003, 0.0001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 2 {
    F1[t-1]
  } else if t > 2 && t <= 4 {
    F2[t-2-1]
  } else if t > 4 && t <= 6 {
    F3[t-4-1]
  } else if t > 6 && t <= 8 {
    F4[t-6-1]
  } else {
    unimplemented!();
  }
}

pub fn adaptive_decimal_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 9] = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1];
  const F2: [f32; 9] = [0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01];
  const F3: [f32; 9] = [0.009, 0.008, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 9 {
    F1[t-1]
  } else if t > 9 && t <= 18 {
    F2[t-9-1]
  } else if t > 18 && t <= 27 {
    F3[t-18-1]
  } else {
    unimplemented!();
  }
}

#[derive(Clone, Copy, Debug)]
pub enum GradientMomentum {
  HeavyBall(f32),
  Nesterov(f32),
}

#[derive(Clone, Copy, Debug)]
pub enum NesterovParamState {
  Orig,
  PlusMomentum,
}

#[derive(Clone, Copy, Debug)]
pub struct StepStats {
  pub elapsed:  Option<f64>,
}

pub trait OptWorker<T, S> {
  type Rng: Rng;

  //fn init_param(&mut self, rng: &mut Xorshiftplus128Rng);
  fn init_param(&mut self, rng: &mut Self::Rng);
  /*fn load_local_param(&mut self, param_reader: &mut ReadBuffer<T>);
  fn store_local_param(&mut self, param_writer: &mut WriteBuffer<T>);
  fn store_global_param(&mut self, param_writer: &mut WriteBuffer<T>);*/

  fn step(&mut self, samples: &mut Iterator<Item=S>) /* -> StepStats*/;
  fn eval(&mut self, epoch_size: usize, samples: &mut Iterator<Item=S>);
}

pub trait OptCheckpoint<Format> where Format: CheckpointFormat {
  fn save_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
  fn restore_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
}

pub trait OptStats<Stats> {
  fn reset_opt_stats(&mut self);
  fn get_opt_stats(&self) -> &Stats;
}

pub trait OptUpdateStats<Stats> {
  fn update_stats(&mut self, stats: &mut Stats);
}

#[derive(Clone, Default, Debug)]
pub struct ClassOptStats {
  pub iter_count:       usize,
  pub sample_count:     usize,
  pub correct_count:    usize,
  pub avg_loss:         f32,
}

impl ClassOptStats {
  pub fn reset(&mut self) {
    self.iter_count = 0;
    self.sample_count = 0;
    self.correct_count = 0;
    self.avg_loss = 0.0;
  }

  pub fn accuracy(&self) -> f32 {
    self.correct_count as f32 / self.sample_count as f32
  }
}

#[derive(Clone, Default, Debug)]
pub struct RegressOptStats {
  pub avg_loss:         f32,
}
<|endoftext|>


<commit_before>extern crate getopts;

use file::File;
use column::{Column, Permissions, FileName, FileSize, User, Group, HardLinks, Inode, Blocks};
use std::ascii::StrAsciiExt;
use term;

pub enum SortField {
    Name, Extension, Size
}

impl SortField {
    fn from_word(word: String) -> SortField {
        match word.as_slice() {
            "name" => Name,
            "size" => Size,
            "ext"  => Extension,
            _      => fail!("Invalid sorting order"),
        }
    }
}

pub enum View {
    Details(Vec<Column>),
    Lines,
    Grid(bool, uint),
}

pub struct Options {
    pub show_invisibles: bool,
    pub sort_field: SortField,
    pub reverse: bool,
    pub dirs: Vec<String>,
    pub view: View,
    pub header: bool,
}

impl Options {
    pub fn getopts(args: Vec<String>) -> Result<Options, getopts::Fail_> {
        let opts = [
            getopts::optflag("1", "oneline", "display one entry per line"),
            getopts::optflag("a", "all", "show dot-files"),
            getopts::optflag("b", "binary", "use binary prefixes in file sizes"),
            getopts::optflag("g", "group", "show group as well as user"),
            getopts::optflag("h", "header", "show a header row at the top"),
            getopts::optflag("H", "links", "show number of hard links"),
            getopts::optflag("l", "long", "display extended details and attributes"),
            getopts::optflag("i", "inode", "show each file's inode number"),
            getopts::optflag("r", "reverse", "reverse order of files"),
            getopts::optopt("s", "sort", "field to sort by", "WORD"),
            getopts::optflag("S", "blocks", "show number of file system blocks"),
            getopts::optflag("x", "across", "sort multi-column view entries across"),
        ];

        match getopts::getopts(args.tail(), opts) {
            Err(f) => Err(f),
            Ok(matches) => Ok(Options {
                show_invisibles: matches.opt_present("all"),
                reverse: matches.opt_present("reverse"),
                header: matches.opt_present("header"),
                sort_field: matches.opt_str("sort").map(|word| SortField::from_word(word)).unwrap_or(Name),
                dirs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
                view: Options::view(matches),
            })
        }
    }

    fn view(matches: getopts::Matches) -> View {
        if matches.opt_present("long") {
            Details(Options::columns(matches))
        }
        else if matches.opt_present("oneline") {
            Lines
        }
        else {
            let (console_width, _) = term::dimensions().unwrap_or((80, 24));
            Grid(matches.opt_present("across"), console_width)
        }
    }

    fn columns(matches: getopts::Matches) -> Vec<Column> {
        let mut columns = vec![];

        if matches.opt_present("inode") {
            columns.push(Inode);
        }

        columns.push(Permissions);

        if matches.opt_present("links") {
            columns.push(HardLinks);
        }

        columns.push(FileSize(matches.opt_present("binary")));

        if matches.opt_present("blocks") {
            columns.push(Blocks);
        }

        columns.push(User);

        if matches.opt_present("group") {
            columns.push(Group);
        }

        columns.push(FileName);

        return columns;
    }

    fn should_display(&self, f: &File) -> bool {
        if self.show_invisibles {
            true
        } else {
            !f.name.as_slice().starts_with(".")
        }
    }

    pub fn transform_files<'a>(&self, unordered_files: &'a Vec<File<'a>>) -> Vec<&'a File<'a>> {
        let mut files: Vec<&'a File<'a>> = unordered_files.iter()
            .filter(|&f| self.should_display(f))
            .collect();

        match self.sort_field {
            Name => files.sort_by(|a, b| a.parts.cmp(&b.parts)),
            Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)),
            Extension => files.sort_by(|a, b| {
                let exts = a.ext.clone().map(|e| e.as_slice().to_ascii_lower()).cmp(&b.ext.clone().map(|e| e.as_slice().to_ascii_lower()));
                let names = a.name.as_slice().to_ascii_lower().cmp(&b.name.as_slice().to_ascii_lower());
                exts.cmp(&names)
            }),
        }

        if self.reverse {
            files.reverse();
        }

        return files;
    }
}
<commit_msg>Use one-line view when output is not to a terminal<commit_after>extern crate getopts;

use file::File;
use column::{Column, Permissions, FileName, FileSize, User, Group, HardLinks, Inode, Blocks};
use std::ascii::StrAsciiExt;
use term;

pub enum SortField {
    Name, Extension, Size
}

impl SortField {
    fn from_word(word: String) -> SortField {
        match word.as_slice() {
            "name" => Name,
            "size" => Size,
            "ext"  => Extension,
            _      => fail!("Invalid sorting order"),
        }
    }
}

pub enum View {
    Details(Vec<Column>),
    Lines,
    Grid(bool, uint),
}

pub struct Options {
    pub show_invisibles: bool,
    pub sort_field: SortField,
    pub reverse: bool,
    pub dirs: Vec<String>,
    pub view: View,
    pub header: bool,
}

impl Options {
    pub fn getopts(args: Vec<String>) -> Result<Options, getopts::Fail_> {
        let opts = [
            getopts::optflag("1", "oneline", "display one entry per line"),
            getopts::optflag("a", "all", "show dot-files"),
            getopts::optflag("b", "binary", "use binary prefixes in file sizes"),
            getopts::optflag("g", "group", "show group as well as user"),
            getopts::optflag("h", "header", "show a header row at the top"),
            getopts::optflag("H", "links", "show number of hard links"),
            getopts::optflag("l", "long", "display extended details and attributes"),
            getopts::optflag("i", "inode", "show each file's inode number"),
            getopts::optflag("r", "reverse", "reverse order of files"),
            getopts::optopt("s", "sort", "field to sort by", "WORD"),
            getopts::optflag("S", "blocks", "show number of file system blocks"),
            getopts::optflag("x", "across", "sort multi-column view entries across"),
        ];

        match getopts::getopts(args.tail(), opts) {
            Err(f) => Err(f),
            Ok(matches) => Ok(Options {
                show_invisibles: matches.opt_present("all"),
                reverse: matches.opt_present("reverse"),
                header: matches.opt_present("header"),
                sort_field: matches.opt_str("sort").map(|word| SortField::from_word(word)).unwrap_or(Name),
                dirs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
                view: Options::view(matches),
            })
        }
    }

    fn view(matches: getopts::Matches) -> View {
        if matches.opt_present("long") {
            Details(Options::columns(matches))
        }
        else if matches.opt_present("oneline") {
            Lines
        }
        else {
            match term::dimensions() {
                None => Lines,
                Some((width, _)) => Grid(matches.opt_present("across"), width),
            }
        }
    }

    fn columns(matches: getopts::Matches) -> Vec<Column> {
        let mut columns = vec![];

        if matches.opt_present("inode") {
            columns.push(Inode);
        }

        columns.push(Permissions);

        if matches.opt_present("links") {
            columns.push(HardLinks);
        }

        columns.push(FileSize(matches.opt_present("binary")));

        if matches.opt_present("blocks") {
            columns.push(Blocks);
        }

        columns.push(User);

        if matches.opt_present("group") {
            columns.push(Group);
        }

        columns.push(FileName);

        return columns;
    }

    fn should_display(&self, f: &File) -> bool {
        if self.show_invisibles {
            true
        } else {
            !f.name.as_slice().starts_with(".")
        }
    }

    pub fn transform_files<'a>(&self, unordered_files: &'a Vec<File<'a>>) -> Vec<&'a File<'a>> {
        let mut files: Vec<&'a File<'a>> = unordered_files.iter()
            .filter(|&f| self.should_display(f))
            .collect();

        match self.sort_field {
            Name => files.sort_by(|a, b| a.parts.cmp(&b.parts)),
            Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)),
            Extension => files.sort_by(|a, b| {
                let exts = a.ext.clone().map(|e| e.as_slice().to_ascii_lower()).cmp(&b.ext.clone().map(|e| e.as_slice().to_ascii_lower()));
                let names = a.name.as_slice().to_ascii_lower().cmp(&b.name.as_slice().to_ascii_lower());
                exts.cmp(&names)
            }),
        }

        if self.reverse {
            files.reverse();
        }

        return files;
    }
}
<|endoftext|>


<commit_before>//! Common ReQL data types

use std::net::IpAddr;
use std::collections::HashMap;

use DateTime;
use serde_json::Value;
use uuid::Uuid;

/// Status returned by a write command
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct WriteStatus {
    pub inserted: u32,
    pub replaced: u32,
    pub unchanged: u32,
    pub skipped: u32,
    pub deleted: u32,
    pub errors: u32,
    pub first_error: Option<String>,
    pub generated_keys: Option<Vec<Uuid>>,
    pub warnings: Option<Vec<String>>,
    pub changes: Option<Value>,
}

/// Structure of data in `cluster_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ClusterConfig {
    pub id: String,
    pub heartbeat_timeout_secs: u32,
}

/// Structure of data in `current_issues` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CurrentIssue {
}

/// Structure of data in `db_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DbConfig {
}

/// Structure of data in `jobs` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Job {
}

/// Structure of data in `logs` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Log {
}

/// Structure of data in `permissions` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Permission {
}

/// Structure of data in `server_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServerConfig {
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CanonicalAddress {
    pub host: IpAddr,
    pub port: u32,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Network {
    pub canonical_addresses: Vec<CanonicalAddress>,
    pub cluster_port: u32,
    pub connected_to: HashMap<String, bool>,
    pub hostname: String,
    pub http_admin_port: u32,
    pub reql_port: u32,
    pub time_connected: DateTime,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Process {
    pub argv: Vec<String>,
    pub cache_size_mb: f64,
    pub pid: u64,
    pub time_started: DateTime,
    pub version: String,
}

/// Structure of data in `server_status` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServerStatus {
    pub id: Uuid,
    pub name: String,
    pub network: Network,
    pub process: Process,
}

/// Structure of data in `cluster_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Stat {
}

/// Structure of data in `cluster_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TableConfig {
}

/// Structure of data in `table_status` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TableStatus {
}

/// Structure of data in `uses` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct User {
}
<commit_msg>Add changes struct<commit_after>//! Common ReQL data types

use std::net::IpAddr;
use std::collections::HashMap;

use DateTime;
use serde::Deserialize;
use serde_json::Value;
use uuid::Uuid;

/// Status returned by a write command
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct WriteStatus {
    pub inserted: u32,
    pub replaced: u32,
    pub unchanged: u32,
    pub skipped: u32,
    pub deleted: u32,
    pub errors: u32,
    pub first_error: Option<String>,
    pub generated_keys: Option<Vec<Uuid>>,
    pub warnings: Option<Vec<String>>,
    pub changes: Option<Value>,
}

/// Structure of data in `cluster_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ClusterConfig {
    pub id: String,
    pub heartbeat_timeout_secs: u32,
}

/// Structure of data in `current_issues` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CurrentIssue {
}

/// Structure of data in `db_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DbConfig {
}

/// Structure of data in `jobs` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Job {
}

/// Structure of data in `logs` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Log {
}

/// Structure of data in `permissions` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Permission {
}

/// Structure of data in `server_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServerConfig {
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CanonicalAddress {
    pub host: IpAddr,
    pub port: u32,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Network {
    pub canonical_addresses: Vec<CanonicalAddress>,
    pub cluster_port: u32,
    pub connected_to: HashMap<String, bool>,
    pub hostname: String,
    pub http_admin_port: u32,
    pub reql_port: u32,
    pub time_connected: DateTime,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Process {
    pub argv: Vec<String>,
    pub cache_size_mb: f64,
    pub pid: u64,
    pub time_started: DateTime,
    pub version: String,
}

/// Structure of data in `server_status` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServerStatus {
    pub id: Uuid,
    pub name: String,
    pub network: Network,
    pub process: Process,
}

/// Structure of data in `cluster_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Stat {
}

/// Structure of data in `cluster_config` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TableConfig {
}

/// Structure of data in `table_status` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TableStatus {
}

/// Structure of data in `uses` table
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct User {
}

#[derive(Deserialize, Debug, Clone)]
pub struct Change<O: Deserialize, N: Deserialize> {
    pub old_val: Option<O>,
    pub new_val: Option<N>,
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;
use std::borrow::BorrowMut;
use std::fmt;
use std::fmt::Display;
use std::cmp;

type Id = String;

/// Returns an `Id` with prefix `x` that is not in the set `vars`
fn fresh_var_like(x: &Id, vars: HashSet<Id>) -> Id {
    let mut suffix = 0;
    let mut result = x.clone();
    let len = result.len();
    loop {
        result.push_str(&suffix.to_string());

        if !vars.contains(&result) {
            return result;
        }

        suffix += 1;
        result.truncate(len);
    }
}

#[derive(Debug)]
pub enum EvaluationError {
    UnboundVariable(String),
    IllformedExpression,
}

impl fmt::Display for EvaluationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::EvaluationError::*;
        match *self {
            UnboundVariable(ref id) => write!(f, "Encountered unbound variable: {}", id),
            IllformedExpression => write!(f, "Illformed expression"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Type {
    Var(Id),
    Fun(Box<Type>, Box<Type>),
    Forall(Id, Box<Type>),
}

impl PartialEq for Type {
    /// Equality is defined as alpha-equivalence of types
    fn eq(&self, other: &Type) -> bool {
        use self::Type::*;

        match (self,other) {
            (&Var(ref x),&Var(ref y)) => {
                *x == *y
            },
            (&Fun(ref t1, ref t2),&Fun(ref t3, ref t4)) => {
                *t1 == *t3 && *t2 == *t4
            },
            (&Forall(ref A, ref t1),&Forall(ref B, ref t2)) => {
                t1.subst(&Var(B.clone()), &A) == **t2
            },
            _ => false,
        }
    }
}

impl Eq for Type { }

impl Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Var(ref x) => write!(f,"{}",x),
            Type::Fun(ref a, ref b) => write!(f,"({}) -> {}",a,b),
            Type::Forall(ref x, ref t) => write!(f,"(forall {}. {})", x, t),
        }
    }
}

impl Type {
    /// Returns the result of the capture avoiding substitution `self` {`t`/`X`}
    fn subst(&self, t: &Type, X: &str) -> Type {
        match *self {
            Type::Var(ref Y) => {
                if X == *Y {
                    t.clone()
                }
                else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.subst(t,X)), Box::new(t2.subst(t,X)))
            },
            Type::Forall(ref Y, ref tau) => {
                if X == *Y {
                    self.clone()
                }
                else {
                    let mut fvs = t.free_vars();
                    if fvs.contains(Y) {
                        let mut vars = self.vars();
                        vars.extend(fvs.drain());
                        vars.insert(String::from(X));
                        let fresh_id = fresh_var_like(Y, vars);
                        let renamed = self.rename(Y, &fresh_id);
                        renamed.subst(t, X)
                    }
                    else {
                        Type::Forall(Y.clone(), Box::new(tau.subst(t,X)))
                    }
                }
            },
        }
    }

    /// Returns an identical type with `var` renamed into `into`
    fn rename(&self, var: &str, into: &str) -> Type {
        match *self {
            Type::Var(ref X) => {
                if *X == var {
                    Type::Var(String::from(into))
                }
                else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.rename(var, into)),
                        Box::new(t2.rename(var,into)))
            },
            Type::Forall(ref X, ref tau) => {
                let binder = {
                    if *X == var {
                        String::from(into)
                    }
                    else {
                        X.clone()
                    }
                };
                Type::Forall(binder, Box::new(tau.rename(var, into)))
            },
        }
    }

    /// Returns a set the free variables contained in `self`
    fn free_vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut fvs = HashSet::new();
                fvs.insert(X.clone());
                fvs
            },
            Type::Fun(ref t1, ref t2) => {
                let mut fvs = t1.free_vars();
                let mut t2_fvs = t2.free_vars();
                fvs.extend(t2_fvs.drain());
                fvs
            }
            Type::Forall(ref X, ref t) => {
                let mut fvs = t.free_vars();
                fvs.remove(X);
                fvs
            }
        }
    }

    /// Returns a set containing all of the variables contained in `self`
    fn vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut vars = HashSet::new();
                vars.insert(X.clone());
                vars
            },
            Type::Fun(ref t1, ref t2) => {
                let mut vars = t1.vars();
                let mut t2_vars = t2.vars();
                vars.extend(t2_vars.drain());
                vars
            }
            Type::Forall(ref X, ref t) => {
                let mut vars = t.vars();
                vars.insert(X.clone());
                vars
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
    Var(Id),
    Lam(Id, Box<Type>, Box<Expr>),
    App(Box<Expr>, Box<Expr>),
    TLam(Id, Box<Expr>),
    TApp(Box<Expr>, Box<Type>),
    Let(Id, Box<Type>, Box<Expr>, Box<Expr>),
    TLet(Id, Box<Type>, Box<Expr>),
}

impl Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Var(ref x) => write!(f,"{}",x),
            Expr::Lam(ref x, ref t, ref e) => write!(f,"(\\{}:{}.{})",x,t,e),
            Expr::App(ref e1, ref e2) => write!(f,"({} {})",e1,e2),
            Expr::TLam(ref X, ref e) => write!(f,"(/\\{}.{})",X,e),
            Expr::TApp(ref e, ref t) => write!(f,"({} [{}])",e,t),
            Expr::Let(ref x, ref t, ref e1, ref e2) => write!(f,"(let {}:{} = {} in {})",x,t,e1,e2),
            Expr::TLet(ref X, ref t, ref e) => write!(f,"(Let {} = {} in {})",X,t,e),
        }
    }
}

impl Expr {
    fn eval(&self) -> Expr {
        unimplemented!()
    }

    fn subst(&self, e: &Expr, x: &str) -> Expr {
        match *self {
            Expr::Var(ref y) => {
                if x == *y {
                    e.clone()
                } else {
                    self.clone()
                }
            },
            Expr::Lam(ref y,ref t,ref e) => {
                if x == *y {
                    unimplemented!()
                }
                else {
                    unimplemented!()
                }
            },
            Expr::App(ref e1,ref e2) => unimplemented!(),
            Expr::TLam(ref X,ref e) => unimplemented!(),
            Expr::TApp(ref e,ref t) => unimplemented!(),
            Expr::Let(ref y,ref t,ref e1,ref e2) => unimplemented!(),
            Expr::TLet(ref X,ref t,ref e) => unimplemented!(),
        }
    }
}<commit_msg>Implement some of eval and the relevant substitutions functions<commit_after>use std::collections::HashMap;
use std::collections::HashSet;
use std::borrow::BorrowMut;
use std::fmt;
use std::fmt::Display;
use std::cmp;

type Id = String;

/// Returns an `Id` with prefix `x` that is not in the set `vars`
fn fresh_var_like(x: &Id, vars: HashSet<Id>) -> Id {
    let mut suffix = 0;
    let mut result = x.clone();
    let len = result.len();
    loop {
        result.push_str(&suffix.to_string());

        if !vars.contains(&result) {
            return result;
        }

        suffix += 1;
        result.truncate(len);
    }
}

#[derive(Debug)]
pub enum EvaluationError {
    UnboundVariable(String),
    IllformedExpression,
}

impl fmt::Display for EvaluationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::EvaluationError::*;
        match *self {
            UnboundVariable(ref id) => write!(f, "Encountered unbound variable: {}", id),
            IllformedExpression => write!(f, "Illformed expression"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Type {
    Var(Id),
    Fun(Box<Type>, Box<Type>),
    Forall(Id, Box<Type>),
}

impl PartialEq for Type {
    /// Equality is defined as alpha-equivalence of types
    fn eq(&self, other: &Type) -> bool {
        use self::Type::*;

        match (self,other) {
            (&Var(ref x),&Var(ref y)) => {
                *x == *y
            },
            (&Fun(ref t1, ref t2),&Fun(ref t3, ref t4)) => {
                *t1 == *t3 && *t2 == *t4
            },
            (&Forall(ref A, ref t1),&Forall(ref B, ref t2)) => {
                t1.subst(&Var(B.clone()), &A) == **t2
            },
            _ => false,
        }
    }
}

impl Eq for Type { }

impl Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Var(ref x) => write!(f,"{}",x),
            Type::Fun(ref a, ref b) => write!(f,"({}) -> {}",a,b),
            Type::Forall(ref x, ref t) => write!(f,"(forall {}. {})", x, t),
        }
    }
}

impl Type {
    /// Returns the result of the capture avoiding substitution `self` {`t`/`X`}
    fn subst(&self, t: &Type, X: &str) -> Type {
        match *self {
            Type::Var(ref Y) => {
                if X == *Y {
                    t.clone()
                } else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.subst(t,X)), Box::new(t2.subst(t,X)))
            },
            Type::Forall(ref Y, ref tau) => {
                if X == *Y {
                    self.clone()
                } else {
                    let mut fvs = t.free_vars();
                    if fvs.contains(Y) {
                        let mut vars = self.vars();
                        vars.extend(fvs.drain());
                        vars.insert(String::from(X));
                        let fresh_id = fresh_var_like(Y, vars);
                        let renamed = self.rename(Y, &fresh_id);
                        renamed.subst(t, X)
                    } else {
                        Type::Forall(Y.clone(), Box::new(tau.subst(t,X)))
                    }
                }
            },
        }
    }

    /// Returns an identical type with `var` renamed into `into`
    fn rename(&self, var: &str, into: &str) -> Type {
        match *self {
            Type::Var(ref X) => {
                if *X == var {
                    Type::Var(String::from(into))
                } else {
                    self.clone()
                }
            },
            Type::Fun(ref t1, ref t2) => {
                Type::Fun(Box::new(t1.rename(var, into)),
                        Box::new(t2.rename(var,into)))
            },
            Type::Forall(ref X, ref tau) => {
                let binder = {
                    if *X == var {
                        String::from(into)
                    } else {
                        X.clone()
                    }
                };
                Type::Forall(binder, Box::new(tau.rename(var, into)))
            },
        }
    }

    /// Returns a set the free variables contained in `self`
    fn free_vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut fvs = HashSet::new();
                fvs.insert(X.clone());
                fvs
            },
            Type::Fun(ref t1, ref t2) => {
                let mut fvs = t1.free_vars();
                let mut t2_fvs = t2.free_vars();
                fvs.extend(t2_fvs.drain());
                fvs
            }
            Type::Forall(ref X, ref t) => {
                let mut fvs = t.free_vars();
                fvs.remove(X);
                fvs
            }
        }
    }

    /// Returns a set containing all of the variables contained in `self`
    fn vars(&self) -> HashSet<Id> {
        match *self {
            Type::Var(ref X) => {
                let mut vars = HashSet::new();
                vars.insert(X.clone());
                vars
            },
            Type::Fun(ref t1, ref t2) => {
                let mut vars = t1.vars();
                let mut t2_vars = t2.vars();
                vars.extend(t2_vars.drain());
                vars
            }
            Type::Forall(ref X, ref t) => {
                let mut vars = t.vars();
                vars.insert(X.clone());
                vars
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
    Var(Id),
    Lam(Id, Box<Type>, Box<Expr>),
    App(Box<Expr>, Box<Expr>),
    TLam(Id, Box<Expr>),
    TApp(Box<Expr>, Box<Type>),
    Let(Id, Box<Type>, Box<Expr>, Box<Expr>),
    TLet(Id, Box<Type>, Box<Expr>),
}

impl Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Var(ref x) => write!(f,"{}",x),
            Expr::Lam(ref x, ref t, ref e) => write!(f,"(\\{}:{}.{})",x,t,e),
            Expr::App(ref e1, ref e2) => write!(f,"({} {})",e1,e2),
            Expr::TLam(ref X, ref e) => write!(f,"(/\\{}.{})",X,e),
            Expr::TApp(ref e, ref t) => write!(f,"({} [{}])",e,t),
            Expr::Let(ref x, ref t, ref e1, ref e2) => write!(f,"(let {}:{} = {} in {})",x,t,e1,e2),
            Expr::TLet(ref X, ref t, ref e) => write!(f,"(Let {} = {} in {})",X,t,e),
        }
    }
}

impl Expr {
    /// Returns the normal form of `self` under call-by-value semantics
    pub fn eval(&self) -> Result<Expr,EvaluationError> {
        match *self {
            Expr::Var(ref x) => {
                Err(EvaluationError::UnboundVariable(x.clone()))
            },
            Expr::Lam(_,_,_) | Expr::TLam(_,_) => Ok(self.clone()),
            Expr::App(ref e1, ref e2) => {
                let v1 = e1.eval()?;
                let v2 = e2.eval()?;
                if let Expr::Lam(x,t,e3) = v1 {
                    let new_expr = e3.subst(&v2, &x);
                    new_expr.eval()
                } else {
                    Err(EvaluationError::IllformedExpression)
                }
            },
            Expr::TApp(ref e, ref t) => {
                let v = e.eval()?;
                if let Expr::TLam(X,e) = v {
                    let new_expr = e.subst_type(t, &X);
                    new_expr.eval()
                } else {
                    Err(EvaluationError::IllformedExpression)
                }
            },
            Expr::Let(ref x, ref t, ref e1, ref e2) => {
                Expr::App(
                    Box::new(Expr::Lam(
                        x.clone(),
                        t.clone(),
                        e2.clone())),
                    e1.clone()).eval()
            },
            Expr::TLet(ref X, ref t, ref e) => {
                Expr::TApp(
                    Box::new(Expr::TLam(
                        X.clone(),
                        e.clone())),
                    t.clone()).eval()
            },
        }
    }

    /// Returns the result of the capture avoiding substitution `self` {`e`/`x`}
    fn subst(&self, e: &Expr, x: &str) -> Expr {
        match *self {
            Expr::Var(ref y) => {
                if x == *y {
                    e.clone()
                } else {
                    self.clone()
                }
            },
            Expr::Lam(ref y,ref t,ref e1) => {
                if x == *y {
                    self.clone()
                } else {
                    // TODO: check freshness
                    unimplemented!()
                }
            },
            Expr::App(ref e1,ref e2) => {
                Expr::App(Box::new(e1.subst(e,x)), Box::new(e2.subst(e,x)))
            },
            Expr::TLam(ref X,ref e1) => {
                Expr::TLam(X.clone(), Box::new(e1.subst(e,x)))
            },
            Expr::TApp(ref e1,ref t) => {
                Expr::TApp(Box::new(e1.subst(e,x)), t.clone())
            },
            Expr::Let(ref y,ref t,ref e1,ref e2) => {
                // Unclear
                unimplemented!()
            },
            Expr::TLet(ref X,ref t,ref e1) => {
                Expr::TLet(X.clone(), t.clone(), Box::new(e1.subst(e,x)))
            },
        }
    }

    fn subst_type(&self, to: &Type, from: &str) -> Expr {
        match *self {
            Expr::Var(ref y) => {
                self.clone()
            },
            Expr::Lam(ref y,ref t,ref e1) => {
                let new_t = t.subst(to, from);
                Expr::Lam(y.clone(), Box::new(new_t), Box::new(e1.subst_type(to,from)))
            },
            Expr::App(ref e1,ref e2) => {
                Expr::App(Box::new(e1.subst_type(to,from)), Box::new(e2.subst_type(to,from)))
            },
            Expr::TLam(ref X,ref e1) => {
                if *X == from {
                    self.clone()
                } else {
                    // FIXME: Do I need to worry about the fvs of `to` here?
                    Expr::TLam(X.clone(), Box::new(e1.subst_type(to,from)))
                }
            },
            Expr::TApp(ref e1,ref t) => {
                let new_t = t.subst(to, from);
                let new_e1 = e1.subst_type(to, from);
                Expr::TApp(Box::new(new_e1), Box::new(new_t))
            },
            Expr::Let(ref y,ref t,ref e1,ref e2) => {
                unimplemented!()
            },
            Expr::TLet(ref X,ref t,ref e1) => {
                unimplemented!()
            },
        }
    }
}<|endoftext|>


<commit_before>mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

use chrono::Duration;
use chrono::prelude::*;
use std::error::Error;
use std::fmt;
use util::Rounding;

#[derive(Debug)]
pub enum ParseError {
    PE(grammar::ParseError),
    Overflow,
    Hour,
    Minute,
    Second,
    Nanosecond,
}

impl From<grammar::ParseError> for ParseError {
    fn from(err: grammar::ParseError) -> ParseError {
        ParseError::PE(err)
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::PE(ref err) => err.description(),
            ParseError::Overflow => "Invalid input",
            ParseError::Hour => "The specified hours is invalid",
            ParseError::Minute => "The specified minutes is invalid",
            ParseError::Second => "The specified seconds is invalid",
            ParseError::Nanosecond => "The specified nanoseconds is invalid",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            ParseError::PE(ref err) => Some(err as &Error),
            _ => None,
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::PE(ref err) => fmt::Display::fmt(err, f),
            _ => fmt::Display::fmt(self.description(), f),
        }
    }
}

pub fn parse_rounding(fmt: &str) -> Result<Rounding, ParseError> {
    let res = try!(grammar::rounding(fmt));
    return Ok(res);
}

pub fn parse_offset(offset: &str,
                    time: DateTime<FixedOffset>)
                    -> Result<DateTime<FixedOffset>, ParseError> {
    let offset = try!(grammar::offset(offset));
    let offset = Duration::seconds(offset as i64);
    time.checked_add_signed(offset).ok_or(ParseError::Overflow)

}

#[allow(dead_code)] // This function may go away if I don't find a use for it soon
pub fn parse_time(input: &str,
                  time: DateTime<FixedOffset>)
                  -> Result<DateTime<FixedOffset>, ParseError> {
    let (hour, minute, second) = try!(grammar::time(input));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));
    Ok(time)
}

pub fn parse_datetime(input: &str,
                      time: DateTime<FixedOffset>)
                      -> Result<DateTime<FixedOffset>, ParseError> {
    let (year, month, day, hour, minute, second, tz) =
        try!(grammar::datetime(input));

    let year = year.unwrap_or(time.year());
    let month = month.unwrap_or(time.month());
    let day = day.unwrap_or(time.day());

    // set timezone
    let tz = tz.unwrap_or(time.offset().utc_minus_local());
    let tzo = FixedOffset::west(tz);
    let time = tzo.ymd(year, month, day);

    // set the time
    let time = time.and_hms(0, 0, 0);
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));
    Ok(time)
}

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

    #[test]
    fn parse_rounding_test() {
        assert_eq!(parse_rounding("+1D").unwrap(), Rounding::Up(86400.0));
        assert_eq!(parse_rounding("-1d").unwrap(), Rounding::Down(86400.0));
        assert_eq!(parse_rounding("=1d").unwrap(), Rounding::Half(86400.0));

        assert_eq!(parse_rounding("+1H").unwrap(), Rounding::Up(3600.0));
        assert_eq!(parse_rounding("-1h").unwrap(), Rounding::Down(3600.0));
        assert_eq!(parse_rounding("=1h").unwrap(), Rounding::Half(3600.0));

        assert_eq!(parse_rounding("+30M").unwrap(), Rounding::Up(1800.0));
        assert_eq!(parse_rounding("-30m").unwrap(), Rounding::Down(1800.0));
        assert_eq!(parse_rounding("=30m").unwrap(), Rounding::Half(1800.0));
        assert_eq!(parse_rounding("7.5").unwrap(), Rounding::Half(450.0));

        assert_eq!(parse_rounding("+30S").unwrap(), Rounding::Up(30.0));
        assert_eq!(parse_rounding("-30s").unwrap(), Rounding::Down(30.0));
        assert_eq!(parse_rounding("30s").unwrap(), Rounding::Half(30.0));
    }

    #[test]
    fn offset_test() {
        assert_eq!(grammar::offset("+2.3s").unwrap(), 2.3);
        assert_eq!(grammar::offset("-1.55h").unwrap(), -5580.0);
        assert_eq!(grammar::offset("+2:22").unwrap(), 8520.0);
        assert_eq!(grammar::offset("-2:22").unwrap(), -8520.0);
    }

    #[test]
    fn parse_offset_test() {
        let ctime = now();
        let n = ctime.checked_add_signed(Duration::seconds(5580)).unwrap();
        assert_eq!(parse_offset("+1.55h", ctime).unwrap(), n);
    }

    #[test]
    fn time_test() {
        assert_eq!(grammar::time("09:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055").unwrap(), (9, 22, 32.055));
        assert_eq!(grammar::time("9:22:32 Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055Pm").unwrap(), (21, 22, 32.055));
        assert_eq!(grammar::time("9:22 Pm").unwrap(), (21, 22, 0.0));
        // Might want to fail on these someday
        assert_eq!(grammar::time("9:22:32. Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22: Pm").unwrap(), (21, 22, 0.0));
        assert_eq!(grammar::time("99:22:32").unwrap(), (99, 22, 32.0));
    }

    #[test]
    fn parse_time_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_time("9:22:31.9617 Pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_time("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }

    #[test]
    fn datetime_test() {
        assert_eq!(grammar::datetime("4/2 9:22 Pm").unwrap(),
                   (None, Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2 9:22 Pm").unwrap(),
                   (Some(2017), Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2").unwrap(),
                   (Some(2017), Some(4), Some(2), 0, 0, 0.0, None));
        assert_eq!(grammar::datetime("9:22 Pm").unwrap(),
                   (None, None, None, 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("12:24 Pm").unwrap(),
                   (None, None, None, 12, 24, 0.0, None));
    }

    #[test]
    fn parse_datetime_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("9:22:31.9617 Pm", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_datetime("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30 9:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T00:00:00-05:00");
        // 12pm == midnight bug
        assert_eq!(parse_datetime("12:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T12:24:00-05:00");
        assert_eq!(parse_datetime("1:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T13:24:00-05:00");
        assert_eq!(parse_datetime("1:24am", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T01:24:00-05:00");
    }

    #[test]
    #[should_panic(expected = "ParseError")]
    fn parse_datetime_seperator_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("2017-4-309:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }
}
<commit_msg>Handle invalid date input without panicking<commit_after>mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

use chrono::Duration;
use chrono::LocalResult;
use chrono::prelude::*;
use std::error::Error;
use std::fmt;
use util::Rounding;

#[derive(Debug)]
pub enum ParseError {
    PE(grammar::ParseError),
    Overflow,
    Hour,
    Minute,
    Second,
    Nanosecond,
    Date,
    Ambiguous,
}

impl From<grammar::ParseError> for ParseError {
    fn from(err: grammar::ParseError) -> ParseError {
        ParseError::PE(err)
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::PE(ref err) => err.description(),
            ParseError::Overflow => "Invalid input",
            ParseError::Hour => "The specified hours is invalid",
            ParseError::Minute => "The specified minutes is invalid",
            ParseError::Second => "The specified seconds is invalid",
            ParseError::Nanosecond => "The specified nanoseconds is invalid",
            ParseError::Date => "The specified date was invalid",
            ParseError::Ambiguous => "The specified date was ambiguous",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            ParseError::PE(ref err) => Some(err as &Error),
            _ => None,
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::PE(ref err) => fmt::Display::fmt(err, f),
            _ => fmt::Display::fmt(self.description(), f),
        }
    }
}

pub fn parse_rounding(fmt: &str) -> Result<Rounding, ParseError> {
    let res = try!(grammar::rounding(fmt));
    return Ok(res);
}

pub fn parse_offset(offset: &str,
                    time: DateTime<FixedOffset>)
                    -> Result<DateTime<FixedOffset>, ParseError> {
    let offset = try!(grammar::offset(offset));
    let offset = Duration::seconds(offset as i64);
    time.checked_add_signed(offset).ok_or(ParseError::Overflow)

}

#[allow(dead_code)] // This function may go away if I don't find a use for it soon
pub fn parse_time(input: &str,
                  time: DateTime<FixedOffset>)
                  -> Result<DateTime<FixedOffset>, ParseError> {
    let (hour, minute, second) = try!(grammar::time(input));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));
    Ok(time)
}

pub fn parse_datetime(input: &str,
                      time: DateTime<FixedOffset>)
                      -> Result<DateTime<FixedOffset>, ParseError> {
    let (year, month, day, hour, minute, second, tz) =
        try!(grammar::datetime(input));

    let year = year.unwrap_or(time.year());
    let month = month.unwrap_or(time.month());
    let day = day.unwrap_or(time.day());

    // set timezone
    let tz = tz.unwrap_or(time.offset().utc_minus_local());
    let tzo = FixedOffset::west(tz);
    let time = match tzo.ymd_opt(year, month, day) {
        LocalResult::None => return Err(ParseError::Date),
        LocalResult::Single(t) => t,
        LocalResult::Ambiguous(_, _) => return Err(ParseError::Ambiguous),
    };

    // set the time
    let time = time.and_hms(0, 0, 0);
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));

    Ok(time)
}

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

    #[test]
    fn parse_rounding_test() {
        assert_eq!(parse_rounding("+1D").unwrap(), Rounding::Up(86400.0));
        assert_eq!(parse_rounding("-1d").unwrap(), Rounding::Down(86400.0));
        assert_eq!(parse_rounding("=1d").unwrap(), Rounding::Half(86400.0));

        assert_eq!(parse_rounding("+1H").unwrap(), Rounding::Up(3600.0));
        assert_eq!(parse_rounding("-1h").unwrap(), Rounding::Down(3600.0));
        assert_eq!(parse_rounding("=1h").unwrap(), Rounding::Half(3600.0));

        assert_eq!(parse_rounding("+30M").unwrap(), Rounding::Up(1800.0));
        assert_eq!(parse_rounding("-30m").unwrap(), Rounding::Down(1800.0));
        assert_eq!(parse_rounding("=30m").unwrap(), Rounding::Half(1800.0));
        assert_eq!(parse_rounding("7.5").unwrap(), Rounding::Half(450.0));

        assert_eq!(parse_rounding("+30S").unwrap(), Rounding::Up(30.0));
        assert_eq!(parse_rounding("-30s").unwrap(), Rounding::Down(30.0));
        assert_eq!(parse_rounding("30s").unwrap(), Rounding::Half(30.0));
    }

    #[test]
    fn offset_test() {
        assert_eq!(grammar::offset("+2.3s").unwrap(), 2.3);
        assert_eq!(grammar::offset("-1.55h").unwrap(), -5580.0);
        assert_eq!(grammar::offset("+2:22").unwrap(), 8520.0);
        assert_eq!(grammar::offset("-2:22").unwrap(), -8520.0);
    }

    #[test]
    fn parse_offset_test() {
        let ctime = now();
        let n = ctime.checked_add_signed(Duration::seconds(5580)).unwrap();
        assert_eq!(parse_offset("+1.55h", ctime).unwrap(), n);
    }

    #[test]
    fn time_test() {
        assert_eq!(grammar::time("09:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055").unwrap(), (9, 22, 32.055));
        assert_eq!(grammar::time("9:22:32 Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055Pm").unwrap(), (21, 22, 32.055));
        assert_eq!(grammar::time("9:22 Pm").unwrap(), (21, 22, 0.0));
        // Might want to fail on these someday
        assert_eq!(grammar::time("9:22:32. Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22: Pm").unwrap(), (21, 22, 0.0));
        assert_eq!(grammar::time("99:22:32").unwrap(), (99, 22, 32.0));
    }

    #[test]
    fn parse_time_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_time("9:22:31.9617 Pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_time("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }

    #[test]
    fn datetime_test() {
        assert_eq!(grammar::datetime("4/2 9:22 Pm").unwrap(),
                   (None, Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2 9:22 Pm").unwrap(),
                   (Some(2017), Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2").unwrap(),
                   (Some(2017), Some(4), Some(2), 0, 0, 0.0, None));
        assert_eq!(grammar::datetime("9:22 Pm").unwrap(),
                   (None, None, None, 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("12:24 Pm").unwrap(),
                   (None, None, None, 12, 24, 0.0, None));
    }

    #[test]
    fn parse_datetime_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("9:22:31.9617 Pm", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_datetime("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30 9:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T00:00:00-05:00");
        // 12pm == midnight bug
        assert_eq!(parse_datetime("12:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T12:24:00-05:00");
        assert_eq!(parse_datetime("1:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T13:24:00-05:00");
        assert_eq!(parse_datetime("1:24am", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T01:24:00-05:00");
    }

    #[test]
    #[should_panic(expected = "ParseError")]
    fn parse_datetime_seperator_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("2017-4-309:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }
}
<|endoftext|>


<commit_before>//! A collection of commonly used items that we recommend importing for ease of use.

pub use app::{App, LoopMode};
pub use color::named::*;
pub use event::SimpleWindowEvent::*;
pub use event::{Event, Key};
pub use frame::Frame;
pub use math::{Point2, Point3, Vector2, Vector3, vec1, vec2, vec3, vec4, pt1, pt2, pt3};
pub use math::prelude::*;
pub use window::Id as WindowId;
<commit_msg>Add PI and TAU to the prelude<commit_after>//! A collection of commonly used items that we recommend importing for ease of use.

pub use app::{App, LoopMode};
pub use color::named::*;
pub use event::SimpleWindowEvent::*;
pub use event::{Event, Key};
pub use frame::Frame;
pub use math::{Point2, Point3, Vector2, Vector3, vec1, vec2, vec3, vec4, pt1, pt2, pt3};
pub use math::prelude::*;
pub use window::Id as WindowId;

// The following constants have "regular" names for the `DefaultScalar` type and type suffixes for
// other types. If the `DefaultScalar` changes, these should probably change too.

pub use std::f32::consts::PI as PI;
pub use std::f64::consts::PI as PI_F64;

/// Two times PI.
pub const TAU: f32 = PI * 2.0;
/// Two times PI.
pub const TAU_F64: f64 = PI_F64 * 2.0;
<|endoftext|>


<commit_before>use std::path::PathBuf;

pub fn spawn(cmd: &str, updated_paths: Vec<PathBuf>) -> Process {
    self::imp::Process::new(cmd, updated_paths).expect("unable to spawn process")
}

pub use self::imp::Process;

#[cfg(target_family = "unix")]
mod imp {
    use libc::*;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;
    use std::sync::*;

    pub struct Process {
        pgid: pid_t,
        lock: Mutex<bool>,
        cvar: Condvar,
    }

    #[allow(unknown_lints)]
    #[allow(mutex_atomic)]
    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use nix::unistd::*;
            use std::fs::File;
            use std::io;
            use std::io::{Read, Write};
            use std::os::unix::io::FromRawFd;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            // command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
            // .spawn()
            // .and_then(|p| Ok(Process { pid: p.id() as i32 }))

            // Wait for child to call setpgid()
            // Else, we risk racing waitpid/killpg (mostly just in tests, but hey)
            let (r, w) = try!(pipe());

            match fork() {
                Ok(ForkResult::Parent { child, .. }) => {
                    {
                        let mut reader = unsafe { File::from_raw_fd(r) };
                        let mut buffer = vec![0];
                        let _ = reader.read_exact(&mut buffer);
                    }
                    let _ = close(w);

                    Ok(Process {
                        pgid: child,
                        lock: Mutex::new(false),
                        cvar: Condvar::new(),
                    })
                }
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);

                    {
                        let mut writer = unsafe { File::from_raw_fd(w) };
                        let _ = writer.write_all(&[42]);
                    }
                    let _ = close(r);

                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => Err(io::Error::from(e)),
            }
        }

        pub fn kill(&self) {
            self.signal(SIGKILL);
        }

        pub fn pause(&self) {
            self.signal(SIGTSTP);
        }

        pub fn reap(&self) {
            use nix::sys::wait::*;

            let mut finished = true;
            loop {
                match waitpid(-self.pgid, Some(WNOHANG)) {
                    Ok(WaitStatus::Exited(_, _)) |
                    Ok(WaitStatus::Signaled(_, _, _)) => finished = finished && true,
                    Ok(_) => finished = false,
                    Err(_) => break,
                }
            }

            if finished {
                let mut done = self.lock.lock().unwrap();
                *done = true;
                self.cvar.notify_one();
            }
        }

        pub fn resume(&self) {
            self.signal(SIGCONT);
        }

        fn signal(&self, sig: c_int) {
            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, sig);
            }

        }

        pub fn terminate(&self) {
            self.signal(SIGTERM);
        }

        pub fn wait(&self) {
            let mut done = self.lock.lock().unwrap();
            while !*done {
                done = self.cvar.wait(done).unwrap();
            }
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            self.terminate();
        }

        pub fn pause(&self) {}

        pub fn reap(&self) {}

        pub fn resume(&self) {}

        pub fn terminate(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::{Path, PathBuf};

    use mktemp::Temp;

    use super::spawn;
    use super::get_longest_common_path;

    fn file_contents(path: &Path) -> String {
        use std::fs::File;
        use std::io::Read;

        let mut f = File::open(path).unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        s
    }

    #[test]
    fn test_start() {
        let _ = spawn("echo hi", vec![]);
    }

    #[test]
    fn test_wait() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();
        let process = spawn(&format!("echo hi > {}", path.to_str().unwrap()), vec![]);
        process.wait();

        assert!(file_contents(&path).starts_with("hi"));
    }

    #[test]
    fn test_kill() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();

        let process = spawn(&format!("sleep 20; echo hi > {}", path.to_str().unwrap()),
                            vec![]);
        process.kill();
        process.wait();

        assert!(file_contents(&path) == "");
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<commit_msg>Fix reap() hanging when child processes are still running<commit_after>use std::path::PathBuf;

pub fn spawn(cmd: &str, updated_paths: Vec<PathBuf>) -> Process {
    self::imp::Process::new(cmd, updated_paths).expect("unable to spawn process")
}

pub use self::imp::Process;

#[cfg(target_family = "unix")]
mod imp {
    use libc::*;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;
    use std::sync::*;

    pub struct Process {
        pgid: pid_t,
        lock: Mutex<bool>,
        cvar: Condvar,
    }

    #[allow(unknown_lints)]
    #[allow(mutex_atomic)]
    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use nix::unistd::*;
            use std::fs::File;
            use std::io;
            use std::io::{Read, Write};
            use std::os::unix::io::FromRawFd;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            // command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
            // .spawn()
            // .and_then(|p| Ok(Process { pid: p.id() as i32 }))

            // Wait for child to call setpgid()
            // Else, we risk racing waitpid/killpg (mostly just in tests, but hey)
            let (r, w) = try!(pipe());

            match fork() {
                Ok(ForkResult::Parent { child, .. }) => {
                    {
                        let mut reader = unsafe { File::from_raw_fd(r) };
                        let mut buffer = vec![0];
                        let _ = reader.read_exact(&mut buffer);
                    }
                    let _ = close(w);

                    Ok(Process {
                        pgid: child,
                        lock: Mutex::new(false),
                        cvar: Condvar::new(),
                    })
                }
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);

                    {
                        let mut writer = unsafe { File::from_raw_fd(w) };
                        let _ = writer.write_all(&[42]);
                    }
                    let _ = close(r);

                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => Err(io::Error::from(e)),
            }
        }

        pub fn kill(&self) {
            self.signal(SIGKILL);
        }

        pub fn pause(&self) {
            self.signal(SIGTSTP);
        }

        pub fn reap(&self) {
            use nix::sys::wait::*;

            let mut finished = true;
            loop {
                match waitpid(-self.pgid, Some(WNOHANG)) {
                    Ok(WaitStatus::Exited(_, _)) |
                    Ok(WaitStatus::Signaled(_, _, _)) => finished = finished && true,
                    Ok(_) => {
                        finished = false;
                        break;
                    }
                    Err(_) => break,
                }
            }

            if finished {
                let mut done = self.lock.lock().unwrap();
                *done = true;
                self.cvar.notify_one();
            }
        }

        pub fn resume(&self) {
            self.signal(SIGCONT);
        }

        fn signal(&self, sig: c_int) {
            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, sig);
            }

        }

        pub fn terminate(&self) {
            self.signal(SIGTERM);
        }

        pub fn wait(&self) {
            let mut done = self.lock.lock().unwrap();
            while !*done {
                done = self.cvar.wait(done).unwrap();
            }
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            self.terminate();
        }

        pub fn pause(&self) {}

        pub fn reap(&self) {}

        pub fn resume(&self) {}

        pub fn terminate(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::{Path, PathBuf};

    use mktemp::Temp;

    use super::spawn;
    use super::get_longest_common_path;

    fn file_contents(path: &Path) -> String {
        use std::fs::File;
        use std::io::Read;

        let mut f = File::open(path).unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        s
    }

    #[test]
    fn test_start() {
        let _ = spawn("echo hi", vec![]);
    }

    #[test]
    fn test_wait() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();
        let process = spawn(&format!("echo hi > {}", path.to_str().unwrap()), vec![]);
        process.wait();

        assert!(file_contents(&path).starts_with("hi"));
    }

    #[test]
    fn test_kill() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();

        let process = spawn(&format!("sleep 20; echo hi > {}", path.to_str().unwrap()),
                            vec![]);
        process.kill();
        process.wait();

        assert!(file_contents(&path) == "");
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<|endoftext|>


<commit_before>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

pub struct JsonHeaderParser {
    spec: Option<FileHeaderSpec>,
}

impl JsonHeaderParser {

    pub fn new(spec: Option<FileHeaderSpec>) -> JsonHeaderParser {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            let btree = btree.clone();
            FileHeaderData::Map{
                keys: btree.into_iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k,
                        value: Box::new(visit_json(&v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<commit_msg>Fix JsonHeaderParser::serialize()<commit_after>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

pub struct JsonHeaderParser {
    spec: Option<FileHeaderSpec>,
}

impl JsonHeaderParser {

    pub fn new(spec: Option<FileHeaderSpec>) -> JsonHeaderParser {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            let btree = btree.clone();
            FileHeaderData::Map{
                keys: btree.into_iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k,
                        value: Box::new(visit_json(&v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => {
                let mut hm = HashMap::new();

                for key in ks {
                    if let &FileHeaderData::Key{name: ref n, value: ref v} = key {
                        hm.insert(n, v);
                    } else {
                        panic!("Not a key: {:?}", key);
                    }
                }

                hm.serialize(ser)
            },
            &FileHeaderData::Key{name: ref n, value: ref v} => unreachable!(),

        }
    }

}
<|endoftext|>