<commit_before>use std::path::Path;
use std::str::FromStr;
use temperature::{self, Simulator};

use platform::{Element, ElementKind, Platform, Profile, ProfileBuilder};
use schedule::Decision;
use system::Job;
use {Config, Result};

/// A platform producing power and temperature data.
pub struct Thermal {
    elements: Vec<Element>,
    simulator: Simulator,
    builder: ProfileBuilder,
}

impl Thermal {
    /// Create a platform.
    pub fn new(config: &Config) -> Result<Thermal> {
        let (elements, simulator) = try!(construct_temperature(config.branch("temperature")
                                                                     .as_ref().unwrap_or(config)));

        let builder = try!(construct_power(&elements, config.branch("power").as_ref()
                                                            .unwrap_or(config)));

        Ok(Thermal { elements: elements, simulator: simulator, builder: builder })
    }
}

impl Platform for Thermal {
    type Data = (Profile, Profile);

    #[inline(always)]
    fn elements(&self) -> &[Element] {
        &self.elements
    }

    fn next(&mut self, time: f64) -> Option<Self::Data> {
        let power = self.builder.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    fn push(&mut self, job: &Job, decision: &Decision) -> Result<()> {
        let (from, onto) = (&job.elements, &self.elements);
        for &(i, j) in &decision.mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.builder.push(onto.id, decision.start, job.time_step, &from.dynamic_power);
        }
        Ok(())
    }
}

fn construct_power(elements: &[Element], config: &Config) -> Result<ProfileBuilder> {
    use workload;

    let units = elements.len();
    let time_step = *some!(config.get::<f64>("time_step"), "a time step is required");

    let path = path!(config, "a leakage pattern is required");
    info!(target: "Platform", "Modeling leakage power based on {:?}...", &path);
    let candidates = try!(workload::Element::collect(path));

    let mut leakage_power = vec![0.0; units];
    for i in 0..units {
        if let Some(element) = candidates.iter().find(|element| element.kind == elements[i].kind) {
            leakage_power[i] = element.leakage_power;
        } else {
            raise!("cannot find leakage data for a processing element");
        }
    }

    Ok(ProfileBuilder::new(units, time_step, leakage_power))
}

fn construct_temperature(config: &Config) -> Result<(Vec<Element>, Simulator)> {
    let path = path!(config, "a thermal specification is required");
    info!(target: "Platform", "Modeling temperature based on {:?}...", &path);
    let (elements, circuit) = match path.extension() {
        Some(extension) if extension == "stk" => try!(construct_threed_ice(&path)),
        _ => raise!("the format of {:?} is unknown", &path),
    };
    info!(target: "Platform", "Found {} processing elements and {} thermal nodes.",
          elements.len(), circuit.capacitance.len());

    info!(target: "Platform", "Initializing the temperature simulator...");
    let config = temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    };
    let simulator = ok!(Simulator::new(circuit, config));

    Ok((elements, simulator))
}

fn construct_threed_ice(path: &Path) -> Result<(Vec<Element>, temperature::Circuit)> {
    use temperature::circuit::ThreeDICE;
    use threed_ice::{StackElement, System};

    let system = ok!(System::new(path));
    let mut elements = vec![];
    for element in system.stack.elements.iter().rev() {
        let die = match element {
            &StackElement::Die(ref die) => die,
            _ => continue,
        };
        for element in die.floorplan.elements.iter() {
            let id = elements.len();
            let kind = try!(ElementKind::from_str(&element.id));
            let area = 1e-6 * 1e-6 * element.area;
            elements.push(Element::new(id, kind, area));
        }
    }
    Ok((elements, ok!(ThreeDICE::from(&system))))
}

#[cfg(test)]
mod tests {
    use configuration::format::TOML;
    use platform::{Element, ElementKind, Thermal};

    #[test]
    fn new() {
        let config = TOML::open("tests/fixtures/streamer.toml").unwrap()
                                                               .branch("platform")
                                                               .unwrap();
        let platform = Thermal::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 1, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 2, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 3, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 4, kind: ElementKind::L3, area: 15904e-6 * 3894e-6 },
        ]);
    }
}
<commit_msg>Platform: scale leakage power based on area<commit_after>use std::path::Path;
use std::str::FromStr;
use temperature::{self, Simulator};

use platform::{Element, ElementKind, Platform, Profile, ProfileBuilder};
use schedule::Decision;
use system::Job;
use {Config, Result};

/// A platform producing power and temperature data.
pub struct Thermal {
    elements: Vec<Element>,
    simulator: Simulator,
    builder: ProfileBuilder,
}

impl Thermal {
    /// Create a platform.
    pub fn new(config: &Config) -> Result<Thermal> {
        let (elements, simulator) = try!(construct_temperature(config.branch("temperature")
                                                                     .as_ref().unwrap_or(config)));

        let builder = try!(construct_power(&elements, config.branch("power").as_ref()
                                                            .unwrap_or(config)));

        Ok(Thermal { elements: elements, simulator: simulator, builder: builder })
    }
}

impl Platform for Thermal {
    type Data = (Profile, Profile);

    #[inline(always)]
    fn elements(&self) -> &[Element] {
        &self.elements
    }

    fn next(&mut self, time: f64) -> Option<Self::Data> {
        let power = self.builder.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    fn push(&mut self, job: &Job, decision: &Decision) -> Result<()> {
        let (from, onto) = (&job.elements, &self.elements);
        for &(i, j) in &decision.mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.builder.push(onto.id, decision.start, job.time_step, &from.dynamic_power);
        }
        Ok(())
    }
}

fn construct_power(elements: &[Element], config: &Config) -> Result<ProfileBuilder> {
    use workload;

    let units = elements.len();
    let time_step = *some!(config.get::<f64>("time_step"), "a time step is required");

    let path = path!(config, "a leakage pattern is required");
    info!(target: "Platform", "Modeling leakage power based on {:?}...", &path);
    let models = try!(workload::Element::collect(path));

    let mut leakage_power = vec![0.0; units];
    for (i, element) in elements.iter().enumerate() {
        if let Some(model) = models.iter().find(|model| model.kind == element.kind) {
            debug_assert!(element.area > 0.0 && model.area > 0.0);
            leakage_power[i] = (element.area / model.area) * model.leakage_power;
        } else {
            raise!("cannot find leakage data for a processing element");
        }
    }

    Ok(ProfileBuilder::new(units, time_step, leakage_power))
}

fn construct_temperature(config: &Config) -> Result<(Vec<Element>, Simulator)> {
    let path = path!(config, "a thermal specification is required");
    info!(target: "Platform", "Modeling temperature based on {:?}...", &path);
    let (elements, circuit) = match path.extension() {
        Some(extension) if extension == "stk" => try!(construct_threed_ice(&path)),
        _ => raise!("the format of {:?} is unknown", &path),
    };
    info!(target: "Platform", "Found {} processing elements and {} thermal nodes.",
          elements.len(), circuit.capacitance.len());

    info!(target: "Platform", "Initializing the temperature simulator...");
    let config = temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    };
    let simulator = ok!(Simulator::new(circuit, config));

    Ok((elements, simulator))
}

fn construct_threed_ice(path: &Path) -> Result<(Vec<Element>, temperature::Circuit)> {
    use temperature::circuit::ThreeDICE;
    use threed_ice::{StackElement, System};

    let system = ok!(System::new(path));
    let mut elements = vec![];
    for element in system.stack.elements.iter().rev() {
        let die = match element {
            &StackElement::Die(ref die) => die,
            _ => continue,
        };
        for element in die.floorplan.elements.iter() {
            let id = elements.len();
            let kind = try!(ElementKind::from_str(&element.id));
            let area = 1e-6 * 1e-6 * element.area;
            elements.push(Element::new(id, kind, area));
        }
    }
    Ok((elements, ok!(ThreeDICE::from(&system))))
}

#[cfg(test)]
mod tests {
    use configuration::format::TOML;
    use platform::{Element, ElementKind, Thermal};

    #[test]
    fn new() {
        let config = TOML::open("tests/fixtures/streamer.toml").unwrap()
                                                               .branch("platform")
                                                               .unwrap();
        let platform = Thermal::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 1, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 2, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 3, kind: ElementKind::Core, area: 3976e-6 * 7950e-6 },
            Element { id: 4, kind: ElementKind::L3, area: 15904e-6 * 3894e-6 },
        ]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use interval::ncollections::ops::*;
use solver::propagator::{BoxedDeepClone, Propagator, PropagatorErasure};
use solver::entailment::Status as EStatus;
use solver::entailment::Entailment;
use variable::{Variable, SharedVar};
use solver::dependencies::VarEventDependencies;
use solver::agenda::Agenda;
use solver::event::EventIndex;
use solver::space::*;
use solver::iterator::*;
use std::rc::{try_unwrap, Rc};
use std::cell::RefCell;
use std::fmt::{Formatter, Display, Error};
use std::result::fold;
use std::slice;

pub struct Solver<E, Dom, Deps, A> {
  propagators: Vec<Box<PropagatorErasure<E, Dom> + 'static>>,
  variables: Vec<SharedVar<Dom>>,
  deps: Deps,
  agenda: A
}

impl<E, Dom, Deps, A> VariableIterator for Solver<E, Dom, Deps, A>
{
  type Variable = SharedVar<Dom>;

  fn vars_iter<'a>(&'a self) -> slice::Iter<'a, SharedVar<Dom>> {
    self.variables.iter()
  }
}

