<commit_before>use core::ops::Deref;
use core::ops::DerefMut;

use core::fmt::{Write, Result, Arguments, write};

use core::mem::size_of;

use xen::event;
use xen::sched;

static mut CONS: InnerConsole = InnerConsole::new();

type ConsRingIdx = u32;

#[macro_export]
macro_rules! println {
    ($fmt:expr) => {
        print!(concat!($fmt, "\r\n"))
    };
    ($fmt:expr, $($arg:tt)*) => {
        print!(concat!($fmt, "\r\n"), $($arg)*)
    }
}

#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => {
        $crate::xen::console::_print(format_args!($($arg)*));
    }
}

pub fn _print(fmt: Arguments) {
    let res = write(&mut console(), fmt);

    if let Err(e) = res {
        panic!("Fail to print on the Xen console: {}", e);
    }
}

#[repr(C)]
pub struct ConsoleInterface {
    input: [u8; 1024],
    output: [u8; 2048],
    in_cons: ConsRingIdx,
    in_prod: ConsRingIdx,
    out_cons: ConsRingIdx,
    out_prod: ConsRingIdx,
}

struct InnerConsole {
    pub interface: *mut ConsoleInterface,
    pub port: event::EvtchnPort,
}

impl InnerConsole {
    pub const fn new() -> InnerConsole {
        InnerConsole {
            interface: 0 as *mut ConsoleInterface,
            port: 0,
        }
    }
}

impl Deref for InnerConsole {
    type Target = ConsoleInterface;

    #[inline]
    fn deref(&self) -> &ConsoleInterface {
        // This isn't totally safe. If the interface has not been initialized
        // this would cause some problems. For this to be safe, the console
        // MUST be initialized before being used
        unsafe {
            &(*self.interface)
        }
    }
}

impl DerefMut for InnerConsole {
    #[inline]
    fn deref_mut(&mut self) -> &mut ConsoleInterface {
        // See deref
        unsafe {
            &mut (*self.interface)
        }
    }
}

pub struct Console {
   console: &'static mut InnerConsole
}

pub fn console() -> Console {
    unsafe {
        Console {
            console: &mut CONS,
        }
    }
}

impl Console {
    pub fn set_interface(&mut self, interface: *mut ConsoleInterface) {
        self.console.interface = interface
    }

    pub fn set_port(&mut self, port: event::EvtchnPort) {
        self.console.port = port
    }

    fn is_output_full(&self) -> bool {
        let data: ConsRingIdx;

        data = self.console.out_prod - self.console.out_cons;

        // size_of output field
        (data as usize) >= size_of::<[u8; 2048]>()
    }

    fn out_idx(&self) -> usize {
        let size_of_output = (size_of::<[u8; 2048]>() - 1) as u32;

        (self.console.out_prod & size_of_output) as usize
    }

    pub fn flush(&self) -> () {
        while self.console.out_cons < self.console.out_prod {
            sched::yield_cpu();
        }
    }
}

impl Write for Console {
    fn write_str(&mut self, s: &str) -> Result {

        for c in s.as_bytes() {
            while self.is_output_full() {
                event::send(self.console.port);
            }

            let index = self.out_idx();

            self.console.output[index] = *c;
            ::arch::barrier::wmb();

            self.console.out_prod += 1;
        }

        event::send(self.console.port);

        Ok(())
    }
}
<commit_msg>xen/console: Implementation now uses a spin lock<commit_after>use core::ops::Deref;
use core::ops::DerefMut;

use core::fmt::{Write, Result, Arguments, write};

use core::mem::size_of;

use os::lock::{SpinLock, SpinGuard};

use xen::event;
use xen::sched;

static CONSOLE: SpinLock<Console> = SpinLock::new(Console::new());

type ConsRingIdx = u32;

#[macro_export]
macro_rules! println {
    ($fmt:expr) => {
        print!(concat!($fmt, "\r\n"))
    };
    ($fmt:expr, $($arg:tt)*) => {
        print!(concat!($fmt, "\r\n"), $($arg)*)
    }
}

#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => {
        $crate::xen::console::_print(format_args!($($arg)*));
    }
}

pub fn _print(fmt: Arguments) {
    let res = write(&mut *console(), fmt);

    if let Err(e) = res {
        panic!("Fail to print on the Xen console: {}", e);
    }
}

pub fn console<'a>() -> SpinGuard<'a, Console> {
    CONSOLE.lock()
}

#[repr(C)]
pub struct ConsoleInterface {
    input: [u8; 1024],
    output: [u8; 2048],
    in_cons: ConsRingIdx,
    in_prod: ConsRingIdx,
    out_cons: ConsRingIdx,
    out_prod: ConsRingIdx,
}

pub struct Console {
    interface: *mut ConsoleInterface,
    port: event::EvtchnPort,
}

impl Console {
    pub const fn new() -> Self {
        Console {
            interface: 0 as *mut ConsoleInterface,
            port: 0,
        }
    }

    pub fn set_interface(&mut self, interface: *mut ConsoleInterface) {
        self.interface = interface
    }

    pub fn set_port(&mut self, port: event::EvtchnPort) {
        self.port = port
    }

    fn is_output_full(&self) -> bool {
        let data: ConsRingIdx;

        data = self.out_prod - self.out_cons;

        // size_of output field
        (data as usize) >= size_of::<[u8; 2048]>()
    }

    fn out_idx(&self) -> usize {
        let size_of_output = (size_of::<[u8; 2048]>() - 1) as u32;

        (self.out_prod & size_of_output) as usize
    }

    pub fn flush(&self) -> () {
        while self.out_cons < self.out_prod {
            sched::yield_cpu();
        }
    }
}

impl Deref for Console {
    type Target = ConsoleInterface;

    #[inline]
    fn deref(&self) -> &ConsoleInterface {
        // This isn't totally safe. If the interface has not been initialized
        // this would cause some problems. For this to be safe, the console
        // MUST be initialized before being used
        unsafe {
            &(*self.interface)
        }
    }
}

impl DerefMut for Console {
    #[inline]
    fn deref_mut(&mut self) -> &mut ConsoleInterface {
        // See deref
        unsafe {
            &mut (*self.interface)
        }
    }
}

impl Write for Console {
    fn write_str(&mut self, s: &str) -> Result {

        for c in s.as_bytes() {
            while self.is_output_full() {
                event::send(self.port);
            }

            let index = self.out_idx();

            self.output[index] = *c;
            ::arch::barrier::wmb();

            self.out_prod += 1;
        }

        event::send(self.port);

        Ok(())
    }
}
<|endoftext|>


<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::{DeterministicRandomId, SiphashIdGenerator, RowId, FieldId, Column, ExtendedTime,
            EventRng, Basics, TimeSteward, FiatEventOperationResult, ValidSince,
            TimeStewardLifetimedMethods};
use std::collections::{HashMap, BTreeMap};
use std::hash::Hash;
// use std::collections::Bound::{Included, Excluded, Unbounded};
use std::any::Any;
use std::borrow::Borrow;
use std::rc::Rc;
use rand::Rng;

#[derive (Clone)]
struct Field<B: Basics> {
  last_change: ExtendedTime<B>,
  data: Rc<Any>,
}

#[derive (Clone)]
struct StewardState<B: Basics> {
  last_change: Option<ExtendedTime<B>>,
  field_states: HashMap<FieldId, Field<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> = Steward<B>;
pub struct Snapshot<'a, B: Basics> {
  now: B::Time,
  state: StewardState<B>,
  settings: &'a StewardSettings<B>,
}
pub struct Mutator<'a, B: Basics> {
  now: ExtendedTime<B>,
  steward: &'a mut StewardImpl<B>,
  generator: EventRng,
}
pub struct PredictorAccessor<'a, B: Basics> {
  steward: &'a StewardImpl<B>,
  soonest_prediction: Option<(B::Time, Event<B>)>,
  dependencies_hasher: SiphashIdGenerator,
}
pub type Event<B> = Rc<for<'d, 'e> Fn(&'d mut Mutator<'e, B>)>;
pub type Predictor<B> = super::Predictor<PredictorFn<B>>;
pub type PredictorFn<B> = Rc<for<'b, 'c> Fn(&'b mut PredictorAccessor<'c, B>, RowId)>;

