<commit_before>/*!

The simplest possible implementation of the TimeSteward API.

This implementation is unusably slow on large simulations. Its main use is to cross-check with other TimeSteward implementations to make sure they are implementing the API correctly.

*/

use super::{SiphashId, RowId, FieldId, Column, ExtendedTime, Basics, TimeSteward, FiatEventOperationResult, ValidSince};
use std::collections::{HashMap, BTreeMap};
// use std::collections::Bound::{Included, Excluded, Unbounded};
use std::any::Any;
use std::borrow::{Borrow, Cow};
use std::rc::Rc;

#[derive (Clone)]
// struct StewardState<'a, B: Basics + 'a> {
struct StewardState<B: Basics> {
  last_change: Option <ExtendedTime<B>>, // B::Time,
  field_states: HashMap<FieldId, Rc<Any>>,
  // fiat_events: BTreeMap<ExtendedTime<B>, Event<'a, B>>,
  fiat_events: BTreeMap<ExtendedTime<B>, Event<B>>,
}

struct StewardSettings<B: Basics> {
  predictors: Vec<Predictor<B>>,
  constants: B::Constants,
}
#[derive (Clone)]
pub struct Steward<B: Basics> {
  state: StewardState<B>,
  settings: Rc<StewardSettings<B>>,
}
type StewardImpl<B: Basics> = Steward<B>;
// pub struct Steward<'a, B: Basics + 'a> {
// steward: Cow<'a, StewardImpl<B>>,
// }
pub struct Snapshot<'a, B: Basics + 'a> {
  now: B::Time,
  steward: &'a StewardImpl<B>,
}
pub struct Mutator<'a, B: Basics + 'a> {
  now: B::Time,
  steward: &'a mut StewardImpl<B>,
}
pub struct PredictorAccessor<'a, B: Basics + 'a> {
  steward: &'a StewardImpl<B>,
  soonest_prediction: Option<(B::Time, Event<B>)>,
}
// pub type Event<'a, B: Basics + 'a> = super::Event<Mutator<'a, B>>;
pub type Event<B: Basics> = Rc<for<'d, 'e> Fn(&'d mut Mutator<'e, B>)>;
//type Prediction<B: Basics> = super::Prediction<B, Event<B>>;
// it seems impossible to write the lifetimes this way
// type Predictor<'a, B: Basics + 'a> = super::Predictor<B, Mutator<'a, B>, PredictorAccessor<'a, B>>;

pub type Predictor<B: Basics> = super::Predictor<PredictorFn<B>>;

type PredictorFn<B: Basics> = Rc<for<'b, 'c> Fn(&'b mut PredictorAccessor<'c, B>, RowId)>;
//type PredictorFn<B: Basics> = Rc<for<'b, 'c> Fn(&'b mut PredictorAccessor<'c, B>, RowId)
//                                              -> Prediction<B>>;
// -> Prediction<B, Event<B>>>;
// -> Prediction<B, Rc<for<'d, 'e> Fn(&'d mut Mutator<'e, B>)>>>;

impl<'a, B: Basics> super::Accessor<B> for Snapshot<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.steward.get::<C>(id)
  }
  fn constants(&self) -> &B::Constants {
    &self.steward.settings.constants
  }
}
impl<'a, B: Basics> super::Accessor<B> for Mutator<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.steward.get::<C>(id)
  }
  fn constants(&self) -> &B::Constants {
    &self.steward.settings.constants
  }
}
impl<'a, B: Basics> super::Accessor<B> for PredictorAccessor<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.steward.get::<C>(id)
  }
  fn constants(&self) -> &B::Constants {
    &self.steward.settings.constants
  }
}

impl<'a, B: Basics> super::MomentaryAccessor<B> for Snapshot<'a, B> {
  fn now(&self) -> &B::Time {
    &self.now
  }
}
impl<'a, B: Basics> super::MomentaryAccessor<B> for Mutator<'a, B> {
  fn now(&self) -> &B::Time {
    &self.now
  }
}
impl<'a, B: Basics> super::PredictorAccessor<B> for PredictorAccessor<'a, B> {
  type Event = Event<B>;
  fn predict_immediately(&mut self, event: Event<B>) {
    self.predict_at_time(&self.steward.state.last_change.as_ref().unwrap().base, event);
  }
  fn predict_at_time(&mut self, time: &B::Time, event: Event<B>) {
    if let Some((ref old_time, _)) = self.soonest_prediction {
      if old_time <= time {
        return;
      }
    }
    self.soonest_prediction = Some((time.clone(), event));
  }
}
impl<'a, B: Basics> super::Snapshot<B> for Snapshot<'a, B> {}

impl<'a, B: Basics> super::Mutator<B> for Mutator<'a, B> {
  /*fn get_mut<C: Column>(&mut self, id: RowId) -> Option<&mut C::FieldType>
    where C::FieldType: Clone
  {
    panic!("are we really doing this");
  }*/
  fn set<C: Column>(&mut self, id: RowId, data: Option<C::FieldType>) {
    self.steward.set_opt::<C>(id, data);
  }
  fn random_bits(&mut self, num_bits: u32) -> u64 {
    panic!("no randomness yet 1");
  }
  fn random_id(&mut self) -> SiphashId {
    panic!("no randomness yet 2");
  }
}

// https://github.com/rust-lang/rfcs/issues/1485
trait Filter<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self;
}
impl<T> Filter<T> for Option<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
    self.and_then(|x| if predicate(&x) {
      Some(x)
    } else {
      None
    })
  }
}

impl<B: Basics> StewardImpl<B> {
  fn get<C: Column>(&self, id: RowId) -> Option<&C::FieldType> {
    self.state
      .field_states
      .get(&FieldId {
        row_id: id,
        column_id: C::column_id(),
      })
      .map(|something| something.downcast_ref::<C::FieldType>().unwrap().borrow())
  }
  fn set<C: Column>(&mut self, id: RowId, value: C::FieldType) {
    self.state
      .field_states
      .insert(FieldId {
                row_id: id,
                column_id: C::column_id(),
              },
              Rc::new(value));
  }
  fn remove<C: Column>(&mut self, id: RowId) {
    self.state
      .field_states
      .remove(&FieldId {
        row_id: id,
        column_id: C::column_id(),
      });
  }
  fn set_opt<C: Column>(&mut self, id: RowId, value_opt: Option<C::FieldType>) {
    if let Some(value) = value_opt {
      self.set::<C>(id, value);
    } else {
      self.remove::<C>(id);
    }
  }

  fn next_event(&self) -> Option<(ExtendedTime<B>, Event<B>)> {
    let first_fiat_event_iter =
    // range is unstable
    // https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
    // and cannot be enabled in stable rustc
    // https://stackoverflow.com/questions/30975088/use-of-unstable-library-feature-how-can-i-fix-those
    // so use something else...
    //  self.state.fiat_events.range(Excluded(&self.state.last_change), Unbounded).next();
      self.state.fiat_events.iter().map(|ev| (ev.0.clone(), ev.1.clone()));
    let predicted_events_iter = self.settings
      .predictors
      .iter()
      .flat_map(|predictor|
      // TODO change field_states
      // to separate by field type, for efficiency,
      // like the haskell does?
      self.state.field_states.keys().filter_map(move |field_id|
        if field_id.column_id != predictor.column_id {
          None
        } else {
          let mut pa = PredictorAccessor{
              steward: self,
              soonest_prediction: None,
            };
          (predictor.function)(&mut pa, field_id.row_id);
          pa.soonest_prediction.and_then(|(event_base_time, event)|
            super::extended_time_of_predicted_event(
              predictor.predictor_id,
              field_id.row_id,
              event_base_time,
              &self.state.last_change.as_ref().unwrap()
            ).map(|event_time| (event_time, event)))}));
    let events_iter = first_fiat_event_iter.chain(predicted_events_iter);
    events_iter.min_by_key(|ev| ev.0.clone())
  }

  fn execute_event(&mut self, event_time: ExtendedTime<B>, event: Event<B>) {
    event(&mut Mutator {
      now: event_time.base.clone(),
      steward: &mut *self,
    });
    // if it was a fiat event, clean it up:
    self.state.fiat_events.remove(&event_time);
    self.state.last_change = Some (event_time);
  }

  fn move_to_future_time(&mut self, future_t: ExtendedTime<B>) {
    if let Some (ref time) = self.state.last_change {if future_t < *time {
      panic!("not defined for past times");
    }}
    while let Some(ev) = self.next_event().filter(|ev| ev.0 < future_t) {
      let (event_time, event) = ev;
      self.execute_event(event_time, event);
    }
  }
}

// impl<'a, B: Basics> Steward<'a, B> {
impl<B: Basics> Steward<B> {}
impl<'a, B: Basics + 'a> super::SnapshotHack<'a, B> for Steward<B> {
  type Snapshot = Snapshot<'a, B>;
}
impl<B: Basics> super::TimeSteward<B> for Steward<B> {
  type Event = Event<B>;
  type Predictor = Predictor<B>;

  fn valid_since (&self) -> ValidSince <B::Time> {
    match self.state.last_change {
      None => ValidSince::TheBeginning,
      Some (ref time) => ValidSince::After (time.base.clone()),
    }
  }
  fn new_empty (constants: B::Constants, predictors: Vec<Self::Predictor>) -> Self {
    StewardImpl {
      state: StewardState {
        last_change: None,
        field_states: HashMap::new(),
        fiat_events: BTreeMap::new(),
      },
      settings: Rc::new(StewardSettings {
        predictors: predictors,
        constants: constants,
      }),
    }
  }

