<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::{ptr, mem};
use core::cell::Cell;

use stack;
use debug;
use arch::{self, StackPointer};

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Runnable,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned or panicked.
  Unavailable
}

/// Generator wraps a function and allows suspending its execution more than once, returning
/// a value each time.
///
/// The first time `resume(input0)` is called, the function is called as `f(yielder, input0)`.
/// It runs until it suspends its execution through `yielder.suspend(output0)`, after which
/// `resume(input0)` returns `output0`. The function can be resumed again using `resume(input1)`,
/// after which `yielder.suspend(output0)` returns `input1`, and so on. Once the function returns,
/// the `resume()` call will return `None`, and it will return `None` every time it is called
/// after that.
///
/// If the generator function panics, the panic is propagated through the `resume()` call as usual.
///
/// After the generator function returns or panics, it is safe to reclaim the generator stack
/// using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Runnable` after creation and suspension, and `State::Unavailable`
/// once the generator function returns or panics.
///
/// When the input type is `()`, a generator implements the Iterator trait.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut add_one = Generator::new(stack, move |yielder, mut input| {
///   loop {
///     if input == 0 { break }
///     input = yielder.suspend(input + 1)
///   }
/// });
/// println!("{:?}", add_one.resume(2)); // prints Some(3)
/// println!("{:?}", add_one.resume(3)); // prints Some(4)
/// println!("{:?}", add_one.resume(0)); // prints None
/// ```
///
/// # Iterator example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut nat = Generator::new(stack, move |yielder, ()| {
///   for i in 1.. { yielder.suspend(i) }
/// });
/// println!("{:?}", nat.next()); // prints Some(0)
/// println!("{:?}", nat.next()); // prints Some(1)
/// println!("{:?}", nat.next()); // prints Some(2)
/// ```
#[derive(Debug)]
pub struct Generator<'a, Input: Send + 'a, Output: Send + 'a, Stack: stack::Stack> {
  state:     State,
  stack:     Stack,
  stack_id:  debug::StackId,
  stack_ptr: arch::StackPointer,
  phantom:   PhantomData<(&'a (), *mut Input, *const Output)>
}

impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
    where Input: Send + 'a, Output: Send + 'a, Stack: stack::Stack {
  /// Creates a new generator.
  ///
  /// See also the [contract](../trait.GuardedStack.html) that needs to be fulfilled by `stack`.
  pub fn new<F>(stack: Stack, f: F) -> Generator<'a, Input, Output, Stack>
      where Stack: stack::GuardedStack,
            F: FnOnce(&Yielder<Input, Output>, Input) + Send + 'a {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  ///
  /// See also the [contract](../trait.Stack.html) that needs to be fulfilled by `stack`.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<'a, Input, Output, Stack>
      where F: FnOnce(&Yielder<Input, Output>, Input) + Send + 'a {
    unsafe extern "C" fn generator_wrapper<Input, Output, Stack, F>(env: usize, stack_ptr: StackPointer) -> !
        where Input: Send, Output: Send, Stack: stack::Stack,
              F: FnOnce(&Yielder<Input, Output>, Input) {
      // Retrieve our environment from the callee and return control to it.
      let f = ptr::read(env as *const F);
      let (data, stack_ptr) = arch::swap(0, stack_ptr, None);
      // See the second half of Yielder::suspend_bare.
      let input = ptr::read(data as *const Input);
      // Run the body of the generator.
      let yielder = Yielder::new(stack_ptr);
      f(&yielder, input);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.suspend_bare(None); }
    }

    let stack_id  = debug::StackId::register(&stack);
    let stack_ptr = arch::init(&stack, generator_wrapper::<Input, Output, Stack, F>);

    // Transfer environment to the callee.
    let stack_ptr = arch::swap(&f as *const F as usize, stack_ptr, Some(&stack)).1;
    mem::forget(f);

    Generator {
      state:     State::Runnable,
      stack:     stack,
      stack_id:  stack_id,
      stack_ptr: stack_ptr,
      phantom:   PhantomData
    }
  }

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  pub fn resume(&mut self, input: Input) -> Option<Output> {
    match self.state {
      State::Runnable => {
        // Set the state to Unavailable. Since we have exclusive access to the generator,
        // the only case where this matters is the generator function panics, after which
        // it must not be invocable again.
        self.state = State::Unavailable;

        // Switch to the generator function, and retrieve the yielded value.
        let val = unsafe {
          let (data_out, stack_ptr) = arch::swap(&input as *const Input as usize, self.stack_ptr, Some(&self.stack));
          self.stack_ptr = stack_ptr;
          mem::forget(input);
          ptr::read(data_out as *const Option<Output>)
        };

        // Unless the generator function has returned, it can be switched to again, so
        // set the state to Runnable.
        if val.is_some() { self.state = State::Runnable }

        val
      }
      State::Unavailable => None
    }
  }

  /// Returns the state of the generator.
  #[inline]
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Runnable`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Runnable    => panic!("Argh! Bastard! Don't touch that!"),
      State::Unavailable => self.stack
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Input: Send, Output: Send> {
  stack_ptr: Cell<StackPointer>,
  phantom: PhantomData<(*const Input, *mut Output)>
}

impl<Input, Output> Yielder<Input, Output>
    where Input: Send, Output: Send {
  fn new(stack_ptr: StackPointer) -> Yielder<Input, Output> {
    Yielder {
      stack_ptr: Cell::new(stack_ptr),
      phantom: PhantomData
    }
  }

  #[inline(always)]
  fn suspend_bare(&self, val: Option<Output>) -> Input {
    unsafe {
      let (data, stack_ptr) = arch::swap(&val as *const Option<Output> as usize, self.stack_ptr.get(), None);
      self.stack_ptr.set(stack_ptr);
      mem::forget(val);
      ptr::read(data as *const Input)
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `resume()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn suspend(&self, item: Output) -> Input {
    self.suspend_bare(Some(item))
  }
}

impl<'a, Output, Stack> Iterator for Generator<'a, (), Output, Stack>
    where Output: Send + 'a, Stack: stack::Stack {
  type Item = Output;

  fn next(&mut self) -> Option<Self::Item> { self.resume(()) }
}
<commit_msg>Implement Send for Generator<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::{ptr, mem};
use core::cell::Cell;

use stack;
use debug;
use arch::{self, StackPointer};

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Runnable,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned or panicked.
  Unavailable
}

/// Generator wraps a function and allows suspending its execution more than once, returning
/// a value each time.
///
/// The first time `resume(input0)` is called, the function is called as `f(yielder, input0)`.
/// It runs until it suspends its execution through `yielder.suspend(output0)`, after which
/// `resume(input0)` returns `output0`. The function can be resumed again using `resume(input1)`,
/// after which `yielder.suspend(output0)` returns `input1`, and so on. Once the function returns,
/// the `resume()` call will return `None`, and it will return `None` every time it is called
/// after that.
///
/// If the generator function panics, the panic is propagated through the `resume()` call as usual.
///
/// After the generator function returns or panics, it is safe to reclaim the generator stack
/// using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Runnable` after creation and suspension, and `State::Unavailable`
/// once the generator function returns or panics.
///
/// When the input type is `()`, a generator implements the Iterator trait.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut add_one = Generator::new(stack, move |yielder, mut input| {
///   loop {
///     if input == 0 { break }
///     input = yielder.suspend(input + 1)
///   }
/// });
/// println!("{:?}", add_one.resume(2)); // prints Some(3)
/// println!("{:?}", add_one.resume(3)); // prints Some(4)
/// println!("{:?}", add_one.resume(0)); // prints None
/// ```
///
/// # Iterator example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut nat = Generator::new(stack, move |yielder, ()| {
///   for i in 1.. { yielder.suspend(i) }
/// });
/// println!("{:?}", nat.next()); // prints Some(0)
/// println!("{:?}", nat.next()); // prints Some(1)
/// println!("{:?}", nat.next()); // prints Some(2)
/// ```
#[derive(Debug)]
pub struct Generator<'a, Input: Send + 'a, Output: Send + 'a, Stack: stack::Stack> {
  state:     State,
  stack:     Stack,
  stack_id:  debug::StackId,
  stack_ptr: arch::StackPointer,
  phantom:   PhantomData<(&'a (), *mut Input, *const Output)>
}

unsafe impl<'a, Input, Output, Stack> Send for Generator<'a, Input, Output, Stack>
  where Input: Send + 'a, Output: Send + 'a, Stack: stack::Stack + Send {}

impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
    where Input: Send + 'a, Output: Send + 'a, Stack: stack::Stack {
  /// Creates a new generator.
  ///
  /// See also the [contract](../trait.GuardedStack.html) that needs to be fulfilled by `stack`.
  pub fn new<F>(stack: Stack, f: F) -> Generator<'a, Input, Output, Stack>
      where Stack: stack::GuardedStack,
            F: FnOnce(&Yielder<Input, Output>, Input) + Send + 'a {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  ///
  /// See also the [contract](../trait.Stack.html) that needs to be fulfilled by `stack`.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<'a, Input, Output, Stack>
      where F: FnOnce(&Yielder<Input, Output>, Input) + Send + 'a {
    unsafe extern "C" fn generator_wrapper<Input, Output, Stack, F>(env: usize, stack_ptr: StackPointer) -> !
        where Input: Send, Output: Send, Stack: stack::Stack,
              F: FnOnce(&Yielder<Input, Output>, Input) {
      // Retrieve our environment from the callee and return control to it.
      let f = ptr::read(env as *const F);
      let (data, stack_ptr) = arch::swap(0, stack_ptr, None);
      // See the second half of Yielder::suspend_bare.
      let input = ptr::read(data as *const Input);
      // Run the body of the generator.
      let yielder = Yielder::new(stack_ptr);
      f(&yielder, input);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.suspend_bare(None); }
    }

    let stack_id  = debug::StackId::register(&stack);
    let stack_ptr = arch::init(&stack, generator_wrapper::<Input, Output, Stack, F>);

    // Transfer environment to the callee.
    let stack_ptr = arch::swap(&f as *const F as usize, stack_ptr, Some(&stack)).1;
    mem::forget(f);

    Generator {
      state:     State::Runnable,
      stack:     stack,
      stack_id:  stack_id,
      stack_ptr: stack_ptr,
      phantom:   PhantomData
    }
  }

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  pub fn resume(&mut self, input: Input) -> Option<Output> {
    match self.state {
      State::Runnable => {
        // Set the state to Unavailable. Since we have exclusive access to the generator,
        // the only case where this matters is the generator function panics, after which
        // it must not be invocable again.
        self.state = State::Unavailable;

        // Switch to the generator function, and retrieve the yielded value.
        let val = unsafe {
          let (data_out, stack_ptr) = arch::swap(&input as *const Input as usize, self.stack_ptr, Some(&self.stack));
          self.stack_ptr = stack_ptr;
          mem::forget(input);
          ptr::read(data_out as *const Option<Output>)
        };

        // Unless the generator function has returned, it can be switched to again, so
        // set the state to Runnable.
        if val.is_some() { self.state = State::Runnable }

        val
      }
      State::Unavailable => None
    }
  }

  /// Returns the state of the generator.
  #[inline]
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Runnable`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Runnable    => panic!("Argh! Bastard! Don't touch that!"),
      State::Unavailable => self.stack
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Input: Send, Output: Send> {
  stack_ptr: Cell<StackPointer>,
  phantom: PhantomData<(*const Input, *mut Output)>
}

impl<Input, Output> Yielder<Input, Output>
    where Input: Send, Output: Send {
  fn new(stack_ptr: StackPointer) -> Yielder<Input, Output> {
    Yielder {
      stack_ptr: Cell::new(stack_ptr),
      phantom: PhantomData
    }
  }

  #[inline(always)]
  fn suspend_bare(&self, val: Option<Output>) -> Input {
    unsafe {
      let (data, stack_ptr) = arch::swap(&val as *const Option<Output> as usize, self.stack_ptr.get(), None);
      self.stack_ptr.set(stack_ptr);
      mem::forget(val);
      ptr::read(data as *const Input)
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `resume()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn suspend(&self, item: Output) -> Input {
    self.suspend_bare(Some(item))
  }
}

impl<'a, Output, Stack> Iterator for Generator<'a, (), Output, Stack>
    where Output: Send + 'a, Stack: stack::Stack {
  type Item = Output;

  fn next(&mut self) -> Option<Self::Item> { self.resume(()) }
}
<|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 kernel::*;
use kernel::Trilean::*;
use propagation::Reactor;
use propagation::Scheduler;
use propagation::propagator::*;
use variable::ops::*;
use interval::ncollections::ops::*;

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

impl<VStore, Event, R> BoxedDeepClone<VStore, Event> for R where
  R: DeepClone,
  R: Consistency<VStore>,
  R: PropagatorDependencies<Event>,
  R: 'static
{
  fn boxed_deep_clone(&self) -> Box<PropagatorErasure<VStore, Event>> {
    Box::new(self.deep_clone())
  }
}

pub trait PropagatorErasure<VStore, Event> :
    Consistency<VStore>
  + PropagatorDependencies<Event>
  + BoxedDeepClone<VStore, Event>
{}

impl<VStore, Event, R> PropagatorErasure<VStore, Event> for R where
 R: Consistency<VStore>,
 R: PropagatorDependencies<Event>,
 R: BoxedDeepClone<VStore, Event>
{}

pub struct Store<VStore, Event, Reactor, Scheduler>
{
  propagators: Vec<Box<PropagatorErasure<VStore, Event> + 'static>>,
  reactor: Reactor,
  scheduler: Scheduler
}

impl<VStore, Event, R, S> Store<VStore, Event, R, S> where
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  pub fn new() -> Store<VStore, Event, R, S> {
    Store {
      propagators: vec![],
      reactor: Reactor::new(0,0),
      scheduler: Scheduler::new(0)
    }
  }
}

impl<VStore, Event, R, S> Store<VStore, Event, R, S> where
 VStore: Cardinality<Size=usize> + DrainDelta<Event>,
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  fn prepare(&mut self, store: &VStore) {
    self.init_reactor(store);
    self.init_scheduler();
  }

  fn init_reactor(&mut self, store: &VStore) {
    self.reactor = Reactor::new(store.size(), Event::size());
    for (p_idx, p) in self.propagators.iter().enumerate() {
      let p_deps = p.dependencies();
      for (v, ev) in p_deps {
        self.reactor.subscribe(v as usize, ev, p_idx);
      }
    }
  }

  fn init_scheduler(&mut self) {
    let num_props = self.propagators.len();
    self.scheduler = Scheduler::new(num_props);
    for p_idx in 0..num_props {
      self.scheduler.schedule(p_idx);
    }
  }

  fn propagation_loop(&mut self, store: &mut VStore) -> Trilean {
    let mut unsatisfiable = false;
    while let Some(p_idx) = self.scheduler.pop() {
      if !self.propagate_one(p_idx, store) {
        unsatisfiable = true;
        break;
      }
    }
    if unsatisfiable { False }
    else if self.reactor.is_empty() { True }
    else { Unknown }
  }

  fn propagate_one(&mut self, p_idx: usize, store: &mut VStore) -> bool {
    let subsumed = self.propagators[p_idx].consistency(store);
    match subsumed {
      False => return false,
      True => self.unlink_prop(p_idx),
      Unknown => self.reschedule_prop(p_idx, store)
    };
    self.react(store);
    true
  }

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

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

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

impl<Prop, VStore, Event, R, S> Assign<Prop> for Store<VStore, Event, R, S> where
 Prop: PropagatorErasure<VStore, Event> + 'static
{
  type Variable = ();
  fn assign(&mut self, p: Prop) {
    self.propagators.push(Box::new(p));
  }
}

impl<VStore, Event, R, S> Consistency<VStore> for Store<VStore, Event, R, S> where
 VStore: Cardinality<Size=usize> + DrainDelta<Event>,
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  fn consistency(&mut self, store: &mut VStore) -> Trilean {
    self.prepare(store);
    self.propagation_loop(store)
  }
}

impl<VStore, Event, R, S> State for Store<VStore, Event, R, S> where
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  type Label = Store<VStore, Event, R, S>;

  fn mark(&self) -> Store<VStore, Event, R, S> {
    self.deep_clone()
  }

  fn restore(self, label: Store<VStore, Event, R, S>) -> Self {
    label
  }
}

impl<VStore, Event, R, S> DeepClone for Store<VStore, Event, R, S> where
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  fn deep_clone(&self) -> Self {
    let mut store = Store::new();
    store.propagators = self.propagators.iter()
      .map(|p| p.boxed_deep_clone())
      .collect();
    store
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use interval::interval::*;
  use interval::ops::*;
  use kernel::*;
  use kernel::Trilean::*;
  use propagation::events::*;
  use propagation::reactors::*;
  use propagation::schedulers::*;
  use propagators::cmp::*;
  use propagators::distinct::*;
  use variable::ops::*;
  use variable::arithmetics::*;
  use variable::delta_store::DeltaStore;

  type VStore = DeltaStore<Interval<i32>, FDEvent>;
  type CStore = Store<VStore, FDEvent, IndexedDeps, RelaxedFifo>;

  #[test]
  fn basic_test() {
    let variables: &mut VStore = &mut VStore::new();
    let mut constraints: CStore = CStore::new();

    assert_eq!(constraints.consistency(variables), True);

    let var1 = variables.assign(Interval::new(1,4));
    let var2 = variables.assign(Interval::new(1,4));
    let var3 = variables.assign(Interval::new(1,1));

    assert_eq!(constraints.consistency(variables), True);

    constraints.assign(XLessY::new(var1.clone(), var2));
    assert_eq!(constraints.consistency(variables), Unknown);

    constraints.assign(XEqY::new(var1, var3));
    assert_eq!(constraints.consistency(variables), True);
  }

  fn chained_lt(n: usize, expect: Trilean) {
    // X1 < X2 < X3 < ... < XN, all in dom [1, 10]
    let variables: &mut VStore = &mut VStore::new();
    let mut constraints: CStore = CStore::new();
    let mut vars = vec![];
    for _ in 0..n {
      vars.push(variables.assign(Interval::new(1,10)));
    }
    for i in 0..n-1 {
      constraints.assign(XLessY::new(vars[i].clone(), vars[i+1].clone()));
    }
    assert_eq!(constraints.consistency(variables), expect);
  }

  #[test]
  fn chained_lt_tests() {
    chained_lt(1, True);
    chained_lt(2, Unknown);
    chained_lt(5, Unknown);
    chained_lt(9, Unknown);
    chained_lt(10, True);
    chained_lt(11, False);
  }

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

  fn nqueens(n: usize, expect: Trilean) {
    let variables: &mut VStore = &mut VStore::new();
    let mut constraints: CStore = CStore::new();
    let mut queens = vec![];
    // 2 queens can't share the same line.
    for _ in 0..n {
      queens.push(variables.assign((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
        constraints.assign(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), q2 - q1)));
        // Xi - i != Xj - j
        constraints.assign(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), -q2 + q1)));
      }
    }
    // 2 queens can't share the same column.
    constraints.assign(Distinct::new(queens));
    assert_eq!(constraints.consistency(variables), expect);
  }
}
<commit_msg>Rename PropagatorErasure to PropagatorRequirements.<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 kernel::*;
use kernel::Trilean::*;
use propagation::Reactor;
use propagation::Scheduler;
use propagation::propagator::*;
use variable::ops::*;
use interval::ncollections::ops::*;

pub trait BoxedDeepClone<VStore, Event>
{
  fn boxed_deep_clone(&self) -> Box<PropagatorRequirements<VStore, Event>>;
}