impl<'a, B: Basics> super::Accessor<B> for Snapshot<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.state.get::<C>(id).map(|p| p.0)
  }
  fn constants(&self) -> &B::Constants {
    &self.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.state.get::<C>(id).map(|p| p.0)
  }
  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.state.get::<C>(id).map(|p| {
      p.1.id.hash(&mut self.dependencies_hasher);
      p.0
    })
  }
  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.base
  }
}
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 set<C: Column>(&mut self, id: RowId, data: Option<C::FieldType>) {
    self.steward.state.set_opt::<C>(id, data, &self.now);
  }
  fn rng(&mut self) -> &mut EventRng {
    &mut self.generator
  }
  fn random_id(&mut self) -> RowId {
    RowId { data: [self.generator.gen::<u64>(), self.generator.gen::<u64>()] }
  }
}

// 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> StewardState<B> {
  fn get<C: Column>(&self, id: RowId) -> Option<(&C::FieldType, &ExtendedTime<B>)> {
    self.field_states
      .get(&FieldId {
        row_id: id,
        column_id: C::column_id(),
      })
      .map(|something| {
        (something.data
          .downcast_ref::<C::FieldType>()
          .expect("a field had the wrong type for its column")
          .borrow(),
         &something.last_change)
      })
  }
  fn set<C: Column>(&mut self, id: RowId, value: C::FieldType, time: &ExtendedTime<B>) {
    self.field_states
      .insert(FieldId {
                row_id: id,
                column_id: C::column_id(),
              },
              Field {
                data: Rc::new(value),
                last_change: time.clone(),
              });
  }
  fn remove<C: Column>(&mut self, id: RowId) {
    self.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>,
                        time: &ExtendedTime<B>) {
    if let Some(value) = value_opt {
      self.set::<C>(id, value, time);
    } else {
      self.remove::<C>(id);
    }
  }
}
impl<B: Basics> StewardImpl<B> {
  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,
              dependencies_hasher: SiphashIdGenerator::new(),
            };
          (predictor.function)(&mut pa, field_id.row_id);
          let dependencies_hash = pa.dependencies_hasher.generate();
          pa.soonest_prediction.and_then(|(event_base_time, event)|
            super::next_extended_time_of_predicted_event(
              predictor.predictor_id,
              field_id.row_id,
              dependencies_hash,
              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.clone(),
      steward: &mut *self,
      generator: super::generator_for_event(event_time.id),
    });
    // if it was a fiat event, clean it up:
    self.state.fiat_events.remove(&event_time);
    self.state.last_change = Some(event_time);
  }

  fn update_until_beginning_of(&mut self, target_time: &B::Time) {
    while let Some(ev) = self.next_event().filter(|ev| ev.0.base < *target_time) {
      let (event_time, event) = ev;
      self.execute_event(event_time, event);
    }
  }
}

impl<B: Basics> Steward<B> {}
impl<'a, B: Basics> TimeStewardLifetimedMethods<'a, B> for Steward<B> {
  type Snapshot = Snapshot<'a, B>;
  fn snapshot_before(&'a mut self, time: &B::Time) -> Option<Self::Snapshot> {
    if let Some(ref change) = self.state.last_change {
      if change.base >= *time {
        return None;
      }
    }
    self.update_until_beginning_of(time);
    Some(Snapshot {
      now: time.clone(),
      state: self.state.clone(),
      settings: self.settings.as_ref(),
    })
  }
}
impl<B: Basics> 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,
                       id: DeterministicRandomId,
                       event: Self::Event)
                       -> FiatEventOperationResult {
    if let Some(ref change) = self.state.last_change {
      if change.base >= time {
        return FiatEventOperationResult::InvalidTime;
      }
    }
    match self.state.fiat_events.insert(super::extended_time_of_fiat_event(time, id), event) {
      None => FiatEventOperationResult::Success,
      Some(_) => FiatEventOperationResult::InvalidInput,
    }
  }
  fn erase_fiat_event(&mut self,
                      time: &B::Time,
                      id: DeterministicRandomId)
                      -> FiatEventOperationResult {
    if let Some(ref change) = self.state.last_change {
      if change.base >= *time {
        return FiatEventOperationResult::InvalidTime;
      }
    }
    match self.state.fiat_events.remove(&super::extended_time_of_fiat_event(time.clone(), id)) {
      None => FiatEventOperationResult::InvalidInput,
      Some(_) => FiatEventOperationResult::Success,
    }
  }
}
<commit_msg>fix sorta bug with multiple predictions from one predictor<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::{DeterministicRandomId, SiphashIdGenerator, RowId, FieldId, Column, ExtendedTime,
            EventRng, Basics, TimeSteward, FiatEventOperationResult, ValidSince,
            TimeStewardLifetimedMethods};
use std::collections::{HashMap, BTreeMap};
use std::hash::Hash;
// use std::collections::Bound::{Included, Excluded, Unbounded};
use std::any::Any;
use std::borrow::Borrow;
use std::rc::Rc;
use rand::Rng;

#[derive (Clone)]
struct Field<B: Basics> {
  last_change: ExtendedTime<B>,
  data: Rc<Any>,
}

#[derive (Clone)]
struct StewardState<B: Basics> {
  last_change: Option<ExtendedTime<B>>,
  field_states: HashMap<FieldId, Field<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> = Steward<B>;
pub struct Snapshot<'a, B: Basics> {
  now: B::Time,
  state: StewardState<B>,
  settings: &'a StewardSettings<B>,
}
pub struct Mutator<'a, B: Basics> {
  now: ExtendedTime<B>,
  steward: &'a mut StewardImpl<B>,
  generator: EventRng,
}
pub struct PredictorAccessor<'a, B: Basics> {
  steward: &'a StewardImpl<B>,
  soonest_prediction: Option<(B::Time, Event<B>)>,
  dependencies_hasher: SiphashIdGenerator,
}
pub type Event<B> = Rc<for<'d, 'e> Fn(&'d mut Mutator<'e, B>)>;
pub type Predictor<B> = super::Predictor<PredictorFn<B>>;
pub type PredictorFn<B> = Rc<for<'b, 'c> Fn(&'b mut PredictorAccessor<'c, B>, RowId)>;

impl<'a, B: Basics> super::Accessor<B> for Snapshot<'a, B> {
  fn get<C: Column>(&mut self, id: RowId) -> Option<&C::FieldType> {
    self.state.get::<C>(id).map(|p| p.0)
  }
  fn constants(&self) -> &B::Constants {
    &self.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.state.get::<C>(id).map(|p| p.0)
  }
  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.state.get::<C>(id).map(|p| {
      p.1.id.hash(&mut self.dependencies_hasher);
      p.0
    })
  }
  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.base
  }
}
impl<'a, B: Basics> PredictorAccessor<'a, B> {
  fn internal_now<'b>(&'b self) -> &'a ExtendedTime<B> {
    self.steward
        .state
        .last_change
        .as_ref()
        .expect("how can we be calling a predictor when there are no fields \
                yet?")
  }
}
impl<'a, B: Basics> super::PredictorAccessor<B> for PredictorAccessor<'a, B> {
  type Event = Event<B>;
  fn predict_immediately(&mut self, event: Event<B>) {
    let t = &self.internal_now().base;
    self.predict_at_time(t, event);
  }
  fn predict_at_time(&mut self, time: &B::Time, event: Event<B>) {
    if time < &self.internal_now().base {
      return;
    }
    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 set<C: Column>(&mut self, id: RowId, data: Option<C::FieldType>) {
    self.steward.state.set_opt::<C>(id, data, &self.now);
  }
  fn rng(&mut self) -> &mut EventRng {
    &mut self.generator
  }
  fn random_id(&mut self) -> RowId {
    RowId { data: [self.generator.gen::<u64>(), self.generator.gen::<u64>()] }
  }
}

// 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> StewardState<B> {
  fn get<C: Column>(&self, id: RowId) -> Option<(&C::FieldType, &ExtendedTime<B>)> {
    self.field_states
      .get(&FieldId {
        row_id: id,
        column_id: C::column_id(),
      })
      .map(|something| {
        (something.data
          .downcast_ref::<C::FieldType>()
          .expect("a field had the wrong type for its column")
          .borrow(),
         &something.last_change)
      })
  }
  fn set<C: Column>(&mut self, id: RowId, value: C::FieldType, time: &ExtendedTime<B>) {
    self.field_states
      .insert(FieldId {
                row_id: id,
                column_id: C::column_id(),
              },
              Field {
                data: Rc::new(value),
                last_change: time.clone(),
              });
  }
  fn remove<C: Column>(&mut self, id: RowId) {
    self.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>,
                        time: &ExtendedTime<B>) {
    if let Some(value) = value_opt {
      self.set::<C>(id, value, time);
    } else {
      self.remove::<C>(id);
    }
  }
}
impl<B: Basics> StewardImpl<B> {
  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,
              dependencies_hasher: SiphashIdGenerator::new(),
            };
          (predictor.function)(&mut pa, field_id.row_id);
          let dependencies_hash = pa.dependencies_hasher.generate();
          pa.soonest_prediction.and_then(|(event_base_time, event)|
            super::next_extended_time_of_predicted_event(
              predictor.predictor_id,
              field_id.row_id,
              dependencies_hash,
              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.clone(),
      steward: &mut *self,
      generator: super::generator_for_event(event_time.id),
    });
    // if it was a fiat event, clean it up:
    self.state.fiat_events.remove(&event_time);
    self.state.last_change = Some(event_time);
  }

  fn update_until_beginning_of(&mut self, target_time: &B::Time) {
    while let Some(ev) = self.next_event().filter(|ev| ev.0.base < *target_time) {
      let (event_time, event) = ev;
      self.execute_event(event_time, event);
    }
  }
}