  fn insert_fiat_event(&mut self,
  time: B::Time,
  distinguisher: u64,
  event: Self::Event)
  -> FiatEventOperationResult {
    unimplemented!();
  }
  fn erase_fiat_event(&mut self, time: B::Time, distinguisher: u64) -> FiatEventOperationResult {
    unimplemented!();
  }

  //fn snapshot_before<'a>(&'a mut self, time: B::Time) -> Option<Snapshot<'a, B>> {}

  fn snapshot_before<'a>(&'a mut self, time: B::Time) ->
  Option<<Self as super::SnapshotHack<'a, B>>::Snapshot>
  where Self: super::SnapshotHack<'a, B> {
    unimplemented!();
  }
}
<commit_msg>Unwrap->expect for better error messages<commit_after>/*!

The simplest possible implementation of the TimeSteward API.

This implementation is unusably slow on large simulations. Its main use is to cross-check with other TimeSteward implementations to make sure they are implementing the API correctly.

*/

use super::{SiphashId, RowId, FieldId, Column, ExtendedTime, Basics, TimeSteward, FiatEventOperationResult, ValidSince};
use std::collections::{HashMap, BTreeMap};
// use std::collections::Bound::{Included, Excluded, Unbounded};
use std::any::Any;
use std::borrow::{Borrow, Cow};
use std::rc::Rc;

#[derive (Clone)]
// struct StewardState<'a, B: Basics + 'a> {
struct StewardState<B: Basics> {
  last_change: Option <ExtendedTime<B>>, // B::Time,
  field_states: HashMap<FieldId, Rc<Any>>,
  // fiat_events: BTreeMap<ExtendedTime<B>, Event<'a, B>>,
  fiat_events: BTreeMap<ExtendedTime<B>, Event<B>>,
}

struct StewardSettings<B: Basics> {
  predictors: Vec<Predictor<B>>,
  constants: B::Constants,
}
#[derive (Clone)]
pub struct Steward<B: Basics> {
  state: StewardState<B>,
  settings: Rc<StewardSettings<B>>,
}
type StewardImpl<B: Basics> = Steward<B>;
// pub struct Steward<'a, B: Basics + 'a> {
// steward: Cow<'a, StewardImpl<B>>,
// }
pub struct Snapshot<'a, B: Basics + 'a> {
  now: B::Time,
  steward: &'a StewardImpl<B>,
}
pub struct Mutator<'a, B: Basics + 'a> {
  now: B::Time,
  steward: &'a mut StewardImpl<B>,
}
pub struct PredictorAccessor<'a, B: Basics + 'a> {
  steward: &'a StewardImpl<B>,
  soonest_prediction: Option<(B::Time, Event<B>)>,
}
// pub type Event<'a, B: Basics + 'a> = super::Event<Mutator<'a, B>>;
pub type Event<B: Basics> = Rc<for<'d, 'e> Fn(&'d mut Mutator<'e, B>)>;
//type Prediction<B: Basics> = super::Prediction<B, Event<B>>;
// it seems impossible to write the lifetimes this way
// type Predictor<'a, B: Basics + 'a> = super::Predictor<B, Mutator<'a, B>, PredictorAccessor<'a, B>>;

pub type Predictor<B: Basics> = super::Predictor<PredictorFn<B>>;

type PredictorFn<B: Basics> = Rc<for<'b, 'c> Fn(&'b mut PredictorAccessor<'c, B>, RowId)>;
//type PredictorFn<B: Basics> = Rc<for<'b, 'c> Fn(&'b mut PredictorAccessor<'c, B>, RowId)
//                                              -> Prediction<B>>;
// -> Prediction<B, Event<B>>>;
// -> Prediction<B, Rc<for<'d, 'e> Fn(&'d mut Mutator<'e, B>)>>>;

impl<'a, B: Basics> super::Accessor<B> for Snapshot<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.steward.get::<C>(id)
  }
  fn constants(&self) -> &B::Constants {
    &self.steward.settings.constants
  }
}
impl<'a, B: Basics> super::Accessor<B> for Mutator<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.steward.get::<C>(id)
  }
  fn constants(&self) -> &B::Constants {
    &self.steward.settings.constants
  }
}
impl<'a, B: Basics> super::Accessor<B> for PredictorAccessor<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.steward.get::<C>(id)
  }
  fn constants(&self) -> &B::Constants {
    &self.steward.settings.constants
  }
}

impl<'a, B: Basics> super::MomentaryAccessor<B> for Snapshot<'a, B> {
  fn now(&self) -> &B::Time {
    &self.now
  }
}
impl<'a, B: Basics> super::MomentaryAccessor<B> for Mutator<'a, B> {
  fn now(&self) -> &B::Time {
    &self.now
  }
}
impl<'a, B: Basics> super::PredictorAccessor<B> for PredictorAccessor<'a, B> {
  type Event = Event<B>;
  fn predict_immediately(&mut self, event: Event<B>) {
    self.predict_at_time(&self.steward.state.last_change.as_ref().expect("how can we be calling a predictor when there are no fields yet?").base, event);
  }
  fn predict_at_time(&mut self, time: &B::Time, event: Event<B>) {
    if let Some((ref old_time, _)) = self.soonest_prediction {
      if old_time <= time {
        return;
      }
    }
    self.soonest_prediction = Some((time.clone(), event));
  }
}
impl<'a, B: Basics> super::Snapshot<B> for Snapshot<'a, B> {}

impl<'a, B: Basics> super::Mutator<B> for Mutator<'a, B> {
  /*fn get_mut<C: Column>(&mut self, id: RowId) -> Option<&mut C::FieldType>
    where C::FieldType: Clone
  {
    panic!("are we really doing this");
  }*/
  fn set<C: Column>(&mut self, id: RowId, data: Option<C::FieldType>) {
    self.steward.set_opt::<C>(id, data);
  }
  fn random_bits(&mut self, num_bits: u32) -> u64 {
    panic!("no randomness yet 1");
  }
  fn random_id(&mut self) -> SiphashId {
    panic!("no randomness yet 2");
  }
}

// https://github.com/rust-lang/rfcs/issues/1485
trait Filter<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self;
}
impl<T> Filter<T> for Option<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
    self.and_then(|x| if predicate(&x) {
      Some(x)
    } else {
      None
    })
  }
}

impl<B: Basics> StewardImpl<B> {
  fn get<C: Column>(&self, id: RowId) -> Option<&C::FieldType> {
    self.state
      .field_states
      .get(&FieldId {
        row_id: id,
        column_id: C::column_id(),
      })
      .map(|something| something.downcast_ref::<C::FieldType>().expect("a field had the wrong type for its column").borrow())
  }
  fn set<C: Column>(&mut self, id: RowId, value: C::FieldType) {
    self.state
      .field_states
      .insert(FieldId {
                row_id: id,
                column_id: C::column_id(),
              },
              Rc::new(value));
  }
  fn remove<C: Column>(&mut self, id: RowId) {
    self.state
      .field_states
      .remove(&FieldId {
        row_id: id,
        column_id: C::column_id(),
      });
  }
  fn set_opt<C: Column>(&mut self, id: RowId, value_opt: Option<C::FieldType>) {
    if let Some(value) = value_opt {
      self.set::<C>(id, value);
    } else {
      self.remove::<C>(id);
    }
  }

  fn next_event(&self) -> Option<(ExtendedTime<B>, Event<B>)> {
    let first_fiat_event_iter =
    // range is unstable
    // https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
    // and cannot be enabled in stable rustc
    // https://stackoverflow.com/questions/30975088/use-of-unstable-library-feature-how-can-i-fix-those
    // so use something else...
    //  self.state.fiat_events.range(Excluded(&self.state.last_change), Unbounded).next();
      self.state.fiat_events.iter().map(|ev| (ev.0.clone(), ev.1.clone()));
    let predicted_events_iter = self.settings
      .predictors
      .iter()
      .flat_map(|predictor|
      // TODO change field_states
      // to separate by field type, for efficiency,
      // like the haskell does?
      self.state.field_states.keys().filter_map(move |field_id|
        if field_id.column_id != predictor.column_id {
          None
        } else {
          let mut pa = PredictorAccessor{
              steward: self,
              soonest_prediction: None,
            };
          (predictor.function)(&mut pa, field_id.row_id);
          pa.soonest_prediction.and_then(|(event_base_time, event)|
            super::extended_time_of_predicted_event(
              predictor.predictor_id,
              field_id.row_id,
              event_base_time,
              &self.state.last_change.as_ref().expect ("how can we be calling a predictor when there are no fields yet?")
            ).map(|event_time| (event_time, event)))}));
    let events_iter = first_fiat_event_iter.chain(predicted_events_iter);
    events_iter.min_by_key(|ev| ev.0.clone())
  }

  fn execute_event(&mut self, event_time: ExtendedTime<B>, event: Event<B>) {
    event(&mut Mutator {
      now: event_time.base.clone(),
      steward: &mut *self,
    });
    // if it was a fiat event, clean it up:
    self.state.fiat_events.remove(&event_time);
    self.state.last_change = Some (event_time);
  }

  fn move_to_future_time(&mut self, future_t: ExtendedTime<B>) {
    if let Some (ref time) = self.state.last_change {if future_t < *time {
      panic!("not defined for past times");
    }}
    while let Some(ev) = self.next_event().filter(|ev| ev.0 < future_t) {
      let (event_time, event) = ev;
      self.execute_event(event_time, event);
    }
  }
}

// impl<'a, B: Basics> Steward<'a, B> {
impl<B: Basics> Steward<B> {}
impl<'a, B: Basics + 'a> super::SnapshotHack<'a, B> for Steward<B> {
  type Snapshot = Snapshot<'a, B>;
}
impl<B: Basics> super::TimeSteward<B> for Steward<B> {
  type Event = Event<B>;
  type Predictor = Predictor<B>;

