<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.

//! 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::iter::Iterator;
use core::{ptr, mem};

use stack;
use context;

#[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, return a value each time.
///
/// It implements the Iterator trait. The first time `next()` is called,
/// the function is called as `f(yielder)`; every time `next()` is called afterwards,
/// the function is resumed. In either case, it runs until it suspends its execution
/// through `yielder.generate(val)`), in which case `next()` returns `Some(val)`, or
/// returns, in which case `next()` returns `None`. `next()` will return `None`
/// every time after that.
///
/// After the generator function returns, 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.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut gen = Generator::new(stack, move |yielder| {
///   for i in 1..4 {
///     yielder.generate(i);
///   }
/// });
/// println!("{:?}", gen.next()); // prints Some(1)
/// println!("{:?}", gen.next()); // prints Some(2)
/// println!("{:?}", gen.next()); // prints Some(3)
/// println!("{:?}", gen.next()); // prints None
/// ```
#[derive(Debug)]
pub struct Generator<Item: Send, Stack: stack::Stack> {
  state:   State,
  context: context::Context<Stack>,
  phantom: PhantomData<Item>
}

impl<Item, Stack> Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  /// Creates a new generator.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where Stack: stack::GuardedStack, F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    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.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
        where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(info as *mut (Yielder<Item, Stack>, F));
      let new_context = context::Context::swap(yielder.context, yielder.context, 0);
      // See Yielder::return_.
      yielder.context = new_context as *mut context::Context<Stack>;
      // Run the body of the generator.
      f(&mut yielder);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.return_(None) }
    }

    let mut generator = Generator {
      state:   State::Runnable,
      context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
      phantom: PhantomData
    };

    // Transfer environment to the callee.
    let mut data = (Yielder::new(&mut generator.context), f);
    context::Context::swap(&mut generator.context, &generator.context,
                           &mut data as *mut (Yielder<Item, Stack>, F) as usize);
    mem::forget(data);

    generator
  }

  /// 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 => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Item: Send, Stack: stack::Stack> {
  context: *mut context::Context<Stack>,
  phantom: PhantomData<Item>
}

impl<Item, Stack> Yielder<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  fn new(context: *mut context::Context<Stack>) -> Yielder<Item, Stack> {
    Yielder {
      context: context,
      phantom: PhantomData
    }
  }

  #[inline(always)]
  fn return_(&mut self, mut val: Option<Item>) {
    unsafe {
      let new_context = context::Context::swap(self.context, self.context,
                                               &mut val as *mut Option<Item> as usize);
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context = new_context as *mut context::Context<Stack>;
      // However, between this point and the next time we enter return_
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `next()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn generate(&mut self, item: Item) {
    self.return_(Some(item))
  }
}

impl<Item, Stack> Iterator for Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  type Item = Item;

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  fn next(&mut self) -> Option<Self::Item> {
    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.
        let new_context = &mut self.context as *mut context::Context<Stack> as usize;
        let val = unsafe {
          ptr::read(context::Context::swap(&mut self.context, &self.context, new_context)
                    as *mut Option<Item>)
        };

        // 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
    }
  }
}
<commit_msg>Use a more semantically correct PhantomData field in Generator.<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.

//! 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::iter::Iterator;
use core::{ptr, mem};

use stack;
use context;

#[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, return a value each time.
///
/// It implements the Iterator trait. The first time `next()` is called,
/// the function is called as `f(yielder)`; every time `next()` is called afterwards,
/// the function is resumed. In either case, it runs until it suspends its execution
/// through `yielder.generate(val)`), in which case `next()` returns `Some(val)`, or
/// returns, in which case `next()` returns `None`. `next()` will return `None`
/// every time after that.
///
/// After the generator function returns, 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.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut gen = Generator::new(stack, move |yielder| {
///   for i in 1..4 {
///     yielder.generate(i);
///   }
/// });
/// println!("{:?}", gen.next()); // prints Some(1)
/// println!("{:?}", gen.next()); // prints Some(2)
/// println!("{:?}", gen.next()); // prints Some(3)
/// println!("{:?}", gen.next()); // prints None
/// ```
#[derive(Debug)]
pub struct Generator<Item: Send, Stack: stack::Stack> {
  state:   State,
  context: context::Context<Stack>,
  phantom: PhantomData<*const Item>
}

impl<Item, Stack> Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  /// Creates a new generator.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where Stack: stack::GuardedStack, F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    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.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
        where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(info as *mut (Yielder<Item, Stack>, F));
      let new_context = context::Context::swap(yielder.context, yielder.context, 0);
      // See Yielder::return_.
      yielder.context = new_context as *mut context::Context<Stack>;
      // Run the body of the generator.
      f(&mut yielder);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.return_(None) }
    }

    let mut generator = Generator {
      state:   State::Runnable,
      context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
      phantom: PhantomData
    };

    // Transfer environment to the callee.
    let mut data = (Yielder::new(&mut generator.context), f);
    context::Context::swap(&mut generator.context, &generator.context,
                           &mut data as *mut (Yielder<Item, Stack>, F) as usize);
    mem::forget(data);

    generator
  }

  /// 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 => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Item: Send, Stack: stack::Stack> {
  context: *mut context::Context<Stack>,
  phantom: PhantomData<Item>
}