impl<B: Basics> Steward<B> {}
impl<'a, B: Basics> TimeStewardLifetimedMethods<'a, B> for Steward<B> {
  type Snapshot = Snapshot<'a, B>;
  fn snapshot_before(&'a mut self, time: &B::Time) -> Option<Self::Snapshot> {
    if let Some(ref change) = self.state.last_change {
      if change.base >= *time {
        return None;
      }
    }
    self.update_until_beginning_of(time);
    Some(Snapshot {
      now: time.clone(),
      state: self.state.clone(),
      settings: self.settings.as_ref(),
    })
  }
}
impl<B: Basics> 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,
                       id: DeterministicRandomId,
                       event: Self::Event)
                       -> FiatEventOperationResult {
    if let Some(ref change) = self.state.last_change {
      if change.base >= time {
        return FiatEventOperationResult::InvalidTime;
      }
    }
    match self.state.fiat_events.insert(super::extended_time_of_fiat_event(time, id), event) {
      None => FiatEventOperationResult::Success,
      Some(_) => FiatEventOperationResult::InvalidInput,
    }
  }
  fn erase_fiat_event(&mut self,
                      time: &B::Time,
                      id: DeterministicRandomId)
                      -> FiatEventOperationResult {
    if let Some(ref change) = self.state.last_change {
      if change.base >= *time {
        return FiatEventOperationResult::InvalidTime;
      }
    }
    match self.state.fiat_events.remove(&super::extended_time_of_fiat_event(time.clone(), id)) {
      None => FiatEventOperationResult::InvalidInput,
      Some(_) => FiatEventOperationResult::Success,
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use util::nodemap::{FxHashMap, FxHashSet};
use ty::context::TyCtxt;
use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
use ty::{DefId, Substs};
use ty::{AdtKind, Visibility};
use ty::TyKind::*;

pub use self::def_id_forest::DefIdForest;

mod def_id_forest;

// The methods in this module calculate DefIdForests of modules in which a
// AdtDef/VariantDef/FieldDef is visibly uninhabited.
//
// # Example
// ```rust
// enum Void {}
// mod a {
//     pub mod b {
//         pub struct SecretlyUninhabited {
//             _priv: !,
//         }
//     }
// }
//
// mod c {
//     pub struct AlsoSecretlyUninhabited {
//         _priv: Void,
//     }
//     mod d {
//     }
// }
//
// struct Foo {
//     x: a::b::SecretlyUninhabited,
//     y: c::AlsoSecretlyUninhabited,
// }
// ```
// In this code, the type Foo will only be visibly uninhabited inside the
// modules b, c and d. Calling uninhabited_from on Foo or its AdtDef will
// return the forest of modules {b, c->d} (represented in a DefIdForest by the
// set {b, c})
//
// We need this information for pattern-matching on Foo or types that contain
// Foo.
//
// # Example
// ```rust
// let foo_result: Result<T, Foo> = ... ;
// let Ok(t) = foo_result;
// ```
// This code should only compile in modules where the uninhabitedness of Foo is
// visible.

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
    /// Checks whether a type is visibly uninhabited from a particular module.
    /// # Example
    /// ```rust
    /// enum Void {}
    /// mod a {
    ///     pub mod b {
    ///         pub struct SecretlyUninhabited {
    ///             _priv: !,
    ///         }
    ///     }
    /// }
    ///
    /// mod c {
    ///     pub struct AlsoSecretlyUninhabited {
    ///         _priv: Void,
    ///     }
    ///     mod d {
    ///     }
    /// }
    ///
    /// struct Foo {
    ///     x: a::b::SecretlyUninhabited,
    ///     y: c::AlsoSecretlyUninhabited,
    /// }
    /// ```
    /// In this code, the type `Foo` will only be visibly uninhabited inside the
    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
    /// contain `Foo`.
    ///
    /// # Example
    /// ```rust
    /// let foo_result: Result<T, Foo> = ... ;
    /// let Ok(t) = foo_result;
    /// ```
    /// This code should only compile in modules where the uninhabitedness of Foo is
    /// visible.
    pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
        // To check whether this type is uninhabited at all (not just from the
        // given node) you could check whether the forest is empty.
        // ```
        // forest.is_empty()
        // ```
        self.ty_inhabitedness_forest(ty).contains(self, module)
    }

    pub fn is_ty_uninhabited_from_all_modules(self, ty: Ty<'tcx>) -> bool {
        !self.ty_inhabitedness_forest(ty).is_empty()
    }

    fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
        ty.uninhabited_from(&mut FxHashMap::default(), self)
    }

    pub fn is_enum_variant_uninhabited_from(self,
                                            module: DefId,
                                            variant: &'tcx VariantDef,
                                            substs: &'tcx Substs<'tcx>)
                                            -> bool
    {
        self.variant_inhabitedness_forest(variant, substs).contains(self, module)
    }

    pub fn is_variant_uninhabited_from_all_modules(self,
                                                   variant: &'tcx VariantDef,
                                                   substs: &'tcx Substs<'tcx>)
                                                   -> bool
    {
        !self.variant_inhabitedness_forest(variant, substs).is_empty()
    }

    fn variant_inhabitedness_forest(self, variant: &'tcx VariantDef, substs: &'tcx Substs<'tcx>)
                                    -> DefIdForest {
        // Determine the ADT kind:
        let adt_def_id = self.adt_def_id_of_variant(variant);
        let adt_kind = self.adt_def(adt_def_id).adt_kind();

        // Compute inhabitedness forest:
        variant.uninhabited_from(&mut FxHashMap::default(), self, substs, adt_kind)
    }
}

impl<'a, 'gcx, 'tcx> AdtDef {
    /// Calculate the forest of DefIds from which this adt is visibly uninhabited.
    fn uninhabited_from(
        &self,
        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        substs: &'tcx Substs<'tcx>) -> DefIdForest
    {
        DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
            v.uninhabited_from(visited, tcx, substs, self.adt_kind())
        }))
    }
}

impl<'a, 'gcx, 'tcx> VariantDef {
    /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
    fn uninhabited_from(
        &self,
        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        substs: &'tcx Substs<'tcx>,
        adt_kind: AdtKind) -> DefIdForest
    {
        let is_enum = match adt_kind {
            // For now, `union`s are never considered uninhabited.
            // The precise semantics of inhabitedness with respect to unions is currently undecided.
            AdtKind::Union => return DefIdForest::empty(),
            AdtKind::Enum => true,
            AdtKind::Struct => false,
        };
        DefIdForest::union(tcx, self.fields.iter().map(|f| {
            f.uninhabited_from(visited, tcx, substs, is_enum)
        }))
    }
}