impl<VStore, Event, R> BoxedDeepClone<VStore, Event> for R where
  R: DeepClone,
  R: Consistency<VStore>,
  R: PropagatorDependencies<Event>,
  R: 'static
{
  fn boxed_deep_clone(&self) -> Box<PropagatorRequirements<VStore, Event>> {
    Box::new(self.deep_clone())
  }
}

pub trait PropagatorRequirements<VStore, Event> :
    Consistency<VStore>
  + PropagatorDependencies<Event>
  + BoxedDeepClone<VStore, Event>
{}

impl<VStore, Event, R> PropagatorRequirements<VStore, Event> for R where
 R: Consistency<VStore>,
 R: PropagatorDependencies<Event>,
 R: BoxedDeepClone<VStore, Event>
{}

pub struct Store<VStore, Event, Reactor, Scheduler>
{
  propagators: Vec<Box<PropagatorRequirements<VStore, Event> + 'static>>,
  reactor: Reactor,
  scheduler: Scheduler
}

impl<VStore, Event, R, S> Store<VStore, Event, R, S> where
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  pub fn new() -> Store<VStore, Event, R, S> {
    Store {
      propagators: vec![],
      reactor: Reactor::new(0,0),
      scheduler: Scheduler::new(0)
    }
  }
}

impl<VStore, Event, R, S> Store<VStore, Event, R, S> where
 VStore: Cardinality<Size=usize> + DrainDelta<Event>,
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  fn prepare(&mut self, store: &VStore) {
    self.init_reactor(store);
    self.init_scheduler();
  }

  fn init_reactor(&mut self, store: &VStore) {
    self.reactor = Reactor::new(store.size(), Event::size());
    for (p_idx, p) in self.propagators.iter().enumerate() {
      let p_deps = p.dependencies();
      for (v, ev) in p_deps {
        self.reactor.subscribe(v as usize, ev, p_idx);
      }
    }
  }

  fn init_scheduler(&mut self) {
    let num_props = self.propagators.len();
    self.scheduler = Scheduler::new(num_props);
    for p_idx in 0..num_props {
      self.scheduler.schedule(p_idx);
    }
  }

  fn propagation_loop(&mut self, store: &mut VStore) -> Trilean {
    let mut unsatisfiable = false;
    while let Some(p_idx) = self.scheduler.pop() {
      if !self.propagate_one(p_idx, store) {
        unsatisfiable = true;
        break;
      }
    }
    if unsatisfiable { False }
    else if self.reactor.is_empty() { True }
    else { Unknown }
  }

  fn propagate_one(&mut self, p_idx: usize, store: &mut VStore) -> bool {
    let subsumed = self.propagators[p_idx].consistency(store);
    match subsumed {
      False => return false,
      True => self.unlink_prop(p_idx),
      Unknown => self.reschedule_prop(p_idx, store)
    };
    self.react(store);
    true
  }

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

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

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

impl<Prop, VStore, Event, R, S> Assign<Prop> for Store<VStore, Event, R, S> where
 Prop: PropagatorRequirements<VStore, Event> + 'static
{
  type Variable = ();
  fn assign(&mut self, p: Prop) {
    self.propagators.push(Box::new(p));
  }
}

impl<VStore, Event, R, S> Consistency<VStore> for Store<VStore, Event, R, S> where
 VStore: Cardinality<Size=usize> + DrainDelta<Event>,
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  fn consistency(&mut self, store: &mut VStore) -> Trilean {
    self.prepare(store);
    self.propagation_loop(store)
  }
}

impl<VStore, Event, R, S> State for Store<VStore, Event, R, S> where
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  type Label = Store<VStore, Event, R, S>;

  fn mark(&self) -> Store<VStore, Event, R, S> {
    self.deep_clone()
  }

  fn restore(self, label: Store<VStore, Event, R, S>) -> Self {
    label
  }
}

impl<VStore, Event, R, S> DeepClone for Store<VStore, Event, R, S> where
 Event: EventIndex,
 R: Reactor,
 S: Scheduler
{
  fn deep_clone(&self) -> Self {
    let mut store = Store::new();
    store.propagators = self.propagators.iter()
      .map(|p| p.boxed_deep_clone())
      .collect();
    store
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use interval::interval::*;
  use interval::ops::*;
  use kernel::*;
  use kernel::Trilean::*;
  use propagation::events::*;
  use propagation::reactors::*;
  use propagation::schedulers::*;
  use propagators::cmp::*;
  use propagators::distinct::*;
  use variable::ops::*;
  use variable::arithmetics::*;
  use variable::delta_store::DeltaStore;

  type VStore = DeltaStore<Interval<i32>, FDEvent>;
  type CStore = Store<VStore, FDEvent, IndexedDeps, RelaxedFifo>;

  #[test]
  fn basic_test() {
    let variables: &mut VStore = &mut VStore::new();
    let mut constraints: CStore = CStore::new();

    assert_eq!(constraints.consistency(variables), True);

    let var1 = variables.assign(Interval::new(1,4));
    let var2 = variables.assign(Interval::new(1,4));
    let var3 = variables.assign(Interval::new(1,1));

    assert_eq!(constraints.consistency(variables), True);

    constraints.assign(XLessY::new(var1.clone(), var2));
    assert_eq!(constraints.consistency(variables), Unknown);

    constraints.assign(XEqY::new(var1, var3));
    assert_eq!(constraints.consistency(variables), True);
  }

  fn chained_lt(n: usize, expect: Trilean) {
    // X1 < X2 < X3 < ... < XN, all in dom [1, 10]
    let variables: &mut VStore = &mut VStore::new();
    let mut constraints: CStore = CStore::new();
    let mut vars = vec![];
    for _ in 0..n {
      vars.push(variables.assign(Interval::new(1,10)));
    }
    for i in 0..n-1 {
      constraints.assign(XLessY::new(vars[i].clone(), vars[i+1].clone()));
    }
    assert_eq!(constraints.consistency(variables), expect);
  }

  #[test]
  fn chained_lt_tests() {
    chained_lt(1, True);
    chained_lt(2, Unknown);
    chained_lt(5, Unknown);
    chained_lt(9, Unknown);
    chained_lt(10, True);
    chained_lt(11, False);
  }

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

  fn nqueens(n: usize, expect: Trilean) {
    let variables: &mut VStore = &mut VStore::new();
    let mut constraints: CStore = CStore::new();
    let mut queens = vec![];
    // 2 queens can't share the same line.
    for _ in 0..n {
      queens.push(variables.assign((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
        constraints.assign(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), q2 - q1)));
        // Xi - i != Xj - j
        constraints.assign(XNeqY::new(queens[i].clone(), Addition::new(queens[j].clone(), -q2 + q1)));
      }
    }
    // 2 queens can't share the same column.
    constraints.assign(Distinct::new(queens));
    assert_eq!(constraints.consistency(variables), expect);
  }
}
<|endoftext|>


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

#![allow(non_camel_case_types)]

// The crate store - a central repo for information collected about external
// crates and libraries

pub use self::MetadataBlob::*;
pub use self::LinkagePreference::*;
pub use self::NativeLibraryKind::*;

use back::svh::Svh;
use metadata::decoder;
use metadata::loader;
use util::nodemap::{FnvHashMap, NodeMap};

use std::cell::RefCell;
use std::c_vec::CVec;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token::IdentInterner;

// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
// own crate numbers.
pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;

pub enum MetadataBlob {
    MetadataVec(CVec<u8>),
    MetadataArchive(loader::ArchiveMetadata),
}

pub struct crate_metadata {
    pub name: String,
    pub data: MetadataBlob,
    pub cnum_map: cnum_map,
    pub cnum: ast::CrateNum,
    pub span: Span,
}

#[deriving(Show, PartialEq, Clone)]
pub enum LinkagePreference {
    RequireDynamic,
    RequireStatic,
}

impl Copy for LinkagePreference {}

#[deriving(Clone, PartialEq, FromPrimitive)]
pub enum NativeLibraryKind {
    NativeStatic,    // native static library (.a archive)
    NativeFramework, // OSX-specific
    NativeUnknown,   // default way to specify a dynamic library
}

impl Copy for NativeLibraryKind {}

// Where a crate came from on the local filesystem. One of these two options
// must be non-None.
#[deriving(PartialEq, Clone)]
pub struct CrateSource {
    pub dylib: Option<Path>,
    pub rlib: Option<Path>,
    pub cnum: ast::CrateNum,
}

pub struct CStore {
    metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
    /// Map from NodeId's of local extern crate statements to crate numbers
    extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
    used_crate_sources: RefCell<Vec<CrateSource>>,
    used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
    used_link_args: RefCell<Vec<String>>,
    pub intr: Rc<IdentInterner>,
}

impl CStore {
    pub fn new(intr: Rc<IdentInterner>) -> CStore {
        CStore {
            metas: RefCell::new(FnvHashMap::new()),
            extern_mod_crate_map: RefCell::new(FnvHashMap::new()),
            used_crate_sources: RefCell::new(Vec::new()),
            used_libraries: RefCell::new(Vec::new()),
            used_link_args: RefCell::new(Vec::new()),
            intr: intr
        }
    }

    pub fn next_crate_num(&self) -> ast::CrateNum {
        self.metas.borrow().len() as ast::CrateNum + 1
    }

    pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
        (*self.metas.borrow())[cnum].clone()
    }

    pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
        let cdata = self.get_crate_data(cnum);
        decoder::get_crate_hash(cdata.data())
    }

    pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) {
        self.metas.borrow_mut().insert(cnum, data);
    }

    pub fn iter_crate_data<I>(&self, mut i: I) where
        I: FnMut(ast::CrateNum, &crate_metadata),
    {
        for (&k, v) in self.metas.borrow().iter() {
            i(k, &**v);
        }
    }

    /// Like `iter_crate_data`, but passes source paths (if available) as well.
    pub fn iter_crate_data_origins<I>(&self, mut i: I) where
        I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
    {
        for (&k, v) in self.metas.borrow().iter() {
            let origin = self.get_used_crate_source(k);
            origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
            i(k, &**v, origin);
        }
    }

    pub fn add_used_crate_source(&self, src: CrateSource) {
        let mut used_crate_sources = self.used_crate_sources.borrow_mut();
        if !used_crate_sources.contains(&src) {
            used_crate_sources.push(src);
        }
    }

    pub fn get_used_crate_source(&self, cnum: ast::CrateNum)
                                     -> Option<CrateSource> {
        self.used_crate_sources.borrow_mut()
            .iter().find(|source| source.cnum == cnum)
            .map(|source| source.clone())
    }

    pub fn reset(&self) {
        self.metas.borrow_mut().clear();
        self.extern_mod_crate_map.borrow_mut().clear();
        self.used_crate_sources.borrow_mut().clear();
        self.used_libraries.borrow_mut().clear();
        self.used_link_args.borrow_mut().clear();
    }

    // This method is used when generating the command line to pass through to
    // system linker. The linker expects undefined symbols on the left of the
    // command line to be defined in libraries on the right, not the other way
    // around. For more info, see some comments in the add_used_library function
    // below.
    //
    // In order to get this left-to-right dependency ordering, we perform a
    // topological sort of all crates putting the leaves at the right-most
    // positions.
    pub fn get_used_crates(&self, prefer: LinkagePreference)
                           -> Vec<(ast::CrateNum, Option<Path>)> {
        let mut ordering = Vec::new();
        fn visit(cstore: &CStore, cnum: ast::CrateNum,
                 ordering: &mut Vec<ast::CrateNum>) {
            if ordering.contains(&cnum) { return }
            let meta = cstore.get_crate_data(cnum);
            for (_, &dep) in meta.cnum_map.iter() {
                visit(cstore, dep, ordering);
            }
            ordering.push(cnum);
        };
        for (&num, _) in self.metas.borrow().iter() {
            visit(self, num, &mut ordering);
        }
        ordering.reverse();
        let mut libs = self.used_crate_sources.borrow()
            .iter()
            .map(|src| (src.cnum, match prefer {
                RequireDynamic => src.dylib.clone(),
                RequireStatic => src.rlib.clone(),
            }))
            .collect::<Vec<(ast::CrateNum, Option<Path>)>>();
        libs.sort_by(|&(a, _), &(b, _)| {
            ordering.position_elem(&a).cmp(&ordering.position_elem(&b))
        });
        libs
    }

    pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
        assert!(!lib.is_empty());
        self.used_libraries.borrow_mut().push((lib, kind));
    }

    pub fn get_used_libraries<'a>(&'a self)
                              -> &'a RefCell<Vec<(String,
                                                  NativeLibraryKind)>> {
        &self.used_libraries
    }

    pub fn add_used_link_args(&self, args: &str) {
        for s in args.split(' ').filter(|s| !s.is_empty()) {
            self.used_link_args.borrow_mut().push(s.to_string());
        }
    }

    pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > {
        &self.used_link_args
    }

    pub fn add_extern_mod_stmt_cnum(&self,
                                    emod_id: ast::NodeId,
                                    cnum: ast::CrateNum) {
        self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
    }

    pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId)
                                     -> Option<ast::CrateNum> {
        self.extern_mod_crate_map.borrow().get(&emod_id).map(|x| *x)
    }
}

impl crate_metadata {
    pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
    pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
    pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
}

impl MetadataBlob {
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        let slice = match *self {
            MetadataVec(ref vec) => vec.as_slice(),
            MetadataArchive(ref ar) => ar.as_slice(),
        };
        if slice.len() < 4 {
            &[]
        } else {
            let len = ((slice[0] as u32) << 24) |
                      ((slice[1] as u32) << 16) |
                      ((slice[2] as u32) << 8) |
                      ((slice[3] as u32) << 0);
            slice.slice(4, len as uint + 4)
        }
    }
}
<commit_msg>auto merge of #19799 : alexcrichton/rust/stop-panicking, r=huonw<commit_after>// Copyright 2012-2014 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.

#![allow(non_camel_case_types)]

// The crate store - a central repo for information collected about external
// crates and libraries

pub use self::MetadataBlob::*;
pub use self::LinkagePreference::*;
pub use self::NativeLibraryKind::*;

use back::svh::Svh;
use metadata::decoder;
use metadata::loader;
use util::nodemap::{FnvHashMap, NodeMap};

use std::cell::RefCell;
use std::c_vec::CVec;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token::IdentInterner;

// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
// own crate numbers.
pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;

pub enum MetadataBlob {
    MetadataVec(CVec<u8>),
    MetadataArchive(loader::ArchiveMetadata),
}

pub struct crate_metadata {
    pub name: String,
    pub data: MetadataBlob,
    pub cnum_map: cnum_map,
    pub cnum: ast::CrateNum,
    pub span: Span,
}

#[deriving(Show, PartialEq, Clone)]
pub enum LinkagePreference {
    RequireDynamic,
    RequireStatic,
}

impl Copy for LinkagePreference {}

#[deriving(Clone, PartialEq, FromPrimitive)]
pub enum NativeLibraryKind {
    NativeStatic,    // native static library (.a archive)
    NativeFramework, // OSX-specific
    NativeUnknown,   // default way to specify a dynamic library
}

impl Copy for NativeLibraryKind {}

// Where a crate came from on the local filesystem. One of these two options
// must be non-None.
#[deriving(PartialEq, Clone)]
pub struct CrateSource {
    pub dylib: Option<Path>,
    pub rlib: Option<Path>,
    pub cnum: ast::CrateNum,
}

pub struct CStore {
    metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
    /// Map from NodeId's of local extern crate statements to crate numbers
    extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
    used_crate_sources: RefCell<Vec<CrateSource>>,
    used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
    used_link_args: RefCell<Vec<String>>,
    pub intr: Rc<IdentInterner>,
}

impl CStore {
    pub fn new(intr: Rc<IdentInterner>) -> CStore {
        CStore {
            metas: RefCell::new(FnvHashMap::new()),
            extern_mod_crate_map: RefCell::new(FnvHashMap::new()),
            used_crate_sources: RefCell::new(Vec::new()),
            used_libraries: RefCell::new(Vec::new()),
            used_link_args: RefCell::new(Vec::new()),
            intr: intr
        }
    }

    pub fn next_crate_num(&self) -> ast::CrateNum {
        self.metas.borrow().len() as ast::CrateNum + 1
    }

    pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
        (*self.metas.borrow())[cnum].clone()
    }

    pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
        let cdata = self.get_crate_data(cnum);
        decoder::get_crate_hash(cdata.data())
    }

    pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) {
        self.metas.borrow_mut().insert(cnum, data);
    }

    pub fn iter_crate_data<I>(&self, mut i: I) where
        I: FnMut(ast::CrateNum, &crate_metadata),
    {
        for (&k, v) in self.metas.borrow().iter() {
            i(k, &**v);
        }
    }

    /// Like `iter_crate_data`, but passes source paths (if available) as well.
    pub fn iter_crate_data_origins<I>(&self, mut i: I) where
        I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
    {
        for (&k, v) in self.metas.borrow().iter() {
            let origin = self.get_used_crate_source(k);
            origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
            i(k, &**v, origin);
        }
    }

    pub fn add_used_crate_source(&self, src: CrateSource) {
        let mut used_crate_sources = self.used_crate_sources.borrow_mut();
        if !used_crate_sources.contains(&src) {
            used_crate_sources.push(src);
        }
    }

    pub fn get_used_crate_source(&self, cnum: ast::CrateNum)
                                     -> Option<CrateSource> {
        self.used_crate_sources.borrow_mut()
            .iter().find(|source| source.cnum == cnum)
            .map(|source| source.clone())
    }

    pub fn reset(&self) {
        self.metas.borrow_mut().clear();
        self.extern_mod_crate_map.borrow_mut().clear();
        self.used_crate_sources.borrow_mut().clear();
        self.used_libraries.borrow_mut().clear();
        self.used_link_args.borrow_mut().clear();
    }

    // This method is used when generating the command line to pass through to
    // system linker. The linker expects undefined symbols on the left of the
    // command line to be defined in libraries on the right, not the other way
    // around. For more info, see some comments in the add_used_library function
    // below.
    //
    // In order to get this left-to-right dependency ordering, we perform a
    // topological sort of all crates putting the leaves at the right-most
    // positions.
    pub fn get_used_crates(&self, prefer: LinkagePreference)
                           -> Vec<(ast::CrateNum, Option<Path>)> {
        let mut ordering = Vec::new();
        fn visit(cstore: &CStore, cnum: ast::CrateNum,
                 ordering: &mut Vec<ast::CrateNum>) {
            if ordering.contains(&cnum) { return }
            let meta = cstore.get_crate_data(cnum);
            for (_, &dep) in meta.cnum_map.iter() {
                visit(cstore, dep, ordering);
            }
            ordering.push(cnum);
        };
        for (&num, _) in self.metas.borrow().iter() {
            visit(self, num, &mut ordering);
        }
        ordering.reverse();
        let mut libs = self.used_crate_sources.borrow()
            .iter()
            .map(|src| (src.cnum, match prefer {
                RequireDynamic => src.dylib.clone(),
                RequireStatic => src.rlib.clone(),
            }))
            .collect::<Vec<(ast::CrateNum, Option<Path>)>>();
        libs.sort_by(|&(a, _), &(b, _)| {
            ordering.position_elem(&a).cmp(&ordering.position_elem(&b))
        });
        libs
    }

    pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
        assert!(!lib.is_empty());
        self.used_libraries.borrow_mut().push((lib, kind));
    }

    pub fn get_used_libraries<'a>(&'a self)
                              -> &'a RefCell<Vec<(String,
                                                  NativeLibraryKind)>> {
        &self.used_libraries
    }

    pub fn add_used_link_args(&self, args: &str) {
        for s in args.split(' ').filter(|s| !s.is_empty()) {
            self.used_link_args.borrow_mut().push(s.to_string());
        }
    }

    pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > {
        &self.used_link_args
    }

    pub fn add_extern_mod_stmt_cnum(&self,
                                    emod_id: ast::NodeId,
                                    cnum: ast::CrateNum) {
        self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
    }

    pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId)
                                     -> Option<ast::CrateNum> {
        self.extern_mod_crate_map.borrow().get(&emod_id).map(|x| *x)
    }
}