  fn valid_since (&self) -> ValidSince <B::Time> {
    match self.state.last_change {
      None => ValidSince::TheBeginning,
      Some (ref time) => ValidSince::After (time.base.clone()),
    }
  }
  fn new_empty (constants: B::Constants, predictors: Vec<Self::Predictor>) -> Self {
    StewardImpl {
      state: StewardState {
        last_change: None,
        field_states: HashMap::new(),
        fiat_events: BTreeMap::new(),
      },
      settings: Rc::new(StewardSettings {
        predictors: predictors,
        constants: constants,
      }),
    }
  }

  fn insert_fiat_event(&mut self,
  time: B::Time,
  distinguisher: u64,
  event: Self::Event)
  -> FiatEventOperationResult {
    unimplemented!();
  }
  fn erase_fiat_event(&mut self, time: B::Time, distinguisher: u64) -> FiatEventOperationResult {
    unimplemented!();
  }

  //fn snapshot_before<'a>(&'a mut self, time: B::Time) -> Option<Snapshot<'a, B>> {}

  fn snapshot_before<'a>(&'a mut self, time: B::Time) ->
  Option<<Self as super::SnapshotHack<'a, B>>::Snapshot>
  where Self: super::SnapshotHack<'a, B> {
    unimplemented!();
  }
}
<|endoftext|>


<commit_before>#![feature(fs_walk)]
#![feature(slice_patterns)]

extern crate rustc_serialize;
extern crate time;
extern crate eve;

use std::env;
use std::fs::{OpenOptions, walk_dir};
use std::io::prelude::*;
use rustc_serialize::json::{ToJson, Json};

use eve::server::*;
use eve::flow::*;
use eve::compiler::*;
use eve::value::*;

fn read_events(filename: &str) -> Vec<Event> {
    let mut events_string = String::new();
    {
        let mut events_file = OpenOptions::new().create(true).open(&filename).unwrap();
        events_file.read_to_string(&mut events_string).unwrap();
    }
    events_string.lines().map(|line|
        FromJson::from_json(&Json::from_str(&line).unwrap())
        ).collect()
}

fn write_events(filename: &str, events: &[Event]) {
    let mut new_events_file = OpenOptions::new().create(true).truncate(true).write(true).open(&filename).unwrap();
    for event in events.iter() {
        new_events_file.write_all(format!("{}", event.to_json()).as_bytes()).unwrap();
        new_events_file.write_all("\n".as_bytes()).unwrap();
    }
}

fn all_filenames() -> Vec<String> {
    let mut filenames = vec![];
    filenames.push("./autosave".to_owned());
    filenames.push("./bootstrap".to_owned());
    for entry in walk_dir("./test-inputs").unwrap() {
        filenames.push(entry.unwrap().path().to_str().unwrap().to_owned());
    }
    for entry in walk_dir("./test-outputs").unwrap() {
        filenames.push(entry.unwrap().path().to_str().unwrap().to_owned());
    }
    for entry in walk_dir("./examples").unwrap() {
        filenames.push(entry.unwrap().path().to_str().unwrap().to_owned());
    }
    filenames
}

fn remove_view(view: &str) {
    for filename in all_filenames() {
        let mut events = read_events(&filename[..]);
        for event in events.iter_mut() {
            event.changes.retain(|&(ref change_view, _)| change_view != view);
        }
        write_events(&filename[..], &events[..]);
    }
}

fn remove_row(view: &str, row: Vec<Value>) {
    for filename in all_filenames() {
        let mut events = read_events(&filename[..]);
        for event in events.iter_mut() {
            for &mut (ref change_view, ref mut change) in event.changes.iter_mut() {
                if change_view == view {
                    change.insert.retain(|insert_row| *insert_row != row)
                }
            }
        }
        write_events(&filename[..], &events[..]);
    }
}

fn reset_internal_views() {
    let compiler_schema = compiler_schema();
    let client_schema = client_schema();
    for filename in all_filenames() {
        let mut events = read_events(&filename[..]);
        for event in events.iter_mut() {
            event.changes.retain(|&(ref change_id, _)|
                !compiler_schema.iter().chain(client_schema.iter()).any(|&(ref id, _)| change_id == id)
                );
        }
        write_events(&filename[..], &events[..]);
    }
}

fn compact(filename: &str) {
    let bootstrap_events = read_events("./bootstrap");
    let events = read_events(&filename[..]);
    let mut flow = Flow::new();
    for event in bootstrap_events.into_iter().chain(events.into_iter()) {
        flow.quiesce(event.changes);
    }
    // TODO session is blank which doesn't seem to matter because it is never used
    write_events(&filename[..], &[Event{changes: flow.as_changes(), commands: vec![]}]);
}

fn make_bug_test() {
    let events = read_events("./autosave");
    let time = time::get_time().sec;
    let input_filename = format!("./test-inputs/bug-{}", time);
    let output_filename = format!("./test-outputs/bug-{}", time);
    write_events(&input_filename[..], &events[..]);
    write_events(&output_filename[..], &[]);
}

fn make_regression_test() {
    let bootstrap_events = read_events("./bootstrap");
    let events = read_events("./autosave");
    let mut flow = Flow::new();
    for event in bootstrap_events.into_iter().chain(events.into_iter()) {
        flow.quiesce(event.changes);
    }
    let time = time::get_time().sec;
    let input_filename = format!("./test-inputs/regression-{}", time);
    let output_filename = format!("./test-outputs/regression-{}", time);
    write_events(&input_filename[..], &[Event{changes: flow.as_changes(), commands: vec![]}]);
    write_events(&output_filename[..],  &[Event{changes: flow.as_changes(), commands: vec![]}]);
}

#[test]
fn test_examples() {
    let inputs = walk_dir("./test-inputs").unwrap().collect::<Vec<_>>();
    let outputs = walk_dir("./test-outputs").unwrap().collect::<Vec<_>>();
    assert_eq!(inputs.len(), outputs.len());
    for (input_entry, output_entry) in inputs.into_iter().zip(outputs.into_iter()) {
        let input_filename = input_entry.unwrap().path().to_str().unwrap().to_owned();
        let output_filename = output_entry.unwrap().path().to_str().unwrap().to_owned();
        println!("Testing {:?} against {:?}", input_filename, output_filename);

        let bootstrap_events = read_events("./bootstrap");
        let input_events = read_events(&input_filename[..]);
        let mut input_flow = Flow::new();
        for event in bootstrap_events.into_iter().chain(input_events.into_iter()) {
            input_flow.quiesce(event.changes);
        }

        let output_events = read_events(&output_filename[..]);
        let mut output_flow = Flow::new();
        for event in output_events.into_iter() {
            output_flow.change(event.changes);
        }

        let schema = schema();
        for output_cell in output_flow.outputs.iter() {
            let output = output_cell.borrow();
            // ignore internal views
            if !schema.iter().any(|&(ref id, _)| **id == *output.view) {
                let input = input_flow.get_output(&output.view[..]);
                assert_eq!((&output.view, &output.index), (&input.view, &input.index));
            }
        }
    }
}

#[allow(dead_code)]
fn main() {
    let args = env::args().collect::<Vec<String>>();
    let borrowed_args = args.iter().map(|s| &s[..]).collect::<Vec<&str>>();
    match &borrowed_args[..] {
        [_, "remove_view", view] => remove_view(view),
        [_, "remove_row", view, row] => remove_row(view, FromJson::from_json(&Json::from_str(&row).unwrap())),
        [_, "reset_internal_views"] => reset_internal_views(),
        [_, "compact", filename] => compact(filename),
        [_, "make_bug_test"] => make_bug_test(),
        [_, "make_regression_test"] => make_regression_test(),
        other => panic!("Bad arguments (look at src/bin/migrate.rs for correct usage): {:?}", &other[1..]),
    }
}
<commit_msg>Remove non-existing files from migrate<commit_after>#![feature(fs_walk)]
#![feature(slice_patterns)]

extern crate rustc_serialize;
extern crate time;
extern crate eve;

use std::env;
use std::fs::{OpenOptions, walk_dir};
use std::io::prelude::*;
use rustc_serialize::json::{ToJson, Json};

use eve::server::*;
use eve::flow::*;
use eve::compiler::*;
use eve::value::*;

fn read_events(filename: &str) -> Vec<Event> {
    let mut events_string = String::new();
    {
        let mut events_file = OpenOptions::new().create(true).open(&filename).unwrap();
        events_file.read_to_string(&mut events_string).unwrap();
    }
    events_string.lines().map(|line|
        FromJson::from_json(&Json::from_str(&line).unwrap())
        ).collect()
}

fn write_events(filename: &str, events: &[Event]) {
    let mut new_events_file = OpenOptions::new().create(true).truncate(true).write(true).open(&filename).unwrap();
    for event in events.iter() {
        new_events_file.write_all(format!("{}", event.to_json()).as_bytes()).unwrap();
        new_events_file.write_all("\n".as_bytes()).unwrap();
    }
}

fn all_filenames() -> Vec<String> {
    let mut filenames = vec![];
    filenames.push("./bootstrap".to_owned());
    for entry in walk_dir("./test-inputs").unwrap() {
        filenames.push(entry.unwrap().path().to_str().unwrap().to_owned());
    }
    for entry in walk_dir("./test-outputs").unwrap() {
        filenames.push(entry.unwrap().path().to_str().unwrap().to_owned());
    }
    filenames
}

fn remove_view(view: &str) {
    for filename in all_filenames() {
        let mut events = read_events(&filename[..]);
        for event in events.iter_mut() {
            event.changes.retain(|&(ref change_view, _)| change_view != view);
        }
        write_events(&filename[..], &events[..]);
    }
}