impl<'a, 'gcx, 'tcx> FieldDef {
    /// Calculate the forest of DefIds from which this field is visibly uninhabited.
    fn uninhabited_from(
        &self,
        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        substs: &'tcx Substs<'tcx>,
        is_enum: bool,
    ) -> DefIdForest {
        let mut data_uninhabitedness = move || {
            self.ty(tcx, substs).uninhabited_from(visited, tcx)
        };
        // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
        // Visibility::Invisible so we need to override self.vis if we're
        // dealing with an enum.
        if is_enum {
            data_uninhabitedness()
        } else {
            match self.vis {
                Visibility::Invisible => DefIdForest::empty(),
                Visibility::Restricted(from) => {
                    let forest = DefIdForest::from_id(from);
                    let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
                    DefIdForest::intersection(tcx, iter)
                },
                Visibility::Public => data_uninhabitedness(),
            }
        }
    }
}

impl<'a, 'gcx, 'tcx> TyS<'tcx> {
    /// Calculate the forest of DefIds from which this type is visibly uninhabited.
    fn uninhabited_from(
        &self,
        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
        tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
    {
        match self.sty {
            Adt(def, substs) => {
                {
                    let substs_set = visited.entry(def.did).or_default();
                    if !substs_set.insert(substs) {
                        // We are already calculating the inhabitedness of this type.
                        // The type must contain a reference to itself. Break the
                        // infinite loop.
                        return DefIdForest::empty();
                    }
                    if substs_set.len() >= tcx.sess.recursion_limit.get() / 4 {
                        // We have gone very deep, reinstantiating this ADT inside
                        // itself with different type arguments. We are probably
                        // hitting an infinite loop. For example, it's possible to write:
                        //                a type Foo<T>
                        //      which contains a Foo<(T, T)>
                        //      which contains a Foo<((T, T), (T, T))>
                        //      which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))>
                        //      etc.
                        let error = format!("reached recursion limit while checking \
                                             inhabitedness of `{}`", self);
                        tcx.sess.fatal(&error);
                    }
                }
                let ret = def.uninhabited_from(visited, tcx, substs);
                let substs_set = visited.get_mut(&def.did).unwrap();
                substs_set.remove(substs);
                ret
            }

            Never => DefIdForest::full(tcx),

            Tuple(ref tys) => {
                DefIdForest::union(tcx, tys.iter().map(|ty| {
                    ty.uninhabited_from(visited, tcx)
                }))
            }

            Array(ty, len) => {
                match len.assert_usize(tcx) {
                    // If the array is definitely non-empty, it's uninhabited if
                    // the type of its elements is uninhabited.
                    Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
                    _ => DefIdForest::empty()
                }
            }

            // References to uninitialised memory is valid for any type, including
            // uninhabited types, in unsafe code, so we treat all references as
            // inhabited.
            // The precise semantics of inhabitedness with respect to references is currently
            // undecided.
            Ref(..) => DefIdForest::empty(),

            _ => DefIdForest::empty(),
        }
    }
}

<commit_msg>Remove "visited" set from inhabitedness checking<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ty::context::TyCtxt;
use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
use ty::{DefId, Substs};
use ty::{AdtKind, Visibility};
use ty::TyKind::*;

pub use self::def_id_forest::DefIdForest;

mod def_id_forest;

// The methods in this module calculate DefIdForests of modules in which a
// AdtDef/VariantDef/FieldDef is visibly uninhabited.
//
// # Example
// ```rust
// enum Void {}
// mod a {
//     pub mod b {
//         pub struct SecretlyUninhabited {
//             _priv: !,
//         }
//     }
// }
//
// mod c {
//     pub struct AlsoSecretlyUninhabited {
//         _priv: Void,
//     }
//     mod d {
//     }
// }
//
// struct Foo {
//     x: a::b::SecretlyUninhabited,
//     y: c::AlsoSecretlyUninhabited,
// }
// ```
// In this code, the type Foo will only be visibly uninhabited inside the
// modules b, c and d. Calling uninhabited_from on Foo or its AdtDef will
// return the forest of modules {b, c->d} (represented in a DefIdForest by the
// set {b, c})
//
// We need this information for pattern-matching on Foo or types that contain
// Foo.
//
// # Example
// ```rust
// let foo_result: Result<T, Foo> = ... ;
// let Ok(t) = foo_result;
// ```
// This code should only compile in modules where the uninhabitedness of Foo is
// visible.

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
    /// Checks whether a type is visibly uninhabited from a particular module.
    /// # Example
    /// ```rust
    /// enum Void {}
    /// mod a {
    ///     pub mod b {
    ///         pub struct SecretlyUninhabited {
    ///             _priv: !,
    ///         }
    ///     }
    /// }
    ///
    /// mod c {
    ///     pub struct AlsoSecretlyUninhabited {
    ///         _priv: Void,
    ///     }
    ///     mod d {
    ///     }
    /// }
    ///
    /// struct Foo {
    ///     x: a::b::SecretlyUninhabited,
    ///     y: c::AlsoSecretlyUninhabited,
    /// }
    /// ```
    /// In this code, the type `Foo` will only be visibly uninhabited inside the
    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
    /// contain `Foo`.
    ///
    /// # Example
    /// ```rust
    /// let foo_result: Result<T, Foo> = ... ;
    /// let Ok(t) = foo_result;
    /// ```
    /// This code should only compile in modules where the uninhabitedness of Foo is
    /// visible.
    pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
        // To check whether this type is uninhabited at all (not just from the
        // given node) you could check whether the forest is empty.
        // ```
        // forest.is_empty()
        // ```
        self.ty_inhabitedness_forest(ty).contains(self, module)
    }

    pub fn is_ty_uninhabited_from_all_modules(self, ty: Ty<'tcx>) -> bool {
        !self.ty_inhabitedness_forest(ty).is_empty()
    }

    fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
        ty.uninhabited_from(self)
    }

    pub fn is_enum_variant_uninhabited_from(self,
                                            module: DefId,
                                            variant: &'tcx VariantDef,
                                            substs: &'tcx Substs<'tcx>)
                                            -> bool
    {
        self.variant_inhabitedness_forest(variant, substs).contains(self, module)
    }

    pub fn is_variant_uninhabited_from_all_modules(self,
                                                   variant: &'tcx VariantDef,
                                                   substs: &'tcx Substs<'tcx>)
                                                   -> bool
    {
        !self.variant_inhabitedness_forest(variant, substs).is_empty()
    }

    fn variant_inhabitedness_forest(self, variant: &'tcx VariantDef, substs: &'tcx Substs<'tcx>)
                                    -> DefIdForest {
        // Determine the ADT kind:
        let adt_def_id = self.adt_def_id_of_variant(variant);
        let adt_kind = self.adt_def(adt_def_id).adt_kind();

        // Compute inhabitedness forest:
        variant.uninhabited_from(self, substs, adt_kind)
    }
}

impl<'a, 'gcx, 'tcx> AdtDef {
    /// Calculate the forest of DefIds from which this adt is visibly uninhabited.
    fn uninhabited_from(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        substs: &'tcx Substs<'tcx>) -> DefIdForest
    {
        DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
            v.uninhabited_from(tcx, substs, self.adt_kind())
        }))
    }
}

impl<'a, 'gcx, 'tcx> VariantDef {
    /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
    fn uninhabited_from(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        substs: &'tcx Substs<'tcx>,
        adt_kind: AdtKind) -> DefIdForest
    {
        let is_enum = match adt_kind {
            // For now, `union`s are never considered uninhabited.
            // The precise semantics of inhabitedness with respect to unions is currently undecided.
            AdtKind::Union => return DefIdForest::empty(),
            AdtKind::Enum => true,
            AdtKind::Struct => false,
        };
        DefIdForest::union(tcx, self.fields.iter().map(|f| {
            f.uninhabited_from(tcx, substs, is_enum)
        }))
    }
}

impl<'a, 'gcx, 'tcx> FieldDef {
    /// Calculate the forest of DefIds from which this field is visibly uninhabited.
    fn uninhabited_from(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        substs: &'tcx Substs<'tcx>,
        is_enum: bool,
    ) -> DefIdForest {
        let data_uninhabitedness = move || {
            self.ty(tcx, substs).uninhabited_from(tcx)
        };
        // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
        // Visibility::Invisible so we need to override self.vis if we're
        // dealing with an enum.
        if is_enum {
            data_uninhabitedness()
        } else {
            match self.vis {
                Visibility::Invisible => DefIdForest::empty(),
                Visibility::Restricted(from) => {
                    let forest = DefIdForest::from_id(from);
                    let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
                    DefIdForest::intersection(tcx, iter)
                },
                Visibility::Public => data_uninhabitedness(),
            }
        }
    }
}