impl<E, Dom, Deps, A> Space for Solver<E, Dom, Deps, A> where
 Dom: Cardinality+Clone,
 E: EventIndex,
 Deps: VarEventDependencies,
 A: Agenda
{
  type Constraint = Box<PropagatorErasure<E, Dom> + 'static>;
  type Variable = SharedVar<Dom>;
  type Domain = Dom;
  type Label = Rc<Solver<E, Dom, Deps, A>>;

  fn newvar(&mut self, dom: Dom) -> SharedVar<Dom> {
    let var_idx = self.variables.len();
    self.variables.push(Rc::new(RefCell::new(Variable::new(var_idx, dom))));
    self.variables[var_idx].clone()
  }

  fn add(&mut self, p: <Solver<E, Dom, Deps, A> as Space>::Constraint) {
    self.propagators.push(p);
  }

  fn solve(&mut self) -> Status {
    self.prepare();
    self.propagation_loop()
  }

  fn mark(&self) -> Rc<Solver<E, Dom, Deps, A>> {
    Rc::new(self.deep_clone())
  }

  fn goto(self, label: Rc<Solver<E, Dom, Deps, A>>) -> Self {
    try_unwrap(label).unwrap_or_else(|l| l.deep_clone())
  }
}

impl<E, Dom, Deps, A> Solver<E, Dom, Deps, A> where
 Dom: Clone,
 E: EventIndex,
 Deps: VarEventDependencies,
 A: Agenda
{
  fn deep_clone(&self) -> Self {
    let mut solver = Solver::new();
    solver.variables = self.variables.iter()
      .map(|v| Rc::new(RefCell::new(v.borrow().clone())))
      .collect();
    solver.propagators = self.propagators.iter()
      .map(|p| p.boxed_deep_clone(&solver.variables))
      .collect();
    solver
  }
}

impl<E, Dom, Deps, A> Solver<E, Dom, Deps, A> where
 E: EventIndex,
 Deps: VarEventDependencies,
 A: Agenda
{
  pub fn new() -> Solver<E, Dom, Deps, A> {
    Solver {
      propagators: vec![],
      variables: vec![],
      deps: VarEventDependencies::new(0,0),
      agenda: Agenda::new(0)
    }
  }

  fn prepare(&mut self) {
    self.init_deps();
    self.init_agenda();
  }

  fn init_deps(&mut self) {
    self.deps = VarEventDependencies::new(self.variables.len(), <E as EventIndex>::size());
    for (p_idx, p) in self.propagators.iter().enumerate() {
      let p_deps = p.dependencies();
      for (v, ev) in p_deps.into_iter() {
        self.deps.subscribe(v as usize, ev, p_idx);
      }
    }
  }

  fn init_agenda(&mut self) {
    let num_props = self.propagators.len();
    self.agenda = Agenda::new(num_props);
    for p_idx in 0..num_props {
      self.agenda.schedule(p_idx);
    }
  }

  fn propagation_loop(&mut self) -> Status {
    let mut unsatisfiable = false;
    while let Some(p_idx) = self.agenda.pop() {
      unsatisfiable = !self.propagate_one(p_idx);
      if unsatisfiable { break; }
    }
    if unsatisfiable { Status::Unsatisfiable }
    else if self.deps.is_empty() { Status::Satisfiable }
    else { Status::Unknown }
  }

  fn propagate_one(&mut self, p_idx: usize) -> bool {
    let mut events = vec![];
    let status = {
      let mut prop = &mut self.propagators[p_idx];
      if prop.propagate(&mut events) {
        prop.is_entailed()
      } else {
        return false
      }
    };
    match status {
      EStatus::Disentailed => return false,
      EStatus::Entailed => self.unlink_prop(p_idx),
      EStatus::Unknown => self.reschedule_prop(&events, p_idx)
    };
    self.react(events);
    true
  }

  fn reschedule_prop(&mut self, events: &Vec<(usize, E)>, p_idx: usize) {
    if !events.is_empty() {
      self.agenda.schedule(p_idx);
    }
  }

  fn react(&mut self, events: Vec<(usize, E)>) {
    for (v, ev) in events.into_iter() {
      let reactions = self.deps.react(v, ev);
      for p in reactions.into_iter() {
        self.agenda.schedule(p);
      }
    }
  }

  fn unlink_prop(&mut self, p_idx: usize) {
    self.agenda.unschedule(p_idx);
    let deps = self.propagators[p_idx].dependencies();
    for &(var, ev) in deps.iter() {
      self.deps.unsubscribe(var, ev, p_idx)
    }
  }
}

impl<E, Dom, Deps, A> Display for Solver<E, Dom, Deps, A> where
 E: EventIndex,
 Dom: Display
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    let format_vars =
      self.variables.iter()
      .map(|v| v.borrow())
      .map(|v| formatter.write_fmt(format_args!("{}\n", *v)));
    fold(format_vars, (), |a,_| a)
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use interval::interval::*;
  use interval::ops::*;
  use solver::space::*;
  use solver::fd::event::*;
  use solver::fd::propagator::*;
  use solver::agenda::RelaxedFifoAgenda;
  use solver::dependencies::VarEventDepsVector;

  type FDSolver = Solver<FDEvent, Interval<i32>, VarEventDepsVector, RelaxedFifoAgenda>;

  #[test]
  fn basic_test() {
    let mut solver: FDSolver = Solver::new();

    assert_eq!(solver.solve(), Status::Satisfiable);

    let var1 = solver.newvar(Interval::new(1,4));
    let var2 = solver.newvar(Interval::new(1,4));
    let var3 = solver.newvar(Interval::new(1,1));

    assert_eq!(solver.solve(), Status::Satisfiable);

    solver.add(Box::new(XLessThanY::new(var1.clone(), var2)));
    assert_eq!(solver.solve(), Status::Unknown);

    solver.add(Box::new(XEqualY::new(var1, var3)));
    assert_eq!(solver.solve(), Status::Satisfiable);
  }

  fn chained_lt(n: usize, expect: Status) {
    // X1 < X2 < X3 < ... < XN, all in dom [1, 10]

    let mut solver: FDSolver = Solver::new();
    let mut vars = vec![];
    for _ in 0..n {
      vars.push(solver.newvar(Interval::new(1,10)));
    }
    for i in 0..n-1 {
      solver.add(Box::new(XLessThanY::new(vars[i].clone(), vars[i+1].clone())));
    }
    assert_eq!(solver.solve(), expect);
  }

  #[test]
  fn chained_lt_tests() {
    chained_lt(1, Status::Satisfiable);
    chained_lt(2, Status::Unknown);
    chained_lt(5, Status::Unknown);
    chained_lt(9, Status::Unknown);
    chained_lt(10, Status::Satisfiable);
    chained_lt(11, Status::Unsatisfiable);
  }

  #[test]
  fn example_nqueens() {
    nqueens(1, Status::Satisfiable);
    nqueens(2, Status::Unknown);
    nqueens(3, Status::Unknown);
    nqueens(4, Status::Unknown);
  }

  fn nqueens(n: usize, expect: Status) {
    let mut solver: FDSolver = Solver::new();
    let mut queens = vec![];
    // 2 queens can't share the same line.
    for _ in 0..n {
      queens.push(solver.newvar((1, n as i32).to_interval()));
    }
    for i in 0..n-1 {
      for j in i + 1..n {
        // 2 queens can't share the same diagonal.
        let q1 = (i + 1) as i32;
        let q2 = (j + 1) as i32;
        // Xi + i != Xj + j
        solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), q2 - q1)));
        // Xi - i != Xj - j
        solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), -q2 + q1)));
      }
    }
    // 2 queens can't share the same column.
    solver.add(Box::new(Distinct::new(queens)));
    assert_eq!(solver.solve(), expect);
  }
}
<commit_msg>Update solver to take into account store-based propagators. Related to #9.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use interval::ncollections::ops::*;
use solver::dependencies::VarEventDependencies;
use solver::agenda::Agenda;
use solver::event::EventIndex;
use solver::iterator::*;
use kernel::*;
use kernel::Trilean::*;
use variable::delta_store::DeltaStore;
use variable::ops::*;
use variable::arithmetics::identity::*;
use std::rc::{try_unwrap, Rc};
use std::fmt::{Formatter, Display, Error};
use std::result::fold;
use std::slice;

pub trait BoxedDeepClone<S, E>
{
  fn boxed_deep_clone(&self) -> Box<PropagatorErasure<S, E>>;
}

impl<S, E, R> BoxedDeepClone<S, E> for R where
  R: DeepClone,
  R: Propagator<S>,
  R: PropagatorDependencies<E>,
  R: Subsumption<S>,
  R: 'static
{
  fn boxed_deep_clone(&self) -> Box<PropagatorErasure<S, E>> {
    Box::new(self.deep_clone())
  }
}

pub trait PropagatorErasure<S, E> :
    Propagator<S>
  + PropagatorDependencies<E>
  + Subsumption<S>
  + BoxedDeepClone<S, E>
{}

impl<S, E, R> PropagatorErasure<S, E> for R where
 R: Propagator<S>,
 R: PropagatorDependencies<E>,
 R: Subsumption<S>,
 R: BoxedDeepClone<S, E>
{}

pub struct Solver<E, Dom, Deps, A> {
  propagators: Vec<Box<PropagatorErasure<DeltaStore<E, Dom>, E> + 'static>>,
  store: DeltaStore<E, Dom>,
  deps: Deps,
  agenda: A
}

impl<E, Dom, Deps, A> VariableIterator for Solver<E, Dom, Deps, A>
{
  type Variable = Dom;

  fn vars_iter<'a>(&'a self) -> slice::Iter<'a, Dom> {
    self.store.vars_iter()
  }
}