fn remove_row(view: &str, row: Vec<Value>) {
    for filename in all_filenames() {
        let mut events = read_events(&filename[..]);
        for event in events.iter_mut() {
            for &mut (ref change_view, ref mut change) in event.changes.iter_mut() {
                if change_view == view {
                    change.insert.retain(|insert_row| *insert_row != row)
                }
            }
        }
        write_events(&filename[..], &events[..]);
    }
}

fn reset_internal_views() {
    let compiler_schema = compiler_schema();
    let client_schema = client_schema();
    for filename in all_filenames() {
        let mut events = read_events(&filename[..]);
        for event in events.iter_mut() {
            event.changes.retain(|&(ref change_id, _)|
                !compiler_schema.iter().chain(client_schema.iter()).any(|&(ref id, _)| change_id == id)
                );
        }
        write_events(&filename[..], &events[..]);
    }
}

fn compact(filename: &str) {
    let bootstrap_events = read_events("./bootstrap");
    let events = read_events(&filename[..]);
    let mut flow = Flow::new();
    for event in bootstrap_events.into_iter().chain(events.into_iter()) {
        flow.quiesce(event.changes);
    }
    // TODO session is blank which doesn't seem to matter because it is never used
    write_events(&filename[..], &[Event{changes: flow.as_changes(), commands: vec![]}]);
}

fn make_bug_test() {
    let events = read_events("./autosave");
    let time = time::get_time().sec;
    let input_filename = format!("./test-inputs/bug-{}", time);
    let output_filename = format!("./test-outputs/bug-{}", time);
    write_events(&input_filename[..], &events[..]);
    write_events(&output_filename[..], &[]);
}

fn make_regression_test() {
    let bootstrap_events = read_events("./bootstrap");
    let events = read_events("./autosave");
    let mut flow = Flow::new();
    for event in bootstrap_events.into_iter().chain(events.into_iter()) {
        flow.quiesce(event.changes);
    }
    let time = time::get_time().sec;
    let input_filename = format!("./test-inputs/regression-{}", time);
    let output_filename = format!("./test-outputs/regression-{}", time);
    write_events(&input_filename[..], &[Event{changes: flow.as_changes(), commands: vec![]}]);
    write_events(&output_filename[..],  &[Event{changes: flow.as_changes(), commands: vec![]}]);
}

#[test]
fn test_examples() {
    let inputs = walk_dir("./test-inputs").unwrap().collect::<Vec<_>>();
    let outputs = walk_dir("./test-outputs").unwrap().collect::<Vec<_>>();
    assert_eq!(inputs.len(), outputs.len());
    for (input_entry, output_entry) in inputs.into_iter().zip(outputs.into_iter()) {
        let input_filename = input_entry.unwrap().path().to_str().unwrap().to_owned();
        let output_filename = output_entry.unwrap().path().to_str().unwrap().to_owned();
        println!("Testing {:?} against {:?}", input_filename, output_filename);

        let bootstrap_events = read_events("./bootstrap");
        let input_events = read_events(&input_filename[..]);
        let mut input_flow = Flow::new();
        for event in bootstrap_events.into_iter().chain(input_events.into_iter()) {
            input_flow.quiesce(event.changes);
        }

        let output_events = read_events(&output_filename[..]);
        let mut output_flow = Flow::new();
        for event in output_events.into_iter() {
            output_flow.change(event.changes);
        }

        let schema = schema();
        for output_cell in output_flow.outputs.iter() {
            let output = output_cell.borrow();
            // ignore internal views
            if !schema.iter().any(|&(ref id, _)| **id == *output.view) {
                let input = input_flow.get_output(&output.view[..]);
                assert_eq!((&output.view, &output.index), (&input.view, &input.index));
            }
        }
    }
}

#[allow(dead_code)]
fn main() {
    let args = env::args().collect::<Vec<String>>();
    let borrowed_args = args.iter().map(|s| &s[..]).collect::<Vec<&str>>();
    match &borrowed_args[..] {
        [_, "remove_view", view] => remove_view(view),
        [_, "remove_row", view, row] => remove_row(view, FromJson::from_json(&Json::from_str(&row).unwrap())),
        [_, "reset_internal_views"] => reset_internal_views(),
        [_, "compact", filename] => compact(filename),
        [_, "make_bug_test"] => make_bug_test(),
        [_, "make_regression_test"] => make_regression_test(),
        other => panic!("Bad arguments (look at src/bin/migrate.rs for correct usage): {:?}", &other[1..]),
    }
}
<|endoftext|>


<commit_before>//! Convenience functions for making requests over HTTP
//!
//! This module provides a few functions that make it easier to make
//! requests over HTTP in a consistent manner e.g. with the 'User-Agent` header
//! set and respecting cache control headers in responses. In addition to reducing
//! the number of network requests for the client, several APIs ask clients
//! to implement caching to reduce load on their servers.

use std::{env, fs::File, io, path::Path};

use eyre::Result;
use http_cache_reqwest::{CACacheManager, Cache, CacheMode, HttpCache};
use once_cell::sync::Lazy;
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};

static USER_AGENT: &str = concat!("stencila/", env!("CARGO_PKG_VERSION"),);

/// Get the directory of the HTTP cache
pub fn cache_dir() -> String {
    let user_cache_dir = dirs::cache_dir().unwrap_or_else(|| env::current_dir().unwrap());
    match env::consts::OS {
        "macos" | "windows" => user_cache_dir.join("Stencila").join("HTTP Cache"),
        _ => user_cache_dir.join("stencila").join("http-cache"),
    }
    .to_string_lossy()
    .to_string()
}

static CLIENT: Lazy<ClientWithMiddleware> = Lazy::new(|| {
    let client = reqwest::Client::builder()
        .user_agent(USER_AGENT)
        .build()
        .expect("Should be able to build HTTP client");
    let caching_middleware = Cache(HttpCache {
        mode: CacheMode::Default,
        manager: CACacheManager { path: cache_dir() },
        options: None,
    });
    ClientBuilder::new(client).with(caching_middleware).build()
});

// Get JSON from a URL
pub async fn get_json(url: &str) -> Result<serde_json::Value> {
    let response = CLIENT
        .get(url)
        .header("accept", "application/json")
        .send()
        .await?
        .error_for_status()?;

    let json = response.json().await?;

    Ok(json)
}

// Download a file from a URL to a path
pub async fn download_file(url: &str, path: &Path) -> Result<()> {
    let response = CLIENT.get(url).send().await?.error_for_status()?;

    let bytes = response.bytes().await?;
    let mut file = File::create(&path)?;
    io::copy(&mut bytes.as_ref(), &mut file)?;

    Ok(())
}

// Download a file from a URL to a path synchronously
pub fn download_file_sync(url: &str, path: &Path) -> Result<()> {
    let url = url.to_owned();
    let path = path.to_owned();
    let (sender, receiver) = std::sync::mpsc::channel();
    tokio::spawn(async move {
        let result = download_file(&url, &path).await;
        sender.send(result)
    });
    receiver.recv()?
}
<commit_msg>feat(HTTP utils): Add `get_json_with` function<commit_after>//! Convenience functions for making requests over HTTP
//!
//! This module provides a few functions that make it easier to make
//! requests over HTTP in a consistent manner e.g. with the 'User-Agent` header
//! set and respecting cache control headers in responses. In addition to reducing
//! the number of network requests for the client, several APIs ask clients
//! to implement caching to reduce load on their servers.

use std::{env, fs::File, io, path::Path};

use eyre::Result;
use http_cache_reqwest::{CACacheManager, Cache, CacheMode, HttpCache};
use once_cell::sync::Lazy;
use reqwest::header::{HeaderMap, HeaderName};
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};

pub use reqwest::header as headers;

static USER_AGENT: &str = concat!("stencila/", env!("CARGO_PKG_VERSION"),);

/// Get the directory of the HTTP cache
pub fn cache_dir() -> String {
    let user_cache_dir = dirs::cache_dir().unwrap_or_else(|| env::current_dir().unwrap());
    match env::consts::OS {
        "macos" | "windows" => user_cache_dir.join("Stencila").join("HTTP Cache"),
        _ => user_cache_dir.join("stencila").join("http-cache"),
    }
    .to_string_lossy()
    .to_string()
}

static CLIENT: Lazy<ClientWithMiddleware> = Lazy::new(|| {
    let client = reqwest::Client::builder()
        .user_agent(USER_AGENT)
        .build()
        .expect("Should be able to build HTTP client");
    let caching_middleware = Cache(HttpCache {
        mode: CacheMode::Default,
        manager: CACacheManager { path: cache_dir() },
        options: None,
    });
    ClientBuilder::new(client).with(caching_middleware).build()
});

// Get JSON from a URL
pub async fn get_json(url: &str) -> Result<serde_json::Value> {
    let response = CLIENT
        .get(url)
        .header("accept", "application/json")
        .send()
        .await?
        .error_for_status()?;

    let json = response.json().await?;

    Ok(json)
}

// Get JSON from a URL with additional request headers
pub async fn get_json_with(url: &str, headers: &[(HeaderName, &str)]) -> Result<serde_json::Value> {
    let mut header_map = HeaderMap::new();
    for (key, value) in headers {
        header_map.insert(key, value.parse()?);
    }

    let response = CLIENT
        .get(url)
        .headers(header_map)
        .send()
        .await?
        .error_for_status()?;

    let json = response.json().await?;

    Ok(json)
}

// Download a file from a URL to a path
pub async fn download_file(url: &str, path: &Path) -> Result<()> {
    let response = CLIENT.get(url).send().await?.error_for_status()?;

    let bytes = response.bytes().await?;
    let mut file = File::create(&path)?;
    io::copy(&mut bytes.as_ref(), &mut file)?;

    Ok(())
}