impl<'a, 'gcx, 'tcx> TyS<'tcx> {
    /// Calculate the forest of DefIds from which this type is visibly uninhabited.
    fn uninhabited_from(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
    {
        match self.sty {
            Adt(def, substs) => def.uninhabited_from(tcx, substs),

            Never => DefIdForest::full(tcx),

            Tuple(ref tys) => {
                DefIdForest::union(tcx, tys.iter().map(|ty| {
                    ty.uninhabited_from(tcx)
                }))
            }

            Array(ty, len) => {
                match len.assert_usize(tcx) {
                    // If the array is definitely non-empty, it's uninhabited if
                    // the type of its elements is uninhabited.
                    Some(n) if n != 0 => ty.uninhabited_from(tcx),
                    _ => DefIdForest::empty()
                }
            }

            // References to uninitialised memory is valid for any type, including
            // uninhabited types, in unsafe code, so we treat all references as
            // inhabited.
            // The precise semantics of inhabitedness with respect to references is currently
            // undecided.
            Ref(..) => DefIdForest::empty(),

            _ => DefIdForest::empty(),
        }
    }
}

<|endoftext|>


<commit_before>use svm::cell::SVMCell;

use self::ExprNode::*;
use self::NumNode::*;
use super::ForkTable;
/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
pub type SymTable<'a>   = ForkTable<'a, &'a str, (usize,usize)>;
/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`.
pub type CompileResult  = Result<SVMCell, &'static str>;

static INDENT: &'static str = "\t";

/// Trait for AST nodes.
pub trait ASTNode {
    /// Compile this node to a list of SVM expressions
    fn compile(self, state: SymTable)   -> CompileResult;

    /// Pretty-print this node
    fn prettyprint(&self)               -> String { self.print_level(0usize) }

    /// Pretty-print this node at the desired indent level
    fn print_level(&self, level: usize) -> String;
}

/// Expression
///
/// All Seax Scheme expressions are one of the following
///
///  + Nested S-Expressions
///  + Identifiers
///  + Lists
///  + Numbers
///     - signed int
///     - unsigned int
///     - floating-point
///  + Characters
///  + Strings
///
///  TODO: implement the entire Scheme 'numeric tower'
///  TODO: macros should happen
///  TODO: figure out quasiquote somehow.
#[derive(Clone, PartialEq,Debug)]
pub enum ExprNode {
    Root(RootNode),
    SExpr(SExprNode),
    Name(NameNode),
    ListConst(ListNode),
    NumConst(NumNode),
    BoolConst(BoolNode),
    StringConst(StringNode),
    CharConst(CharNode),
}

impl ASTNode for ExprNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        match self {
            //  TODO: should some of these nodes cause a state fork?
            Root(node)          => node.compile(state),
            SExpr(node)         => node.compile(state),
            Name(node)          => node.compile(state),
            ListConst(node)     => node.compile(state),
            NumConst(node)      => node.compile(state),
            BoolConst(node)     => node.compile(state),
            CharConst(node)     => node.compile(state),
            StringConst(node)   => node.compile(state)
        }
    }

    fn print_level(&self, level: usize) -> String {
        match *self {
            Root(ref node)          => node.print_level(level),
            SExpr(ref node)         => node.print_level(level),
            Name(ref node)          => node.print_level(level),
            ListConst(ref node)     => node.print_level(level),
            NumConst(ref node)      => node.print_level(level),
            BoolConst(ref node)     => node.print_level(level),
            CharConst(ref node)     => node.print_level(level),
            StringConst(ref node)   => node.print_level(level)
        }
    }
}

#[derive(Clone, PartialEq,Debug)]
pub enum NumNode {
    IntConst(IntNode),
    UIntConst(UIntNode),
    FloatConst(FloatNode)
}

/// AST node for the root of a program's AST
#[derive(Clone, PartialEq,Debug)]
pub struct RootNode { pub exprs: Vec<ExprNode> }

impl ASTNode for RootNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        self.exprs
            .iter()
            .fold(
                String::new(),
                |mut s, i| {
                    s.push_str(i.print_level(level + 1).as_ref());
                    s
                })
    }

}

/// AST node for an S-expression.
///
/// This includes function application, assignment,
/// function definition, et cetera...Scheme is not a complexl anguage.
#[derive(Clone, PartialEq,Debug)]
pub struct SExprNode {
    pub operator: NameNode,
    pub operands: Vec<ExprNode>,
}

impl ASTNode for SExprNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level { tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("S-Expression:\n");
        tab.push_str(INDENT);

        // op
        result.push_str(tab.as_ref());
        result.push_str("Operator:\n");
        result.push_str(self.operator.print_level(level + 1).as_ref());
        result.push('\n');

        for operand in self.operands.iter() {
            result.push_str(tab.as_ref());
            result.push_str("Operand: \n");
            result.push_str(operand.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for a list literal
#[derive(Clone, PartialEq,Debug)]
pub struct ListNode { pub elements: Vec<ExprNode> }

impl ASTNode for ListNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("List:\n");
        tab.push_str(INDENT);

        for elem in self.elements.iter() {
            result.push_str(tab.as_ref());
            result.push_str(elem.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for an identifier
#[derive(Clone, PartialEq,Debug)]
pub struct NameNode { pub name: String }

impl ASTNode for NameNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT)};

        let mut result = String::new();
        result.push_str(tab.as_ref());
        result.push_str("Name: ");
        result.push_str(self.name.as_ref());
        result.push_str("\n");

        result
    }

}

/// AST node for an integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct IntNode { pub value: isize }

impl ASTNode for NumNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Number: ");

        match *self {
            NumNode::UIntConst(ref node) => {
                result.push_str(format!("{}u", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::IntConst(ref node) => {
                result.push_str(format!("{}", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::FloatConst(ref node) => {
                result.push_str(format!("{}f", node.value).as_ref());
                result.push_str("\n");
            }
        }
        result
    }
}

/// AST node for an unsigned integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct UIntNode { pub value: usize }

/// AST node for a floating-point constant
#[derive(Clone, PartialEq,Debug)]
pub struct FloatNode { pub value: f64 }

/// AST node for a boolean constant
#[derive(Clone, PartialEq,Debug)]
pub struct BoolNode { pub value: bool }

impl ASTNode for BoolNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Boolean: ");
        result.push_str(format!("{}", self.value).as_ref());
        result.push_str("\n");
        result
    }
}

/// AST node for a character constant
#[derive(Clone, PartialEq,Debug)]
pub struct CharNode { pub value: char }

impl ASTNode for CharNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("Character: \'");
        result.push(self.value);
        result.push_str("\'\n");
        result
    }
}

/// AST node for a  string constant
#[derive(Clone, PartialEq,Debug)]
pub struct StringNode { pub value: String }

impl ASTNode for StringNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("String: \"");
        result.push_str(self.value.as_ref());
        result.push_str("\"\n");
        result
    }
}

<commit_msg>Implemented AsRef for NameNode<commit_after>use svm::cell::SVMCell;

use self::ExprNode::*;
use self::NumNode::*;
use super::ForkTable;
/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
pub type SymTable<'a>   = ForkTable<'a, &'a str, (usize,usize)>;
/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`.
pub type CompileResult  = Result<SVMCell, &'static str>;

static INDENT: &'static str = "\t";

/// Trait for AST nodes.
pub trait ASTNode {
    /// Compile this node to a list of SVM expressions
    fn compile(self, state: SymTable)   -> CompileResult;

    /// Pretty-print this node
    fn prettyprint(&self)               -> String { self.print_level(0usize) }