impl<E, Dom, Deps, A> Space for Solver<E, Dom, Deps, A> where
 Dom: Cardinality+Clone,
 E: EventIndex,
 Deps: VarEventDependencies,
 A: Agenda
{
  type Constraint = Box<PropagatorErasure<DeltaStore<E, Dom>, E> + 'static>;
  type Variable = Identity<Dom>;
  type Domain = Dom;
  type Label = Rc<Solver<E, Dom, Deps, A>>;

  fn newvar(&mut self, dom: Dom) -> Identity<Dom> {
    self.store.assign(dom)
  }

  fn add(&mut self, p: Self::Constraint) {
    self.propagators.push(p);
  }

  fn solve(&mut self) -> Trilean {
    self.prepare();
    self.propagation_loop()
  }

  fn mark(&self) -> Rc<Solver<E, Dom, Deps, A>> {
    Rc::new(self.deep_clone())
  }

  fn goto(self, label: Rc<Solver<E, Dom, Deps, A>>) -> Self {
    try_unwrap(label).unwrap_or_else(|l| l.deep_clone())
  }
}

impl<E, Dom, Deps, A> DeepClone for Solver<E, Dom, Deps, A> where
 Dom: Clone,
 E: EventIndex,
 Deps: VarEventDependencies,
 A: Agenda
{
  fn deep_clone(&self) -> Self {
    let mut solver = Solver::new();
    solver.store = self.store.deep_clone();
    solver.propagators = self.propagators.iter()
      .map(|p| p.boxed_deep_clone())
      .collect();
    solver
  }
}

impl<E, Dom, Deps, A> Solver<E, Dom, Deps, A> where
 E: EventIndex,
 Deps: VarEventDependencies,
 A: Agenda
{
  pub fn new() -> Solver<E, Dom, Deps, A> {
    Solver {
      propagators: vec![],
      store: DeltaStore::new(),
      deps: VarEventDependencies::new(0,0),
      agenda: Agenda::new(0)
    }
  }

  fn prepare(&mut self) {
    self.init_deps();
    self.init_agenda();
  }

  fn init_deps(&mut self) {
    self.deps = VarEventDependencies::new(self.store.size(), <E as EventIndex>::size());
    for (p_idx, p) in self.propagators.iter().enumerate() {
      let p_deps = p.dependencies();
      for (v, ev) in p_deps.into_iter() {
        self.deps.subscribe(v as usize, ev, p_idx);
      }
    }
  }

  fn init_agenda(&mut self) {
    let num_props = self.propagators.len();
    self.agenda = Agenda::new(num_props);
    for p_idx in 0..num_props {
      self.agenda.schedule(p_idx);
    }
  }

  fn propagation_loop(&mut self) -> Trilean {
    let mut unsatisfiable = false;
    while let Some(p_idx) = self.agenda.pop() {
      unsatisfiable = !self.propagate_one(p_idx);
      if unsatisfiable { break; }
    }
    if unsatisfiable { False }
    else if self.deps.is_empty() { True }
    else { Unknown }
  }

  fn propagate_one(&mut self, p_idx: usize) -> bool {
    let status = {
      let mut prop = &mut self.propagators[p_idx];
      if prop.propagate(&mut self.store) {
        prop.is_subsumed(&self.store)
      } else {
        return false
      }
    };
    match status {
      False => return false,
      True => self.unlink_prop(p_idx),
      Unknown => self.reschedule_prop(p_idx)
    };
    self.react();
    true
  }

  fn reschedule_prop(&mut self, p_idx: usize) {
    if !self.store.drain_delta().peekable().is_empty() {
      self.agenda.schedule(p_idx);
    }
  }

  fn react(&mut self) {
    for (v, ev) in self.store.drain_delta() {
      let reactions = self.deps.react(v, ev);
      for p in reactions.into_iter() {
        self.agenda.schedule(p);
      }
    }
  }

  fn unlink_prop(&mut self, p_idx: usize) {
    self.agenda.unschedule(p_idx);
    let deps = self.propagators[p_idx].dependencies();
    for &(var, ev) in deps.iter() {
      self.deps.unsubscribe(var, ev, p_idx)
    }
  }
}

impl<E, Dom, Deps, A> Display for Solver<E, Dom, Deps, A> where
 E: EventIndex,
 Dom: Display
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    let format_vars =
      self.store.vars_iter()
      .map(|v| formatter.write_fmt(format_args!("{}\n", v)));
    fold(format_vars, (), |a,_| a)
  }
}

// #[cfg(test)]
// mod test {
  // use super::*;
  // use interval::interval::*;
  // use interval::ops::*;
  // use solver::space::*;
  // use solver::fd::event::*;
  // use solver::fd::propagator::*;
  // use solver::agenda::RelaxedFifoAgenda;
  // use solver::dependencies::VarEventDepsVector;

  // type FDSolver = Solver<FDEvent, Interval<i32>, VarEventDepsVector, RelaxedFifoAgenda>;

  // #[test]
  // fn basic_test() {
  //   let mut solver: FDSolver = Solver::new();

  //   assert_eq!(solver.solve(), Status::Satisfiable);

  //   let var1 = solver.newvar(Interval::new(1,4));
  //   let var2 = solver.newvar(Interval::new(1,4));
  //   let var3 = solver.newvar(Interval::new(1,1));

  //   assert_eq!(solver.solve(), Status::Satisfiable);

  //   solver.add(Box::new(XLessThanY::new(var1.clone(), var2)));
  //   assert_eq!(solver.solve(), Status::Unknown);

  //   solver.add(Box::new(XEqualY::new(var1, var3)));
  //   assert_eq!(solver.solve(), Status::Satisfiable);
  // }

  // fn chained_lt(n: usize, expect: Status) {
  //   // X1 < X2 < X3 < ... < XN, all in dom [1, 10]

  //   let mut solver: FDSolver = Solver::new();
  //   let mut vars = vec![];
  //   for _ in 0..n {
  //     vars.push(solver.newvar(Interval::new(1,10)));
  //   }
  //   for i in 0..n-1 {
  //     solver.add(Box::new(XLessThanY::new(vars[i].clone(), vars[i+1].clone())));
  //   }
  //   assert_eq!(solver.solve(), expect);
  // }

  // #[test]
  // fn chained_lt_tests() {
  //   chained_lt(1, Status::Satisfiable);
  //   chained_lt(2, Status::Unknown);
  //   chained_lt(5, Status::Unknown);
  //   chained_lt(9, Status::Unknown);
  //   chained_lt(10, Status::Satisfiable);
  //   chained_lt(11, Status::Unsatisfiable);
  // }

  // #[test]
  // fn example_nqueens() {
  //   nqueens(1, Status::Satisfiable);
  //   nqueens(2, Status::Unknown);
  //   nqueens(3, Status::Unknown);
  //   nqueens(4, Status::Unknown);
  // }

  // fn nqueens(n: usize, expect: Status) {
  //   let mut solver: FDSolver = Solver::new();
  //   let mut queens = vec![];
  //   // 2 queens can't share the same line.
  //   for _ in 0..n {
  //     queens.push(solver.newvar((1, n as i32).to_interval()));
  //   }
  //   for i in 0..n-1 {
  //     for j in i + 1..n {
  //       // 2 queens can't share the same diagonal.
  //       let q1 = (i + 1) as i32;
  //       let q2 = (j + 1) as i32;
  //       // Xi + i != Xj + j
  //       solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), q2 - q1)));
  //       // Xi - i != Xj - j
  //       solver.add(Box::new(XNotEqualYPlusC::new(queens[i].clone(), queens[j].clone(), -q2 + q1)));
  //     }
  //   }
  //   // 2 queens can't share the same column.
  //   solver.add(Box::new(Distinct::new(queens)));
  //   assert_eq!(solver.solve(), expect);
  // }
// }
<|endoftext|>


<commit_before>use crate::ffi::{CStr, CString, OsString};
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, Error, ErrorKind};
use crate::io::{IoSlice, IoSliceMut, SeekFrom};
use crate::path::{Path, PathBuf};
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::{O_RDONLY, O_WRONLY, O_RDWR,O_CREAT, O_EXCL, O_TRUNC, O_APPEND};
use crate::sys::hermit::fd::FileDesc;
use crate::sys::time::SystemTime;
use crate::sys::{unsupported, Void};
use crate::sys_common::os_str_bytes::OsStrExt;

pub use crate::sys_common::fs::copy;
//pub use crate::sys_common::fs::remove_dir_all;

fn cstr(path: &Path) -> io::Result<CString> {
    Ok(CString::new(path.as_os_str().as_bytes())?)
}

#[derive(Debug)]
pub struct File(FileDesc);

pub struct FileAttr(Void);

pub struct ReadDir(Void);

pub struct DirEntry(Void);

#[derive(Clone, Debug)]
pub struct OpenOptions {
    // generic
    read: bool,
    write: bool,
    append: bool,
    truncate: bool,
    create: bool,
    create_new: bool,
    // system-specific
    mode: i32,
}

pub struct FilePermissions(Void);

pub struct FileType(Void);

#[derive(Debug)]
pub struct DirBuilder {}

impl FileAttr {
    pub fn size(&self) -> u64 {
        match self.0 {}
    }

    pub fn perm(&self) -> FilePermissions {
        match self.0 {}
    }

    pub fn file_type(&self) -> FileType {
        match self.0 {}
    }

    pub fn modified(&self) -> io::Result<SystemTime> {
        match self.0 {}
    }

    pub fn accessed(&self) -> io::Result<SystemTime> {
        match self.0 {}
    }

    pub fn created(&self) -> io::Result<SystemTime> {
        match self.0 {}
    }
}

impl Clone for FileAttr {
    fn clone(&self) -> FileAttr {
        match self.0 {}
    }
}

impl FilePermissions {
    pub fn readonly(&self) -> bool {
        match self.0 {}
    }

    pub fn set_readonly(&mut self, _readonly: bool) {
        match self.0 {}
    }
}

impl Clone for FilePermissions {
    fn clone(&self) -> FilePermissions {
        match self.0 {}
    }
}

impl PartialEq for FilePermissions {
    fn eq(&self, _other: &FilePermissions) -> bool {
        match self.0 {}
    }
}