// Download a file from a URL to a path synchronously
pub fn download_file_sync(url: &str, path: &Path) -> Result<()> {
    let url = url.to_owned();
    let path = path.to_owned();
    let (sender, receiver) = std::sync::mpsc::channel();
    tokio::spawn(async move {
        let result = download_file(&url, &path).await;
        sender.send(result)
    });
    receiver.recv()?
}
<|endoftext|>


<commit_before>//! [Church pair](https://en.wikipedia.org/wiki/Church_encoding#Church_pairs)

use term::*;
use term::Error::*;
use booleans::*;

/// Produces a Church-encoded pair; applying it to two other terms puts them inside it.
///
/// PAIR := λxyz.z x y = λ λ λ 1 3 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::pair::pair;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// let pair01 = app!(pair(), zero(), one());
///
/// assert_eq!(pair01.fst_ref(), Ok(&zero()));
/// assert_eq!(pair01.snd_ref(), Ok(&one()));
/// # }
/// ```
pub fn pair() -> Term {
    abs(abs(abs(
        app!(Var(1), Var(3), Var(2))
    )))
}

/// Applied to a Church-encoded pair `(a, b)` it yields `a`.
///
/// FST := λp.p TRUE = λ 1 TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::pair::{pair, fst};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// let pair_0_1 = app!(pair(), zero(), one());
///
/// assert_eq!(beta(fst().app(pair_0_1), NOR, 0, false), zero());
/// # }
/// ```
pub fn fst() -> Term { abs(Var(1).app(tru())) }

/// Applied to a Church-encoded pair `(a, b)` it yields `b`.
///
/// SND := λp.p FALSE = λ 1 FALSE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::pair::{pair, snd};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// let pair_0_1 = app!(pair(), zero(), one());
///
/// assert_eq!(beta(snd().app(pair_0_1), NOR, 0, false), one());
/// # }
/// ```
pub fn snd() -> Term { abs(Var(1).app(fls())) }

impl Term {
    /// Checks whether `self` is a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert!(pair01.is_pair());
    /// # }
    /// ```
    pub fn is_pair(&self) -> bool {
        self.unpair_ref().is_ok()
    }

    /// Splits a Church-encoded pair into a pair of terms, consuming `self`.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.unpair(), Ok((zero(), one())));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn unpair(self) -> Result<(Term, Term), Error> {
        let candidate = if let Abs(abstracted) = self { *abstracted } else { self };

        if let Ok((wrapped_a, b)) = candidate.unapp() {
            Ok((try!(wrapped_a.rhs()), b))
        } else {
            Err(NotAPair)
        }
    }

    /// Splits a Church-encoded pair into a pair of references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.unpair_ref(), Ok((&zero(), &one())));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn unpair_ref(&self) -> Result<(&Term, &Term), Error> {
        let candidate = if let Abs(ref abstracted) = *self { abstracted } else { self };

        if let Ok((wrapped_a, b)) = candidate.unapp_ref() {
            Ok((try!(wrapped_a.rhs_ref()), b))
        } else {
            Err(NotAPair)
        }
    }

    /// Splits a Church-encoded pair into a pair of mutable references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.unpair_mut(), Ok((&mut zero(), &mut one())));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn unpair_mut(&mut self) -> Result<(&mut Term, &mut Term), Error> {
        let mut candidate = if let Abs(ref mut abstracted) = *self { abstracted } else { self };

        if let Ok((wrapped_a, b)) = candidate.unapp_mut() {
            Ok((try!(wrapped_a.rhs_mut()), b))
        } else {
            Err(NotAPair)
        }
    }

    /// Returns the first term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.fst(), Ok(zero()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn fst(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).0)
    }

    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.fst_ref(), Ok(&zero()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn fst_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).0)
    }

    /// Returns a mutable reference to the first term of a Church-encoded pair.
    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.fst_mut(), Ok(&mut zero()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn fst_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_mut()).0)
    }

    /// Returns the second term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.snd(), Ok(one()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn snd(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).1)
    }

    /// Returns a reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.snd_ref(), Ok(&one()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn snd_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).1)
    }

    /// Returns a mutable reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.snd_mut(), Ok(&mut one()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn snd_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_mut()).1)
    }
}

impl From<(Term, Term)> for Term {
    fn from((t1, t2): (Term, Term)) -> Self {
        abs(app!(Var(1), t1, t2))
    }
}

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

    #[test]
    fn pair_from_pair() {
        assert_eq!(Term::from((0.into(), 1.into())),
                   beta(app!(pair(), 0.into(), 1.into()), NOR, 0, false));
    }

    #[test]
    fn pair_operations() {
        let pair_four_three = beta(app!(pair(), 4.into(), 3.into()), NOR, 0, false);

        assert!(pair_four_three.is_pair());

        assert_eq!(pair_four_three.fst_ref(), Ok(&4.into()));
        assert_eq!(pair_four_three.snd_ref(), Ok(&3.into()));

        let unpaired = pair_four_three.unpair();
        assert_eq!(unpaired, Ok((4.into(), 3.into())));
    }
}

<commit_msg>remove redundant pair lib tests<commit_after>//! [Church pair](https://en.wikipedia.org/wiki/Church_encoding#Church_pairs)

use term::*;
use term::Error::*;
use booleans::*;

/// Produces a Church-encoded pair; applying it to two other terms puts them inside it.
///
/// PAIR := λxyz.z x y = λ λ λ 1 3 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::pair::pair;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// let pair01 = app!(pair(), zero(), one());
///
/// assert_eq!(pair01.fst_ref(), Ok(&zero()));
/// assert_eq!(pair01.snd_ref(), Ok(&one()));
/// # }
/// ```
pub fn pair() -> Term {
    abs(abs(abs(
        app!(Var(1), Var(3), Var(2))
    )))
}

/// Applied to a Church-encoded pair `(a, b)` it yields `a`.
///
/// FST := λp.p TRUE = λ 1 TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::pair::{pair, fst};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// let pair_0_1 = app!(pair(), zero(), one());
///
/// assert_eq!(beta(fst().app(pair_0_1), NOR, 0, false), zero());
/// # }
/// ```
pub fn fst() -> Term { abs(Var(1).app(tru())) }

/// Applied to a Church-encoded pair `(a, b)` it yields `b`.
///
/// SND := λp.p FALSE = λ 1 FALSE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::pair::{pair, snd};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// let pair_0_1 = app!(pair(), zero(), one());
///
/// assert_eq!(beta(snd().app(pair_0_1), NOR, 0, false), one());
/// # }
/// ```
pub fn snd() -> Term { abs(Var(1).app(fls())) }

impl Term {
    /// Checks whether `self` is a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert!(pair01.is_pair());
    /// # }
    /// ```
    pub fn is_pair(&self) -> bool {
        self.unpair_ref().is_ok()
    }

    /// Splits a Church-encoded pair into a pair of terms, consuming `self`.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.unpair(), Ok((zero(), one())));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn unpair(self) -> Result<(Term, Term), Error> {
        let candidate = if let Abs(abstracted) = self { *abstracted } else { self };

        if let Ok((wrapped_a, b)) = candidate.unapp() {
            Ok((try!(wrapped_a.rhs()), b))
        } else {
            Err(NotAPair)
        }
    }

    /// Splits a Church-encoded pair into a pair of references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.unpair_ref(), Ok((&zero(), &one())));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn unpair_ref(&self) -> Result<(&Term, &Term), Error> {
        let candidate = if let Abs(ref abstracted) = *self { abstracted } else { self };

        if let Ok((wrapped_a, b)) = candidate.unapp_ref() {
            Ok((try!(wrapped_a.rhs_ref()), b))
        } else {
            Err(NotAPair)
        }
    }

    /// Splits a Church-encoded pair into a pair of mutable references to its underlying terms.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.unpair_mut(), Ok((&mut zero(), &mut one())));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn unpair_mut(&mut self) -> Result<(&mut Term, &mut Term), Error> {
        let mut candidate = if let Abs(ref mut abstracted) = *self { abstracted } else { self };

        if let Ok((wrapped_a, b)) = candidate.unapp_mut() {
            Ok((try!(wrapped_a.rhs_mut()), b))
        } else {
            Err(NotAPair)
        }
    }

    /// Returns the first term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.fst(), Ok(zero()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn fst(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).0)
    }

    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.fst_ref(), Ok(&zero()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn fst_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).0)
    }

    /// Returns a mutable reference to the first term of a Church-encoded pair.
    /// Returns a reference to the first term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.fst_mut(), Ok(&mut zero()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn fst_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_mut()).0)
    }

    /// Returns the second term from a Church-encoded pair, consuming `self`.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.snd(), Ok(one()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn snd(self) -> Result<Term, Error> {
        Ok(try!(self.unpair()).1)
    }

    /// Returns a reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.snd_ref(), Ok(&one()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn snd_ref(&self) -> Result<&Term, Error> {
        Ok(try!(self.unpair_ref()).1)
    }

    /// Returns a mutable reference to the second term of a Church-encoded pair.
    ///
    /// # Example
    /// ```
    /// # #[macro_use] extern crate lambda_calculus;
    /// # fn main() {
    /// use lambda_calculus::pair::pair;
    /// use lambda_calculus::arithmetic::{zero, one};
    ///
    /// let mut pair01 = app!(pair(), zero(), one());
    ///
    /// assert_eq!(pair01.snd_mut(), Ok(&mut one()));
    /// # }
    /// ```
    /// # Errors
    ///
    /// The function will return an error if `self` is not a Church pair.
    pub fn snd_mut(&mut self) -> Result<&mut Term, Error> {
        Ok(try!(self.unpair_mut()).1)
    }
}

impl From<(Term, Term)> for Term {
    fn from((t1, t2): (Term, Term)) -> Self {
        abs(app!(Var(1), t1, t2))
    }
}
<|endoftext|>