    /// Pretty-print this node at the desired indent level
    fn print_level(&self, level: usize) -> String;
}

/// Expression
///
/// All Seax Scheme expressions are one of the following
///
///  + Nested S-Expressions
///  + Identifiers
///  + Lists
///  + Numbers
///     - signed int
///     - unsigned int
///     - floating-point
///  + Characters
///  + Strings
///
///  TODO: implement the entire Scheme 'numeric tower'
///  TODO: macros should happen
///  TODO: figure out quasiquote somehow.
#[derive(Clone, PartialEq,Debug)]
pub enum ExprNode {
    Root(RootNode),
    SExpr(SExprNode),
    Name(NameNode),
    ListConst(ListNode),
    NumConst(NumNode),
    BoolConst(BoolNode),
    StringConst(StringNode),
    CharConst(CharNode),
}

impl ASTNode for ExprNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        match self {
            //  TODO: should some of these nodes cause a state fork?
            Root(node)          => node.compile(state),
            SExpr(node)         => node.compile(state),
            Name(node)          => node.compile(state),
            ListConst(node)     => node.compile(state),
            NumConst(node)      => node.compile(state),
            BoolConst(node)     => node.compile(state),
            CharConst(node)     => node.compile(state),
            StringConst(node)   => node.compile(state)
        }
    }

    fn print_level(&self, level: usize) -> String {
        match *self {
            Root(ref node)          => node.print_level(level),
            SExpr(ref node)         => node.print_level(level),
            Name(ref node)          => node.print_level(level),
            ListConst(ref node)     => node.print_level(level),
            NumConst(ref node)      => node.print_level(level),
            BoolConst(ref node)     => node.print_level(level),
            CharConst(ref node)     => node.print_level(level),
            StringConst(ref node)   => node.print_level(level)
        }
    }
}

#[derive(Clone, PartialEq,Debug)]
pub enum NumNode {
    IntConst(IntNode),
    UIntConst(UIntNode),
    FloatConst(FloatNode)
}

/// AST node for the root of a program's AST
#[derive(Clone, PartialEq,Debug)]
pub struct RootNode { pub exprs: Vec<ExprNode> }

impl ASTNode for RootNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        self.exprs
            .iter()
            .fold(
                String::new(),
                |mut s, i| {
                    s.push_str(i.print_level(level + 1).as_ref());
                    s
                })
    }

}

/// AST node for an S-expression.
///
/// This includes function application, assignment,
/// function definition, et cetera...Scheme is not a complexl anguage.
#[derive(Clone, PartialEq,Debug)]
pub struct SExprNode {
    pub operator: NameNode,
    pub operands: Vec<ExprNode>,
}

impl ASTNode for SExprNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level { tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("S-Expression:\n");
        tab.push_str(INDENT);

        // op
        result.push_str(tab.as_ref());
        result.push_str("Operator:\n");
        result.push_str(self.operator.print_level(level + 1).as_ref());
        result.push('\n');

        for operand in self.operands.iter() {
            result.push_str(tab.as_ref());
            result.push_str("Operand: \n");
            result.push_str(operand.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for a list literal
#[derive(Clone, PartialEq,Debug)]
pub struct ListNode { pub elements: Vec<ExprNode> }

impl ASTNode for ListNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT); };

        let mut result = String::new();
        result.push_str("List:\n");
        tab.push_str(INDENT);

        for elem in self.elements.iter() {
            result.push_str(tab.as_ref());
            result.push_str(elem.print_level(level + 1).as_ref());
            result.push('\n');
        };
        result
    }

}

/// AST node for an identifier
#[derive(Clone, PartialEq,Debug)]
pub struct NameNode { pub name: String }

impl AsRef<str> for NameNode {

    /// Converts the `String` value of this node to a `&str` reference.
    ///
    /// # Examples:
    /// ```
    /// # use seax_scheme::ast::NameNode;
    /// let node = NameNode { name: "a string".to_string() };
    /// assert_eq!(node.as_ref(), "a string")
    /// ```
    fn as_ref(&self) -> &str {
        self.name.as_ref()
    }
}

impl ASTNode for NameNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT)};

        let mut result = String::new();
        result.push_str(tab.as_ref());
        result.push_str("Name: ");
        result.push_str(self.name.as_ref());
        result.push_str("\n");

        result
    }

}

/// AST node for an integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct IntNode { pub value: isize }

impl ASTNode for NumNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Number: ");

        match *self {
            NumNode::UIntConst(ref node) => {
                result.push_str(format!("{}u", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::IntConst(ref node) => {
                result.push_str(format!("{}", node.value).as_ref());
                result.push_str("\n");
            },
            NumNode::FloatConst(ref node) => {
                result.push_str(format!("{}f", node.value).as_ref());
                result.push_str("\n");
            }
        }
        result
    }
}

/// AST node for an unsigned integer constant
#[derive(Clone, PartialEq,Debug)]
pub struct UIntNode { pub value: usize }

/// AST node for a floating-point constant
#[derive(Clone, PartialEq,Debug)]
pub struct FloatNode { pub value: f64 }

/// AST node for a boolean constant
#[derive(Clone, PartialEq,Debug)]
pub struct BoolNode { pub value: bool }

impl ASTNode for BoolNode {

    fn compile(self,state: SymTable)    -> CompileResult {
        Err("UNINPLEMENTED")
    }

    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str(tab.as_ref());
        result.push_str("Boolean: ");
        result.push_str(format!("{}", self.value).as_ref());
        result.push_str("\n");
        result
    }
}

/// AST node for a character constant
#[derive(Clone, PartialEq,Debug)]
pub struct CharNode { pub value: char }

impl ASTNode for CharNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("Character: \'");
        result.push(self.value);
        result.push_str("\'\n");
        result
    }
}

/// AST node for a  string constant
#[derive(Clone, PartialEq,Debug)]
pub struct StringNode { pub value: String }

impl ASTNode for StringNode {
    fn compile(self, state: SymTable)   -> CompileResult {
        Err("UNINPLEMENTED")
    }
    fn print_level(&self, level: usize) -> String {
        let mut tab = String::new();
        for _ in 0 .. level {tab.push_str(INDENT);};

        let mut result = String::new();

        result.push_str("String: \"");
        result.push_str(self.value.as_ref());
        result.push_str("\"\n");
        result
    }
}

<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly", feature(lang_items, core_intrinsics, panic_implementation))]
#![cfg_attr(feature = "nightly", no_std)]
#![cfg_attr(feature = "nightly", no_main)]

// Pull in the system libc library for what crt0.o likely requires.
extern crate libc;
extern crate raw_cpuid;

#[cfg(feature = "nightly")]
use core::panic::PanicInfo;

#[cfg(feature = "nightly")]
#[no_mangle]
pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
    let _c = raw_cpuid::CpuId::new();
    0
}

#[cfg(not(feature = "nightly"))]
fn main() {
    let _c = raw_cpuid::CpuId::new();
}

#[cfg(feature = "nightly")]
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

#[cfg(feature = "nightly")]
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {}

#[cfg(feature = "nightly")]
#[panic_implementation]
#[no_mangle]
pub fn panic_impl(_info: &PanicInfo) -> ! {
    loop {}
}
<commit_msg>Update formattig.<commit_after>#![cfg_attr(
    feature = "nightly",
    feature(lang_items, core_intrinsics, panic_implementation)
)]
#![cfg_attr(feature = "nightly", no_std)]
#![cfg_attr(feature = "nightly", no_main)]

// Pull in the system libc library for what crt0.o likely requires.
extern crate libc;
extern crate raw_cpuid;

#[cfg(feature = "nightly")]
use core::panic::PanicInfo;

#[cfg(feature = "nightly")]
#[no_mangle]
pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
    let _c = raw_cpuid::CpuId::new();
    0
}

#[cfg(not(feature = "nightly"))]
fn main() {
    let _c = raw_cpuid::CpuId::new();
}

#[cfg(feature = "nightly")]
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

#[cfg(feature = "nightly")]
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {}

#[cfg(feature = "nightly")]
#[panic_implementation]
#[no_mangle]
pub fn panic_impl(_info: &PanicInfo) -> ! {
    loop {}
}
<|endoftext|>


<commit_before>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![allow(dead_code, unused_imports)]

extern crate hyper;
extern crate git2 as git;

use git::{ResetType, Repository, Oid, ObjectType};

use std::env;
use std::io::{Read, Write, Error, Seek, SeekFrom};
use std::fs;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::process::Command;

const MPV_COMMIT: &'static str = "d276a01ac3fd8655a48c4a39d3d8574c25e83027";
const WIN_MPV_ARCHIVE_SIZE: usize = 109615618;
const WIN_MPV_ARCHIVE_URL: &'static str = "https://mpv.srsfckn.biz/mpv-dev-20170212.7z";