impl crate_metadata {
    pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
    pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
    pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
}

impl MetadataBlob {
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        let slice = match *self {
            MetadataVec(ref vec) => vec.as_slice(),
            MetadataArchive(ref ar) => ar.as_slice(),
        };
        if slice.len() < 4 {
            &[] // corrupt metadata
        } else {
            let len = (((slice[0] as u32) << 24) |
                       ((slice[1] as u32) << 16) |
                       ((slice[2] as u32) << 8) |
                       ((slice[3] as u32) << 0)) as uint;
            if len + 4 <= slice.len() {
                slice.slice(4, len + 4)
            } else {
                &[] // corrupt or old metadata
            }
        }
    }
}
<|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.

//! Finds crate binaries and loads their metadata

use core::prelude::*;

use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
use metadata::decoder;
use metadata::encoder;
use metadata::filesearch::FileSearch;
use metadata::filesearch;
use syntax::codemap::span;
use syntax::diagnostic::span_handler;
use syntax::parse::token::ident_interner;
use syntax::print::pprust;
use syntax::{ast, attr};

use core::cast;
use core::flate;
use core::io::WriterUtil;
use core::io;
use core::os::consts::{macos, freebsd, linux, android, win32};
use core::option;
use core::ptr;
use core::str;
use core::uint;
use core::vec;

pub enum os {
    os_macos,
    os_win32,
    os_linux,
    os_android,
    os_freebsd
}

pub struct Context {
    diag: @span_handler,
    filesearch: @FileSearch,
    span: span,
    ident: ast::ident,
    metas: ~[@ast::meta_item],
    hash: @~str,
    os: os,
    is_static: bool,
    intr: @ident_interner
}

pub fn load_library_crate(cx: Context) -> (~str, @~[u8]) {
    match find_library_crate(cx) {
      Some(ref t) => return (/*bad*/copy *t),
      None => {
        cx.diag.span_fatal(
            cx.span, fmt!("can't find crate for `%s`",
                          *cx.intr.get(cx.ident)));
      }
    }
}

fn find_library_crate(cx: Context) -> Option<(~str, @~[u8])> {
    attr::require_unique_names(cx.diag, cx.metas);
    find_library_crate_aux(cx, libname(cx), cx.filesearch)
}

fn libname(cx: Context) -> (~str, ~str) {
    if cx.is_static { return (~"lib", ~".rlib"); }
    let (dll_prefix, dll_suffix) = match cx.os {
        os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
        os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
        os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
        os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
        os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
    };

    (str::from_slice(dll_prefix), str::from_slice(dll_suffix))
}

fn find_library_crate_aux(
    cx: Context,
    (prefix, suffix): (~str, ~str),
    filesearch: @filesearch::FileSearch
) -> Option<(~str, @~[u8])> {
    let crate_name = crate_name_from_metas(cx.metas);
    let prefix: ~str = prefix + *crate_name + ~"-";
    let suffix: ~str = /*bad*/copy suffix;

    let mut matches = ~[];
    filesearch::search(filesearch, |path| {
        debug!("inspecting file %s", path.to_str());
        let f: ~str = path.filename().get();
        if !(f.starts_with(prefix) && f.ends_with(suffix)) {
            debug!("skipping %s, doesn't look like %s*%s", path.to_str(),
                   prefix, suffix);
            option::None::<()>
        } else {
            debug!("%s is a candidate", path.to_str());
            match get_metadata_section(cx.os, path) {
              option::Some(cvec) => {
                if !crate_matches(cvec, cx.metas, cx.hash) {
                    debug!("skipping %s, metadata doesn't match",
                           path.to_str());
                    option::None::<()>
                } else {
                    debug!("found %s with matching metadata", path.to_str());
                    matches.push((path.to_str(), cvec));
                    option::None::<()>
                }
              }
              _ => {
                debug!("could not load metadata for %s", path.to_str());
                option::None::<()>
              }
            }
        }
    });

    if matches.is_empty() {
        None
    } else if matches.len() == 1u {
        Some(/*bad*/copy matches[0])
    } else {
        cx.diag.span_err(
            cx.span, fmt!("multiple matching crates for `%s`", *crate_name));
        cx.diag.handler().note(~"candidates:");
        for matches.each |&(ident, data)| {
            cx.diag.handler().note(fmt!("path: %s", ident));
            let attrs = decoder::get_crate_attributes(data);
            note_linkage_attrs(cx.intr, cx.diag, attrs);
        }
        cx.diag.handler().abort_if_errors();
        None
    }
}

pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @~str {
    let name_items = attr::find_meta_items_by_name(metas, ~"name");
    match name_items.last_opt() {
        Some(i) => {
            match attr::get_meta_item_value_str(*i) {
                Some(n) => n,
                // FIXME (#2406): Probably want a warning here since the user
                // is using the wrong type of meta item.
                _ => fail!()
            }
        }
        None => fail!(~"expected to find the crate name")
    }
}

pub fn note_linkage_attrs(intr: @ident_interner,
                          diag: @span_handler,
                          attrs: ~[ast::attribute]) {
    for attr::find_linkage_metas(attrs).each |mi| {
        diag.handler().note(fmt!("meta: %s",
              pprust::meta_item_to_str(*mi,intr)));
    }
}

fn crate_matches(crate_data: @~[u8],
                 metas: &[@ast::meta_item],
                 hash: @~str) -> bool {
    let attrs = decoder::get_crate_attributes(crate_data);
    let linkage_metas = attr::find_linkage_metas(attrs);
    if !hash.is_empty() {
        let chash = decoder::get_crate_hash(crate_data);
        if chash != hash { return false; }
    }
    metadata_matches(linkage_metas, metas)
}

pub fn metadata_matches(extern_metas: &[@ast::meta_item],
                        local_metas: &[@ast::meta_item]) -> bool {

    debug!("matching %u metadata requirements against %u items",
           vec::len(local_metas), vec::len(extern_metas));

    for local_metas.each |needed| {
        if !attr::contains(extern_metas, *needed) {
            return false;
        }
    }
    return true;
}

fn get_metadata_section(os: os,
                        filename: &Path) -> Option<@~[u8]> {
    unsafe {
        let mb = str::as_c_str(filename.to_str(), |buf| {
            llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
        });
        if mb as int == 0 { return option::None::<@~[u8]>; }
        let of = match mk_object_file(mb) {
            option::Some(of) => of,
            _ => return option::None::<@~[u8]>
        };
        let si = mk_section_iter(of.llof);
        while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
            let name_buf = llvm::LLVMGetSectionName(si.llsi);
            let name = unsafe { str::raw::from_c_str(name_buf) };
            if name == meta_section_name(os) {
                let cbuf = llvm::LLVMGetSectionContents(si.llsi);
                let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
                let mut found = None;
                unsafe {
                    let cvbuf: *u8 = cast::reinterpret_cast(&cbuf);
                    let vlen = vec::len(encoder::metadata_encoding_version);
                    debug!("checking %u bytes of metadata-version stamp",
                           vlen);
                    let minsz = uint::min(vlen, csz);
                    let mut version_ok = false;
                    do vec::raw::buf_as_slice(cvbuf, minsz) |buf0| {
                        version_ok = (buf0 ==
                                      encoder::metadata_encoding_version);
                    }
                    if !version_ok { return None; }

                    let cvbuf1 = ptr::offset(cvbuf, vlen);
                    debug!("inflating %u bytes of compressed metadata",
                           csz - vlen);
                    do vec::raw::buf_as_slice(cvbuf1, csz-vlen) |bytes| {
                        let inflated = flate::inflate_bytes(bytes);
                        found = Some(@(inflated));
                    }
                    if found != None {
                        return found;
                    }
                }
            }
            llvm::LLVMMoveToNextSection(si.llsi);
        }
        return option::None::<@~[u8]>;
    }
}

pub fn meta_section_name(os: os) -> ~str {
    match os {
      os_macos => ~"__DATA,__note.rustc",
      os_win32 => ~".note.rustc",
      os_linux => ~".note.rustc",
      os_android => ~".note.rustc",
      os_freebsd => ~".note.rustc"
    }
}

// A diagnostic function for dumping crate metadata to an output stream
pub fn list_file_metadata(intr: @ident_interner,
                          os: os,
                          path: &Path,
                          out: @io::Writer) {
    match get_metadata_section(os, path) {
      option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
      option::None => {
        out.write_str(~"could not find metadata in "
                      + path.to_str() + ~".\n");
      }
    }
}
<commit_msg>FIX meta_section_name for macos<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.

//! Finds crate binaries and loads their metadata

use core::prelude::*;

use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
use metadata::decoder;
use metadata::encoder;
use metadata::filesearch::FileSearch;
use metadata::filesearch;
use syntax::codemap::span;
use syntax::diagnostic::span_handler;
use syntax::parse::token::ident_interner;
use syntax::print::pprust;
use syntax::{ast, attr};

use core::cast;
use core::flate;
use core::io::WriterUtil;
use core::io;
use core::os::consts::{macos, freebsd, linux, android, win32};
use core::option;
use core::ptr;
use core::str;
use core::uint;
use core::vec;

pub enum os {
    os_macos,
    os_win32,
    os_linux,
    os_android,
    os_freebsd
}

pub struct Context {
    diag: @span_handler,
    filesearch: @FileSearch,
    span: span,
    ident: ast::ident,
    metas: ~[@ast::meta_item],
    hash: @~str,
    os: os,
    is_static: bool,
    intr: @ident_interner
}