<commit_before>
use error::{NcclError, ErrorKind};
use value::Value;
use ::TryInto;

use std::ops::{Index, IndexMut};
use std::error::Error;

/// Struct that contains configuration information.
///
/// Examples:
///
/// ```
/// let p = nccl::parse_file("examples/config.nccl").unwrap();
/// let ports = p["server"]["port"].keys_as::<i64>().unwrap();
///
/// println!("Operating on ports:");
/// for port in ports.iter() {
///     println!("  {}", port);
/// }
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    key: Value,
    value: Vec<Pair>
}

impl Pair {
    /// Creates a new Pair.
    pub fn new<T: Into<Value>>(key: T) -> Self {
        Pair {
            key: key.into(),
            value: vec![]
        }
    }

    /// Adds a value to a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let mut p = nccl::Pair::new("hello");
    /// p.add(true);
    /// p.add("world");
    /// ```
    pub fn add<T: Into<Value>>(&mut self, value: T) {
        self.value.push(Pair::new(value.into()));
    }

    /// Recursively adds a slice to a Pair.
    pub fn add_slice(&mut self, path: &[Value]) {
        let mut s = self.traverse_path(&path[0..path.len() - 1]);
        if !s.has_key(&path[path.len() - 1]) {
            s.add(&path[path.len() - 1]);
        }
    }

    /// Adds a Pair to a Pair.
    pub fn add_pair(&mut self, pair: Pair) {
        if !self.has_key(&pair.key) {
            self.value.push(pair);
        } else {
            self[&pair.key].value = pair.value;
        }
    }

    /// Test if a pair has a key.
    ///
    /// Examples:
    ///
    /// ```
    /// use nccl::NcclError;
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_key("server"));
    /// assert!(p["server"]["port"].has_key(80));
    /// ```
    pub fn has_key<T>(&self, key: T) -> bool where Value: From<T> {
        let k = key.into();
        for item in &self.value {
            if item.key == k {
                return true;
            }
        }

        false
    }

    /// Test if a pair has a path of values. Use `vec_into!` to make
    /// this method easier to use.
    ///
    /// Examples:
    ///
    /// ```
    /// # #[macro_use] extern crate nccl; fn main() {
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_path(vec_into!["server", "port", 80]));
    /// # }
    /// ```
    pub fn has_path(&self, path: Vec<Value>) -> bool {
        if path.len() == 0 {
            true
        } else {
            if self.has_key(path[0].clone()) {
                self[path[0].clone()].has_path(path[1..path.len()].to_vec())
            } else {
                false
            }
        }
    }

    /// Traverses a Pair using a slice, adding the item if it does not exist.
    pub fn traverse_path(&mut self, path: &[Value]) -> &mut Pair {
        if path.is_empty() {
            self
        } else {
            if !self.has_key(&path[0]) {
                self.add(&path[0]);
            }
            self.get(&path[0]).unwrap().traverse_path(&path[1..path.len()])
        }
    }

    /// Gets a child Pair from a Pair. Used by Pair's implementation of Index.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add("hello!");
    /// p.get("hello!").unwrap();
    /// ```
    pub fn get<T>(&mut self, value: T) -> Result<&mut Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Pair does not have key: {}", v), 0)));
        } else {
            for item in &mut self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Could not find key: {}", v), 0)))
    }

    /// Gets a mutable child Pair from a Pair. Used by Pair's implementation of
    /// IndexMut.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add(32);
    /// p.get(32).unwrap();
    /// ```
    pub fn get_ref<T>(&self, value: T) -> Result<&Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Ok(self);
        } else {
            for item in &self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, "Cound not find key", 0)))
    }

    fn value(&self) -> Option<Value>  {
        if self.value.len() == 1 {
            Some(self.value[0].key.clone())
        } else {
            None
        }
    }

    /// Gets the value of a key as a specified type, if there is only one.
    ///
    /// Examples:
    ///
    /// ```
    /// let p = nccl::parse_file("examples/long.nccl").unwrap();
    /// assert!(!p["bool too"].value_as::<bool>().unwrap());
    /// ```
    pub fn value_as<T>(&self) -> Result<T, Box<Error>> where Value: TryInto<T> {
        match self.value() {
            Some(v) => match v.try_into() {
                Ok(t) => Ok(t),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            },
            None => Err(Box::new(NcclError::new(ErrorKind::MultipleValues, "Could not convert value: multiple values. Use keys() or keys_as()", 0)))
        }
    }

    fn keys(&self) -> Vec<Value> {
        self.value.clone().into_iter().map(|x| x.key).collect()
    }

    /// Gets keys of a value as a vector of T.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// let ports = config["server"]["port"].keys_as::<i64>().unwrap();
    /// assert_eq!(ports, vec![80, 443]);
    /// ```
    pub fn keys_as<T>(&self) -> Result<Vec<T>, Box<Error>> where Value: TryInto<T> {
        let mut v: Vec<T> = vec![];
        for key in self.keys() {
            match key.try_into() {
                Ok(k) => v.push(k),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            }
        }
        Ok(v)
    }

    /// Pretty-prints a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// config.pretty_print();
    ///
    /// // String("__top_level__")
    /// //     String("server")
    /// //         String("domain")
    /// //             String("example.com")
    /// //             String("www.example.com")
    /// //         String("port")
    /// //             Integer(80)
    /// //             Integer(443)
    /// //         String("root")
    /// //             String("/var/www/html")
    /// ```
    ///
    pub fn pretty_print(&self) {
        self.pp_rec(0);
    }

    fn pp_rec(&self, indent: u32) {
        for _ in 0..indent {
            print!("    ");
        }
        println!("{}", self.key);
        for value in &self.value {
            value.pp_rec(indent + 1);
        }
    }
}

impl<T> Index<T> for Pair where Value: From<T> {
    type Output = Pair;
    fn index(&self, i: T) -> &Pair {
        self.get_ref(i).unwrap()
    }
}

impl<T> IndexMut<T> for Pair where Value: From<T> {
    fn index_mut(&mut self, i: T) -> &mut Pair {
        self.get(i).unwrap()
    }
}

<commit_msg>remove unnecessary mut<commit_after>
use error::{NcclError, ErrorKind};
use value::Value;
use ::TryInto;

use std::ops::{Index, IndexMut};
use std::error::Error;

/// Struct that contains configuration information.
///
/// Examples:
///
/// ```
/// let p = nccl::parse_file("examples/config.nccl").unwrap();
/// let ports = p["server"]["port"].keys_as::<i64>().unwrap();
///
/// println!("Operating on ports:");
/// for port in ports.iter() {
///     println!("  {}", port);
/// }
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    key: Value,
    value: Vec<Pair>
}

impl Pair {
    /// Creates a new Pair.
    pub fn new<T: Into<Value>>(key: T) -> Self {
        Pair {
            key: key.into(),
            value: vec![]
        }
    }

    /// Adds a value to a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let mut p = nccl::Pair::new("hello");
    /// p.add(true);
    /// p.add("world");
    /// ```
    pub fn add<T: Into<Value>>(&mut self, value: T) {
        self.value.push(Pair::new(value.into()));
    }

    /// Recursively adds a slice to a Pair.
    pub fn add_slice(&mut self, path: &[Value]) {
        let s = self.traverse_path(&path[0..path.len() - 1]);
        if !s.has_key(&path[path.len() - 1]) {
            s.add(&path[path.len() - 1]);
        }
    }

    /// Adds a Pair to a Pair.
    pub fn add_pair(&mut self, pair: Pair) {
        if !self.has_key(&pair.key) {
            self.value.push(pair);
        } else {
            self[&pair.key].value = pair.value;
        }
    }