impl Eq for FilePermissions {}

impl fmt::Debug for FilePermissions {
    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {}
    }
}

impl FileType {
    pub fn is_dir(&self) -> bool {
        match self.0 {}
    }

    pub fn is_file(&self) -> bool {
        match self.0 {}
    }

    pub fn is_symlink(&self) -> bool {
        match self.0 {}
    }
}

impl Clone for FileType {
    fn clone(&self) -> FileType {
        match self.0 {}
    }
}

impl Copy for FileType {}

impl PartialEq for FileType {
    fn eq(&self, _other: &FileType) -> bool {
        match self.0 {}
    }
}

impl Eq for FileType {}

impl Hash for FileType {
    fn hash<H: Hasher>(&self, _h: &mut H) {
        match self.0 {}
    }
}

impl fmt::Debug for FileType {
    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {}
    }
}

impl fmt::Debug for ReadDir {
    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {}
    }
}

impl Iterator for ReadDir {
    type Item = io::Result<DirEntry>;

    fn next(&mut self) -> Option<io::Result<DirEntry>> {
        match self.0 {}
    }
}

impl DirEntry {
    pub fn path(&self) -> PathBuf {
        match self.0 {}
    }

    pub fn file_name(&self) -> OsString {
        match self.0 {}
    }

    pub fn metadata(&self) -> io::Result<FileAttr> {
        match self.0 {}
    }

    pub fn file_type(&self) -> io::Result<FileType> {
        match self.0 {}
    }
}

impl OpenOptions {
    pub fn new() -> OpenOptions {
        OpenOptions {
            // generic
            read: false,
            write: false,
            append: false,
            truncate: false,
            create: false,
            create_new: false,
            // system-specific
            mode: 0x777,
        }
    }

    pub fn read(&mut self, read: bool) {
        self.read = read;
    }
    pub fn write(&mut self, write: bool) {
        self.write = write;
    }
    pub fn append(&mut self, append: bool) {
        self.append = append;
    }
    pub fn truncate(&mut self, truncate: bool) {
        self.truncate = truncate;
    }
    pub fn create(&mut self, create: bool) {
        self.create = create;
    }
    pub fn create_new(&mut self, create_new: bool) {
        self.create_new = create_new;
    }

    fn get_access_mode(&self) -> io::Result<i32> {
        match (self.read, self.write, self.append) {
            (true, false, false) => Ok(O_RDONLY),
            (false, true, false) => Ok(O_WRONLY),
            (true, true, false) => Ok(O_RDWR),
            (false, _, true) => Ok(O_WRONLY | O_APPEND),
            (true, _, true) => Ok(O_RDWR | O_APPEND),
            (false, false, false) => {
                Err(io::Error::new(ErrorKind::InvalidInput, "invalid access mode"))
            }
        }
    }

    fn get_creation_mode(&self) -> io::Result<i32> {
        match (self.write, self.append) {
            (true, false) => {}
            (false, false) => {
                if self.truncate || self.create || self.create_new {
                    return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
                }
            }
            (_, true) => {
                if self.truncate && !self.create_new {
                    return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
                }
            }
        }

        Ok(match (self.create, self.truncate, self.create_new) {
            (false, false, false) => 0,
            (true, false, false) => O_CREAT,
            (false, true, false) => O_TRUNC,
            (true, true, false) => O_CREAT | O_TRUNC,
            (_, _, true) => O_CREAT | O_EXCL,
        })
    }
}

impl File {
    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
        let path = cstr(path)?;
        File::open_c(&path, opts)
    }

    pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
        let mut flags = opts.get_access_mode()?;
        flags = flags | opts.get_creation_mode()?;

        let mode;
        if flags & O_CREAT == O_CREAT {
            mode = opts.mode;
        } else {
            mode = 0;
        }

        let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
        Ok(File(FileDesc::new(fd as i32)))
    }

    pub fn file_attr(&self) -> io::Result<FileAttr> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn fsync(&self) -> io::Result<()> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn datasync(&self) -> io::Result<()> {
        self.fsync()
    }

    pub fn truncate(&self, _size: u64) -> io::Result<()> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        crate::io::default_read_vectored(|buf| self.read(buf), bufs)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        crate::io::default_write_vectored(|buf| self.write(buf), bufs)
    }

    pub fn flush(&self) -> io::Result<()> {
        Ok(())
    }

    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn duplicate(&self) -> io::Result<File> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn diverge(&self) -> ! {
        loop {}
    }
}

impl DirBuilder {
    pub fn new() -> DirBuilder {
        DirBuilder {}
    }

    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
        unsupported()
    }
}

pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
    unsupported()
}

pub fn unlink(path: &Path) -> io::Result<()> {
    let name = cstr(path)?;
    let _ = unsafe { cvt(abi::unlink(name.as_ptr()))? };
    Ok(())
}

pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
    unsupported()
}

pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
    match perm.0 {}
}

pub fn rmdir(_p: &Path) -> io::Result<()> {
    unsupported()
}

pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
    //unsupported()
    Ok(())
}

pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
    unsupported()
}

pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
    unsupported()
}

pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
    unsupported()
}

pub fn stat(_p: &Path) -> io::Result<FileAttr> {
    unsupported()
}

pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
    unsupported()
}

pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
    unsupported()
}
<commit_msg>reorder imports to pass the format check<commit_after>use crate::ffi::{CStr, CString, OsString};
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, Error, ErrorKind};
use crate::io::{IoSlice, IoSliceMut, SeekFrom};
use crate::path::{Path, PathBuf};
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::{O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY};
use crate::sys::hermit::fd::FileDesc;
use crate::sys::time::SystemTime;
use crate::sys::{unsupported, Void};
use crate::sys_common::os_str_bytes::OsStrExt;

pub use crate::sys_common::fs::copy;
//pub use crate::sys_common::fs::remove_dir_all;

fn cstr(path: &Path) -> io::Result<CString> {
    Ok(CString::new(path.as_os_str().as_bytes())?)
}

#[derive(Debug)]
pub struct File(FileDesc);

pub struct FileAttr(Void);

pub struct ReadDir(Void);

pub struct DirEntry(Void);

#[derive(Clone, Debug)]
pub struct OpenOptions {
    // generic
    read: bool,
    write: bool,
    append: bool,
    truncate: bool,
    create: bool,
    create_new: bool,
    // system-specific
    mode: i32,
}

pub struct FilePermissions(Void);

pub struct FileType(Void);

#[derive(Debug)]
pub struct DirBuilder {}

impl FileAttr {
    pub fn size(&self) -> u64 {
        match self.0 {}
    }

    pub fn perm(&self) -> FilePermissions {
        match self.0 {}
    }

    pub fn file_type(&self) -> FileType {
        match self.0 {}
    }

    pub fn modified(&self) -> io::Result<SystemTime> {
        match self.0 {}
    }

    pub fn accessed(&self) -> io::Result<SystemTime> {
        match self.0 {}
    }

    pub fn created(&self) -> io::Result<SystemTime> {
        match self.0 {}
    }
}

impl Clone for FileAttr {
    fn clone(&self) -> FileAttr {
        match self.0 {}
    }
}

impl FilePermissions {
    pub fn readonly(&self) -> bool {
        match self.0 {}
    }

    pub fn set_readonly(&mut self, _readonly: bool) {
        match self.0 {}
    }
}

impl Clone for FilePermissions {
    fn clone(&self) -> FilePermissions {
        match self.0 {}
    }
}

impl PartialEq for FilePermissions {
    fn eq(&self, _other: &FilePermissions) -> bool {
        match self.0 {}
    }
}

impl Eq for FilePermissions {}

impl fmt::Debug for FilePermissions {
    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {}
    }
}

impl FileType {
    pub fn is_dir(&self) -> bool {
        match self.0 {}
    }

    pub fn is_file(&self) -> bool {
        match self.0 {}
    }

    pub fn is_symlink(&self) -> bool {
        match self.0 {}
    }
}

impl Clone for FileType {
    fn clone(&self) -> FileType {
        match self.0 {}
    }
}

impl Copy for FileType {}

impl PartialEq for FileType {
    fn eq(&self, _other: &FileType) -> bool {
        match self.0 {}
    }
}

impl Eq for FileType {}

impl Hash for FileType {
    fn hash<H: Hasher>(&self, _h: &mut H) {
        match self.0 {}
    }
}

impl fmt::Debug for FileType {
    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {}
    }
}

impl fmt::Debug for ReadDir {
    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {}
    }
}

impl Iterator for ReadDir {
    type Item = io::Result<DirEntry>;

    fn next(&mut self) -> Option<io::Result<DirEntry>> {
        match self.0 {}
    }
}

impl DirEntry {
    pub fn path(&self) -> PathBuf {
        match self.0 {}
    }

    pub fn file_name(&self) -> OsString {
        match self.0 {}
    }

    pub fn metadata(&self) -> io::Result<FileAttr> {
        match self.0 {}
    }

    pub fn file_type(&self) -> io::Result<FileType> {
        match self.0 {}
    }
}

impl OpenOptions {
    pub fn new() -> OpenOptions {
        OpenOptions {
            // generic
            read: false,
            write: false,
            append: false,
            truncate: false,
            create: false,
            create_new: false,
            // system-specific
            mode: 0x777,
        }
    }

    pub fn read(&mut self, read: bool) {
        self.read = read;
    }
    pub fn write(&mut self, write: bool) {
        self.write = write;
    }
    pub fn append(&mut self, append: bool) {
        self.append = append;
    }
    pub fn truncate(&mut self, truncate: bool) {
        self.truncate = truncate;
    }
    pub fn create(&mut self, create: bool) {
        self.create = create;
    }
    pub fn create_new(&mut self, create_new: bool) {
        self.create_new = create_new;
    }