fn main() {
#[cfg(feature="build_libmpv")]    {
        let out_dir = env::var("OUT_DIR").unwrap();

        if env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
            let path = format!("{}/libmpv.7z", out_dir);
            let archive = OpenOptions::new().read(true).write(true).open(&path);

            let dummy_err = Error::last_os_error();
            let legacy = archive
                .as_ref()
                .and_then(|v| {
                              if v.metadata().unwrap().len() != WIN_MPV_ARCHIVE_SIZE as u64 {
                                  Ok(&dummy_err)
                              } else {
                                  // The returned error does not matter
                                  Err(&dummy_err)
                              }
                          })
                .is_ok();

            if archive.is_err() || legacy {
                let mut buf = Vec::with_capacity(WIN_MPV_ARCHIVE_SIZE);

                hyper::Client::new()
                    .get(WIN_MPV_ARCHIVE_URL)
                    .send()
                    .expect("retrieving libmpv failed")
                    .read_to_end(&mut buf)
                    .unwrap();

                if legacy {
                    archive.as_ref().unwrap().set_len(0).unwrap();
                    archive.unwrap().write_all(&buf).unwrap();
                } else {
                    File::create(&path)
                        .expect("failed to create file")
                        .write_all(&buf)
                        .unwrap();
                }

                Command::new("7z")
                    .arg("x")
                    .arg(&format!("-o{}", out_dir))
                    .arg(path)
                    .spawn()
                    .expect("7z execution failed")
                    .wait()
                    .expect("7z execution failed");
            }

            if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" {
                println!("cargo:rustc-link-search={}/64/", out_dir);
            } else {
                println!("cargo:rustc-link-search={}/32/", out_dir);
            }
        } else {
            // Assume unix like with sh

            // `target` (in cfg) doesn't really mean target. It means target(host) of build script,
            // which is a bit confusing because it means the actual `--target` everywhere else.
#[cfg(target_pointer_width = "64")]            {
                if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" {
                    panic!("Cross-compiling to different arch not yet supported");
                }
            }
#[cfg(target_pointer_width = "32")]            {
                if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" {
                    panic!("Cross-compiling to different arch not yet supported");
                }
            }

            let url = "https://github.com/mpv-player/mpv-build";
            let path = format!("{}/mpv-build", out_dir);
            let num_threads = env::var("NUM_JOBS").unwrap();
            let needs_rebuild;

            if !Path::new(&path).exists() {
                needs_rebuild = true;
                Repository::clone(url, &path).expect("failed to clone mpv-build");

                Command::new("sh")
                    .arg("-c")
                    .arg(&format!("cd {} && {0}/update", path))
                    .spawn()
                    .expect("mpv-build update failed")
                    .wait()
                    .expect("mpv-build update failed");

                let mpv_repo = Repository::open(&format!("{}/mpv/", path)).unwrap();
                mpv_repo
                    .reset(&mpv_repo
                                .find_object(Oid::from_str(MPV_COMMIT).unwrap(),
                                             Some(ObjectType::Commit))
                                .unwrap(),
                           ResetType::Soft,
                           None)
                    .unwrap();
            } else {
                let mpv_repo = Repository::open(&format!("{}/mpv/", path)).unwrap();

                // If repo is older version cloned by older build script, update
                if mpv_repo
                       .find_object(Oid::from_str(MPV_COMMIT).unwrap(),
                                    Some(ObjectType::Commit))
                       .is_err() {
                    needs_rebuild = true;
                    Command::new("sh")
                        .arg("-c")
                        .arg(&format!("cd {} && {0}/update", path))
                        .spawn()
                        .expect("mpv-build update failed")
                        .wait()
                        .expect("mpv-build update failed");
                } else {
                    needs_rebuild = false;
                }

                mpv_repo
                    .reset(&mpv_repo
                                .find_object(Oid::from_str(MPV_COMMIT).unwrap(),
                                             Some(ObjectType::Commit))
                                .unwrap(),
                           ResetType::Hard,
                           None)
                    .unwrap();
            }

            // The mpv build script interprets the TARGET env var, which is set by cargo to e.g.
            // x86_64-unknown-linux-gnu, thus the script can't find the compiler.
            // TODO: When Cross-compiling to different archs is implemented, this has to be handled.
            env::remove_var("TARGET");

            let cmd = format!("cd {} && echo \"--enable-libmpv-shared\" > {0}/mpv_options \
							  && {0}/build -j{}",
                              path,
                              num_threads);

            if needs_rebuild {
                Command::new("sh")
                    .arg("-c")
                    .arg(&cmd)
                    .spawn()
                    .expect("mpv-build build failed")
                    .wait()
                    .expect("mpv-build build failed");
            }

            println!("cargo:rustc-link-search={}/mpv/build/", path);
        }
    }
}
<commit_msg>[build] Remove indentation level<commit_after>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![allow(dead_code, unused_imports)]

extern crate hyper;
extern crate git2 as git;

use git::{ResetType, Repository, Oid, ObjectType};

use std::env;
use std::io::{Read, Write, Error, Seek, SeekFrom};
use std::fs;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::process::Command;

const MPV_COMMIT: &'static str = "d276a01ac3fd8655a48c4a39d3d8574c25e83027";
const WIN_MPV_ARCHIVE_SIZE: usize = 109615618;
const WIN_MPV_ARCHIVE_URL: &'static str = "https://mpv.srsfckn.biz/mpv-dev-20170212.7z";

// TODO: Once compile_error hits stable, enable this
//#[cfg(all(feature="events_simple", feature="events_complex"))]
//compile_error!("\"events_simple\" and \"events_complex\" are mutually exclusive for thread-safety reasons.");

#[cfg(not(feature="build_libmpv"))]
fn main() {}

#[cfg(feature="build_libmpv")]
fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    if env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
        let path = format!("{}/libmpv.7z", out_dir);
        let archive = OpenOptions::new().read(true).write(true).open(&path);

        let dummy_err = Error::last_os_error();
        let legacy = archive
            .as_ref()
            .and_then(|v| {
                          if v.metadata().unwrap().len() != WIN_MPV_ARCHIVE_SIZE as u64 {
                              Ok(&dummy_err)
                          } else {
                              // The returned error does not matter
                              Err(&dummy_err)
                          }
                      })
            .is_ok();

        if archive.is_err() || legacy {
            let mut buf = Vec::with_capacity(WIN_MPV_ARCHIVE_SIZE);

            hyper::Client::new()
                .get(WIN_MPV_ARCHIVE_URL)
                .send()
                .expect("retrieving libmpv failed")
                .read_to_end(&mut buf)
                .unwrap();

            if legacy {
                archive.as_ref().unwrap().set_len(0).unwrap();
                archive.unwrap().write_all(&buf).unwrap();
            } else {
                File::create(&path)
                    .expect("failed to create file")
                    .write_all(&buf)
                    .unwrap();
            }

            Command::new("7z")
                .arg("x")
                .arg(&format!("-o{}", out_dir))
                .arg(path)
                .spawn()
                .expect("7z execution failed")
                .wait()
                .expect("7z execution failed");
        }

        if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" {
            println!("cargo:rustc-link-search={}/64/", out_dir);
        } else {
            println!("cargo:rustc-link-search={}/32/", out_dir);
        }
    } else {
        // Assume unix like with sh

        // `target` (in cfg) doesn't really mean target. It means target(host) of build script,
        // which is a bit confusing because it means the actual `--target` everywhere else.
#[cfg(target_pointer_width = "64")]            {
            if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" {
                panic!("Cross-compiling to different arch not yet supported");
            }
        }