pub fn load_library_crate(cx: Context) -> (~str, @~[u8]) {
    match find_library_crate(cx) {
      Some(ref t) => return (/*bad*/copy *t),
      None => {
        cx.diag.span_fatal(
            cx.span, fmt!("can't find crate for `%s`",
                          *cx.intr.get(cx.ident)));
      }
    }
}

fn find_library_crate(cx: Context) -> Option<(~str, @~[u8])> {
    attr::require_unique_names(cx.diag, cx.metas);
    find_library_crate_aux(cx, libname(cx), cx.filesearch)
}

fn libname(cx: Context) -> (~str, ~str) {
    if cx.is_static { return (~"lib", ~".rlib"); }
    let (dll_prefix, dll_suffix) = match cx.os {
        os_win32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
        os_macos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
        os_linux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
        os_android => (android::DLL_PREFIX, android::DLL_SUFFIX),
        os_freebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
    };

    (str::from_slice(dll_prefix), str::from_slice(dll_suffix))
}

fn find_library_crate_aux(
    cx: Context,
    (prefix, suffix): (~str, ~str),
    filesearch: @filesearch::FileSearch
) -> Option<(~str, @~[u8])> {
    let crate_name = crate_name_from_metas(cx.metas);
    let prefix: ~str = prefix + *crate_name + ~"-";
    let suffix: ~str = /*bad*/copy suffix;

    let mut matches = ~[];
    filesearch::search(filesearch, |path| {
        debug!("inspecting file %s", path.to_str());
        let f: ~str = path.filename().get();
        if !(f.starts_with(prefix) && f.ends_with(suffix)) {
            debug!("skipping %s, doesn't look like %s*%s", path.to_str(),
                   prefix, suffix);
            option::None::<()>
        } else {
            debug!("%s is a candidate", path.to_str());
            match get_metadata_section(cx.os, path) {
              option::Some(cvec) => {
                if !crate_matches(cvec, cx.metas, cx.hash) {
                    debug!("skipping %s, metadata doesn't match",
                           path.to_str());
                    option::None::<()>
                } else {
                    debug!("found %s with matching metadata", path.to_str());
                    matches.push((path.to_str(), cvec));
                    option::None::<()>
                }
              }
              _ => {
                debug!("could not load metadata for %s", path.to_str());
                option::None::<()>
              }
            }
        }
    });

    if matches.is_empty() {
        None
    } else if matches.len() == 1u {
        Some(/*bad*/copy matches[0])
    } else {
        cx.diag.span_err(
            cx.span, fmt!("multiple matching crates for `%s`", *crate_name));
        cx.diag.handler().note(~"candidates:");
        for matches.each |&(ident, data)| {
            cx.diag.handler().note(fmt!("path: %s", ident));
            let attrs = decoder::get_crate_attributes(data);
            note_linkage_attrs(cx.intr, cx.diag, attrs);
        }
        cx.diag.handler().abort_if_errors();
        None
    }
}

pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @~str {
    let name_items = attr::find_meta_items_by_name(metas, ~"name");
    match name_items.last_opt() {
        Some(i) => {
            match attr::get_meta_item_value_str(*i) {
                Some(n) => n,
                // FIXME (#2406): Probably want a warning here since the user
                // is using the wrong type of meta item.
                _ => fail!()
            }
        }
        None => fail!(~"expected to find the crate name")
    }
}

pub fn note_linkage_attrs(intr: @ident_interner,
                          diag: @span_handler,
                          attrs: ~[ast::attribute]) {
    for attr::find_linkage_metas(attrs).each |mi| {
        diag.handler().note(fmt!("meta: %s",
              pprust::meta_item_to_str(*mi,intr)));
    }
}

fn crate_matches(crate_data: @~[u8],
                 metas: &[@ast::meta_item],
                 hash: @~str) -> bool {
    let attrs = decoder::get_crate_attributes(crate_data);
    let linkage_metas = attr::find_linkage_metas(attrs);
    if !hash.is_empty() {
        let chash = decoder::get_crate_hash(crate_data);
        if chash != hash { return false; }
    }
    metadata_matches(linkage_metas, metas)
}

pub fn metadata_matches(extern_metas: &[@ast::meta_item],
                        local_metas: &[@ast::meta_item]) -> bool {

    debug!("matching %u metadata requirements against %u items",
           vec::len(local_metas), vec::len(extern_metas));

    for local_metas.each |needed| {
        if !attr::contains(extern_metas, *needed) {
            return false;
        }
    }
    return true;
}

fn get_metadata_section(os: os,
                        filename: &Path) -> Option<@~[u8]> {
    unsafe {
        let mb = str::as_c_str(filename.to_str(), |buf| {
            llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
        });
        if mb as int == 0 { return option::None::<@~[u8]>; }
        let of = match mk_object_file(mb) {
            option::Some(of) => of,
            _ => return option::None::<@~[u8]>
        };
        let si = mk_section_iter(of.llof);
        while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
            let name_buf = llvm::LLVMGetSectionName(si.llsi);
            let name = unsafe { str::raw::from_c_str(name_buf) };
            debug!("get_matadata_section: name %s", name);
            if name == read_meta_section_name(os) {
                let cbuf = llvm::LLVMGetSectionContents(si.llsi);
                let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
                let mut found = None;
                unsafe {
                    let cvbuf: *u8 = cast::reinterpret_cast(&cbuf);
                    let vlen = vec::len(encoder::metadata_encoding_version);
                    debug!("checking %u bytes of metadata-version stamp",
                           vlen);
                    let minsz = uint::min(vlen, csz);
                    let mut version_ok = false;
                    do vec::raw::buf_as_slice(cvbuf, minsz) |buf0| {
                        version_ok = (buf0 ==
                                      encoder::metadata_encoding_version);
                    }
                    if !version_ok { return None; }

                    let cvbuf1 = ptr::offset(cvbuf, vlen);
                    debug!("inflating %u bytes of compressed metadata",
                           csz - vlen);
                    do vec::raw::buf_as_slice(cvbuf1, csz-vlen) |bytes| {
                        let inflated = flate::inflate_bytes(bytes);
                        found = Some(@(inflated));
                    }
                    if found != None {
                        return found;
                    }
                }
            }
            llvm::LLVMMoveToNextSection(si.llsi);
        }
        return option::None::<@~[u8]>;
    }
}

pub fn meta_section_name(os: os) -> ~str {
    match os {
      os_macos => ~"__DATA,__note.rustc",
      os_win32 => ~".note.rustc",
      os_linux => ~".note.rustc",
      os_android => ~".note.rustc",
      os_freebsd => ~".note.rustc"
    }
}

pub fn read_meta_section_name(os: os) -> ~str {
    match os {
      os_macos => ~"__note.rustc",
      os_win32 => ~".note.rustc",
      os_linux => ~".note.rustc",
      os_android => ~".note.rustc",
      os_freebsd => ~".note.rustc"
    }
}

// A diagnostic function for dumping crate metadata to an output stream
pub fn list_file_metadata(intr: @ident_interner,
                          os: os,
                          path: &Path,
                          out: @io::Writer) {
    match get_metadata_section(os, path) {
      option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
      option::None => {
        out.write_str(~"could not find metadata in "
                      + path.to_str() + ~".\n");
      }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Allows you to create surfaces that fill a whole display, outside of the windowing system.
//!
//! **As far as the author knows, no existing device supports these features. Therefore the code
//! here is mostly a draft and needs rework in both the API and the implementation.**
//!
//! The purpose of the objects in this module is to let you create a `Surface` object that
//! represents a location on the screen. This is done in four steps:
//!
//! - Choose a `Display` where the surface will be located. A `Display` represents a display
//!   display, usually a monitor. The available displays can be enumerated with
//!   `Display::enumerate`.
//! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh
//!   rate. You can enumerate the modes available on a display with `Display::display_modes`, or
//!   attempt to create your own mode with `TODO`.
//! - Choose a `DisplayPlane`. A display can show multiple planes in a stacking fashion.
//! - Create a `Surface` object with `Surface::from_display_mode` and pass the chosen `DisplayMode`
//!   and `DisplayPlane`.

#![allow(dead_code)] // TODO: this module isn't finished
#![allow(unused_variables)] // TODO: this module isn't finished

use crate::check_errors;
use crate::instance::Instance;
use crate::instance::PhysicalDevice;
use crate::swapchain::SupportedSurfaceTransforms;
use crate::OomError;
use crate::VulkanObject;
use std::ffi::CStr;
use std::ptr;
use std::sync::Arc;
use std::vec::IntoIter;

// TODO: extract this to a `display` module and solve the visibility problems

/// ?
// TODO: plane capabilities
// TODO: store properties in the instance?
pub struct DisplayPlane {
    instance: Arc<Instance>,
    physical_device: usize,
    index: u32,
    properties: ash::vk::DisplayPlanePropertiesKHR,
    supported_displays: Vec<ash::vk::DisplayKHR>,
}

impl DisplayPlane {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError> {
        let fns = device.instance().fns();

        assert!(device.instance().loaded_extensions().khr_display); // TODO: return error instead

        let num = unsafe {
            let mut num: u32 = 0;
            check_errors(
                fns.khr_display
                    .get_physical_device_display_plane_properties_khr(
                        device.internal_object(),
                        &mut num,
                        ptr::null_mut(),
                    ),
            )?;
            num
        };

        let planes: Vec<ash::vk::DisplayPlanePropertiesKHR> = unsafe {
            let mut planes = Vec::with_capacity(num as usize);
            let mut num = num;
            check_errors(
                fns.khr_display
                    .get_physical_device_display_plane_properties_khr(
                        device.internal_object(),
                        &mut num,
                        planes.as_mut_ptr(),
                    ),
            )?;
            planes.set_len(num as usize);
            planes
        };

        Ok(planes
            .into_iter()
            .enumerate()
            .map(|(index, prop)| {
                let num = unsafe {
                    let mut num: u32 = 0;
                    check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
                        device.internal_object(),
                        index as u32,
                        &mut num,
                        ptr::null_mut(),
                    ))
                    .unwrap(); // TODO: shouldn't unwrap
                    num
                };

                let supported_displays: Vec<ash::vk::DisplayKHR> = unsafe {
                    let mut displays = Vec::with_capacity(num as usize);
                    let mut num = num;
                    check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
                        device.internal_object(),
                        index as u32,
                        &mut num,
                        displays.as_mut_ptr(),
                    ))
                    .unwrap(); // TODO: shouldn't unwrap
                    displays.set_len(num as usize);
                    displays
                };

                DisplayPlane {
                    instance: device.instance().clone(),
                    physical_device: device.index(),
                    index: index as u32,
                    properties: prop,
                    supported_displays: supported_displays,
                }
            })
            .collect::<Vec<_>>()
            .into_iter())
    }

    /// Enumerates all the display planes that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: PhysicalDevice) -> IntoIter<DisplayPlane> {
        DisplayPlane::enumerate_raw(device).unwrap()
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the index of the plane.
    #[inline]
    pub fn index(&self) -> u32 {
        self.index
    }

    /// Returns true if this plane supports the given display.
    #[inline]
    pub fn supports(&self, display: &Display) -> bool {
        // making sure that the physical device is the same
        if self.physical_device().internal_object() != display.physical_device().internal_object() {
            return false;
        }

        self.supported_displays
            .iter()
            .find(|&&d| d == display.internal_object())
            .is_some()
    }
}