    fn get_access_mode(&self) -> io::Result<i32> {
        match (self.read, self.write, self.append) {
            (true, false, false) => Ok(O_RDONLY),
            (false, true, false) => Ok(O_WRONLY),
            (true, true, false) => Ok(O_RDWR),
            (false, _, true) => Ok(O_WRONLY | O_APPEND),
            (true, _, true) => Ok(O_RDWR | O_APPEND),
            (false, false, false) => {
                Err(io::Error::new(ErrorKind::InvalidInput, "invalid access mode"))
            }
        }
    }

    fn get_creation_mode(&self) -> io::Result<i32> {
        match (self.write, self.append) {
            (true, false) => {}
            (false, false) => {
                if self.truncate || self.create || self.create_new {
                    return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
                }
            }
            (_, true) => {
                if self.truncate && !self.create_new {
                    return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
                }
            }
        }

        Ok(match (self.create, self.truncate, self.create_new) {
            (false, false, false) => 0,
            (true, false, false) => O_CREAT,
            (false, true, false) => O_TRUNC,
            (true, true, false) => O_CREAT | O_TRUNC,
            (_, _, true) => O_CREAT | O_EXCL,
        })
    }
}

impl File {
    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
        let path = cstr(path)?;
        File::open_c(&path, opts)
    }

    pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
        let mut flags = opts.get_access_mode()?;
        flags = flags | opts.get_creation_mode()?;

        let mode;
        if flags & O_CREAT == O_CREAT {
            mode = opts.mode;
        } else {
            mode = 0;
        }

        let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
        Ok(File(FileDesc::new(fd as i32)))
    }

    pub fn file_attr(&self) -> io::Result<FileAttr> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn fsync(&self) -> io::Result<()> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn datasync(&self) -> io::Result<()> {
        self.fsync()
    }

    pub fn truncate(&self, _size: u64) -> io::Result<()> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        crate::io::default_read_vectored(|buf| self.read(buf), bufs)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        crate::io::default_write_vectored(|buf| self.write(buf), bufs)
    }

    pub fn flush(&self) -> io::Result<()> {
        Ok(())
    }

    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn duplicate(&self) -> io::Result<File> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
        Err(Error::from_raw_os_error(22))
    }

    pub fn diverge(&self) -> ! {
        loop {}
    }
}

impl DirBuilder {
    pub fn new() -> DirBuilder {
        DirBuilder {}
    }

    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
        unsupported()
    }
}

pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
    unsupported()
}

pub fn unlink(path: &Path) -> io::Result<()> {
    let name = cstr(path)?;
    let _ = unsafe { cvt(abi::unlink(name.as_ptr()))? };
    Ok(())
}

pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
    unsupported()
}

pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
    match perm.0 {}
}

pub fn rmdir(_p: &Path) -> io::Result<()> {
    unsupported()
}

pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
    //unsupported()
    Ok(())
}

pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
    unsupported()
}

pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
    unsupported()
}

pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
    unsupported()
}

pub fn stat(_p: &Path) -> io::Result<FileAttr> {
    unsupported()
}

pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
    unsupported()
}

pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
    unsupported()
}
<|endoftext|>


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

//! Runtime calls emitted by the compiler.

use cast::transmute;
use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int};
use str;
use sys;
use rt::{context, OldTaskContext};
use rt::task::Task;
use rt::local::Local;
use rt::borrowck;

#[allow(non_camel_case_types)]
pub type rust_task = c_void;

pub mod rustrt {
    use unstable::lang::rust_task;
    use libc::{c_char, uintptr_t};

    extern {
        #[rust_stack]
        pub fn rust_upcall_malloc(td: *c_char, size: uintptr_t) -> *c_char;
        #[rust_stack]
        pub fn rust_upcall_free(ptr: *c_char);
        #[fast_ffi]
        pub fn rust_upcall_malloc_noswitch(td: *c_char, size: uintptr_t)
                                           -> *c_char;
        #[rust_stack]
        pub fn rust_try_get_task() -> *rust_task;
    }
}

#[lang="fail_"]
pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! {
    sys::begin_unwind_(expr, file, line);
}

#[lang="fail_bounds_check"]
pub fn fail_bounds_check(file: *c_char, line: size_t,
                         index: size_t, len: size_t) {
    let msg = fmt!("index out of bounds: the len is %d but the index is %d",
                    len as int, index as int);
    do msg.as_c_str |buf| {
        fail_(buf, file, line);
    }
}

#[lang="malloc"]
pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
    match context() {
        OldTaskContext => {
            return rustrt::rust_upcall_malloc_noswitch(td, size);
        }
        _ => {
            let mut alloc = ::ptr::null();
            do Local::borrow::<Task,()> |task| {
                alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char;
            }
            return alloc;
        }
    }
}

// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
// inside a landing pad may corrupt the state of the exception handler. If a
// problem occurs, call exit instead.
#[lang="free"]
pub unsafe fn local_free(ptr: *c_char) {
    ::rt::local_heap::local_free(ptr);
}

#[lang="borrow_as_imm"]
#[inline]
pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint {
    borrowck::borrow_as_imm(a, file, line)
}

#[lang="borrow_as_mut"]
#[inline]
pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint {
    borrowck::borrow_as_mut(a, file, line)
}

#[lang="record_borrow"]
pub unsafe fn record_borrow(a: *u8, old_ref_count: uint,
                            file: *c_char, line: size_t) {
    borrowck::record_borrow(a, old_ref_count, file, line)
}

#[lang="unrecord_borrow"]
pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint,
                              file: *c_char, line: size_t) {
    borrowck::unrecord_borrow(a, old_ref_count, file, line)
}

#[lang="return_to_mut"]
#[inline]
pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint,
                            file: *c_char, line: size_t) {
    borrowck::return_to_mut(a, orig_ref_count, file, line)
}

#[lang="check_not_borrowed"]
#[inline]
pub unsafe fn check_not_borrowed(a: *u8,
                                 file: *c_char,
                                 line: size_t) {
    borrowck::check_not_borrowed(a, file, line)
}

#[lang="strdup_uniq"]
#[inline]
pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str {
    str::raw::from_buf_len(ptr, len)
}

#[lang="annihilate"]
pub unsafe fn annihilate() {
    ::cleanup::annihilate()
}

#[lang="start"]
pub fn start(main: *u8, argc: int, argv: **c_char,
             crate_map: *u8) -> int {
    use rt;
    use os;

    unsafe {
        let use_old_rt = os::getenv("RUST_NEWRT").is_none();
        if use_old_rt {
            return rust_start(main as *c_void, argc as c_int, argv,
                              crate_map as *c_void) as int;
        } else {
            return do rt::start(argc, argv as **u8, crate_map) {
                let main: extern "Rust" fn() = transmute(main);
                main();
            };
        }
    }

    extern {
        fn rust_start(main: *c_void, argc: c_int, argv: **c_char,
                      crate_map: *c_void) -> c_int;
    }
}
<commit_msg>Turn on the new runtime<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Runtime calls emitted by the compiler.

use cast::transmute;
use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int};
use str;
use sys;
use rt::{context, OldTaskContext};
use rt::task::Task;
use rt::local::Local;
use rt::borrowck;

#[allow(non_camel_case_types)]
pub type rust_task = c_void;

pub mod rustrt {
    use unstable::lang::rust_task;
    use libc::{c_char, uintptr_t};

    extern {
        #[rust_stack]
        pub fn rust_upcall_malloc(td: *c_char, size: uintptr_t) -> *c_char;
        #[rust_stack]
        pub fn rust_upcall_free(ptr: *c_char);
        #[fast_ffi]
        pub fn rust_upcall_malloc_noswitch(td: *c_char, size: uintptr_t)
                                           -> *c_char;
        #[rust_stack]
        pub fn rust_try_get_task() -> *rust_task;
    }
}

#[lang="fail_"]
pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! {
    sys::begin_unwind_(expr, file, line);
}

#[lang="fail_bounds_check"]
pub fn fail_bounds_check(file: *c_char, line: size_t,
                         index: size_t, len: size_t) {
    let msg = fmt!("index out of bounds: the len is %d but the index is %d",
                    len as int, index as int);
    do msg.as_c_str |buf| {
        fail_(buf, file, line);
    }
}

#[lang="malloc"]
pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
    match context() {
        OldTaskContext => {
            return rustrt::rust_upcall_malloc_noswitch(td, size);
        }
        _ => {
            let mut alloc = ::ptr::null();
            do Local::borrow::<Task,()> |task| {
                alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char;
            }
            return alloc;
        }
    }
}

// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
// inside a landing pad may corrupt the state of the exception handler. If a
// problem occurs, call exit instead.
#[lang="free"]
pub unsafe fn local_free(ptr: *c_char) {
    ::rt::local_heap::local_free(ptr);
}

#[lang="borrow_as_imm"]
#[inline]
pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint {
    borrowck::borrow_as_imm(a, file, line)
}

#[lang="borrow_as_mut"]
#[inline]
pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint {
    borrowck::borrow_as_mut(a, file, line)
}

#[lang="record_borrow"]
pub unsafe fn record_borrow(a: *u8, old_ref_count: uint,
                            file: *c_char, line: size_t) {
    borrowck::record_borrow(a, old_ref_count, file, line)
}

#[lang="unrecord_borrow"]
pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint,
                              file: *c_char, line: size_t) {
    borrowck::unrecord_borrow(a, old_ref_count, file, line)
}

#[lang="return_to_mut"]
#[inline]
pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint,
                            file: *c_char, line: size_t) {
    borrowck::return_to_mut(a, orig_ref_count, file, line)
}

#[lang="check_not_borrowed"]
#[inline]
pub unsafe fn check_not_borrowed(a: *u8,
                                 file: *c_char,
                                 line: size_t) {
    borrowck::check_not_borrowed(a, file, line)
}