#[cfg(target_pointer_width = "32")]            {
            if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" {
                panic!("Cross-compiling to different arch not yet supported");
            }
        }

        let url = "https://github.com/mpv-player/mpv-build";
        let path = format!("{}/mpv-build", out_dir);
        let num_threads = env::var("NUM_JOBS").unwrap();
        let needs_rebuild;

        if !Path::new(&path).exists() {
            needs_rebuild = true;
            Repository::clone(url, &path).expect("failed to clone mpv-build");

            Command::new("sh")
                .arg("-c")
                .arg(&format!("cd {} && {0}/update", path))
                .spawn()
                .expect("mpv-build update failed")
                .wait()
                .expect("mpv-build update failed");

            let mpv_repo = Repository::open(&format!("{}/mpv/", path)).unwrap();
            mpv_repo
                .reset(&mpv_repo
                            .find_object(Oid::from_str(MPV_COMMIT).unwrap(),
                                         Some(ObjectType::Commit))
                            .unwrap(),
                       ResetType::Soft,
                       None)
                .unwrap();
        } else {
            let mpv_repo = Repository::open(&format!("{}/mpv/", path)).unwrap();

            // If repo is older version cloned by older build script, update
            if mpv_repo
                   .find_object(Oid::from_str(MPV_COMMIT).unwrap(),
                                Some(ObjectType::Commit))
                   .is_err() {
                needs_rebuild = true;
                Command::new("sh")
                    .arg("-c")
                    .arg(&format!("cd {} && {0}/update", path))
                    .spawn()
                    .expect("mpv-build update failed")
                    .wait()
                    .expect("mpv-build update failed");
            } else {
                needs_rebuild = false;
            }

            mpv_repo
                .reset(&mpv_repo
                            .find_object(Oid::from_str(MPV_COMMIT).unwrap(),
                                         Some(ObjectType::Commit))
                            .unwrap(),
                       ResetType::Hard,
                       None)
                .unwrap();
        }

        // The mpv build script interprets the TARGET env var, which is set by cargo to e.g.
        // x86_64-unknown-linux-gnu, thus the script can't find the compiler.
        // TODO: When Cross-compiling to different archs is implemented, this has to be handled.
        env::remove_var("TARGET");

        let cmd = format!("cd {} && echo \"--enable-libmpv-shared\" > {0}/mpv_options \
						  && {0}/build -j{}",
                          path,
                          num_threads);

        if needs_rebuild {
            Command::new("sh")
                .arg("-c")
                .arg(&cmd)
                .spawn()
                .expect("mpv-build build failed")
                .wait()
                .expect("mpv-build build failed");
        }

        println!("cargo:rustc-link-search={}/mpv/build/", path);
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;

fn osx_version() -> Result<String, std::io::Error> {
    use std::process::Command;

    let output = Command::new("defaults")
        .arg("read")
        .arg("loginwindow")
        .arg("SystemVersionStampAsString")
        .output()?
        .stdout;
    let version_str = std::str::from_utf8(&output).expect("invalid output from `defaults`");
    let version = version_str.trim_right();

    Ok(version.to_owned())
}

fn parse_version(version: &str) -> Option<i32> {
    version
        .split(".")
        .skip(1)
        .next()
        .and_then(|m| m.parse::<i32>().ok())
}

fn frameworks_path() -> Result<String, std::io::Error> {
    // For 10.13 and higher:
    //
    // While macOS has its system frameworks located at "/System/Library/Frameworks"
    // for actually linking against them (especially for cross-compilation) once
    // has to refer to the frameworks as found within "Xcode.app/Contents/Developer/…".

    // Use environment variable if set
    if let Ok(path) = std::env::var("COREAUDIO_FRAMEWORKS_PATH") {
        return Ok(path)
    }

    if osx_version()
        .and_then(|version| Ok(parse_version(&version).map(|v| v >= 13).unwrap_or(false)))
        .unwrap_or(false)
    {
        use std::process::Command;

        let output = Command::new("xcode-select").arg("-p").output()?.stdout;
        let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcode-select`");
        let prefix = prefix_str.trim_right();

        let target = std::env::var("TARGET").unwrap();
        let platform = if target.contains("apple-darwin") {
            "MacOSX"
        } else if target.contains("apple-ios") {
            "iPhoneOS"
        } else {
            unreachable!();
        };

        let infix = if prefix == "/Library/Developer/CommandLineTools" {
            format!("SDKs/{}.sdk", platform)
        } else {
            format!(
                "Platforms/{}.platform/Developer/SDKs/{}.sdk",
                platform, platform
            )
        };

        let suffix = "System/Library/Frameworks";
        let directory = format!("{}/{}/{}", prefix, infix, suffix);

        Ok(directory)
    } else {
        Ok("/System/Library/Frameworks".to_string())
    }
}

fn build(frameworks_path: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox.framework/Headers/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        headers.push("AudioUnit.framework/Headers/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        headers.push("CoreAudio.framework/Headers/CoreAudio.h");
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL.framework/Headers/al.h");
        headers.push("OpenAL.framework/Headers/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if std::env::var("TARGET").unwrap().contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
        }
    }

    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    builder = builder.clang_arg(format!("-F/{}", frameworks_path));

    // Add all headers.
    for relative_path in headers {
        let absolute_path = format!("{}/{}", frameworks_path, relative_path);
        builder = builder.header(absolute_path);
    }

    // Generate the bindings.
    builder = builder
        .trust_clang_mangling(false)
        .derive_default(true)
        .rustfmt_bindings(false);

    if let Ok(cflags) = std::env::var("COREAUDIO_CFLAGS") {
        builder = builder.clang_args(cflags.split(" "));
    }

    let bindings = builder
        .generate()
        .expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if ! (target.contains("apple-darwin") || target.contains("apple-ios")) {
        eprintln!("coreaudio-sys requires macos or ios target");
    }

    if let Ok(directory) = frameworks_path() {
        build(&directory);
    } else {
        eprintln!("coreaudio-sys could not find frameworks path");
    }
}

<commit_msg>Run cargo fmt<commit_after>extern crate bindgen;

fn osx_version() -> Result<String, std::io::Error> {
    use std::process::Command;

    let output = Command::new("defaults")
        .arg("read")
        .arg("loginwindow")
        .arg("SystemVersionStampAsString")
        .output()?
        .stdout;
    let version_str = std::str::from_utf8(&output).expect("invalid output from `defaults`");
    let version = version_str.trim_right();

    Ok(version.to_owned())
}

fn parse_version(version: &str) -> Option<i32> {
    version
        .split(".")
        .skip(1)
        .next()
        .and_then(|m| m.parse::<i32>().ok())
}

fn frameworks_path() -> Result<String, std::io::Error> {
    // For 10.13 and higher:
    //
    // While macOS has its system frameworks located at "/System/Library/Frameworks"
    // for actually linking against them (especially for cross-compilation) once
    // has to refer to the frameworks as found within "Xcode.app/Contents/Developer/…".

    // Use environment variable if set
    if let Ok(path) = std::env::var("COREAUDIO_FRAMEWORKS_PATH") {
        return Ok(path);
    }

    if osx_version()
        .and_then(|version| Ok(parse_version(&version).map(|v| v >= 13).unwrap_or(false)))
        .unwrap_or(false)
    {
        use std::process::Command;

        let output = Command::new("xcode-select").arg("-p").output()?.stdout;
        let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcode-select`");
        let prefix = prefix_str.trim_right();

        let target = std::env::var("TARGET").unwrap();
        let platform = if target.contains("apple-darwin") {
            "MacOSX"
        } else if target.contains("apple-ios") {
            "iPhoneOS"
        } else {
            unreachable!();
        };

        let infix = if prefix == "/Library/Developer/CommandLineTools" {
            format!("SDKs/{}.sdk", platform)
        } else {
            format!(
                "Platforms/{}.platform/Developer/SDKs/{}.sdk",
                platform, platform
            )
        };

        let suffix = "System/Library/Frameworks";
        let directory = format!("{}/{}/{}", prefix, infix, suffix);

        Ok(directory)
    } else {
        Ok("/System/Library/Frameworks".to_string())
    }
}

fn build(frameworks_path: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox.framework/Headers/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        headers.push("AudioUnit.framework/Headers/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        headers.push("CoreAudio.framework/Headers/CoreAudio.h");
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL.framework/Headers/al.h");
        headers.push("OpenAL.framework/Headers/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if std::env::var("TARGET").unwrap().contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
        }
    }

    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    builder = builder.clang_arg(format!("-F/{}", frameworks_path));

    // Add all headers.
    for relative_path in headers {
        let absolute_path = format!("{}/{}", frameworks_path, relative_path);
        builder = builder.header(absolute_path);
    }

    // Generate the bindings.
    builder = builder
        .trust_clang_mangling(false)
        .derive_default(true)
        .rustfmt_bindings(false);

    if let Ok(cflags) = std::env::var("COREAUDIO_CFLAGS") {
        builder = builder.clang_args(cflags.split(" "));
    }

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        eprintln!("coreaudio-sys requires macos or ios target");
    }

    if let Ok(directory) = frameworks_path() {
        build(&directory);
    } else {
        eprintln!("coreaudio-sys could not find frameworks path");
    }
}
<|endoftext|>