/// Represents a monitor connected to a physical device.
// TODO: store properties in the instance?
#[derive(Clone)]
pub struct Display {
    instance: Arc<Instance>,
    physical_device: usize,
    properties: Arc<ash::vk::DisplayPropertiesKHR>, // TODO: Arc because struct isn't clone
}

impl Display {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<Display>, OomError> {
        let fns = device.instance().fns();
        assert!(device.instance().loaded_extensions().khr_display); // TODO: return error instead

        let num = unsafe {
            let mut num = 0;
            check_errors(fns.khr_display.get_physical_device_display_properties_khr(
                device.internal_object(),
                &mut num,
                ptr::null_mut(),
            ))?;
            num
        };

        let displays: Vec<ash::vk::DisplayPropertiesKHR> = unsafe {
            let mut displays = Vec::with_capacity(num as usize);
            let mut num = num;
            check_errors(fns.khr_display.get_physical_device_display_properties_khr(
                device.internal_object(),
                &mut num,
                displays.as_mut_ptr(),
            ))?;
            displays.set_len(num as usize);
            displays
        };

        Ok(displays
            .into_iter()
            .map(|prop| Display {
                instance: device.instance().clone(),
                physical_device: device.index(),
                properties: Arc::new(prop),
            })
            .collect::<Vec<_>>()
            .into_iter())
    }

    /// Enumerates all the displays that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: PhysicalDevice) -> IntoIter<Display> {
        Display::enumerate_raw(device).unwrap()
    }

    /// Returns the name of the display.
    #[inline]
    pub fn name(&self) -> &str {
        unsafe {
            CStr::from_ptr(self.properties.display_name)
                .to_str()
                .expect("non UTF-8 characters in display name")
        }
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the physical dimensions of the display in millimeters.
    #[inline]
    pub fn physical_dimensions(&self) -> [u32; 2] {
        let ref r = self.properties.physical_dimensions;
        [r.width, r.height]
    }

    /// Returns the physical, native, or preferred resolution of the display.
    ///
    /// > **Note**: The display is usually still capable of displaying other resolutions. This is
    /// > only the "best" resolution.
    #[inline]
    pub fn physical_resolution(&self) -> [u32; 2] {
        let ref r = self.properties.physical_resolution;
        [r.width, r.height]
    }

    /// Returns the transforms supported by this display.
    #[inline]
    pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
        self.properties.supported_transforms.into()
    }

    /// Returns true if TODO.
    #[inline]
    pub fn plane_reorder_possible(&self) -> bool {
        self.properties.plane_reorder_possible != 0
    }

    /// Returns true if TODO.
    #[inline]
    pub fn persistent_content(&self) -> bool {
        self.properties.persistent_content != 0
    }

    /// See the docs of display_modes().
    pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> {
        let fns = self.instance.fns();

        let num = unsafe {
            let mut num = 0;
            check_errors(fns.khr_display.get_display_mode_properties_khr(
                self.physical_device().internal_object(),
                self.properties.display,
                &mut num,
                ptr::null_mut(),
            ))?;
            num
        };

        let modes: Vec<ash::vk::DisplayModePropertiesKHR> = unsafe {
            let mut modes = Vec::with_capacity(num as usize);
            let mut num = num;
            check_errors(fns.khr_display.get_display_mode_properties_khr(
                self.physical_device().internal_object(),
                self.properties.display,
                &mut num,
                modes.as_mut_ptr(),
            ))?;
            modes.set_len(num as usize);
            modes
        };

        Ok(modes
            .into_iter()
            .map(|mode| DisplayMode {
                display: self.clone(),
                display_mode: mode.display_mode,
                parameters: mode.parameters,
            })
            .collect::<Vec<_>>()
            .into_iter())
    }

    /// Returns a list of all modes available on this display.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from display_modes_raw?
    #[inline]
    pub fn display_modes(&self) -> IntoIter<DisplayMode> {
        self.display_modes_raw().unwrap()
    }
}

unsafe impl VulkanObject for Display {
    type Object = ash::vk::DisplayKHR;

    #[inline]
    fn internal_object(&self) -> ash::vk::DisplayKHR {
        self.properties.display
    }
}

/// Represents a mode on a specific display.
pub struct DisplayMode {
    display: Display,
    display_mode: ash::vk::DisplayModeKHR,
    parameters: ash::vk::DisplayModeParametersKHR,
}

impl DisplayMode {
    /*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, OomError> {
        let fns = instance.fns();
        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let parameters = ash::vk::DisplayModeParametersKHR {
            visibleRegion: ash::vk::Extent2D { width: , height:  },
            refreshRate: ,
        };

        let display_mode = {
            let infos = ash::vk::DisplayModeCreateInfoKHR {
                flags: ash::vk::DisplayModeCreateFlags::empty(),
                parameters: parameters,
                ..Default::default()
            };

            let mut output = mem::uninitialized();
            check_errors(fns.v1_0.CreateDisplayModeKHR(display.device.internal_object(),
                                                      display.display, &infos, ptr::null(),
                                                      &mut output))?;
            output
        };

        Ok(Arc::new(DisplayMode {
            instance: display.device.instance().clone(),
            display_mode: display_mode,
            parameters: ,
        }))
    }*/

    /// Returns the display corresponding to this mode.
    #[inline]
    pub fn display(&self) -> &Display {
        &self.display
    }

    /// Returns the dimensions of the region that is visible on the monitor.
    #[inline]
    pub fn visible_region(&self) -> [u32; 2] {
        let ref d = self.parameters.visible_region;
        [d.width, d.height]
    }

    /// Returns the refresh rate of this mode.
    #[inline]
    pub fn refresh_rate(&self) -> u32 {
        self.parameters.refresh_rate
    }
}

unsafe impl VulkanObject for DisplayMode {
    type Object = ash::vk::DisplayModeKHR;

    #[inline]
    fn internal_object(&self) -> ash::vk::DisplayModeKHR {
        self.display_mode
    }
}
<commit_msg>Implement `fmt::Display` for `DisplayMode` and clarify what the return value of `DisplayMode.refresh_rate` means (#1603)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Allows you to create surfaces that fill a whole display, outside of the windowing system.
//!
//! **As far as the author knows, no existing device supports these features. Therefore the code
//! here is mostly a draft and needs rework in both the API and the implementation.**
//!
//! The purpose of the objects in this module is to let you create a `Surface` object that
//! represents a location on the screen. This is done in four steps:
//!
//! - Choose a `Display` where the surface will be located. A `Display` represents a display
//!   display, usually a monitor. The available displays can be enumerated with
//!   `Display::enumerate`.
//! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh
//!   rate. You can enumerate the modes available on a display with `Display::display_modes`, or
//!   attempt to create your own mode with `TODO`.
//! - Choose a `DisplayPlane`. A display can show multiple planes in a stacking fashion.
//! - Create a `Surface` object with `Surface::from_display_mode` and pass the chosen `DisplayMode`
//!   and `DisplayPlane`.

#![allow(dead_code)] // TODO: this module isn't finished
#![allow(unused_variables)] // TODO: this module isn't finished

use crate::check_errors;
use crate::instance::Instance;
use crate::instance::PhysicalDevice;
use crate::swapchain::SupportedSurfaceTransforms;
use crate::OomError;
use crate::VulkanObject;
use std::ffi::CStr;
use std::fmt::Formatter;
use std::sync::Arc;
use std::vec::IntoIter;
use std::{fmt, ptr};

// TODO: extract this to a `display` module and solve the visibility problems

/// ?
// TODO: plane capabilities
// TODO: store properties in the instance?
pub struct DisplayPlane {
    instance: Arc<Instance>,
    physical_device: usize,
    index: u32,
    properties: ash::vk::DisplayPlanePropertiesKHR,
    supported_displays: Vec<ash::vk::DisplayKHR>,
}

impl DisplayPlane {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError> {
        let fns = device.instance().fns();

        assert!(device.instance().loaded_extensions().khr_display); // TODO: return error instead

        let num = unsafe {
            let mut num: u32 = 0;
            check_errors(
                fns.khr_display
                    .get_physical_device_display_plane_properties_khr(
                        device.internal_object(),
                        &mut num,
                        ptr::null_mut(),
                    ),
            )?;
            num
        };

        let planes: Vec<ash::vk::DisplayPlanePropertiesKHR> = unsafe {
            let mut planes = Vec::with_capacity(num as usize);
            let mut num = num;
            check_errors(
                fns.khr_display
                    .get_physical_device_display_plane_properties_khr(
                        device.internal_object(),
                        &mut num,
                        planes.as_mut_ptr(),
                    ),
            )?;
            planes.set_len(num as usize);
            planes
        };

        Ok(planes
            .into_iter()
            .enumerate()
            .map(|(index, prop)| {
                let num = unsafe {
                    let mut num: u32 = 0;
                    check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
                        device.internal_object(),
                        index as u32,
                        &mut num,
                        ptr::null_mut(),
                    ))
                    .unwrap(); // TODO: shouldn't unwrap
                    num
                };

                let supported_displays: Vec<ash::vk::DisplayKHR> = unsafe {
                    let mut displays = Vec::with_capacity(num as usize);
                    let mut num = num;
                    check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
                        device.internal_object(),
                        index as u32,
                        &mut num,
                        displays.as_mut_ptr(),
                    ))
                    .unwrap(); // TODO: shouldn't unwrap
                    displays.set_len(num as usize);
                    displays
                };

                DisplayPlane {
                    instance: device.instance().clone(),
                    physical_device: device.index(),
                    index: index as u32,
                    properties: prop,
                    supported_displays: supported_displays,
                }
            })
            .collect::<Vec<_>>()
            .into_iter())
    }

    /// Enumerates all the display planes that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: PhysicalDevice) -> IntoIter<DisplayPlane> {
        DisplayPlane::enumerate_raw(device).unwrap()
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the index of the plane.
    #[inline]
    pub fn index(&self) -> u32 {
        self.index
    }

    /// Returns true if this plane supports the given display.
    #[inline]
    pub fn supports(&self, display: &Display) -> bool {
        // making sure that the physical device is the same
        if self.physical_device().internal_object() != display.physical_device().internal_object() {
            return false;
        }

        self.supported_displays
            .iter()
            .find(|&&d| d == display.internal_object())
            .is_some()
    }
}