#[lang="strdup_uniq"]
#[inline]
pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str {
    str::raw::from_buf_len(ptr, len)
}

#[lang="annihilate"]
pub unsafe fn annihilate() {
    ::cleanup::annihilate()
}

#[lang="start"]
pub fn start(main: *u8, argc: int, argv: **c_char,
             crate_map: *u8) -> int {
    use rt;
    use os;

    unsafe {
        let use_old_rt = os::getenv("RUST_OLDRT").is_some();
        if use_old_rt {
            return rust_start(main as *c_void, argc as c_int, argv,
                              crate_map as *c_void) as int;
        } else {
            return do rt::start(argc, argv as **u8, crate_map) {
                let main: extern "Rust" fn() = transmute(main);
                main();
            };
        }
    }

    extern {
        fn rust_start(main: *c_void, argc: c_int, argv: **c_char,
                      crate_map: *c_void) -> c_int;
    }
}
<|endoftext|>


<commit_before>/// Event log for a drawing session
/// Menu selections must pass through here to ensure they can be referenced
/// Motion events can be shoved in wherever, though
/// TODO: replay
/// use timestamps on point events, rather than Frame events, so writing can be done from one
/// thread
/// think about how to make shaders handle accelerated time
///
// TODO: remove all this duplication

use core::prelude::*;
use collections::vec::Vec;
use collections::{Mutable, MutableSeq};
use collections::slice::CloneableVector;
use collections::string::String;
use point::PointEntry;
use glstore::{DrawObjectIndex, DrawObjectList};
use glstore::{ShaderInitValues, BrushInitValues, LuaInitValues};
use gltexture::{Texture, PixelFormat};
use pointshader::PointShader;
use copyshader::CopyShader;
use luascript::LuaScript;
use paintlayer::PaintLayer;

enum DrawEvent {
    UseAnimShader(DrawObjectIndex<CopyShader>),
    UseCopyShader(DrawObjectIndex<CopyShader>),
    UsePointShader(DrawObjectIndex<PointShader>),
    UseBrush(DrawObjectIndex<Texture>),
    UseInterpolator(DrawObjectIndex<LuaScript>),
    Point(PointEntry),
    AddLayer(Option<DrawObjectIndex<CopyShader>>, Option<DrawObjectIndex<PointShader>>, i32),
    ClearLayers,
    Frame,
}

pub struct Events<'a> {
    eventlist: Vec<DrawEvent>,
    pointshaders: DrawObjectList<'a, PointShader, ShaderInitValues>,
    copyshaders: DrawObjectList<'a, CopyShader, ShaderInitValues>,
    textures: DrawObjectList<'a, Texture, BrushInitValues>,
    luascripts: DrawObjectList<'a, LuaScript, LuaInitValues>,
}

impl<'a> Events<'a> {
    pub fn new() -> Events<'a> {
        Events {
            eventlist: Vec::new(),
            pointshaders: DrawObjectList::new(),
            copyshaders: DrawObjectList::new(),
            textures: DrawObjectList::new(),
            luascripts: DrawObjectList::new(),
        }
    }

    // FIXME: let glstore deal with optionalness
    pub fn load_copyshader(&mut self, vert: Option<String>, frag: Option<String>) -> Option<DrawObjectIndex<CopyShader>> {
        let initargs = (vert, frag);
        self.copyshaders.push_object(initargs)
    }

    pub fn use_copyshader(&mut self, idx: DrawObjectIndex<CopyShader>) -> &CopyShader {
        self.eventlist.push(UseCopyShader(idx));
        self.copyshaders.get_object(idx)
    }

    pub fn use_animshader(&mut self, idx: DrawObjectIndex<CopyShader>) -> &CopyShader {
        self.eventlist.push(UseAnimShader(idx));
        self.copyshaders.get_object(idx)
    }

    pub fn load_pointshader(&mut self, vert: Option<String>, frag: Option<String>) -> Option<DrawObjectIndex<PointShader>> {
        let initargs = (vert, frag);
        self.pointshaders.push_object(initargs)
    }
    pub fn use_pointshader(&mut self, idx: DrawObjectIndex<PointShader>) -> &PointShader {
        self.eventlist.push(UsePointShader(idx));
        self.pointshaders.get_object(idx)
    }
    pub fn load_brush(&mut self, w: i32, h: i32, pixels: &[u8], format: PixelFormat) -> DrawObjectIndex<Texture> {
        let ownedpixels = pixels.to_vec();
        let init: BrushInitValues = (format, (w, h), ownedpixels);
        self.textures.safe_push_object(init)
    }
    pub fn use_brush(&mut self, idx: DrawObjectIndex<Texture>) -> &Texture {
        self.eventlist.push(UseBrush(idx));
        self.textures.get_object(idx)
    }
    pub fn load_interpolator(&mut self, script: Option<String>) -> Option<DrawObjectIndex<LuaScript>> {
        let initopt: LuaInitValues = script;
        self.luascripts.push_object(initopt)
    }

    pub fn use_interpolator(&mut self, idx: DrawObjectIndex<LuaScript>) -> &LuaScript {
        self.eventlist.push(UseInterpolator(idx));
        self.luascripts.get_object(idx)
    }

    pub fn add_layer(&mut self, dimensions: (i32, i32)
                     , copyshader: Option<DrawObjectIndex<CopyShader>>, pointshader: Option<DrawObjectIndex<PointShader>>
                     , pointidx: i32) -> PaintLayer {
        self.eventlist.push(AddLayer(copyshader, pointshader, pointidx));
        let copyshader = match copyshader { Some(x) => Some(self.copyshaders.get_object(x)), None => None };
        let pointshader = match pointshader { Some(x) => Some(self.pointshaders.get_object(x)), None => None };
        PaintLayer::new(dimensions, copyshader, pointshader, pointidx)
    }

    pub fn clear_layers(&mut self) {
        self.eventlist.push(ClearLayers);
    }

    pub fn pushpoint(&mut self, event: PointEntry) {
        self.eventlist.push(Point(event));
    }
    pub fn pushframe(&mut self) {
        self.eventlist.push(Frame);
    }
    pub fn clear(&mut self) {
        self.eventlist.clear();
    }
    fn get_event(&self, idx: uint) -> DrawEvent {
        self.eventlist[idx]
    }
    pub fn get_eventcount(&self) -> uint {
        self.eventlist.len()
    }
}

pub struct EventStream {
    position: uint,
}

impl EventStream {
    pub fn new() -> EventStream {
        EventStream { position: 0 }
    }
    pub fn advance<'a>(&mut self, events: &'a mut Events<'a>, mut framecount: u32, playback: bool, m: &mut ::point::PointProducer, gl: &'a mut ::glinit::GLInit<'a>) {
        if framecount == 0 || self.position >= events.get_eventcount() {
            return;
        }
        let limit = events.get_eventcount();
        self.position += 1;
        let event = events.get_event(self.position);
        while framecount > 0 && self.position < limit {
            match event {
                // FIXME do this without exposing Events or GLInit internal details
                UseAnimShader(idx) => gl.paintstate.animshader = Some(events.copyshaders.get_object(idx)),
                UseCopyShader(idx) => gl.paintstate.copyshader = Some(events.copyshaders.get_object(idx)),
                UsePointShader(idx) => gl.paintstate.pointshader = Some(events.pointshaders.get_object(idx)),
                UseBrush(idx) => gl.paintstate.brush = Some(events.textures.get_object(idx)),
                UseInterpolator(idx) => gl.paintstate.interpolator = Some(events.luascripts.get_object(idx)),
                Frame => {
                    framecount -= 1;
                    if playback {
                        gl.render_frame();
                    }
                },
                Point(p) => m.push(p),
                AddLayer(_, _, _) => { },
                ClearLayers => { },
            }
        }
    }
}
<commit_msg>move paint state onto glinit<commit_after>/// Event log for a drawing session
/// Menu selections must pass through here to ensure they can be referenced
/// Motion events can be shoved in wherever, though
/// TODO: replay
/// use timestamps on point events, rather than Frame events, so writing can be done from one
/// thread
/// think about how to make shaders handle accelerated time
///
// TODO: remove all this duplication

use core::prelude::*;
use collections::vec::Vec;
use collections::{Mutable, MutableSeq};
use collections::slice::CloneableVector;
use collections::string::String;
use point::PointEntry;
use glstore::{DrawObjectIndex, DrawObjectList};
use glstore::{ShaderInitValues, BrushInitValues, LuaInitValues};
use gltexture::{Texture, PixelFormat};
use pointshader::PointShader;
use copyshader::CopyShader;
use luascript::LuaScript;
use paintlayer::PaintLayer;

enum DrawEvent {
    UseAnimShader(DrawObjectIndex<CopyShader>),
    UseCopyShader(DrawObjectIndex<CopyShader>),
    UsePointShader(DrawObjectIndex<PointShader>),
    UseBrush(DrawObjectIndex<Texture>),
    UseInterpolator(DrawObjectIndex<LuaScript>),
    Point(PointEntry),
    AddLayer(Option<DrawObjectIndex<CopyShader>>, Option<DrawObjectIndex<PointShader>>, i32),
    ClearLayers,
    Frame,
}

pub struct Events<'a> {
    eventlist: Vec<DrawEvent>,
    pointshaders: DrawObjectList<'a, PointShader, ShaderInitValues>,
    copyshaders: DrawObjectList<'a, CopyShader, ShaderInitValues>,
    textures: DrawObjectList<'a, Texture, BrushInitValues>,
    luascripts: DrawObjectList<'a, LuaScript, LuaInitValues>,
}