    /// Test if a pair has a key.
    ///
    /// Examples:
    ///
    /// ```
    /// use nccl::NcclError;
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_key("server"));
    /// assert!(p["server"]["port"].has_key(80));
    /// ```
    pub fn has_key<T>(&self, key: T) -> bool where Value: From<T> {
        let k = key.into();
        for item in &self.value {
            if item.key == k {
                return true;
            }
        }

        false
    }

    /// Test if a pair has a path of values. Use `vec_into!` to make
    /// this method easier to use.
    ///
    /// Examples:
    ///
    /// ```
    /// # #[macro_use] extern crate nccl; fn main() {
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_path(vec_into!["server", "port", 80]));
    /// # }
    /// ```
    pub fn has_path(&self, path: Vec<Value>) -> bool {
        if path.len() == 0 {
            true
        } else {
            if self.has_key(path[0].clone()) {
                self[path[0].clone()].has_path(path[1..path.len()].to_vec())
            } else {
                false
            }
        }
    }

    /// Traverses a Pair using a slice, adding the item if it does not exist.
    pub fn traverse_path(&mut self, path: &[Value]) -> &mut Pair {
        if path.is_empty() {
            self
        } else {
            if !self.has_key(&path[0]) {
                self.add(&path[0]);
            }
            self.get(&path[0]).unwrap().traverse_path(&path[1..path.len()])
        }
    }

    /// Gets a child Pair from a Pair. Used by Pair's implementation of Index.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add("hello!");
    /// p.get("hello!").unwrap();
    /// ```
    pub fn get<T>(&mut self, value: T) -> Result<&mut Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Pair does not have key: {}", v), 0)));
        } else {
            for item in &mut self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Could not find key: {}", v), 0)))
    }

    /// Gets a mutable child Pair from a Pair. Used by Pair's implementation of
    /// IndexMut.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add(32);
    /// p.get(32).unwrap();
    /// ```
    pub fn get_ref<T>(&self, value: T) -> Result<&Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Ok(self);
        } else {
            for item in &self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, "Cound not find key", 0)))
    }

    fn value(&self) -> Option<Value>  {
        if self.value.len() == 1 {
            Some(self.value[0].key.clone())
        } else {
            None
        }
    }

    /// Gets the value of a key as a specified type, if there is only one.
    ///
    /// Examples:
    ///
    /// ```
    /// let p = nccl::parse_file("examples/long.nccl").unwrap();
    /// assert!(!p["bool too"].value_as::<bool>().unwrap());
    /// ```
    pub fn value_as<T>(&self) -> Result<T, Box<Error>> where Value: TryInto<T> {
        match self.value() {
            Some(v) => match v.try_into() {
                Ok(t) => Ok(t),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            },
            None => Err(Box::new(NcclError::new(ErrorKind::MultipleValues, "Could not convert value: multiple values. Use keys() or keys_as()", 0)))
        }
    }

    fn keys(&self) -> Vec<Value> {
        self.value.clone().into_iter().map(|x| x.key).collect()
    }

    /// Gets keys of a value as a vector of T.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// let ports = config["server"]["port"].keys_as::<i64>().unwrap();
    /// assert_eq!(ports, vec![80, 443]);
    /// ```
    pub fn keys_as<T>(&self) -> Result<Vec<T>, Box<Error>> where Value: TryInto<T> {
        let mut v: Vec<T> = vec![];
        for key in self.keys() {
            match key.try_into() {
                Ok(k) => v.push(k),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            }
        }
        Ok(v)
    }

    /// Pretty-prints a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// config.pretty_print();
    ///
    /// // String("__top_level__")
    /// //     String("server")
    /// //         String("domain")
    /// //             String("example.com")
    /// //             String("www.example.com")
    /// //         String("port")
    /// //             Integer(80)
    /// //             Integer(443)
    /// //         String("root")
    /// //             String("/var/www/html")
    /// ```
    ///
    pub fn pretty_print(&self) {
        self.pp_rec(0);
    }

    fn pp_rec(&self, indent: u32) {
        for _ in 0..indent {
            print!("    ");
        }
        println!("{}", self.key);
        for value in &self.value {
            value.pp_rec(indent + 1);
        }
    }
}

impl<T> Index<T> for Pair where Value: From<T> {
    type Output = Pair;
    fn index(&self, i: T) -> &Pair {
        self.get_ref(i).unwrap()
    }
}

impl<T> IndexMut<T> for Pair where Value: From<T> {
    fn index_mut(&mut self, i: T) -> &mut Pair {
        self.get(i).unwrap()
    }
}

<|endoftext|>


<commit_before>extern crate serialize;

use std::io::process::Command;
use std::io::{File, TempDir};

fn main() {
    use std::io::fs;

    let (args, passthrough) = parse_arguments();

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory
    let directory = build_directory(&sdk_path);

    // compiling android_native_app_glue.c
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::io::process::InheritFd(1)).stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-Wl,-E")
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling elfedit
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-elfedit"))
        .arg("--output-type").arg("dyn")
        .arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing elfedit");
        std::os::set_exit_status(1);
        return;
    }

    // executing ant
    if Command::new("ant").arg("debug").stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2)).cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing ant debug");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to OUTPUT
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &Path::new("output")).unwrap();     // FIXME
}

struct Args {
    shared: bool,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_args = Args { shared: false };
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.move_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (result_args, result_passthrough),
            Some(arg) => arg
        };

        match arg.as_slice() {
            _ => result_passthrough.push(arg.clone())
        }
    }
}

fn build_directory(sdk_dir: &Path) -> TempDir {
    use std::io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let src_path = build_directory.path().join("src").join("com").join("example")
            .join("native_activity");
        fs::mkdir_recursive(&src_path, std::io::UserRWX).unwrap();
        File::create(&src_path.join("MyNativeActivity.java")).unwrap()
            .write_str(build_java_class().as_slice())
            .unwrap();
    }

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::io::UserRWX).unwrap();
    }

    build_directory
}

fn build_manifest() -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="18" />

    <application android:label="NativeActivity" android:hasCode="true">
        <activity android:name="com.example.native_activity.MyNativeActivity"
                android:label="NativeActivity"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}

fn build_java_class() -> String {
    format!(r#"
package com.example.native_activity;

import android.app.NativeActivity;
import android.util.Log;

public class MyNativeActivity extends NativeActivity {{
  static {{
    System.loadLibrary("main");
  }}

  private static String TAG = "MyNativeActivity";

  public MyNativeActivity() {{
    super();
    Log.v(TAG, "Creating MyNativeActivity");
  }}
}}"#)
}
<commit_msg>Fix output file name<commit_after>extern crate serialize;

use std::io::process::Command;
use std::io::{File, TempDir};

fn main() {
    use std::io::fs;

    let (args, passthrough) = parse_arguments();

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory that will contain all the necessary files to create teh apk
    let directory = build_directory(&sdk_path);

    // compiling android_native_app_glue.c
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::io::process::InheritFd(1)).stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to an executable
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-Wl,-E")
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling elfedit to turn our executable into a shared object
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-elfedit"))
        .arg("--output-type").arg("dyn")
        .arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing elfedit");
        std::os::set_exit_status(1);
        return;
    }

    // executing ant
    if Command::new("ant").arg("debug").stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2)).cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing ant debug");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &Path::new(args.output)).unwrap();
}

struct Args {
    output: Path,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.move_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument")
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(Path::new(args.next().expect("-o must be followed by the output name")));
            },
            _ => result_passthrough.push(arg)
        };
    }
}

fn build_directory(sdk_dir: &Path) -> TempDir {
    use std::io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let src_path = build_directory.path().join("src").join("com").join("example")
            .join("native_activity");
        fs::mkdir_recursive(&src_path, std::io::UserRWX).unwrap();
        File::create(&src_path.join("MyNativeActivity.java")).unwrap()
            .write_str(build_java_class().as_slice())
            .unwrap();
    }

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::io::UserRWX).unwrap();
    }

    build_directory
}

fn build_manifest() -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="18" />

    <application android:label="NativeActivity" android:hasCode="true">
        <activity android:name="com.example.native_activity.MyNativeActivity"
                android:label="NativeActivity"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}

fn build_java_class() -> String {
    format!(r#"
package com.example.native_activity;

import android.app.NativeActivity;
import android.util.Log;

public class MyNativeActivity extends NativeActivity {{
  static {{
    System.loadLibrary("main");
  }}

  private static String TAG = "MyNativeActivity";

  public MyNativeActivity() {{
    super();
    Log.v(TAG, "Creating MyNativeActivity");
  }}
}}"#)
}
<|endoftext|>


<commit_before>use crate::clippy_project_root;
use std::path::PathBuf;
use std::process::Command;
// represents an archive we download from crates.io
#[derive(Debug)]
struct KrateSource {
    version: String,
    name: String,
}

// represents the extracted sourcecode of a crate
#[derive(Debug)]
struct Krate {
    version: String,
    name: String,
    // path to the extracted sources that clippy can check
    path: PathBuf,
}

impl KrateSource {
    fn new(name: &str, version: &str) -> Self {
        KrateSource {
            version: version.into(),
            name: name.into(),
        }
    }

    fn download_and_extract(&self) -> Krate {
        let extract_dir = PathBuf::from("target/crater/crates");
        let krate_download_dir = PathBuf::from("target/crater/downloads");

        // url to download the crate from crates.io
        let url = format!(
            "https://crates.io/api/v1/crates/{}/{}/download",
            self.name, self.version
        );
        println!("Downloading and extracting {} {} from {}", self.name, self.version, url);
        let _ = std::fs::create_dir("target/crater/");
        let _ = std::fs::create_dir(&krate_download_dir);
        let _ = std::fs::create_dir(&extract_dir);

        let krate_file_path = krate_download_dir.join(format!("{}-{}.crate.tar.gz", &self.name, &self.version));
        // don't download/extract if we already have done so
        if !krate_file_path.is_file() {
            // create a file path to download and write the crate data into
            let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap();
            let mut krate_req = ureq::get(&url).call().unwrap().into_reader();
            // copy the crate into the file
            std::io::copy(&mut krate_req, &mut krate_dest).unwrap();

            // unzip the tarball
            let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap());
            // extract the tar archive
            let mut archiv = tar::Archive::new(ungz_tar);
            archiv.unpack(&extract_dir).expect("Failed to extract!");

            // unzip the tarball
            let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap());
            // extract the tar archive
            let mut archiv = tar::Archive::new(ungz_tar);
            archiv.unpack(&extract_dir).expect("Failed to extract!");
        }
        // crate is extracted, return a new Krate object which contains the path to the extracted
        // sources that clippy can check
        Krate {
            version: self.version.clone(),
            name: self.name.clone(),
            path: extract_dir.join(format!("{}-{}/", self.name, self.version)),
        }
    }
}

impl Krate {
    fn run_clippy_lints(&self, cargo_clippy_path: &PathBuf) -> Vec<String> {
        println!("Linting {} {}...", &self.name, &self.version);
        let cargo_clippy_path = std::fs::canonicalize(cargo_clippy_path).unwrap();

        let shared_target_dir = clippy_project_root().join("target/crater/shared_target_dir/");

        let all_output = std::process::Command::new(cargo_clippy_path)
            .env("CARGO_TARGET_DIR", shared_target_dir)
            // lint warnings will look like this:
            // src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
            .args(&[
                "--",
                "--message-format=short",
                "--",
                "--cap-lints=warn",
                "-Wclippy::pedantic",
                "-Wclippy::cargo",
            ])
            .current_dir(&self.path)
            .output()
            .unwrap();
        let stderr = String::from_utf8_lossy(&all_output.stderr);
        let output_lines = stderr.lines();
        let mut output: Vec<String> = output_lines
            .into_iter()
            .filter(|line| line.contains(": warning: "))
            // prefix with the crate name and version
            // cargo-0.49.0/src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
            .map(|line| format!("{}-{}/{}", self.name, self.version, line))
            // remove the "warning: "
            .map(|line| {
                let remove_pat = "warning: ";
                let pos = line
                    .find(&remove_pat)
                    .expect("clippy output did not contain \"warning: \"");
                let mut new = line[0..pos].to_string();
                new.push_str(&line[pos + remove_pat.len()..]);
                new.push('\n');
                new
            })
            .collect();

        // sort messages alphabtically to avoid noise in the logs
        output.sort();
        output
    }
}