/// Represents a monitor connected to a physical device.
// TODO: store properties in the instance?
#[derive(Clone)]
pub struct Display {
    instance: Arc<Instance>,
    physical_device: usize,
    properties: Arc<ash::vk::DisplayPropertiesKHR>, // TODO: Arc because struct isn't clone
}

impl Display {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<Display>, OomError> {
        let fns = device.instance().fns();
        assert!(device.instance().loaded_extensions().khr_display); // TODO: return error instead

        let num = unsafe {
            let mut num = 0;
            check_errors(fns.khr_display.get_physical_device_display_properties_khr(
                device.internal_object(),
                &mut num,
                ptr::null_mut(),
            ))?;
            num
        };

        let displays: Vec<ash::vk::DisplayPropertiesKHR> = unsafe {
            let mut displays = Vec::with_capacity(num as usize);
            let mut num = num;
            check_errors(fns.khr_display.get_physical_device_display_properties_khr(
                device.internal_object(),
                &mut num,
                displays.as_mut_ptr(),
            ))?;
            displays.set_len(num as usize);
            displays
        };

        Ok(displays
            .into_iter()
            .map(|prop| Display {
                instance: device.instance().clone(),
                physical_device: device.index(),
                properties: Arc::new(prop),
            })
            .collect::<Vec<_>>()
            .into_iter())
    }

    /// Enumerates all the displays that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: PhysicalDevice) -> IntoIter<Display> {
        Display::enumerate_raw(device).unwrap()
    }

    /// Returns the name of the display.
    #[inline]
    pub fn name(&self) -> &str {
        unsafe {
            CStr::from_ptr(self.properties.display_name)
                .to_str()
                .expect("non UTF-8 characters in display name")
        }
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the physical dimensions of the display in millimeters.
    #[inline]
    pub fn physical_dimensions(&self) -> [u32; 2] {
        let ref r = self.properties.physical_dimensions;
        [r.width, r.height]
    }

    /// Returns the physical, native, or preferred resolution of the display.
    ///
    /// > **Note**: The display is usually still capable of displaying other resolutions. This is
    /// > only the "best" resolution.
    #[inline]
    pub fn physical_resolution(&self) -> [u32; 2] {
        let ref r = self.properties.physical_resolution;
        [r.width, r.height]
    }

    /// Returns the transforms supported by this display.
    #[inline]
    pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
        self.properties.supported_transforms.into()
    }

    /// Returns true if TODO.
    #[inline]
    pub fn plane_reorder_possible(&self) -> bool {
        self.properties.plane_reorder_possible != 0
    }

    /// Returns true if TODO.
    #[inline]
    pub fn persistent_content(&self) -> bool {
        self.properties.persistent_content != 0
    }

    /// See the docs of display_modes().
    pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> {
        let fns = self.instance.fns();

        let num = unsafe {
            let mut num = 0;
            check_errors(fns.khr_display.get_display_mode_properties_khr(
                self.physical_device().internal_object(),
                self.properties.display,
                &mut num,
                ptr::null_mut(),
            ))?;
            num
        };

        let modes: Vec<ash::vk::DisplayModePropertiesKHR> = unsafe {
            let mut modes = Vec::with_capacity(num as usize);
            let mut num = num;
            check_errors(fns.khr_display.get_display_mode_properties_khr(
                self.physical_device().internal_object(),
                self.properties.display,
                &mut num,
                modes.as_mut_ptr(),
            ))?;
            modes.set_len(num as usize);
            modes
        };

        Ok(modes
            .into_iter()
            .map(|mode| DisplayMode {
                display: self.clone(),
                display_mode: mode.display_mode,
                parameters: mode.parameters,
            })
            .collect::<Vec<_>>()
            .into_iter())
    }

    /// Returns a list of all modes available on this display.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from display_modes_raw?
    #[inline]
    pub fn display_modes(&self) -> IntoIter<DisplayMode> {
        self.display_modes_raw().unwrap()
    }
}

unsafe impl VulkanObject for Display {
    type Object = ash::vk::DisplayKHR;

    #[inline]
    fn internal_object(&self) -> ash::vk::DisplayKHR {
        self.properties.display
    }
}

/// Represents a mode on a specific display.
///
/// A display mode describes a supported display resolution and refresh rate.
pub struct DisplayMode {
    display: Display,
    display_mode: ash::vk::DisplayModeKHR,
    parameters: ash::vk::DisplayModeParametersKHR,
}

impl DisplayMode {
    /*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, OomError> {
        let fns = instance.fns();
        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let parameters = ash::vk::DisplayModeParametersKHR {
            visibleRegion: ash::vk::Extent2D { width: , height:  },
            refreshRate: ,
        };

        let display_mode = {
            let infos = ash::vk::DisplayModeCreateInfoKHR {
                flags: ash::vk::DisplayModeCreateFlags::empty(),
                parameters: parameters,
                ..Default::default()
            };

            let mut output = mem::uninitialized();
            check_errors(fns.v1_0.CreateDisplayModeKHR(display.device.internal_object(),
                                                      display.display, &infos, ptr::null(),
                                                      &mut output))?;
            output
        };

        Ok(Arc::new(DisplayMode {
            instance: display.device.instance().clone(),
            display_mode: display_mode,
            parameters: ,
        }))
    }*/

    /// Returns the display corresponding to this mode.
    #[inline]
    pub fn display(&self) -> &Display {
        &self.display
    }

    /// Returns the dimensions of the region that is visible on the monitor.
    #[inline]
    pub fn visible_region(&self) -> [u32; 2] {
        let ref d = self.parameters.visible_region;
        [d.width, d.height]
    }

    /// Returns the refresh rate of this mode.
    ///
    /// The returned value is multiplied by 1000. As such the value is in terms of millihertz (mHz).
    /// For example, a 60Hz display mode would have a refresh rate of 60,000 mHz.
    #[inline]
    pub fn refresh_rate(&self) -> u32 {
        self.parameters.refresh_rate
    }
}

impl fmt::Display for DisplayMode {
    #[inline]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let visible_region = self.visible_region();

        write!(
            f,
            "{}×{}px @ {}.{:03} Hz",
            visible_region[0],
            visible_region[1],
            self.refresh_rate() / 1000,
            self.refresh_rate() % 1000
        )
    }
}

unsafe impl VulkanObject for DisplayMode {
    type Object = ash::vk::DisplayModeKHR;

    #[inline]
    fn internal_object(&self) -> ash::vk::DisplayModeKHR {
        self.display_mode
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;
extern crate cc;

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

fn main() {
    let mut lmdb: PathBuf = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    lmdb.push("lmdb");
    lmdb.push("libraries");
    lmdb.push("liblmdb");

    if !pkg_config::find_library("liblmdb").is_ok() {
        cc::Build::new()
                    .file(lmdb.join("mdb.c"))
                    .file(lmdb.join("midl.c"))
                    // https://github.com/LMDB/lmdb/blob/LMDB_0.9.21/libraries/liblmdb/Makefile#L25
                    .opt_level(2)
                    .compile("liblmdb.a")
    }
}
<commit_msg>Fix Android cross-compile build: `cargo build --target armv7-linux-androideabi`<commit_after>extern crate pkg_config;
extern crate cc;

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

fn main() {
    let mut lmdb: PathBuf = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    lmdb.push("lmdb");
    lmdb.push("libraries");
    lmdb.push("liblmdb");

    if !pkg_config::find_library("liblmdb").is_ok() {
        let target = env::var("TARGET").expect("No TARGET found");
        let mut build = cc::Build::new();
        if target.contains("android") {
            build.define("ANDROID", "1");
        }
        build
            .file(lmdb.join("mdb.c"))
            .file(lmdb.join("midl.c"))
            // https://github.com/LMDB/lmdb/blob/LMDB_0.9.21/libraries/liblmdb/Makefile#L25
            .opt_level(2)
            .compile("liblmdb.a")
    }
}
<|endoftext|>