impl<'a> Events<'a> {
    pub fn new() -> Events<'a> {
        Events {
            eventlist: Vec::new(),
            pointshaders: DrawObjectList::new(),
            copyshaders: DrawObjectList::new(),
            textures: DrawObjectList::new(),
            luascripts: DrawObjectList::new(),
        }
    }

    // FIXME: let glstore deal with optionalness
    pub fn load_copyshader(&mut self, vert: Option<String>, frag: Option<String>) -> Option<DrawObjectIndex<CopyShader>> {
        let initargs = (vert, frag);
        self.copyshaders.push_object(initargs)
    }

    pub fn use_copyshader(&mut self, idx: DrawObjectIndex<CopyShader>) -> &'a CopyShader {
        self.eventlist.push(UseCopyShader(idx));
        self.copyshaders.get_object(idx)
    }

    pub fn use_animshader(&mut self, idx: DrawObjectIndex<CopyShader>) -> &'a CopyShader {
        self.eventlist.push(UseAnimShader(idx));
        self.copyshaders.get_object(idx)
    }

    pub fn load_pointshader(&mut self, vert: Option<String>, frag: Option<String>) -> Option<DrawObjectIndex<PointShader>> {
        let initargs = (vert, frag);
        self.pointshaders.push_object(initargs)
    }
    pub fn use_pointshader(&mut self, idx: DrawObjectIndex<PointShader>) -> &'a PointShader {
        self.eventlist.push(UsePointShader(idx));
        self.pointshaders.get_object(idx)
    }
    pub fn load_brush(&mut self, w: i32, h: i32, pixels: &[u8], format: PixelFormat) -> DrawObjectIndex<Texture> {
        let ownedpixels = pixels.to_vec();
        let init: BrushInitValues = (format, (w, h), ownedpixels);
        self.textures.safe_push_object(init)
    }
    pub fn use_brush(&mut self, idx: DrawObjectIndex<Texture>) -> &'a Texture {
        self.eventlist.push(UseBrush(idx));
        self.textures.get_object(idx)
    }
    pub fn load_interpolator(&mut self, script: Option<String>) -> Option<DrawObjectIndex<LuaScript>> {
        let initopt: LuaInitValues = script;
        self.luascripts.push_object(initopt)
    }

    pub fn use_interpolator(&mut self, idx: DrawObjectIndex<LuaScript>) -> &'a LuaScript {
        self.eventlist.push(UseInterpolator(idx));
        self.luascripts.get_object(idx)
    }

    pub fn add_layer(&mut self, dimensions: (i32, i32)
                     , copyshader: Option<DrawObjectIndex<CopyShader>>, pointshader: Option<DrawObjectIndex<PointShader>>
                     , pointidx: i32) -> PaintLayer<'a> {
        self.eventlist.push(AddLayer(copyshader, pointshader, pointidx));
        let copyshader = match copyshader { Some(x) => Some(self.copyshaders.get_object(x)), None => None };
        let pointshader = match pointshader { Some(x) => Some(self.pointshaders.get_object(x)), None => None };
        PaintLayer::new(dimensions, copyshader, pointshader, pointidx)
    }

    pub fn clear_layers(&mut self) {
        self.eventlist.push(ClearLayers);
    }

    pub fn pushpoint(&mut self, event: PointEntry) {
        self.eventlist.push(Point(event));
    }
    pub fn pushframe(&mut self) {
        self.eventlist.push(Frame);
    }
    pub fn clear(&mut self) {
        self.eventlist.clear();
    }
    fn get_event(&self, idx: uint) -> DrawEvent {
        self.eventlist[idx]
    }
    pub fn get_eventcount(&self) -> uint {
        self.eventlist.len()
    }
}

pub struct EventStream {
    position: uint,
}

impl EventStream {
    pub fn new() -> EventStream {
        EventStream { position: 0 }
    }
    pub fn advance<'a>(&mut self, events: &'a mut Events<'a>, mut framecount: u32, playback: bool, m: &mut ::point::PointProducer, gl: &'a mut ::glinit::GLInit<'a>) {
        if framecount == 0 || self.position >= events.get_eventcount() {
            return;
        }
        let limit = events.get_eventcount();
        self.position += 1;
        let event = events.get_event(self.position);
        while framecount > 0 && self.position < limit {
            match event {
                // FIXME do this without exposing Events or GLInit internal details
                UseAnimShader(idx) => gl.paintstate.animshader = Some(events.copyshaders.get_object(idx)),
                UseCopyShader(idx) => gl.paintstate.copyshader = Some(events.copyshaders.get_object(idx)),
                UsePointShader(idx) => gl.paintstate.pointshader = Some(events.pointshaders.get_object(idx)),
                UseBrush(idx) => gl.paintstate.brush = Some(events.textures.get_object(idx)),
                UseInterpolator(idx) => gl.paintstate.interpolator = Some(events.luascripts.get_object(idx)),
                Frame => {
                    framecount -= 1;
                    if playback {
                        gl.render_frame();
                    }
                },
                Point(p) => m.push(p),
                AddLayer(_, _, _) => { },
                ClearLayers => { },
            }
        }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test

use crate::io::Write;
use core::sync::atomic::{AtomicUsize, Ordering};

// runtime features
pub(super) mod panic;
mod reloc;

// library features
pub mod mem;
pub mod thread;
pub mod tls;
#[macro_use]
pub mod usercalls;

#[cfg(not(test))]
global_asm!(include_str!("entry.S"));

#[cfg(not(test))]
#[no_mangle]
unsafe extern "C" fn tcs_init(secondary: bool) {
    // Be very careful when changing this code: it runs before the binary has been
    // relocated. Any indirect accesses to symbols will likely fail.
    const UNINIT: usize = 0;
    const BUSY: usize = 1;
    const DONE: usize = 2;
    // Three-state spin-lock
    static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);

    if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
        rtabort!("Entered secondary TCS before main TCS!")
    }

    // Try to atomically swap UNINIT with BUSY. The returned state can be:
    match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
        // This thread just obtained the lock and other threads will observe BUSY
        UNINIT => {
            reloc::relocate_elf_rela();
            RELOC_STATE.store(DONE, Ordering::Release);
        }
        // We need to wait until the initialization is done.
        BUSY => {
            while RELOC_STATE.load(Ordering::Acquire) == BUSY {
                core::arch::x86_64::_mm_pause()
            }
        }
        // Initialization is done.
        DONE => {}
        _ => unreachable!(),
    }
}

// FIXME: this item should only exist if this is linked into an executable
// (main function exists). If this is a library, the crate author should be
// able to specify this
#[cfg(not(test))]
#[no_mangle]
#[allow(improper_ctypes_definitions)]
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
    // FIXME: how to support TLS in library mode?
    let tls = Box::new(tls::Tls::new());
    let _tls_guard = unsafe { tls.activate() };

    if secondary {
        super::thread::Thread::entry();

        (0, 0)
    } else {
        extern "C" {
            fn main(argc: isize, argv: *const *const u8) -> isize;
        }

        // check entry is being called according to ABI
        rtassert!(p3 == 0);
        rtassert!(p4 == 0);
        rtassert!(p5 == 0);

        unsafe {
            // The actual types of these arguments are `p1: *const Arg, p2:
            // usize`. We can't currently customize the argument list of Rust's
            // main function, so we pass these in as the standard pointer-sized
            // values in `argc` and `argv`.
            let ret = main(p2 as _, p1 as _);
            exit_with_code(ret)
        }
    }
}

pub(super) fn exit_with_code(code: isize) -> ! {
    if code != 0 {
        if let Some(mut out) = panic::SgxPanicOutput::new() {
            let _ = write!(out, "Exited with status code {}", code);
        }
    }
    usercalls::exit(code != 0);
}

#[cfg(not(test))]
#[no_mangle]
extern "C" fn abort_reentry() -> ! {
    usercalls::exit(false)
}
<commit_msg>Obviate #[allow(improper_ctypes_definitions)]<commit_after>#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test

use crate::io::Write;
use core::sync::atomic::{AtomicUsize, Ordering};

// runtime features
pub(super) mod panic;
mod reloc;

// library features
pub mod mem;
pub mod thread;
pub mod tls;
#[macro_use]
pub mod usercalls;

#[cfg(not(test))]
global_asm!(include_str!("entry.S"));

#[repr(C)]
struct EntryReturn(u64, u64);

#[cfg(not(test))]
#[no_mangle]
unsafe extern "C" fn tcs_init(secondary: bool) {
    // Be very careful when changing this code: it runs before the binary has been
    // relocated. Any indirect accesses to symbols will likely fail.
    const UNINIT: usize = 0;
    const BUSY: usize = 1;
    const DONE: usize = 2;
    // Three-state spin-lock
    static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);

    if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
        rtabort!("Entered secondary TCS before main TCS!")
    }

    // Try to atomically swap UNINIT with BUSY. The returned state can be:
    match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
        // This thread just obtained the lock and other threads will observe BUSY
        UNINIT => {
            reloc::relocate_elf_rela();
            RELOC_STATE.store(DONE, Ordering::Release);
        }
        // We need to wait until the initialization is done.
        BUSY => {
            while RELOC_STATE.load(Ordering::Acquire) == BUSY {
                core::arch::x86_64::_mm_pause()
            }
        }
        // Initialization is done.
        DONE => {}
        _ => unreachable!(),
    }
}

// FIXME: this item should only exist if this is linked into an executable
// (main function exists). If this is a library, the crate author should be
// able to specify this
#[cfg(not(test))]
#[no_mangle]
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
    // FIXME: how to support TLS in library mode?
    let tls = Box::new(tls::Tls::new());
    let _tls_guard = unsafe { tls.activate() };

    if secondary {
        super::thread::Thread::entry();

        EntryReturn(0, 0)
    } else {
        extern "C" {
            fn main(argc: isize, argv: *const *const u8) -> isize;
        }

        // check entry is being called according to ABI
        rtassert!(p3 == 0);
        rtassert!(p4 == 0);
        rtassert!(p5 == 0);

        unsafe {
            // The actual types of these arguments are `p1: *const Arg, p2:
            // usize`. We can't currently customize the argument list of Rust's
            // main function, so we pass these in as the standard pointer-sized
            // values in `argc` and `argv`.
            let ret = main(p2 as _, p1 as _);
            exit_with_code(ret)
        }
    }
}