fn build_clippy() {
    Command::new("cargo")
        .arg("build")
        .output()
        .expect("Failed to build clippy!");
}

// the main fn
pub fn run() {
    let cargo_clippy_path: PathBuf = PathBuf::from("target/debug/cargo-clippy");

    // crates we want to check:
    let krates: Vec<KrateSource> = vec![
        // some of these are form cargotest
        KrateSource::new("cargo", "0.49.0"),
        KrateSource::new("iron", "0.6.1"),
        KrateSource::new("ripgrep", "12.1.1"),
        //KrateSource::new("tokei", "12.0.4"),
        KrateSource::new("xsv", "0.13.0"),
        KrateSource::new("serde", "1.0.118"),
        KrateSource::new("rayon", "1.5.0"),
        // top 10 crates.io dls
        KrateSource::new("rand", "0.7.3"),
        KrateSource::new("syn", "1.0.54"),
        KrateSource::new("libc", "0.2.81"),
        KrateSource::new("quote", "1.0.7"),
        KrateSource::new("rand_core", "0.6.0"),
        KrateSource::new("unicode-xid", "0.2.1"),
        KrateSource::new("proc-macro2", "1.0.24"),
        KrateSource::new("bitflags", "1.2.1"),
        KrateSource::new("log", "0.4.11"),
        KrateSource::new("regex", "1.4.2"),
    ];

    println!("Compiling clippy...");
    build_clippy();
    println!("Done compiling");

    // assert that clippy is found
    assert!(
        cargo_clippy_path.is_file(),
        "target/debug/cargo-clippy binary not found! {}",
        cargo_clippy_path.display()
    );

    // download and extract the crates, then run clippy on them and collect clippys warnings
    let clippy_lint_results: Vec<Vec<String>> = krates
        .into_iter()
        .map(|krate| krate.download_and_extract())
        .map(|krate| krate.run_clippy_lints(&cargo_clippy_path))
        .collect();

    let all_warnings: Vec<String> = clippy_lint_results.into_iter().flatten().collect();

    // save the text into mini-crater/logs.txt
    let text = all_warnings.join("");
    std::fs::write("mini-crater/logs.txt", text).unwrap();
}
<commit_msg>allow clippy::filter_map<commit_after>#![allow(clippy::filter_map)]

use crate::clippy_project_root;
use std::path::PathBuf;
use std::process::Command;

// represents an archive we download from crates.io
#[derive(Debug)]
struct KrateSource {
    version: String,
    name: String,
}

// represents the extracted sourcecode of a crate
#[derive(Debug)]
struct Krate {
    version: String,
    name: String,
    // path to the extracted sources that clippy can check
    path: PathBuf,
}

impl KrateSource {
    fn new(name: &str, version: &str) -> Self {
        KrateSource {
            version: version.into(),
            name: name.into(),
        }
    }

    fn download_and_extract(&self) -> Krate {
        let extract_dir = PathBuf::from("target/crater/crates");
        let krate_download_dir = PathBuf::from("target/crater/downloads");

        // url to download the crate from crates.io
        let url = format!(
            "https://crates.io/api/v1/crates/{}/{}/download",
            self.name, self.version
        );
        println!("Downloading and extracting {} {} from {}", self.name, self.version, url);
        let _ = std::fs::create_dir("target/crater/");
        let _ = std::fs::create_dir(&krate_download_dir);
        let _ = std::fs::create_dir(&extract_dir);

        let krate_file_path = krate_download_dir.join(format!("{}-{}.crate.tar.gz", &self.name, &self.version));
        // don't download/extract if we already have done so
        if !krate_file_path.is_file() {
            // create a file path to download and write the crate data into
            let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap();
            let mut krate_req = ureq::get(&url).call().unwrap().into_reader();
            // copy the crate into the file
            std::io::copy(&mut krate_req, &mut krate_dest).unwrap();

            // unzip the tarball
            let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap());
            // extract the tar archive
            let mut archiv = tar::Archive::new(ungz_tar);
            archiv.unpack(&extract_dir).expect("Failed to extract!");

            // unzip the tarball
            let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap());
            // extract the tar archive
            let mut archiv = tar::Archive::new(ungz_tar);
            archiv.unpack(&extract_dir).expect("Failed to extract!");
        }
        // crate is extracted, return a new Krate object which contains the path to the extracted
        // sources that clippy can check
        Krate {
            version: self.version.clone(),
            name: self.name.clone(),
            path: extract_dir.join(format!("{}-{}/", self.name, self.version)),
        }
    }
}

impl Krate {
    fn run_clippy_lints(&self, cargo_clippy_path: &PathBuf) -> Vec<String> {
        println!("Linting {} {}...", &self.name, &self.version);
        let cargo_clippy_path = std::fs::canonicalize(cargo_clippy_path).unwrap();

        let shared_target_dir = clippy_project_root().join("target/crater/shared_target_dir/");

        let all_output = std::process::Command::new(cargo_clippy_path)
            .env("CARGO_TARGET_DIR", shared_target_dir)
            // lint warnings will look like this:
            // src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
            .args(&[
                "--",
                "--message-format=short",
                "--",
                "--cap-lints=warn",
                "-Wclippy::pedantic",
                "-Wclippy::cargo",
            ])
            .current_dir(&self.path)
            .output()
            .unwrap();
        let stderr = String::from_utf8_lossy(&all_output.stderr);
        let output_lines = stderr.lines();
        let mut output: Vec<String> = output_lines
            .into_iter()
            .filter(|line| line.contains(": warning: "))
            // prefix with the crate name and version
            // cargo-0.49.0/src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
            .map(|line| format!("{}-{}/{}", self.name, self.version, line))
            // remove the "warning: "
            .map(|line| {
                let remove_pat = "warning: ";
                let pos = line
                    .find(&remove_pat)
                    .expect("clippy output did not contain \"warning: \"");
                let mut new = line[0..pos].to_string();
                new.push_str(&line[pos + remove_pat.len()..]);
                new.push('\n');
                new
            })
            .collect();

        // sort messages alphabtically to avoid noise in the logs
        output.sort();
        output
    }
}

fn build_clippy() {
    Command::new("cargo")
        .arg("build")
        .output()
        .expect("Failed to build clippy!");
}

// the main fn
pub fn run() {
    let cargo_clippy_path: PathBuf = PathBuf::from("target/debug/cargo-clippy");

    // crates we want to check:
    let krates: Vec<KrateSource> = vec![
        // some of these are form cargotest
        KrateSource::new("cargo", "0.49.0"),
        KrateSource::new("iron", "0.6.1"),
        KrateSource::new("ripgrep", "12.1.1"),
        //KrateSource::new("tokei", "12.0.4"),
        KrateSource::new("xsv", "0.13.0"),
        KrateSource::new("serde", "1.0.118"),
        KrateSource::new("rayon", "1.5.0"),
        // top 10 crates.io dls
        KrateSource::new("rand", "0.7.3"),
        KrateSource::new("syn", "1.0.54"),
        KrateSource::new("libc", "0.2.81"),
        KrateSource::new("quote", "1.0.7"),
        KrateSource::new("rand_core", "0.6.0"),
        KrateSource::new("unicode-xid", "0.2.1"),
        KrateSource::new("proc-macro2", "1.0.24"),
        KrateSource::new("bitflags", "1.2.1"),
        KrateSource::new("log", "0.4.11"),
        KrateSource::new("regex", "1.4.2"),
    ];

    println!("Compiling clippy...");
    build_clippy();
    println!("Done compiling");

    // assert that clippy is found
    assert!(
        cargo_clippy_path.is_file(),
        "target/debug/cargo-clippy binary not found! {}",
        cargo_clippy_path.display()
    );

    // download and extract the crates, then run clippy on them and collect clippys warnings
    let clippy_lint_results: Vec<Vec<String>> = krates
        .into_iter()
        .map(|krate| krate.download_and_extract())
        .map(|krate| krate.run_clippy_lints(&cargo_clippy_path))
        .collect();

    let all_warnings: Vec<String> = clippy_lint_results.into_iter().flatten().collect();

    // save the text into mini-crater/logs.txt
    let text = all_warnings.join("");
    std::fs::write("mini-crater/logs.txt", text).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.
<commit_msg>Create RRG-specific wrappers for logging macros.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

#[macro_export]
macro_rules! error {
    ($($arg:tt)*) => {
        ::log::error!(target: "rrg", $($arg)*);
    }
}

#[macro_export]
macro_rules! warn {
    ($($arg:tt)*) => {
        ::log::warn!(target: "rrg", $($arg)*);
    }
}

#[macro_export]
macro_rules! info {
    ($($arg:tt)*) => {
        ::log::info!(target: "rrg", $($arg)*);
    }
}

#[macro_export]
macro_rules! debug {
    ($($arg:tt)*) => {
        ::log::debug!(target: "rrg", $($arg)*);
    }
}

#[macro_export]
macro_rules! trace {
    ($($arg:tt)*) => {
        ::log::trace!(target: "rrg", $($arg)*);
    }
}
<|endoftext|>