impl<Item, Stack> Yielder<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  fn new(context: *mut context::Context<Stack>) -> Yielder<Item, Stack> {
    Yielder {
      context: context,
      phantom: PhantomData
    }
  }

  #[inline(always)]
  fn return_(&mut self, mut val: Option<Item>) {
    unsafe {
      let new_context = context::Context::swap(self.context, self.context,
                                               &mut val as *mut Option<Item> as usize);
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context = new_context as *mut context::Context<Stack>;
      // However, between this point and the next time we enter return_
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `next()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn generate(&mut self, item: Item) {
    self.return_(Some(item))
  }
}

impl<Item, Stack> Iterator for Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  type Item = Item;

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  fn next(&mut self) -> Option<Self::Item> {
    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.
        let new_context = &mut self.context as *mut context::Context<Stack> as usize;
        let val = unsafe {
          ptr::read(context::Context::swap(&mut self.context, &self.context, new_context)
                    as *mut Option<Item>)
        };

        // 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
    }
  }
}
<|endoftext|>


<commit_before>//! Linux-specific definitions for linux-like values

s! {
    pub struct glob_t {
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut ::c_char,
        pub gl_offs:  ::size_t,
        pub gl_flags: ::c_int,

        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }

    pub struct ifaddrs {
        pub ifa_next: *mut ::ifaddrs,
        pub ifa_name: *mut ::c_char,
        pub ifa_flags: ::c_uint,
        pub ifa_addr: *mut ::sockaddr,
        pub ifa_netmask: *mut ::sockaddr,
        pub ifa_ifu: *mut ::sockaddr, // FIXME This should be a union
        pub ifa_data: *mut ::c_void
    }
}

pub const BUFSIZ: ::c_uint = 8192;
pub const FILENAME_MAX: ::c_uint = 4096;
pub const FOPEN_MAX: ::c_uint = 16;
pub const L_tmpnam: ::c_uint = 20;
pub const TMP_MAX: ::c_uint = 238328;
pub const _PC_NAME_MAX: ::c_int = 3;

pub const _SC_ARG_MAX: ::c_int = 0;
pub const _SC_CHILD_MAX: ::c_int = 1;
pub const _SC_CLK_TCK: ::c_int = 2;
pub const _SC_NGROUPS_MAX: ::c_int = 3;
pub const _SC_OPEN_MAX: ::c_int = 4;
pub const _SC_STREAM_MAX: ::c_int = 5;
pub const _SC_TZNAME_MAX: ::c_int = 6;
pub const _SC_JOB_CONTROL: ::c_int = 7;
pub const _SC_SAVED_IDS: ::c_int = 8;
pub const _SC_REALTIME_SIGNALS: ::c_int = 9;
pub const _SC_PRIORITY_SCHEDULING: ::c_int = 10;
pub const _SC_TIMERS: ::c_int = 11;
pub const _SC_ASYNCHRONOUS_IO: ::c_int = 12;
pub const _SC_PRIORITIZED_IO: ::c_int = 13;
pub const _SC_SYNCHRONIZED_IO: ::c_int = 14;
pub const _SC_FSYNC: ::c_int = 15;
pub const _SC_MAPPED_FILES: ::c_int = 16;
pub const _SC_MEMLOCK: ::c_int = 17;
pub const _SC_MEMLOCK_RANGE: ::c_int = 18;
pub const _SC_MEMORY_PROTECTION: ::c_int = 19;
pub const _SC_MESSAGE_PASSING: ::c_int = 20;
pub const _SC_SEMAPHORES: ::c_int = 21;
pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 22;
pub const _SC_AIO_LISTIO_MAX: ::c_int = 23;
pub const _SC_AIO_MAX: ::c_int = 24;
pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 25;
pub const _SC_DELAYTIMER_MAX: ::c_int = 26;
pub const _SC_MQ_OPEN_MAX: ::c_int = 27;
pub const _SC_MQ_PRIO_MAX: ::c_int = 28;
pub const _SC_VERSION: ::c_int = 29;
pub const _SC_PAGESIZE: ::c_int = 30;
pub const _SC_RTSIG_MAX: ::c_int = 31;
pub const _SC_SEM_NSEMS_MAX: ::c_int = 32;
pub const _SC_SEM_VALUE_MAX: ::c_int = 33;
pub const _SC_SIGQUEUE_MAX: ::c_int = 34;
pub const _SC_TIMER_MAX: ::c_int = 35;
pub const _SC_BC_BASE_MAX: ::c_int = 36;
pub const _SC_BC_DIM_MAX: ::c_int = 37;
pub const _SC_BC_SCALE_MAX: ::c_int = 38;
pub const _SC_BC_STRING_MAX: ::c_int = 39;
pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 40;
pub const _SC_EXPR_NEST_MAX: ::c_int = 42;
pub const _SC_LINE_MAX: ::c_int = 43;
pub const _SC_RE_DUP_MAX: ::c_int = 44;
pub const _SC_2_VERSION: ::c_int = 46;
pub const _SC_2_C_BIND: ::c_int = 47;
pub const _SC_2_C_DEV: ::c_int = 48;
pub const _SC_2_FORT_DEV: ::c_int = 49;
pub const _SC_2_FORT_RUN: ::c_int = 50;
pub const _SC_2_SW_DEV: ::c_int = 51;
pub const _SC_2_LOCALEDEF: ::c_int = 52;
pub const _SC_IOV_MAX: ::c_int = 60;
pub const _SC_THREADS: ::c_int = 67;
pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 68;
pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 69;
pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 70;
pub const _SC_LOGIN_NAME_MAX: ::c_int = 71;
pub const _SC_TTY_NAME_MAX: ::c_int = 72;
pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 73;
pub const _SC_THREAD_KEYS_MAX: ::c_int = 74;
pub const _SC_THREAD_STACK_MIN: ::c_int = 75;
pub const _SC_THREAD_THREADS_MAX: ::c_int = 76;
pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 77;
pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 78;
pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 79;
pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 80;
pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 81;
pub const _SC_NPROCESSORS_ONLN: ::c_int = 84;
pub const _SC_ATEXIT_MAX: ::c_int = 87;
pub const _SC_XOPEN_VERSION: ::c_int = 89;
pub const _SC_XOPEN_XCU_VERSION: ::c_int = 90;
pub const _SC_XOPEN_UNIX: ::c_int = 91;
pub const _SC_XOPEN_CRYPT: ::c_int = 92;
pub const _SC_XOPEN_ENH_I18N: ::c_int = 93;
pub const _SC_XOPEN_SHM: ::c_int = 94;
pub const _SC_2_CHAR_TERM: ::c_int = 95;
pub const _SC_2_C_VERSION: ::c_int = 96;
pub const _SC_2_UPE: ::c_int = 97;
pub const _SC_XBS5_ILP32_OFF32: ::c_int = 125;
pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 126;
pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 128;
pub const _SC_XOPEN_LEGACY: ::c_int = 129;
pub const _SC_XOPEN_REALTIME: ::c_int = 130;
pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 131;

pub const RLIMIT_NLIMITS: ::c_int = 16;
pub const RLIM_SAVED_MAX: ::rlim_t = ::RLIM_INFINITY;
pub const RLIM_SAVED_CUR: ::rlim_t = ::RLIM_INFINITY;

#[cfg(not(target_env = "musl"))]
pub const RUSAGE_THREAD: ::c_int = 1;

pub const GLOB_ERR: ::c_int = 1 << 0;
pub const GLOB_MARK: ::c_int = 1 << 1;
pub const GLOB_NOSORT: ::c_int = 1 << 2;
pub const GLOB_DOOFFS: ::c_int = 1 << 3;
pub const GLOB_NOCHECK: ::c_int = 1 << 4;
pub const GLOB_APPEND: ::c_int = 1 << 5;
pub const GLOB_NOESCAPE: ::c_int = 1 << 6;

pub const GLOB_NOSPACE: ::c_int = 1;
pub const GLOB_ABORTED: ::c_int = 2;
pub const GLOB_NOMATCH: ::c_int = 3;

pub const POSIX_MADV_NORMAL: ::c_int = 0;
pub const POSIX_MADV_RANDOM: ::c_int = 1;
pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2;
pub const POSIX_MADV_WILLNEED: ::c_int = 3;
pub const POSIX_MADV_DONTNEED: ::c_int = 4;

pub const S_IEXEC: ::mode_t = 64;
pub const S_IWRITE: ::mode_t = 128;
pub const S_IREAD: ::mode_t = 256;

pub const F_LOCK: ::c_int = 1;
pub const F_TEST: ::c_int = 3;
pub const F_TLOCK: ::c_int = 2;
pub const F_ULOCK: ::c_int = 0;

pub const ERFKILL: ::c_int = 132;
pub const EHWPOISON: ::c_int = 133;

pub const O_SYNC: ::c_int = 1052672;
pub const O_RSYNC: ::c_int = 1052672;
pub const O_DSYNC: ::c_int = 4096;

pub const MAP_32BIT: ::c_int = 0x0040;

pub const TCP_MD5SIG: ::c_int = 14;
pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15;
pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16;
pub const TCP_THIN_DUPACK: ::c_int = 17;
pub const TCP_USER_TIMEOUT: ::c_int = 18;
pub const TCP_REPAIR: ::c_int = 19;
pub const TCP_REPAIR_QUEUE: ::c_int = 20;
pub const TCP_QUEUE_SEQ: ::c_int = 21;
pub const TCP_REPAIR_OPTIONS: ::c_int = 22;
pub const TCP_FASTOPEN: ::c_int = 23;
pub const TCP_TIMESTAMP: ::c_int = 24;

pub const SO_REUSEPORT: ::c_int = 15;

cfg_if! {
    if #[cfg(any(target_arch = "arm", target_arch = "x86",
                 target_arch = "x86_64"))] {
        pub const PTHREAD_STACK_MIN: ::size_t = 16384;
    } else {
        pub const PTHREAD_STACK_MIN: ::size_t = 131072;
    }
}
<commit_msg>Fix arm-linux compile<commit_after>//! Linux-specific definitions for linux-like values

s! {
    pub struct glob_t {
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut ::c_char,
        pub gl_offs:  ::size_t,
        pub gl_flags: ::c_int,

        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }

    pub struct ifaddrs {
        pub ifa_next: *mut ::ifaddrs,
        pub ifa_name: *mut ::c_char,
        pub ifa_flags: ::c_uint,
        pub ifa_addr: *mut ::sockaddr,
        pub ifa_netmask: *mut ::sockaddr,
        pub ifa_ifu: *mut ::sockaddr, // FIXME This should be a union
        pub ifa_data: *mut ::c_void
    }
}

pub const BUFSIZ: ::c_uint = 8192;
pub const FILENAME_MAX: ::c_uint = 4096;
pub const FOPEN_MAX: ::c_uint = 16;
pub const L_tmpnam: ::c_uint = 20;
pub const TMP_MAX: ::c_uint = 238328;
pub const _PC_NAME_MAX: ::c_int = 3;

pub const _SC_ARG_MAX: ::c_int = 0;
pub const _SC_CHILD_MAX: ::c_int = 1;
pub const _SC_CLK_TCK: ::c_int = 2;
pub const _SC_NGROUPS_MAX: ::c_int = 3;
pub const _SC_OPEN_MAX: ::c_int = 4;
pub const _SC_STREAM_MAX: ::c_int = 5;
pub const _SC_TZNAME_MAX: ::c_int = 6;
pub const _SC_JOB_CONTROL: ::c_int = 7;
pub const _SC_SAVED_IDS: ::c_int = 8;
pub const _SC_REALTIME_SIGNALS: ::c_int = 9;
pub const _SC_PRIORITY_SCHEDULING: ::c_int = 10;
pub const _SC_TIMERS: ::c_int = 11;
pub const _SC_ASYNCHRONOUS_IO: ::c_int = 12;
pub const _SC_PRIORITIZED_IO: ::c_int = 13;
pub const _SC_SYNCHRONIZED_IO: ::c_int = 14;
pub const _SC_FSYNC: ::c_int = 15;
pub const _SC_MAPPED_FILES: ::c_int = 16;
pub const _SC_MEMLOCK: ::c_int = 17;
pub const _SC_MEMLOCK_RANGE: ::c_int = 18;
pub const _SC_MEMORY_PROTECTION: ::c_int = 19;
pub const _SC_MESSAGE_PASSING: ::c_int = 20;
pub const _SC_SEMAPHORES: ::c_int = 21;
pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 22;
pub const _SC_AIO_LISTIO_MAX: ::c_int = 23;
pub const _SC_AIO_MAX: ::c_int = 24;
pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 25;
pub const _SC_DELAYTIMER_MAX: ::c_int = 26;
pub const _SC_MQ_OPEN_MAX: ::c_int = 27;
pub const _SC_MQ_PRIO_MAX: ::c_int = 28;
pub const _SC_VERSION: ::c_int = 29;
pub const _SC_PAGESIZE: ::c_int = 30;
pub const _SC_RTSIG_MAX: ::c_int = 31;
pub const _SC_SEM_NSEMS_MAX: ::c_int = 32;
pub const _SC_SEM_VALUE_MAX: ::c_int = 33;
pub const _SC_SIGQUEUE_MAX: ::c_int = 34;
pub const _SC_TIMER_MAX: ::c_int = 35;
pub const _SC_BC_BASE_MAX: ::c_int = 36;
pub const _SC_BC_DIM_MAX: ::c_int = 37;
pub const _SC_BC_SCALE_MAX: ::c_int = 38;
pub const _SC_BC_STRING_MAX: ::c_int = 39;
pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 40;
pub const _SC_EXPR_NEST_MAX: ::c_int = 42;
pub const _SC_LINE_MAX: ::c_int = 43;
pub const _SC_RE_DUP_MAX: ::c_int = 44;
pub const _SC_2_VERSION: ::c_int = 46;
pub const _SC_2_C_BIND: ::c_int = 47;
pub const _SC_2_C_DEV: ::c_int = 48;
pub const _SC_2_FORT_DEV: ::c_int = 49;
pub const _SC_2_FORT_RUN: ::c_int = 50;
pub const _SC_2_SW_DEV: ::c_int = 51;
pub const _SC_2_LOCALEDEF: ::c_int = 52;
pub const _SC_IOV_MAX: ::c_int = 60;
pub const _SC_THREADS: ::c_int = 67;
pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 68;
pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 69;
pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 70;
pub const _SC_LOGIN_NAME_MAX: ::c_int = 71;
pub const _SC_TTY_NAME_MAX: ::c_int = 72;
pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 73;
pub const _SC_THREAD_KEYS_MAX: ::c_int = 74;
pub const _SC_THREAD_STACK_MIN: ::c_int = 75;
pub const _SC_THREAD_THREADS_MAX: ::c_int = 76;
pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 77;
pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 78;
pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 79;
pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 80;
pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 81;
pub const _SC_NPROCESSORS_ONLN: ::c_int = 84;
pub const _SC_ATEXIT_MAX: ::c_int = 87;
pub const _SC_XOPEN_VERSION: ::c_int = 89;
pub const _SC_XOPEN_XCU_VERSION: ::c_int = 90;
pub const _SC_XOPEN_UNIX: ::c_int = 91;
pub const _SC_XOPEN_CRYPT: ::c_int = 92;
pub const _SC_XOPEN_ENH_I18N: ::c_int = 93;
pub const _SC_XOPEN_SHM: ::c_int = 94;
pub const _SC_2_CHAR_TERM: ::c_int = 95;
pub const _SC_2_C_VERSION: ::c_int = 96;
pub const _SC_2_UPE: ::c_int = 97;
pub const _SC_XBS5_ILP32_OFF32: ::c_int = 125;
pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 126;
pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 128;
pub const _SC_XOPEN_LEGACY: ::c_int = 129;
pub const _SC_XOPEN_REALTIME: ::c_int = 130;
pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 131;

pub const RLIMIT_NLIMITS: ::c_int = 16;
pub const RLIM_SAVED_MAX: ::rlim_t = ::RLIM_INFINITY;
pub const RLIM_SAVED_CUR: ::rlim_t = ::RLIM_INFINITY;

#[cfg(not(target_env = "musl"))]
pub const RUSAGE_THREAD: ::c_int = 1;

pub const GLOB_ERR: ::c_int = 1 << 0;
pub const GLOB_MARK: ::c_int = 1 << 1;
pub const GLOB_NOSORT: ::c_int = 1 << 2;
pub const GLOB_DOOFFS: ::c_int = 1 << 3;
pub const GLOB_NOCHECK: ::c_int = 1 << 4;
pub const GLOB_APPEND: ::c_int = 1 << 5;
pub const GLOB_NOESCAPE: ::c_int = 1 << 6;

pub const GLOB_NOSPACE: ::c_int = 1;
pub const GLOB_ABORTED: ::c_int = 2;
pub const GLOB_NOMATCH: ::c_int = 3;

pub const POSIX_MADV_NORMAL: ::c_int = 0;
pub const POSIX_MADV_RANDOM: ::c_int = 1;
pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2;
pub const POSIX_MADV_WILLNEED: ::c_int = 3;
pub const POSIX_MADV_DONTNEED: ::c_int = 4;

pub const S_IEXEC: ::mode_t = 64;
pub const S_IWRITE: ::mode_t = 128;
pub const S_IREAD: ::mode_t = 256;

pub const F_LOCK: ::c_int = 1;
pub const F_TEST: ::c_int = 3;
pub const F_TLOCK: ::c_int = 2;
pub const F_ULOCK: ::c_int = 0;

pub const ERFKILL: ::c_int = 132;
pub const EHWPOISON: ::c_int = 133;

pub const O_SYNC: ::c_int = 1052672;
pub const O_RSYNC: ::c_int = 1052672;
pub const O_DSYNC: ::c_int = 4096;

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub const MAP_32BIT: ::c_int = 0x0040;

pub const TCP_MD5SIG: ::c_int = 14;
pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15;
pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16;
pub const TCP_THIN_DUPACK: ::c_int = 17;
pub const TCP_USER_TIMEOUT: ::c_int = 18;
pub const TCP_REPAIR: ::c_int = 19;
pub const TCP_REPAIR_QUEUE: ::c_int = 20;
pub const TCP_QUEUE_SEQ: ::c_int = 21;
pub const TCP_REPAIR_OPTIONS: ::c_int = 22;
pub const TCP_FASTOPEN: ::c_int = 23;
pub const TCP_TIMESTAMP: ::c_int = 24;

pub const SO_REUSEPORT: ::c_int = 15;

cfg_if! {
    if #[cfg(any(target_arch = "arm", target_arch = "x86",
                 target_arch = "x86_64"))] {
        pub const PTHREAD_STACK_MIN: ::size_t = 16384;
    } else {
        pub const PTHREAD_STACK_MIN: ::size_t = 131072;
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix bug when counting CSV records for indexing.<commit_after><|endoftext|>


<commit_before><commit_msg>Add test case for #3878, which didn't get merged somehow<commit_after>fn main()
{
    let y = ~1;
    move y;
}
<|endoftext|>


<commit_before>use {ast, typeinf, util};
use core::{Src, SessionRef, CompletionType};
#[cfg(test)] use core;

use std::iter::Iterator;
use std::path::Path;
use std::str::from_utf8;
use util::char_at;

fn find_close<'a, A>(iter: A, open: u8, close: u8, level_end: u32) -> Option<usize> where A: Iterator<Item=&'a u8> {
    let mut count = 0usize;
    let mut levels = 0u32;
    for &b in iter {
        if b == close {
            if levels == level_end { return Some(count); }
            levels -= 1;
        } else if b == open { levels += 1; }
        count += 1;
    }
    None
}

pub fn find_closing_paren(src: &str, pos: usize) -> usize {
    find_close(src.as_bytes()[pos..].iter(), b'(', b')', 0)
    .map_or(src.len(), |count| pos + count)
}

pub fn scope_start(src: Src, point: usize) -> usize {
    let masked_src = mask_comments(src.to(point));
    find_close(masked_src.as_bytes().iter().rev(), b'}', b'{', 0)
    .map_or(0, |count| point - count)
}

pub fn find_stmt_start(msrc: Src, point: usize) -> Option<usize> {
    // iterate the scope to find the start of the statement
    let scopestart = scope_start(msrc, point);
    msrc.from(scopestart).iter_stmts()
        .find(|&(_, end)| scopestart + end > point)
        .map(|(start, _)| scopestart + start)
}

pub fn get_local_module_path(msrc: Src, point: usize) -> Vec<String> {
    let mut v = Vec::new();
    get_local_module_path_(msrc, point, &mut v);
    v
}

fn get_local_module_path_(msrc: Src, point: usize, out: &mut Vec<String>) {
    for (start, end) in msrc.iter_stmts() {
        if start < point && end > point {
            let blob = msrc.from_to(start, end);
            if blob.starts_with("pub mod ") || blob.starts_with("mod ") {
                let p = typeinf::generate_skeleton_for_parsing(&blob);
                ast::parse_mod(p).name.map(|name| {
                    out.push(name);
                    let newstart = blob.find("{").unwrap() + 1;
                    get_local_module_path_(blob.from(newstart),
                                           point - start - newstart, out);
                });
            }
        }
    }
}

pub fn find_impl_start(msrc: Src, point: usize, scopestart: usize) -> Option<usize> {
    let len = point-scopestart;
    match msrc.from(scopestart).iter_stmts().find(|&(_, end)| end > len) {
        Some((start, _)) => {
            let blob = msrc.from(scopestart + start);
            // TODO:: the following is a bit weak at matching traits. make this better
            if blob.starts_with("impl") || blob.starts_with("trait") || blob.starts_with("pub trait") {
                Some(scopestart + start)
            } else {
                let newstart = blob.find("{").unwrap() + 1;
                find_impl_start(msrc, point, scopestart+start+newstart)
            }
        },
        None => None
    }
}
#[test]
fn finds_subnested_module() {
    use core;
    let src = "
    pub mod foo {
        pub mod bar {
            here
        }
    }";
    let point = coords_to_point(&src, 4, 12);
    let src = core::new_source(String::from(src));
    let v = get_local_module_path(src.as_ref(), point);
    assert_eq!("foo", &v[0][..]);
    assert_eq!("bar", &v[1][..]);

    let point = coords_to_point(&src, 3, 8);
    let v = get_local_module_path(src.as_ref(), point);
    assert_eq!("foo", &v[0][..]);
}

pub fn split_into_context_and_completion(s: &str) -> (&str, &str, CompletionType) {
    match s.char_indices().rev().find(|&(_, c)| !util::is_ident_char(c)) {
        Some((i,c)) => {
            //println!("PHIL s '{}' i {} c '{}'",s,i,c);
            match c {
                '.' => (&s[..i], &s[(i+1)..], CompletionType::CompleteField),
                ':' if s.len() > 1 => (&s[..(i-1)], &s[(i+1)..], CompletionType::CompletePath),
                _   => (&s[..(i+1)], &s[(i+1)..], CompletionType::CompletePath)
            }
        },
        None => ("", s, CompletionType::CompletePath)
    }
}

pub fn get_start_of_search_expr(src: &str, point: usize) -> usize {
    let mut i = point;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        i -= 1;
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_search_expr_char(char_at(src, i)) ||
                    util::is_double_dot(src,i) {
                    return i+1;
                }
            }
        }
    }
    0
}

pub fn get_start_of_pattern(src: &str, point: usize) -> usize {
    let mut i = point-1;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_pattern_char(char_at(src, i)) {
                    return i+1;
                }
            }
        }
        i -= 1;
    }
    0
}

#[test]
fn get_start_of_pattern_handles_variant() {
    assert_eq!(4, get_start_of_pattern("foo, Some(a) =>",13));
}

#[test]
fn get_start_of_pattern_handles_variant2() {
    assert_eq!(4, get_start_of_pattern("bla, ast::PatTup(ref tuple_elements) => {",36));
}

pub fn expand_search_expr(msrc: &str, point: usize) -> (usize, usize) {
    let start = get_start_of_search_expr(msrc, point);
    (start, util::find_ident_end(msrc, point))
}

#[test]
fn expand_search_expr_finds_ident() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 5))
}

#[test]
fn expand_search_expr_handles_chained_calls() {
    assert_eq!((0, 20), expand_search_expr("yeah::blah.foo().bar", 18))
}

#[test]
fn expand_search_expr_handles_inline_closures() {
    assert_eq!((0, 24), expand_search_expr("yeah::blah.foo(||{}).bar", 22))
}
#[test]
fn expand_search_expr_handles_a_function_arg() {
    assert_eq!((5, 25), expand_search_expr("myfn(foo::new().baz().com)", 23))
}

#[test]
fn expand_search_expr_handles_pos_at_end_of_search_str() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 7))
}

pub fn mask_comments(src: Src) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = &[b' '; 128];
    let buffer = from_utf8(buf_byte).unwrap();
    let mut prev: usize = 0;
    for (start, end) in src.chunk_indices() {
        for _ in 0..((start-prev)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((start-prev)%128)]);
        result.push_str(&src[start..end]);
        prev = end;
    }
    result
}

pub fn mask_sub_scopes(src: &str) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = [b' '; 128];
    let buffer = from_utf8(&buf_byte).unwrap();
    let mut levels = 0i32;
    let mut start = 0usize;
    let mut pos = 0usize;

    for &b in src.as_bytes() {
        pos += 1;
        match b {
            b'{' => {
                if levels == 0 {
                    result.push_str(&src[start..(pos)]);
                    start = pos+1;
                }
                levels += 1;
            },
            b'}' => {
                if levels == 1 {
                    let num_spaces = pos-start;
                    for _ in 0..(num_spaces/128) { result.push_str(buffer); }
                    result.push_str(&buffer[..((num_spaces)%128)]);
                    result.push_str("}");
                    start = pos;
                }
                levels -= 1;
            },
            b'\n' if levels > 0 => {
                for _ in 0..((pos-start)/128) { result.push_str(buffer); }
                result.push_str(&buffer[..((pos-start)%128)]);
                result.push('\n');
                start = pos+1;
            },
            _ => {}
        }
    }
    if start > pos {
        start = pos;
    }
    if levels > 0 {
        for _ in 0..((pos - start)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((pos-start)%128)]);
    } else {
        result.push_str(&src[start..pos]);
    }
    result
}

pub fn end_of_next_scope(src: &str) -> &str {
    match find_close(src.as_bytes().iter(), b'{', b'}', 1) {
        Some(count) => &src[..count+1],
        None => ""
    }
}

pub fn coords_to_point(src: &str, mut linenum: usize, col: usize) -> usize {
    let mut point = 0;
    for line in src.lines() {
        linenum -= 1;
        if linenum == 0 { break }
        point += line.len() + 1;  // +1 for the \n
    }
    point + col
}

pub fn point_to_coords(src: &str, point: usize) -> (usize, usize) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    for &b in src[..point].as_bytes() {
        i += 1;
        if b == b'\n' {
            nlines += 1;
            linestart = i;
        }
    }
    (nlines, point - linestart)
}

pub fn point_to_coords_from_file(path: &Path, point: usize, session: SessionRef) -> Option<(usize, usize)> {
    let mut lineno = 0;
    let mut p = 0;
    for line in session.load_file(path).lines() {
        lineno += 1;
        if point < (p + line.len()) {
            return Some((lineno, point - p));
        }
        p += line.len() + 1;  // +1 for the newline char
    }
    None
}

#[test]
fn coords_to_point_works() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}";
    assert!(coords_to_point(src, 3, 5) == 18);
}

#[test]
fn test_scope_start() {
    let src = String::from("
fn myfn() {
    let a = 3;
    print(a);
}
");
    let src = core::new_source(src);
    let point = coords_to_point(&src, 4, 10);
    let start = scope_start(src.as_ref(), point);
    assert!(start == 12);
}

#[test]
fn test_scope_start_handles_sub_scopes() {
    let src = String::from("
fn myfn() {
    let a = 3;
    {
      let b = 4;
    }
    print(a);
}
");
    let src = core::new_source(src);
    let point = coords_to_point(&src, 7, 10);
    let start = scope_start(src.as_ref(), point);
    assert!(start == 12);
}

#[test]
fn masks_out_comments() {
    let src = String::from("
this is some code
this is a line // with a comment
some more
");
    let src = core::new_source(src);
    let r = mask_comments(src.as_ref());

    assert!(src.len() == r.len());
    // characters at the start are the same
    assert!(src.as_bytes()[5] == r.as_bytes()[5]);
    // characters in the comments are masked
    let commentoffset = coords_to_point(&src,3,23);
    assert!(char_at(&r, commentoffset) == ' ');
    assert!(src.as_bytes()[commentoffset] != r.as_bytes()[commentoffset]);
    // characters afterwards are the same
    assert!(src.as_bytes()[src.len()-3] == r.as_bytes()[src.len()-3]);
}

#[test]
fn test_point_to_coords() {
    let src = "
fn myfn(b:usize) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    round_trip_point_and_coords(src, 4, 5);
}

pub fn round_trip_point_and_coords(src: &str, lineno: usize, charno: usize) {
    let (a,b) = point_to_coords(src, coords_to_point(src, lineno, charno));
     assert_eq!((a,b), (lineno,charno));
}

#[test]
fn finds_end_of_struct_scope() {
    let src="
struct foo {
   a: usize,
   blah: ~str
}
Some other junk";

    let expected="
struct foo {
   a: usize,
   blah: ~str
}";
    let s = end_of_next_scope(src);
    assert_eq!(expected, s);
}
<commit_msg>Fix Offsets of CRLF files<commit_after>use {ast, typeinf, util};
use core::{Src, SessionRef, CompletionType};
#[cfg(test)] use core;

use std::iter::Iterator;
use std::path::Path;
use std::str::from_utf8;
use util::char_at;

fn find_close<'a, A>(iter: A, open: u8, close: u8, level_end: u32) -> Option<usize> where A: Iterator<Item=&'a u8> {
    let mut count = 0usize;
    let mut levels = 0u32;
    for &b in iter {
        if b == close {
            if levels == level_end { return Some(count); }
            levels -= 1;
        } else if b == open { levels += 1; }
        count += 1;
    }
    None
}

pub fn find_closing_paren(src: &str, pos: usize) -> usize {
    find_close(src.as_bytes()[pos..].iter(), b'(', b')', 0)
    .map_or(src.len(), |count| pos + count)
}

pub fn scope_start(src: Src, point: usize) -> usize {
    let masked_src = mask_comments(src.to(point));
    find_close(masked_src.as_bytes().iter().rev(), b'}', b'{', 0)
    .map_or(0, |count| point - count)
}

pub fn find_stmt_start(msrc: Src, point: usize) -> Option<usize> {
    // iterate the scope to find the start of the statement
    let scopestart = scope_start(msrc, point);
    msrc.from(scopestart).iter_stmts()
        .find(|&(_, end)| scopestart + end > point)
        .map(|(start, _)| scopestart + start)
}

pub fn get_local_module_path(msrc: Src, point: usize) -> Vec<String> {
    let mut v = Vec::new();
    get_local_module_path_(msrc, point, &mut v);
    v
}

fn get_local_module_path_(msrc: Src, point: usize, out: &mut Vec<String>) {
    for (start, end) in msrc.iter_stmts() {
        if start < point && end > point {
            let blob = msrc.from_to(start, end);
            if blob.starts_with("pub mod ") || blob.starts_with("mod ") {
                let p = typeinf::generate_skeleton_for_parsing(&blob);
                ast::parse_mod(p).name.map(|name| {
                    out.push(name);
                    let newstart = blob.find("{").unwrap() + 1;
                    get_local_module_path_(blob.from(newstart),
                                           point - start - newstart, out);
                });
            }
        }
    }
}

pub fn find_impl_start(msrc: Src, point: usize, scopestart: usize) -> Option<usize> {
    let len = point-scopestart;
    match msrc.from(scopestart).iter_stmts().find(|&(_, end)| end > len) {
        Some((start, _)) => {
            let blob = msrc.from(scopestart + start);
            // TODO:: the following is a bit weak at matching traits. make this better
            if blob.starts_with("impl") || blob.starts_with("trait") || blob.starts_with("pub trait") {
                Some(scopestart + start)
            } else {
                let newstart = blob.find("{").unwrap() + 1;
                find_impl_start(msrc, point, scopestart+start+newstart)
            }
        },
        None => None
    }
}
#[test]
fn finds_subnested_module() {
    use core;
    let src = "
    pub mod foo {
        pub mod bar {
            here
        }
    }";
    let point = coords_to_point(&src, 4, 12);
    let src = core::new_source(String::from(src));
    let v = get_local_module_path(src.as_ref(), point);
    assert_eq!("foo", &v[0][..]);
    assert_eq!("bar", &v[1][..]);

    let point = coords_to_point(&src, 3, 8);
    let v = get_local_module_path(src.as_ref(), point);
    assert_eq!("foo", &v[0][..]);
}

pub fn split_into_context_and_completion(s: &str) -> (&str, &str, CompletionType) {
    match s.char_indices().rev().find(|&(_, c)| !util::is_ident_char(c)) {
        Some((i,c)) => {
            //println!("PHIL s '{}' i {} c '{}'",s,i,c);
            match c {
                '.' => (&s[..i], &s[(i+1)..], CompletionType::CompleteField),
                ':' if s.len() > 1 => (&s[..(i-1)], &s[(i+1)..], CompletionType::CompletePath),
                _   => (&s[..(i+1)], &s[(i+1)..], CompletionType::CompletePath)
            }
        },
        None => ("", s, CompletionType::CompletePath)
    }
}

pub fn get_start_of_search_expr(src: &str, point: usize) -> usize {
    let mut i = point;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        i -= 1;
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_search_expr_char(char_at(src, i)) ||
                    util::is_double_dot(src,i) {
                    return i+1;
                }
            }
        }
    }
    0
}

pub fn get_start_of_pattern(src: &str, point: usize) -> usize {
    let mut i = point-1;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_pattern_char(char_at(src, i)) {
                    return i+1;
                }
            }
        }
        i -= 1;
    }
    0
}

#[test]
fn get_start_of_pattern_handles_variant() {
    assert_eq!(4, get_start_of_pattern("foo, Some(a) =>",13));
}

#[test]
fn get_start_of_pattern_handles_variant2() {
    assert_eq!(4, get_start_of_pattern("bla, ast::PatTup(ref tuple_elements) => {",36));
}

pub fn expand_search_expr(msrc: &str, point: usize) -> (usize, usize) {
    let start = get_start_of_search_expr(msrc, point);
    (start, util::find_ident_end(msrc, point))
}

#[test]
fn expand_search_expr_finds_ident() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 5))
}

#[test]
fn expand_search_expr_handles_chained_calls() {
    assert_eq!((0, 20), expand_search_expr("yeah::blah.foo().bar", 18))
}

#[test]
fn expand_search_expr_handles_inline_closures() {
    assert_eq!((0, 24), expand_search_expr("yeah::blah.foo(||{}).bar", 22))
}
#[test]
fn expand_search_expr_handles_a_function_arg() {
    assert_eq!((5, 25), expand_search_expr("myfn(foo::new().baz().com)", 23))
}

#[test]
fn expand_search_expr_handles_pos_at_end_of_search_str() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 7))
}

pub fn mask_comments(src: Src) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = &[b' '; 128];
    let buffer = from_utf8(buf_byte).unwrap();
    let mut prev: usize = 0;
    for (start, end) in src.chunk_indices() {
        for _ in 0..((start-prev)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((start-prev)%128)]);
        result.push_str(&src[start..end]);
        prev = end;
    }
    result
}

pub fn mask_sub_scopes(src: &str) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = [b' '; 128];
    let buffer = from_utf8(&buf_byte).unwrap();
    let mut levels = 0i32;
    let mut start = 0usize;
    let mut pos = 0usize;

    for &b in src.as_bytes() {
        pos += 1;
        match b {
            b'{' => {
                if levels == 0 {
                    result.push_str(&src[start..(pos)]);
                    start = pos+1;
                }
                levels += 1;
            },
            b'}' => {
                if levels == 1 {
                    let num_spaces = pos-start;
                    for _ in 0..(num_spaces/128) { result.push_str(buffer); }
                    result.push_str(&buffer[..((num_spaces)%128)]);
                    result.push_str("}");
                    start = pos;
                }
                levels -= 1;
            },
            b'\n' if levels > 0 => {
                for _ in 0..((pos-start)/128) { result.push_str(buffer); }
                result.push_str(&buffer[..((pos-start)%128)]);
                result.push('\n');
                start = pos+1;
            },
            _ => {}
        }
    }
    if start > pos {
        start = pos;
    }
    if levels > 0 {
        for _ in 0..((pos - start)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((pos-start)%128)]);
    } else {
        result.push_str(&src[start..pos]);
    }
    result
}

pub fn end_of_next_scope(src: &str) -> &str {
    match find_close(src.as_bytes().iter(), b'{', b'}', 1) {
        Some(count) => &src[..count+1],
        None => ""
    }
}

pub fn coords_to_point(src: &str, mut linenum: usize, col: usize) -> usize {
    let mut point = 0;
    for line in src.split('\n') {
        linenum -= 1;
        if linenum == 0 { break }
        point += line.len() + 1;  // +1 for the \n
    }
    point + col
}

pub fn point_to_coords(src: &str, point: usize) -> (usize, usize) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    for &b in src[..point].as_bytes() {
        i += 1;
        if b == b'\n' {
            nlines += 1;
            linestart = i;
        }
    }
    (nlines, point - linestart)
}

pub fn point_to_coords_from_file(path: &Path, point: usize, session: SessionRef) -> Option<(usize, usize)> {
    let mut lineno = 0;
    let mut p = 0;
    for line in session.load_file(path).split('\n') {
        lineno += 1;
        if point < (p + line.len()) {
            return Some((lineno, point - p));
        }
        p += line.len() + 1;  // +1 for the newline char
    }
    None
}

#[test]
fn coords_to_point_works() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}";
    assert!(coords_to_point(src, 3, 5) == 18);
}

#[test]
fn test_scope_start() {
    let src = String::from("
fn myfn() {
    let a = 3;
    print(a);
}
");
    let src = core::new_source(src);
    let point = coords_to_point(&src, 4, 10);
    let start = scope_start(src.as_ref(), point);
    assert!(start == 12);
}

#[test]
fn test_scope_start_handles_sub_scopes() {
    let src = String::from("
fn myfn() {
    let a = 3;
    {
      let b = 4;
    }
    print(a);
}
");
    let src = core::new_source(src);
    let point = coords_to_point(&src, 7, 10);
    let start = scope_start(src.as_ref(), point);
    assert!(start == 12);
}

#[test]
fn masks_out_comments() {
    let src = String::from("
this is some code
this is a line // with a comment
some more
");
    let src = core::new_source(src);
    let r = mask_comments(src.as_ref());

    assert!(src.len() == r.len());
    // characters at the start are the same
    assert!(src.as_bytes()[5] == r.as_bytes()[5]);
    // characters in the comments are masked
    let commentoffset = coords_to_point(&src,3,23);
    assert!(char_at(&r, commentoffset) == ' ');
    assert!(src.as_bytes()[commentoffset] != r.as_bytes()[commentoffset]);
    // characters afterwards are the same
    assert!(src.as_bytes()[src.len()-3] == r.as_bytes()[src.len()-3]);
}

#[test]
fn test_point_to_coords() {
    let src = "
fn myfn(b:usize) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    round_trip_point_and_coords(src, 4, 5);
}

pub fn round_trip_point_and_coords(src: &str, lineno: usize, charno: usize) {
    let (a,b) = point_to_coords(src, coords_to_point(src, lineno, charno));
     assert_eq!((a,b), (lineno,charno));
}

#[test]
fn finds_end_of_struct_scope() {
    let src="
struct foo {
   a: usize,
   blah: ~str
}
Some other junk";

    let expected="
struct foo {
   a: usize,
   blah: ~str
}";
    let s = end_of_next_scope(src);
    assert_eq!(expected, s);
}
<|endoftext|>


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

use rustc_back::slice;
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;

use traversal;

/**
 * Breaks critical edges in the MIR.
 *
 * Critical edges are edges that are neither the only edge leaving a
 * block, nor the only edge entering one.
 *
 * When you want something to happen "along" an edge, you can either
 * do at the end of the predecessor block, or at the start of the
 * successor block. Critical edges have to be broken in order to prevent
 * "edge actions" from affecting other edges.
 *
 * This function will break those edges by inserting new blocks along them.
 *
 * A special case is Drop and Call terminators with unwind/cleanup successors,
 * They use `invoke` in LLVM, which terminates a block, meaning that code cannot
 * be inserted after them, so even if an edge is the only edge leaving a block
 * like that, we still insert blocks if the edge is one of many entering the
 * target.
 *
 * NOTE: Simplify CFG will happily undo most of the work this pass does.
 *
 */
pub fn break_critical_edges<'tcx>(mir_map: &mut MirMap<'tcx>) {
    for (_, mir) in &mut mir_map.map {
        break_critical_edges_fn(mir);
    }
}

/*
 * Predecessor map for tracking the predecessors of a block
 */
struct PredMap {
    preds: Vec<BlockPredecessors>
}

/**
 * Most blocks only have one predecessor, so we can cut down on
 * some allocation by not using Vec until we have more than one.
 */
#[derive(Clone)]
enum BlockPredecessors {
    None,
    One(BasicBlock),
    Some(Vec<BasicBlock>)
}

impl PredMap {
    pub fn new(n: usize) -> PredMap {
        let preds = vec![BlockPredecessors::None; n];

        PredMap {
            preds: preds
        }
    }

    fn ensure_len(&mut self, bb: BasicBlock) {
        let idx = bb.index();
        while self.preds.len() <= idx {
            self.preds.push(BlockPredecessors::None);
        }
    }

    pub fn add_pred(&mut self, target: BasicBlock, pred: BasicBlock) {
        self.ensure_len(target);

        let preds = mem::replace(&mut self.preds[target.index()], BlockPredecessors::None);
        match preds {
            BlockPredecessors::None => {
                self.preds[target.index()] = BlockPredecessors::One(pred);
            }
            BlockPredecessors::One(bb) => {
                self.preds[target.index()] = BlockPredecessors::Some(vec![bb, pred]);
            }
            BlockPredecessors::Some(mut preds) => {
                preds.push(pred);
                self.preds[target.index()] = BlockPredecessors::Some(preds);
            }
        }
    }

    pub fn remove_pred(&mut self, target: BasicBlock, pred: BasicBlock) {
        self.ensure_len(target);

        let preds = mem::replace(&mut self.preds[target.index()], BlockPredecessors::None);
        match preds {
            BlockPredecessors::None => {}
            BlockPredecessors::One(bb) if bb == pred => {}

            BlockPredecessors::One(bb) => {
                self.preds[target.index()] = BlockPredecessors::One(bb);
            }

            BlockPredecessors::Some(mut preds) => {
                preds.retain(|&bb| bb != pred);
                self.preds[target.index()] = BlockPredecessors::Some(preds);
            }
        }
    }

    pub fn get_preds(&self, bb: BasicBlock) -> &[BasicBlock] {
        match self.preds[bb.index()] {
            BlockPredecessors::None => &[],
            BlockPredecessors::One(ref bb) => slice::ref_slice(bb),
            BlockPredecessors::Some(ref bbs) => &bbs[..]
        }
    }
}

fn break_critical_edges_fn(mir: &mut Mir) {
    let mut pred_map = PredMap::new(mir.basic_blocks.len());

    // Build the precedecessor map for the MIR
    for (pred, data) in traversal::preorder(mir) {
        if let Some(ref term) = data.terminator {
            for &tgt in term.successors().iter() {
                pred_map.add_pred(tgt, pred);
            }
        }
    }

    // We need a place to store the new blocks generated
    let mut new_blocks = Vec::new();

    let bbs = mir.all_basic_blocks();
    let cur_len = mir.basic_blocks.len();

    for &bb in &bbs {
        let data = mir.basic_block_data_mut(bb);

        if let Some(ref mut term) = data.terminator {
            let is_invoke = term_is_invoke(term);
            let succs = term.successors_mut();
            if succs.len() > 1 || (succs.len() > 0 && is_invoke) {
                for tgt in succs {
                    let num_preds = pred_map.get_preds(*tgt).len();
                    if num_preds > 1 {
                        // It's a critical edge, break it
                        let goto = Terminator::Goto { target: *tgt };
                        let data = BasicBlockData::new(Some(goto));
                        // Get the index it will be when inserted into the MIR
                        let idx = cur_len + new_blocks.len();
                        new_blocks.push(data);
                        *tgt = BasicBlock::new(idx);
                    }
                }
            }
        }
    }

    debug!("Broke {} N edges", new_blocks.len());

    mir.basic_blocks.extend_from_slice(&new_blocks);
}

// Returns true if the terminator would use an invoke in LLVM.
fn term_is_invoke(term: &Terminator) -> bool {
    match *term {
        Terminator::Call { cleanup: Some(_), .. } |
        Terminator::Drop { unwind: Some(_), .. } => true,
        _ => false
    }
}
<commit_msg>Don't build a map of predecessors, just count them instead<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;

use traversal;

/**
 * Breaks critical edges in the MIR.
 *
 * Critical edges are edges that are neither the only edge leaving a
 * block, nor the only edge entering one.
 *
 * When you want something to happen "along" an edge, you can either
 * do at the end of the predecessor block, or at the start of the
 * successor block. Critical edges have to be broken in order to prevent
 * "edge actions" from affecting other edges.
 *
 * This function will break those edges by inserting new blocks along them.
 *
 * A special case is Drop and Call terminators with unwind/cleanup successors,
 * They use `invoke` in LLVM, which terminates a block, meaning that code cannot
 * be inserted after them, so even if an edge is the only edge leaving a block
 * like that, we still insert blocks if the edge is one of many entering the
 * target.
 *
 * NOTE: Simplify CFG will happily undo most of the work this pass does.
 *
 */
pub fn break_critical_edges<'tcx>(mir_map: &mut MirMap<'tcx>) {
    for (_, mir) in &mut mir_map.map {
        break_critical_edges_fn(mir);
    }
}

fn break_critical_edges_fn(mir: &mut Mir) {
    let mut pred_count = vec![0u32; mir.basic_blocks.len()];

    // Build the precedecessor map for the MIR
    for (_, data) in traversal::preorder(mir) {
        if let Some(ref term) = data.terminator {
            for &tgt in term.successors().iter() {
                pred_count[tgt.index()] += 1;
            }
        }
    }

    // We need a place to store the new blocks generated
    let mut new_blocks = Vec::new();

    let bbs = mir.all_basic_blocks();
    let cur_len = mir.basic_blocks.len();

    for &bb in &bbs {
        let data = mir.basic_block_data_mut(bb);

        if let Some(ref mut term) = data.terminator {
            let is_invoke = term_is_invoke(term);
            let succs = term.successors_mut();
            if succs.len() > 1 || (succs.len() > 0 && is_invoke) {
                for tgt in succs {
                    let num_preds = pred_count[tgt.index()];
                    if num_preds > 1 {
                        // It's a critical edge, break it
                        let goto = Terminator::Goto { target: *tgt };
                        let data = BasicBlockData::new(Some(goto));
                        // Get the index it will be when inserted into the MIR
                        let idx = cur_len + new_blocks.len();
                        new_blocks.push(data);
                        *tgt = BasicBlock::new(idx);
                    }
                }
            }
        }
    }

    debug!("Broke {} N edges", new_blocks.len());

    mir.basic_blocks.extend_from_slice(&new_blocks);
}

// Returns true if the terminator would use an invoke in LLVM.
fn term_is_invoke(term: &Terminator) -> bool {
    match *term {
        Terminator::Call { cleanup: Some(_), .. } |
        Terminator::Drop { unwind: Some(_), .. } => true,
        _ => false
    }
}
<|endoftext|>


<commit_before><commit_msg>add Direct Connect integration tests<commit_after>#![cfg(feature = "directconnect")]

extern crate rusoto;

use rusoto::directconnect::{DirectConnectClient, DescribeConnectionsRequest, DescribeConnectionsError};
use rusoto::{DefaultCredentialsProvider, Region};

#[test]
fn should_describe_connections() {
    let credentials = DefaultCredentialsProvider::new().unwrap();
    let client = DirectConnectClient::new(credentials, Region::UsEast1);

    let request = DescribeConnectionsRequest::default();

    match client.describe_connections(&request) {
        Ok(response) => {
            println!("{:#?}", response);
            assert!(true)
        },
        Err(err) => panic!("Expected OK response, got {:#?}", err)
    };
}

#[test]
fn should_fail_gracefully() {
    let credentials = DefaultCredentialsProvider::new().unwrap();
    let client = DirectConnectClient::new(credentials, Region::UsEast1);

    let request = DescribeConnectionsRequest {
        connection_id: Some("invalid".to_string())
    };

    match client.describe_connections(&request) {
        Err(DescribeConnectionsError::DirectConnectClient(msg)) => assert!(msg.contains("Connection ID")),
        err @ _ => panic!("Expected DirectConnectClient error, got {:#?}", err)
    };
}

#[test]
fn should_describe_locations() {
    let credentials = DefaultCredentialsProvider::new().unwrap();
    let client = DirectConnectClient::new(credentials, Region::UsEast1);

    match client.describe_locations() {
        Ok(response) => {
            println!("{:#?}", response);
            assert!(true)
        },
        Err(err) => panic!("Expected OK response, got {:#?}", err)
    };
}

#[test]
fn should_describe_virtual_gateways() {
    let credentials = DefaultCredentialsProvider::new().unwrap();
    let client = DirectConnectClient::new(credentials, Region::UsEast1);

    match client.describe_virtual_gateways() {
        Ok(response) => {
            println!("{:#?}", response);
            assert!(true)
        },
        Err(err) => panic!("Expected OK response, got {:#?}", err)
    };
}
<|endoftext|>


<commit_before><commit_msg>ping loop<commit_after><|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.

// aux-build:enums.rs
extern crate enums;

use enums::NonExhaustiveEnum;

fn main() {
    let enum_unit = NonExhaustiveEnum::Unit;

    match enum_unit {
        NonExhaustiveEnum::Unit => 1,
        NonExhaustiveEnum::Tuple(_) => 2,
        // This particular arm tests that a enum marked as non-exhaustive
        // will not error if its variants are matched exhaustively.
        NonExhaustiveEnum::Struct { field } => field,
        _ => 0 // no error with wildcard
    };

    match enum_unit {
        _ => "no error with only wildcard"
    };
}
<commit_msg>Ignoring pretty print for test due to #37199<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.

// aux-build:enums.rs
extern crate enums;

// ignore-pretty issue #37199

use enums::NonExhaustiveEnum;

fn main() {
    let enum_unit = NonExhaustiveEnum::Unit;

    match enum_unit {
        NonExhaustiveEnum::Unit => 1,
        NonExhaustiveEnum::Tuple(_) => 2,
        // This particular arm tests that a enum marked as non-exhaustive
        // will not error if its variants are matched exhaustively.
        NonExhaustiveEnum::Struct { field } => field,
        _ => 0 // no error with wildcard
    };

    match enum_unit {
        _ => "no error with only wildcard"
    };
}
<|endoftext|>


<commit_before><commit_msg>Add a test for the new raw writing API<commit_after>//! Tests for the raw write logging functionality.
extern crate fern;
extern crate log;

use std::io;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

use log::Level::*;

mod support;

use support::manual_log;

#[test]
fn test_raw_write_logging() {
    struct TestWriter {
        buf: Vec<u8>,
        flag: Arc<AtomicBool>,
    }

    impl io::Write for TestWriter {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            self.buf.write(buf)
        }

        fn flush(&mut self) -> io::Result<()> {
            self.buf.flush()?;

            let expected = b"[INFO] Test information message\n";

            if self.buf == expected {
                self.flag.store(true, Ordering::SeqCst);
            } else {
                eprintln!("{:?} does not match {:?}", self.buf, expected);
            }

            Ok(())
        }
    }

    let flag = Arc::new(AtomicBool::new(false));

    // Create a basic logger configuration
    let (_max_level, logger) = fern::Dispatch::new()
        .format(|out, msg, record| out.finish(format_args!("[{}] {}", record.level(), msg)))
        .level(log::LevelFilter::Info)
        .chain(io::stdout())
        .chain(Box::new(TestWriter {
            buf: Vec::new(),
            flag: flag.clone(),
        }) as Box<io::Write + Send>)
        .into_log();

    let l = &*logger;
    manual_log(l, Info, "Test information message");

    // ensure all File objects are dropped and OS buffers are flushed.
    log::logger().flush();

    assert!(
        flag.load(Ordering::SeqCst),
        "raw Write test failed: did not match buffer"
    );
}
<|endoftext|>


<commit_before><commit_msg>macros<commit_after>macro_rules! create_function {
    ($func_name:ident) => {
        fn $func_name() {
            println!("You called: {:?}()", stringify!($func_name))
        }
    }
}

create_function!(foo);
create_function!(bar);

macro_rules! print_result {
    ($expression:expr) => {
        println!("{:?} = {:?}", stringify!($expression), $expression);
    };
}

fn main() {

    foo();
    bar();

    print_result!(1i32+1);
    print_result!({
        let _x = 5i32;
        _x * _x + 5 * _x + 30
    });
}<|endoftext|>


<commit_before><commit_msg>Implement enough lexing for the punctuation test case.<commit_after><|endoftext|>


<commit_before>extern crate getopts;
extern crate libudev;

fn usage(progname: &str, opts: getopts::Options) {
    let brief = format!("Usage: {} [options]", progname);
    print!("{}", opts.usage(&brief));
}

fn get_hidraw_node() -> Option<std::path::PathBuf> {
    let udev = libudev::Context::new().unwrap();
    let mut enumerator = libudev::Enumerator::new(&udev).unwrap();

    enumerator.match_subsystem("hidraw").unwrap();

    for device in enumerator.scan_devices().unwrap() {
        if let Some(usb_parent) = device.parent_with_subsystem_devtype("usb", "usb_device") {
            if usb_parent.attribute_value("idVendor").unwrap() == "1532" &&
                usb_parent.attribute_value("idProduct").unwrap() == "0037" {
                return Some(device.devnode().unwrap().to_owned());
            }
        }
    }

    None
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let progname = args[0].clone();

    let mut opts = getopts::Options::new();
    opts.optopt("d", "device", "hidraw node of the mouse", "DEV");
    opts.optopt("r", "dpi", "Sensor resolution (100-6400 DPI in increments of 100)", "RES/X,Y");
    opts.optopt("f", "freq", "Polling rate (125, 500 or 1000 Hz)", "HZ");
    opts.optopt("l", "logo", "Logo LED", "on/off");
    opts.optopt("w", "wheel", "Scroll wheel LED", "on/off");
    opts.optflag("h", "help", "Print help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            println!("{}", f.to_string());
            usage(&progname, opts);
            return;
        }
    };

    // Show help when loose arguments are passed
    if matches.opt_present("h") || !matches.free.is_empty() {
        usage(&progname, opts);
        return;
    }

    // TODO I'm sure this can be improved somehow
    let dev = match (matches.opt_str("d"), get_hidraw_node()) {
        (Some(d), _) => std::path::PathBuf::from(d),
        (None, Some(d)) => d,
        (None, None) => {
            println!("Can't detect the device with udev, make sure it's plugged in, \
                     or specify -d");
            usage(&progname, opts);
            return;
        }
    };

    let freq = matches.opt_str("f").map(|s| {
        match s.as_str() {
            "125" => 125,
            "500" => 500,
            "1000" => 1000,
            _ => {
                println!("Polling rate must be one of 125, 500 or 1000 Hz");
                std::process::exit(1);
            }
        }
    });

    println!("Using device {}", dev.to_str().unwrap());
}
<commit_msg>Complete arg parsing<commit_after>extern crate getopts;
extern crate libudev;

fn usage(progname: &str, opts: getopts::Options) {
    let brief = format!("Usage: {} [options]", progname);
    print!("{}", opts.usage(&brief));
}

fn get_hidraw_node() -> Option<std::path::PathBuf> {
    let udev = libudev::Context::new().unwrap();
    let mut enumerator = libudev::Enumerator::new(&udev).unwrap();

    enumerator.match_subsystem("hidraw").unwrap();

    for device in enumerator.scan_devices().unwrap() {
        if let Some(usb_parent) = device.parent_with_subsystem_devtype("usb", "usb_device") {
            if usb_parent.attribute_value("idVendor").unwrap() == "1532" &&
                usb_parent.attribute_value("idProduct").unwrap() == "0037" {
                return Some(device.devnode().unwrap().to_owned());
            }
        }
    }

    None
}

fn boolarg(a: String, argname: &str) -> bool {
    match a.to_lowercase().as_str() {
        "on" | "true" | "1" | "enabled" => true,
        "off" | "false" | "0" | "disabled" => false,
        _ => {
            println!("Invalid boolean for {}", argname);
            std::process::exit(1);
        }
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let progname = args[0].clone();

    let mut opts = getopts::Options::new();
    opts.optopt("d", "device", "hidraw node of the mouse", "DEV");
    opts.optopt("r", "dpi", "Sensor resolution (100-6400 DPI in increments of 100)", "RES/X,Y");
    opts.optopt("f", "freq", "Polling rate (125, 500 or 1000 Hz)", "HZ");
    opts.optopt("l", "logo", "Logo LED", "on/off");
    opts.optopt("w", "wheel", "Scroll wheel LED", "on/off");
    opts.optflag("h", "help", "Print help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            println!("{}", f.to_string());
            usage(&progname, opts);
            return;
        }
    };

    // Show help when loose arguments are passed
    if matches.opt_present("h") || !matches.free.is_empty() {
        usage(&progname, opts);
        return;
    }

    // TODO I'm sure this can be improved somehow
    let dev = match (matches.opt_str("d"), get_hidraw_node()) {
        (Some(d), _) => std::path::PathBuf::from(d),
        (None, Some(d)) => d,
        (None, None) => {
            println!("Can't detect the device with udev, make sure it's plugged in, \
                     or specify -d");
            usage(&progname, opts);
            return;
        }
    };

    let dpi = matches.opt_str("r").map(|s| {
        let r = s.split(',').map(|s| match s.parse::<i32>() {
            Ok(r) => {
                if r < 100 || r > 6400 || (r % 100 != 0) {
                    println!("Invalid resolution value");
                    std::process::exit(1);
                }
                r
            }
            Err(_) => {
                println!("Resolution is not a valid integer");
                std::process::exit(1);
            }
        }).collect::<Vec<_>>();
        if r.len() > 2 {
            println!("Too many values for resolution");
            std::process::exit(1);
        }
        r
    });

    let freq = matches.opt_str("f").map(|s| {
        match s.as_str() {
            "125" => 125,
            "500" => 500,
            "1000" => 1000,
            _ => {
                println!("Polling rate must be one of 125, 500 or 1000 Hz");
                std::process::exit(1);
            }
        }
    });

    let led_logo = matches.opt_str("l").map(|s| boolarg(s, "logo LED"));
    let led_wheel = matches.opt_str("w").map(|s| boolarg(s, "wheel LED"));

    println!("Using device {}", dev.to_str().unwrap());
}
<|endoftext|>


<commit_before><commit_msg>Rewrite edit_in_tmpfile() for new Runtime::editor() signature<commit_after><|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use rustc::lint::Context;
use rustc::middle::{ty, def};

use syntax::ptr::P;
use syntax::{ast, ast_map};
use syntax::ast::{TyPath, Path, AngleBracketedParameters, PathSegment, Ty};
use syntax::attr::mark_used;

/// Matches a type with a provided string, and returns its type parameters if successful
///
/// Try not to use this for types defined in crates you own, use match_lang_ty instead (for lint passes)
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(Path {segments: ref seg, ..}, _) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.as_str() == *b) {
                match seg.as_slice().last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(a.types.as_slice())
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

/// Checks if a type has a #[servo_lang = "str"] attribute
pub fn match_lang_ty(cx: &Context, ty: &Ty, value: &str) -> bool {
    let mut found = false;
    if let TyPath(_, ty_id) = ty.node {
        if let Some(def::DefTy(def_id, _)) = cx.tcx.def_map.borrow().get(&ty_id).cloned() {
            // Iterating through attributes is hard because of cross-crate defs
            for attr in ty::get_attrs(cx.tcx, def_id).iter() {
                if let ast::MetaNameValue(ref name, ref val) = attr.node.value.node {
                    if &**name == "servo_lang" {
                        if let ast::LitStr(ref v, _) = val.node {
                            if &**v == value {
                                mark_used(attr);
                                found = true;
                                break
                            }
                        }
                    }
                }
            }
        };
    }
    found
}

// Determines if a block is in an unsafe context so that an unhelpful
// lint can be aborted.
pub fn unsafe_context(map: &ast_map::Map, id: ast::NodeId) -> bool {
    match map.find(map.get_parent(id)) {
        Some(ast_map::NodeImplItem(itm)) => {
            match *itm {
                ast::MethodImplItem(ref meth) => match meth.node {
                    ast::MethDecl(_, _, _, _, style, _, _, _) => match style {
                        ast::Unsafety::Unsafe => true,
                        _ => false,
                    },
                    _ => false,
                },
                _ => false,
            }
        },
        Some(ast_map::NodeItem(itm)) => {
            match itm.node {
                ast::ItemFn(_, style, _, _, _) => match style {
                    ast::Unsafety::Unsafe => true,
                    _ => false,
                },
                _ => false,
            }
        }
        _ => false // There are probably a couple of other unsafe cases we don't care to lint, those will need to be added.
    }
}
<commit_msg>auto merge of #4914 : Ms2ger/servo/match_lang_ty, r=saneyuki<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use rustc::lint::Context;
use rustc::middle::{ty, def};

use syntax::ptr::P;
use syntax::{ast, ast_map};
use syntax::ast::{TyPath, Path, AngleBracketedParameters, PathSegment, Ty};
use syntax::attr::mark_used;

/// Matches a type with a provided string, and returns its type parameters if successful
///
/// Try not to use this for types defined in crates you own, use match_lang_ty instead (for lint passes)
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(Path {segments: ref seg, ..}, _) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.as_str() == *b) {
                match seg.as_slice().last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(a.types.as_slice())
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

/// Checks if a type has a #[servo_lang = "str"] attribute
pub fn match_lang_ty(cx: &Context, ty: &Ty, value: &str) -> bool {
    let ty_id = match ty.node {
        TyPath(_, ty_id) => ty_id,
        _ => return false,
    };

    let def_id = match cx.tcx.def_map.borrow().get(&ty_id).cloned() {
        Some(def::DefTy(def_id, _)) => def_id,
        _ => return false,
    };

    ty::get_attrs(cx.tcx, def_id).iter().any(|attr| {
        match attr.node.value.node {
            ast::MetaNameValue(ref name, ref val) if &**name == "servo_lang" => {
                match val.node {
                    ast::LitStr(ref v, _) if &**v == value => {
                        mark_used(attr);
                        true
                    },
                    _ => false,
                }
            }
            _ => false,
        }
    })
}

// Determines if a block is in an unsafe context so that an unhelpful
// lint can be aborted.
pub fn unsafe_context(map: &ast_map::Map, id: ast::NodeId) -> bool {
    match map.find(map.get_parent(id)) {
        Some(ast_map::NodeImplItem(itm)) => {
            match *itm {
                ast::MethodImplItem(ref meth) => match meth.node {
                    ast::MethDecl(_, _, _, _, style, _, _, _) => match style {
                        ast::Unsafety::Unsafe => true,
                        _ => false,
                    },
                    _ => false,
                },
                _ => false,
            }
        },
        Some(ast_map::NodeItem(itm)) => {
            match itm.node {
                ast::ItemFn(_, style, _, _, _) => match style {
                    ast::Unsafety::Unsafe => true,
                    _ => false,
                },
                _ => false,
            }
        }
        _ => false // There are probably a couple of other unsafe cases we don't care to lint, those will need to be added.
    }
}
<|endoftext|>


<commit_before><commit_msg>Add tuple indexing exercise from @ruipserra!! 👏<commit_after><|endoftext|>


<commit_before>#![crate_name="redox"]
#![crate_type="rlib"]
#![feature(alloc)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![feature(lang_items)]
#![feature(vec_push_all)]
#![feature(no_std)]
#![no_std]

// Yep I'm evil (this is a good idea!)
#![warn(missing_docs)]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

pub use alloc::boxed::Box;

pub use collections::*;
pub use collections::string::ToString;

pub use common::random::*;
pub use common::time::*;

pub use externs::*;

pub use syscall::call::*;

pub use audio::wav::*;
pub use console::*;
pub use env::*;
pub use event::*;
pub use fs::file::*;
pub use graphics::bmp::*;
pub use orbital::*;

/// A module for common functionalities.
/// Primary functionality provided by std.
#[path="../../src/common/src/"]
mod common {
    pub mod debug;
    pub mod random;
    pub mod time;
}

#[path="../../src/externs.rs"]
pub mod externs;

/// A module for system calls
#[path="../../src/syscall/src"]
mod syscall {
    /// Calls
    pub mod call;
    /// Common
    pub mod common;
}

/// A module for audio
mod audio {
    pub mod wav;
}

/// A module for console functionality
#[macro_use]
pub mod console;
/// A module for commands and enviroment
pub mod env;
/// A module for events
pub mod event;
/// A module for the filesystem
#[path="fs/lib.rs"]
mod fs;
/// Graphics support
mod graphics {
    pub mod bmp;
}
/// A module for window support
pub mod orbital;

/// A module for shell based functions
pub mod ion;

/* Extensions for String { */
/// Parse the string to a integer using a given radix
pub trait ToNum {
    fn to_num_radix(&self, radix: usize) -> usize;
    fn to_num_radix_signed(&self, radix: usize) -> isize;
    fn to_num(&self) -> usize;
    fn to_num_signed(&self) -> isize;
}

impl ToNum for String {
    fn to_num_radix(&self, radix: usize) -> usize {
        if radix == 0 {
            return 0;
        }

        let mut num = 0;
        for c in self.chars() {
            let digit;
            if c >= '0' && c <= '9' {
                digit = c as usize - '0' as usize
            } else if c >= 'A' && c <= 'Z' {
                digit = c as usize - 'A' as usize + 10
            } else if c >= 'a' && c <= 'z' {
                digit = c as usize - 'a' as usize + 10
            } else {
                break;
            }

            if digit >= radix {
                break;
            }

            num *= radix;
            num += digit;
        }

        num
    }

    /// Parse the string as a signed integer using a given radix
    fn to_num_radix_signed(&self, radix: usize) -> isize {
        if self.starts_with('-') {
            -(self[1 .. self.len()].to_string().to_num_radix(radix) as isize)
        } else {
            self.to_num_radix(radix) as isize
        }
    }

    /// Parse it as a unsigned integer in base 10
    fn to_num(&self) -> usize {
        self.to_num_radix(10)
    }

    /// Parse it as a signed integer in base 10
    fn to_num_signed(&self) -> isize {
        self.to_num_radix_signed(10)
    }
}
/* } Extensions for String */
<commit_msg>Small updates to Documentation<commit_after>//! # The Redox Library
//!
//! The Redox Library contains a collection of commonly used low-level software
//! constructs to be used on top of the base operating system, including graphics
//! support and windowing, a basic filesystem, audio support, a simple console
//! with shell style functions, an event system, and environment argument support.

#![crate_name="redox"]
#![crate_type="rlib"]
#![feature(alloc)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![feature(lang_items)]
#![feature(vec_push_all)]
#![feature(no_std)]
#![no_std]

// Yep I'm evil (this is a good idea!)
#![warn(missing_docs)]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

pub use alloc::boxed::Box;

pub use collections::*;
pub use collections::string::ToString;

pub use common::random::*;
pub use common::time::*;

pub use externs::*;

pub use syscall::call::*;

pub use audio::wav::*;
pub use console::*;
pub use env::*;
pub use event::*;
pub use fs::file::*;
pub use graphics::bmp::*;
pub use orbital::*;

/// A module for common functionalities.
/// Primary functionality provided by std.
#[path="../../src/common/src/"]
mod common {
    pub mod debug;
    pub mod random;
    pub mod time;
}

/// A module for necessary C and assembly constructs
#[path="../../src/externs.rs"]
pub mod externs;

/// A module for system calls
#[path="../../src/syscall/src"]
mod syscall {
    /// Calls
    pub mod call;
    /// Common
    pub mod common;
}

/// A module for audio
mod audio {
    pub mod wav;
}

/// A module for console functionality
#[macro_use]
pub mod console;
/// A module for commands and enviroment
pub mod env;
/// A module for events
pub mod event;
/// A module for the filesystem
#[path="fs/lib.rs"]
mod fs;
/// Graphics support
mod graphics {
    pub mod bmp;
}
/// A module for window support
pub mod orbital;

/// A module for shell based functions
pub mod ion;

/* Extensions for String { */
/// Parse the string to a integer using a given radix
pub trait ToNum {
    fn to_num_radix(&self, radix: usize) -> usize;
    fn to_num_radix_signed(&self, radix: usize) -> isize;
    fn to_num(&self) -> usize;
    fn to_num_signed(&self) -> isize;
}

impl ToNum for String {
    fn to_num_radix(&self, radix: usize) -> usize {
        if radix == 0 {
            return 0;
        }

        let mut num = 0;
        for c in self.chars() {
            let digit;
            if c >= '0' && c <= '9' {
                digit = c as usize - '0' as usize
            } else if c >= 'A' && c <= 'Z' {
                digit = c as usize - 'A' as usize + 10
            } else if c >= 'a' && c <= 'z' {
                digit = c as usize - 'a' as usize + 10
            } else {
                break;
            }

            if digit >= radix {
                break;
            }

            num *= radix;
            num += digit;
        }

        num
    }

    /// Parse the string as a signed integer using a given radix
    fn to_num_radix_signed(&self, radix: usize) -> isize {
        if self.starts_with('-') {
            -(self[1 .. self.len()].to_string().to_num_radix(radix) as isize)
        } else {
            self.to_num_radix(radix) as isize
        }
    }

    /// Parse it as a unsigned integer in base 10
    fn to_num(&self) -> usize {
        self.to_num_radix(10)
    }

    /// Parse it as a signed integer in base 10
    fn to_num_signed(&self) -> isize {
        self.to_num_radix_signed(10)
    }
}
/* } Extensions for String */
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Texture creation and modification.
//!
//! "Texture" is an overloaded term. In gfx-rs, a texture consists of two
//! separate pieces of information: image storage description (which is
//! immutable for a single texture object), and image data. To actually use a
//! texture, a "sampler" is needed, which provides a way of accessing the
//! texture data.

use std::default::Default;

/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
/// texture when sampling. They correspond to increasing levels of quality,
/// but also cost. They "layer" on top of each other: it is not possible to
/// have bilinear filtering without mipmapping, for example.
///
/// These names are somewhat poor, in that "bilinear" is really just doing
/// linear filtering on each axis, and it is only bilinear in the case of 2D
/// textures. Similarly for trilinear, it is really Quadralinear(?) for 3D
/// textures. Alas, these names are simple, and match certain intuitions
/// ingrained by many years of public use of inaccurate terminology.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum FilterMethod {
    /// The dumbest filtering possible, nearest-neighbor interpolation.
    Scale,
    /// Add simple mipmapping.
    Mipmap,
    /// Sample multiple texels within a single mipmap level to increase
    /// quality.
    Bilinear,
    /// Sample multiple texels across two mipmap levels to increase quality.
    Trilinear,
    /// Anisotropic filtering with a given "max", must be between 1 and 16,
    /// inclusive.
    Anisotropic(u8)
}

/// Specifies how a given texture may be used. The available texture types are restricted by what
/// Metal exposes, though this could conceivably be extended in the future. Note that a single
/// texture can *only* ever be of one kind. A texture created as `Texture2D` will forever be
/// `Texture2D`.
// TODO: "Texture views" let you get around that limitation.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureKind {
    Texture1D,
    Texture1DArray,
    Texture2D,
    Texture2DArray,
    TextureCube,
    Texture3D
    // TODO: Multisampling?
}

/// Describes the layout of each texel within a texture.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureFormat {
    RGB8,
    RGBA8,
}

/// Describes the storage of a texture.
///
/// Portability note: textures larger than 1024px in any dimension are
/// unlikely to be supported by mobile platforms.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct TextureInfo {
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    /// Mipmap levels outside the range of `[lo, hi]` will never be used for
    /// this texture. Defaults to `(0, -1)`, that is, every mipmap level
    /// available. 0 is the base mipmap level, with the full-sized texture,
    /// and every level after that shrinks each dimension by a factor of 2.
    pub mipmap_range: (u8, u8),
    pub kind: TextureKind,
    pub format: TextureFormat,
}

/// Describes a subvolume of a texture, which image data can be uploaded into.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct ImageInfo {
    pub xoffset: u16,
    pub yoffset: u16,
    pub zoffset: u16,
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    pub format: TextureFormat,
    /// Which mipmap to select.
    pub mipmap: u8,
}

impl Default for ImageInfo {
    fn default() -> ImageInfo {
        ImageInfo {
            xoffset: 0,
            yoffset: 0,
            zoffset: 0,
            width: 0,
            height: 1,
            depth: 1,
            format: RGBA8,
            mipmap: 0
        }
    }
}

impl Default for TextureInfo {
    fn default() -> TextureInfo {
        TextureInfo {
            width: 0,
            height: 1,
            depth: 1,
            mipmap_range: (0, -1),
            kind: Texture2D,
            format: RGBA8,
        }
    }
}

impl TextureInfo { pub fn new() -> TextureInfo { Default::default() } }
impl ImageInfo { pub fn new() -> ImageInfo { Default::default() } }

/// Specifies how texture coordinates outside the range `[0, 1]` are handled.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum WrapMode {
    /// Tile the texture. That is, sample the coordinate modulo `1.0`. This is
    /// the default.
    Tile,
    /// Mirror the texture. Like tile, but uses abs(coord) before the modulo.
    Mirror,
    /// Clamp the texture to the value at `0.0` or `1.0` respectively.
    Clamp,
}

/// Specifies how to sample from a texture.
#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct SamplerInfo {
    pub filtering: FilterMethod,
    /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
    /// speak)
    pub wrap_mode: (WrapMode, WrapMode, WrapMode),
    /// This bias is added to every computed mipmap level (N + lod_bias). For
    /// example, if it would select mipmap level 2 and lod_bias is 1, it will
    /// use mipmap level 3.
    pub lod_bias: f32,
    /// Mipmap levels outside of `[lo, hi]` will never be sampled. Defaults to
    /// `(0, -1)` (every mipmap available), but will be clamped to the
    /// texture's mipmap_range.
    pub mipmap_range: (u8, u8),
    // TODO: comparison mode
}
<commit_msg>Use markdown header for portability note<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Texture creation and modification.
//!
//! "Texture" is an overloaded term. In gfx-rs, a texture consists of two
//! separate pieces of information: image storage description (which is
//! immutable for a single texture object), and image data. To actually use a
//! texture, a "sampler" is needed, which provides a way of accessing the
//! texture data.

use std::default::Default;

/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
/// texture when sampling. They correspond to increasing levels of quality,
/// but also cost. They "layer" on top of each other: it is not possible to
/// have bilinear filtering without mipmapping, for example.
///
/// These names are somewhat poor, in that "bilinear" is really just doing
/// linear filtering on each axis, and it is only bilinear in the case of 2D
/// textures. Similarly for trilinear, it is really Quadralinear(?) for 3D
/// textures. Alas, these names are simple, and match certain intuitions
/// ingrained by many years of public use of inaccurate terminology.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum FilterMethod {
    /// The dumbest filtering possible, nearest-neighbor interpolation.
    Scale,
    /// Add simple mipmapping.
    Mipmap,
    /// Sample multiple texels within a single mipmap level to increase
    /// quality.
    Bilinear,
    /// Sample multiple texels across two mipmap levels to increase quality.
    Trilinear,
    /// Anisotropic filtering with a given "max", must be between 1 and 16,
    /// inclusive.
    Anisotropic(u8)
}

/// Specifies how a given texture may be used. The available texture types are restricted by what
/// Metal exposes, though this could conceivably be extended in the future. Note that a single
/// texture can *only* ever be of one kind. A texture created as `Texture2D` will forever be
/// `Texture2D`.
// TODO: "Texture views" let you get around that limitation.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureKind {
    Texture1D,
    Texture1DArray,
    Texture2D,
    Texture2DArray,
    TextureCube,
    Texture3D
    // TODO: Multisampling?
}

/// Describes the layout of each texel within a texture.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureFormat {
    RGB8,
    RGBA8,
}

/// Describes the storage of a texture.
///
/// # Portability note
///
/// Textures larger than 1024px in any dimension are unlikely to be supported by mobile platforms.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct TextureInfo {
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    /// Mipmap levels outside the range of `[lo, hi]` will never be used for
    /// this texture. Defaults to `(0, -1)`, that is, every mipmap level
    /// available. 0 is the base mipmap level, with the full-sized texture,
    /// and every level after that shrinks each dimension by a factor of 2.
    pub mipmap_range: (u8, u8),
    pub kind: TextureKind,
    pub format: TextureFormat,
}

/// Describes a subvolume of a texture, which image data can be uploaded into.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct ImageInfo {
    pub xoffset: u16,
    pub yoffset: u16,
    pub zoffset: u16,
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    pub format: TextureFormat,
    /// Which mipmap to select.
    pub mipmap: u8,
}

impl Default for ImageInfo {
    fn default() -> ImageInfo {
        ImageInfo {
            xoffset: 0,
            yoffset: 0,
            zoffset: 0,
            width: 0,
            height: 1,
            depth: 1,
            format: RGBA8,
            mipmap: 0
        }
    }
}

impl Default for TextureInfo {
    fn default() -> TextureInfo {
        TextureInfo {
            width: 0,
            height: 1,
            depth: 1,
            mipmap_range: (0, -1),
            kind: Texture2D,
            format: RGBA8,
        }
    }
}

impl TextureInfo { pub fn new() -> TextureInfo { Default::default() } }
impl ImageInfo { pub fn new() -> ImageInfo { Default::default() } }

/// Specifies how texture coordinates outside the range `[0, 1]` are handled.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum WrapMode {
    /// Tile the texture. That is, sample the coordinate modulo `1.0`. This is
    /// the default.
    Tile,
    /// Mirror the texture. Like tile, but uses abs(coord) before the modulo.
    Mirror,
    /// Clamp the texture to the value at `0.0` or `1.0` respectively.
    Clamp,
}

/// Specifies how to sample from a texture.
#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct SamplerInfo {
    pub filtering: FilterMethod,
    /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
    /// speak)
    pub wrap_mode: (WrapMode, WrapMode, WrapMode),
    /// This bias is added to every computed mipmap level (N + lod_bias). For
    /// example, if it would select mipmap level 2 and lod_bias is 1, it will
    /// use mipmap level 3.
    pub lod_bias: f32,
    /// Mipmap levels outside of `[lo, hi]` will never be sampled. Defaults to
    /// `(0, -1)` (every mipmap available), but will be clamped to the
    /// texture's mipmap_range.
    pub mipmap_range: (u8, u8),
    // TODO: comparison mode
}
<|endoftext|>