pub(super) fn exit_with_code(code: isize) -> ! {
    if code != 0 {
        if let Some(mut out) = panic::SgxPanicOutput::new() {
            let _ = write!(out, "Exited with status code {}", code);
        }
    }
    usercalls::exit(code != 0);
}

#[cfg(not(test))]
#[no_mangle]
extern "C" fn abort_reentry() -> ! {
    usercalls::exit(false)
}
<|endoftext|>


<commit_before>use vec_shift::Shift;
use std::str::FromStr;
use std::error::Error as StdError;
use std::fmt;
use utils::parse_quotes;

/// Defines how an operation on an `Args` method failed.
#[derive(Debug)]
pub enum Error<E: StdError> {
    /// "END-OF-STRING", more precisely, there isn't anything to parse anymore.
    Eos,
    /// A parsing operation failed; the error in it can be of any returned from the `FromStr`
    /// trait.
    Parse(E),
}

impl<E: StdError> From<E> for Error<E> {
    fn from(e: E) -> Self {
        Error::Parse(e)
    }
}

impl<E: StdError> StdError for Error<E> {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            Eos => "end-of-string",
            Parse(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;

        match *self {
            Parse(ref e) => Some(e),
            _ => None,
        }
    }
}

impl<E: StdError> fmt::Display for Error<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            Eos => write!(f, "end of string"),
            Parse(ref e) => fmt::Display::fmt(&e, f),
        }
    }
}

type Result<T, E> = ::std::result::Result<T, Error<E>>;

#[derive(Clone, Debug)]
pub struct Args {
    delimiter: String,
    delimiter_split: Vec<String>,
}

impl Args {
    pub fn new(message: &str, delimiter: &str) -> Self {
        let split = if message.trim().is_empty() {
            Vec::new()
        } else {
            message.split(delimiter).map(|s| s.to_string()).collect()
        };

        Args {
            delimiter: delimiter.to_string(),
            delimiter_split: split,
        }
    }

    /// Removes the first element, parses it to a specific type if necessary, returns.
    pub fn single<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .shift()
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Like [`single`], but doesn't remove the element.
    ///
    /// [`single`]: #method.single
    pub fn single_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .get(0)
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Skips if there's a first element, but also returns it.
    pub fn skip(&mut self) -> Option<String> { self.delimiter_split.shift() }

    /// Like [`skip`], but allows for multiple at once.
    ///
    /// [`skip`]: #method.skip
    pub fn skip_for(&mut self, i: u32) -> Option<Vec<String>> {
        let mut vec = Vec::with_capacity(i as usize);

        for _ in 0..i {
            vec.push(match self.delimiter_split.shift() {
                Some(x) => x,
                None => return None,
            });
        }

        Some(vec)
    }

    /// Like [`single`], but takes quotes into account.
    ///
    /// [`single`]: #method.single
    pub fn single_quoted<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(&self.delimiter_split.shift().ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`single_quoted`], but doesn't remove the element.
    ///
    /// [`single_quoted`]: #method.single_quoted
    pub fn single_quoted_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(self.delimiter_split.get(0).ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`list`], but takes quotes into account.
    ///
    /// [`list`]: #method.list
    pub fn multiple_quoted<T: FromStr>(self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        parse_quotes(&self.delimiter_split.join(&self.delimiter))
            .into_iter()
            .map(|s| s.parse::<T>().map_err(Error::Parse))
            .collect()
    }

    /// Empty outs the internal vector while parsing (if necessary) and returning them
    pub fn list<T: FromStr>(self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        self.delimiter_split
            .into_iter()
            .map(|s| s.parse::<T>().map_err(Error::Parse))
            .collect()
    }

    /// This method is just `internal_vector.join(delimiter)`
    pub fn full(&self) -> String { self.delimiter_split.join(&self.delimiter) }

    /// Returns the first argument that can be converted and removes it from the list.
    pub fn find<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        match self.delimiter_split
                  .iter()
                  .position(|e| e.parse::<T>().is_ok())
        {
            Some(index) => {
                let value = self.delimiter_split
                    .get(index)
                    .ok_or(Error::Eos)?
                    .parse::<T>()?;

                self.delimiter_split.remove(index);

                Ok(value)
            },
            _ => Err(Error::Eos),
        }
    }

    /// Returns the first argument that can be converted and does not remove it from the list.
    pub fn find_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .iter()
            .find(|e| e.parse::<T>().is_ok())
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }
}

impl ::std::ops::Deref for Args {
    type Target = [String];

    fn deref(&self) -> &Self::Target { &self.delimiter_split }
}
<commit_msg>Add some docs to `Args`<commit_after>use vec_shift::Shift;
use std::str::FromStr;
use std::error::Error as StdError;
use std::fmt;
use utils::parse_quotes;

/// Defines how an operation on an `Args` method failed.
#[derive(Debug)]
pub enum Error<E: StdError> {
    /// "END-OF-STRING", more precisely, there isn't anything to parse anymore.
    Eos,
    /// A parsing operation failed; the error in it can be of any returned from the `FromStr`
    /// trait.
    Parse(E),
}

impl<E: StdError> From<E> for Error<E> {
    fn from(e: E) -> Self {
        Error::Parse(e)
    }
}

impl<E: StdError> StdError for Error<E> {
    fn description(&self) -> &str {
        use self::Error::*;

        match *self {
            Eos => "end-of-string",
            Parse(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;

        match *self {
            Parse(ref e) => Some(e),
            _ => None,
        }
    }
}

impl<E: StdError> fmt::Display for Error<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            Eos => write!(f, "end of string"),
            Parse(ref e) => fmt::Display::fmt(&e, f),
        }
    }
}

type Result<T, E> = ::std::result::Result<T, Error<E>>;

/// A utility struct for handling arguments of a command.
///
/// General functionality is done via removing an item, parsing it, then returning it; this however
/// can be mitigated with the `*_n` methods, which just parse and return.
#[derive(Clone, Debug)]
pub struct Args {
    delimiter: String,
    delimiter_split: Vec<String>,
}

impl Args {
    pub fn new(message: &str, delimiter: &str) -> Self {
        let split = if message.trim().is_empty() {
            Vec::new()
        } else {
            message.split(delimiter).map(|s| s.to_string()).collect()
        };

        Args {
            delimiter: delimiter.to_string(),
            delimiter_split: split,
        }
    }

    /// Removes the first element, parses it to a specific type if necessary, returns.
    pub fn single<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .shift()
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Like [`single`], but doesn't remove the element.
    ///
    /// [`single`]: #method.single
    pub fn single_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .get(0)
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }

    /// Skips if there's a first element, but also returns it.
    pub fn skip(&mut self) -> Option<String> { self.delimiter_split.shift() }

    /// Like [`skip`], but allows for multiple at once.
    ///
    /// [`skip`]: #method.skip
    pub fn skip_for(&mut self, i: u32) -> Option<Vec<String>> {
        let mut vec = Vec::with_capacity(i as usize);

        for _ in 0..i {
            vec.push(match self.delimiter_split.shift() {
                Some(x) => x,
                None => return None,
            });
        }

        Some(vec)
    }

    /// Like [`single`], but takes quotes into account.
    ///
    /// [`single`]: #method.single
    pub fn single_quoted<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(&self.delimiter_split.shift().ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`single_quoted`], but doesn't remove the element.
    ///
    /// [`single_quoted`]: #method.single_quoted
    pub fn single_quoted_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        Ok(parse_quotes(self.delimiter_split.get(0).ok_or(Error::Eos)?)
            .remove(0)
            .parse::<T>()?)
    }

    /// Like [`list`], but takes quotes into account.
    ///
    /// [`list`]: #method.list
    pub fn multiple_quoted<T: FromStr>(self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        parse_quotes(&self.delimiter_split.join(&self.delimiter))
            .into_iter()
            .map(|s| s.parse::<T>().map_err(Error::Parse))
            .collect()
    }

    /// Empty outs the internal vector while parsing (if necessary) and returning them
    pub fn list<T: FromStr>(self) -> Result<Vec<T>, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        self.delimiter_split
            .into_iter()
            .map(|s| s.parse::<T>().map_err(Error::Parse))
            .collect()
    }

    /// This method is just `internal_vector.join(delimiter)`
    pub fn full(&self) -> String { self.delimiter_split.join(&self.delimiter) }

    /// Returns the first argument that can be converted and removes it from the list.
    pub fn find<T: FromStr>(&mut self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        match self.delimiter_split
                  .iter()
                  .position(|e| e.parse::<T>().is_ok())
        {
            Some(index) => {
                let value = self.delimiter_split
                    .get(index)
                    .ok_or(Error::Eos)?
                    .parse::<T>()?;

                self.delimiter_split.remove(index);

                Ok(value)
            },
            _ => Err(Error::Eos),
        }
    }

    /// Returns the first argument that can be converted and does not remove it from the list.
    pub fn find_n<T: FromStr>(&self) -> Result<T, T::Err>
        where T::Err: StdError {
        if self.delimiter_split.is_empty() {
            return Err(Error::Eos);
        }

        Ok(self.delimiter_split
            .iter()
            .find(|e| e.parse::<T>().is_ok())
            .ok_or(Error::Eos)?
            .parse::<T>()?)
    }
}

impl ::std::ops::Deref for Args {
    type Target = [String];

    fn deref(&self) -> &Self::Target { &self.delimiter_split }
}
<|endoftext|>