<commit_before>//! The main event loop which performs I/O on the pseudoterminal.

use std::borrow::Cow;
use std::collections::VecDeque;
use std::fs::File;
use std::io::{self, ErrorKind, Read, Write};
use std::marker::Send;
use std::sync::Arc;
use std::thread::JoinHandle;
use std::time::Instant;

use log::error;
#[cfg(not(windows))]
use mio::unix::UnixReady;
use mio::{self, Events, PollOpt, Ready};
use mio_extras::channel::{self, Receiver, Sender};

use crate::ansi;
use crate::event::{self, Event, EventListener};
use crate::sync::FairMutex;
use crate::term::{SizeInfo, Term};
use crate::thread;
use crate::tty;

/// Max bytes to read from the PTY before forced terminal synchronization.
const READ_BUFFER_SIZE: usize = 0x10_0000;

/// Max bytes to read from the PTY while the terminal is locked.
const MAX_LOCKED_READ: usize = u16::max_value() as usize;

/// Messages that may be sent to the `EventLoop`.
#[derive(Debug)]
pub enum Msg {
    /// Data that should be written to the PTY.
    Input(Cow<'static, [u8]>),

    /// Indicates that the `EventLoop` should shut down, as Alacritty is shutting down.
    Shutdown,

    /// Instruction to resize the PTY.
    Resize(SizeInfo),
}

/// The main event!.. loop.
///
/// Handles all the PTY I/O and runs the PTY parser which updates terminal
/// state.
pub struct EventLoop<T: tty::EventedPty, U: EventListener> {
    poll: mio::Poll,
    pty: T,
    rx: Receiver<Msg>,
    tx: Sender<Msg>,
    terminal: Arc<FairMutex<Term<U>>>,
    event_proxy: U,
    hold: bool,
    ref_test: bool,
}

/// Helper type which tracks how much of a buffer has been written.
struct Writing {
    source: Cow<'static, [u8]>,
    written: usize,
}

pub struct Notifier(pub Sender<Msg>);

impl event::Notify for Notifier {
    fn notify<B>(&self, bytes: B)
    where
        B: Into<Cow<'static, [u8]>>,
    {
        let bytes = bytes.into();
        // terminal hangs if we send 0 bytes through.
        if bytes.len() == 0 {
            return;
        }

        self.0.send(Msg::Input(bytes)).expect("send event loop msg");
    }
}

impl event::OnResize for Notifier {
    fn on_resize(&mut self, size: &SizeInfo) {
        self.0.send(Msg::Resize(*size)).expect("expected send event loop msg");
    }
}

/// All of the mutable state needed to run the event loop.
///
/// Contains list of items to write, current write state, etc. Anything that
/// would otherwise be mutated on the `EventLoop` goes here.
#[derive(Default)]
pub struct State {
    write_list: VecDeque<Cow<'static, [u8]>>,
    writing: Option<Writing>,
    parser: ansi::Processor,
}

impl State {
    #[inline]
    fn ensure_next(&mut self) {
        if self.writing.is_none() {
            self.goto_next();
        }
    }

    #[inline]
    fn goto_next(&mut self) {
        self.writing = self.write_list.pop_front().map(Writing::new);
    }

    #[inline]
    fn take_current(&mut self) -> Option<Writing> {
        self.writing.take()
    }

    #[inline]
    fn needs_write(&self) -> bool {
        self.writing.is_some() || !self.write_list.is_empty()
    }

    #[inline]
    fn set_current(&mut self, new: Option<Writing>) {
        self.writing = new;
    }
}

impl Writing {
    #[inline]
    fn new(c: Cow<'static, [u8]>) -> Writing {
        Writing { source: c, written: 0 }
    }

    #[inline]
    fn advance(&mut self, n: usize) {
        self.written += n;
    }

    #[inline]
    fn remaining_bytes(&self) -> &[u8] {
        &self.source[self.written..]
    }

    #[inline]
    fn finished(&self) -> bool {
        self.written >= self.source.len()
    }
}

impl<T, U> EventLoop<T, U>
where
    T: tty::EventedPty + event::OnResize + Send + 'static,
    U: EventListener + Send + 'static,
{
    /// Create a new event loop.
    pub fn new(
        terminal: Arc<FairMutex<Term<U>>>,
        event_proxy: U,
        pty: T,
        hold: bool,
        ref_test: bool,
    ) -> EventLoop<T, U> {
        let (tx, rx) = channel::channel();
        EventLoop {
            poll: mio::Poll::new().expect("create mio Poll"),
            pty,
            tx,
            rx,
            terminal,
            event_proxy,
            hold,
            ref_test,
        }
    }

    pub fn channel(&self) -> Sender<Msg> {
        self.tx.clone()
    }

    /// Drain the channel.
    ///
    /// Returns `false` when a shutdown message was received.
    fn drain_recv_channel(&mut self, state: &mut State) -> bool {
        while let Ok(msg) = self.rx.try_recv() {
            match msg {
                Msg::Input(input) => state.write_list.push_back(input),
                Msg::Shutdown => return false,
                Msg::Resize(size) => self.pty.on_resize(&size),
            }
        }

        true
    }

    /// Returns a `bool` indicating whether or not the event loop should continue running.
    #[inline]
    fn channel_event(&mut self, token: mio::Token, state: &mut State) -> bool {
        if !self.drain_recv_channel(state) {
            return false;
        }

        self.poll
            .reregister(&self.rx, token, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
            .unwrap();

        true
    }

    #[inline]
    fn pty_read<X>(
        &mut self,
        state: &mut State,
        buf: &mut [u8],
        mut writer: Option<&mut X>,
    ) -> io::Result<()>
    where
        X: Write,
    {
        let mut unprocessed = 0;
        let mut processed = 0;

        // Reserve the next terminal lock for PTY reading.
        let _terminal_lease = Some(self.terminal.lease());
        let mut terminal = None;

        loop {
            // Read from the PTY.
            match self.pty.reader().read(&mut buf[unprocessed..]) {
                // This is received on Windows/macOS when no more data is readable from the PTY.
                Ok(0) if unprocessed == 0 => break,
                Ok(got) => unprocessed += got,
                Err(err) => match err.kind() {
                    ErrorKind::Interrupted | ErrorKind::WouldBlock => {
                        // Go back to mio if we're caught up on parsing and the PTY would block.
                        if unprocessed == 0 {
                            break;
                        }
                    },
                    _ => return Err(err),
                },
            }

            // Attempt to lock the terminal.
            let terminal = match &mut terminal {
                Some(terminal) => terminal,
                None => terminal.insert(match self.terminal.try_lock_unfair() {
                    // Force block if we are at the buffer size limit.
                    None if unprocessed >= READ_BUFFER_SIZE => self.terminal.lock_unfair(),
                    None => continue,
                    Some(terminal) => terminal,
                }),
            };

            // Write a copy of the bytes to the ref test file.
            if let Some(writer) = &mut writer {
                writer.write_all(&buf[..unprocessed]).unwrap();
            }

            // Parse the incoming bytes.
            for byte in &buf[..unprocessed] {
                state.parser.advance(&mut **terminal, *byte);
            }

            processed += unprocessed;
            unprocessed = 0;

            // Assure we're not blocking the terminal too long unnecessarily.
            if processed >= MAX_LOCKED_READ {
                break;
            }
        }

        // Queue terminal redraw unless all processed bytes were synchronized.
        if state.parser.sync_bytes_count() < processed && processed > 0 {
            self.event_proxy.send_event(Event::Wakeup);
        }

        Ok(())
    }

    #[inline]
    fn pty_write(&mut self, state: &mut State) -> io::Result<()> {
        state.ensure_next();

        'write_many: while let Some(mut current) = state.take_current() {
            'write_one: loop {
                match self.pty.writer().write(current.remaining_bytes()) {
                    Ok(0) => {
                        state.set_current(Some(current));
                        break 'write_many;
                    },
                    Ok(n) => {
                        current.advance(n);
                        if current.finished() {
                            state.goto_next();
                            break 'write_one;
                        }
                    },
                    Err(err) => {
                        state.set_current(Some(current));
                        match err.kind() {
                            ErrorKind::Interrupted | ErrorKind::WouldBlock => break 'write_many,
                            _ => return Err(err),
                        }
                    },
                }
            }
        }

        Ok(())
    }

    pub fn spawn(mut self) -> JoinHandle<(Self, State)> {
        thread::spawn_named("PTY reader", move || {
            let mut state = State::default();
            let mut buf = [0u8; READ_BUFFER_SIZE];

            let mut tokens = (0..).map(Into::into);

            let poll_opts = PollOpt::edge() | PollOpt::oneshot();

            let channel_token = tokens.next().unwrap();
            self.poll.register(&self.rx, channel_token, Ready::readable(), poll_opts).unwrap();

            // Register TTY through EventedRW interface.
            self.pty.register(&self.poll, &mut tokens, Ready::readable(), poll_opts).unwrap();

            let mut events = Events::with_capacity(1024);

            let mut pipe = if self.ref_test {
                Some(File::create("./alacritty.recording").expect("create alacritty recording"))
            } else {
                None
            };

            'event_loop: loop {
                // Wakeup the event loop when a synchronized update timeout was reached.
                let sync_timeout = state.parser.sync_timeout();
                let timeout = sync_timeout.map(|st| st.saturating_duration_since(Instant::now()));

                if let Err(err) = self.poll.poll(&mut events, timeout) {
                    match err.kind() {
                        ErrorKind::Interrupted => continue,
                        _ => panic!("EventLoop polling error: {:?}", err),
                    }
                }

                // Handle synchronized update timeout.
                if events.is_empty() {
                    state.parser.stop_sync(&mut *self.terminal.lock());
                    self.event_proxy.send_event(Event::Wakeup);
                    continue;
                }

                for event in events.iter() {
                    match event.token() {
                        token if token == channel_token => {
                            if !self.channel_event(channel_token, &mut state) {
                                break 'event_loop;
                            }
                        },

                        token if token == self.pty.child_event_token() => {
                            if let Some(tty::ChildEvent::Exited) = self.pty.next_child_event() {
                                if self.hold {
                                    // With hold enabled, make sure the PTY is drained.
                                    let _ = self.pty_read(&mut state, &mut buf, pipe.as_mut());
                                } else {
                                    // Without hold, shutdown the terminal.
                                    self.terminal.lock().exit();
                                }

                                self.event_proxy.send_event(Event::Wakeup);
                                break 'event_loop;
                            }
                        },

                        token
                            if token == self.pty.read_token()
                                || token == self.pty.write_token() =>
                        {
                            #[cfg(unix)]
                            if UnixReady::from(event.readiness()).is_hup() {
                                // Don't try to do I/O on a dead PTY.
                                continue;
                            }

                            if event.readiness().is_readable() {
                                if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut())
                                {
                                    // On Linux, a `read` on the master side of a PTY can fail
                                    // with `EIO` if the client side hangs up.  In that case,
                                    // just loop back round for the inevitable `Exited` event.
                                    // This sucks, but checking the process is either racy or
                                    // blocking.
                                    #[cfg(target_os = "linux")]
                                    if err.kind() == ErrorKind::Other {
                                        continue;
                                    }

                                    error!("Error reading from PTY in event loop: {}", err);
                                    break 'event_loop;
                                }
                            }

                            if event.readiness().is_writable() {
                                if let Err(err) = self.pty_write(&mut state) {
                                    error!("Error writing to PTY in event loop: {}", err);
                                    break 'event_loop;
                                }
                            }
                        }
                        _ => (),
                    }
                }

                // Register write interest if necessary.
                let mut interest = Ready::readable();
                if state.needs_write() {
                    interest.insert(Ready::writable());
                }
                // Reregister with new interest.
                self.pty.reregister(&self.poll, interest, poll_opts).unwrap();
            }

            // The evented instances are not dropped here so deregister them explicitly.
            let _ = self.poll.deregister(&self.rx);
            let _ = self.pty.deregister(&self.poll);

            (self, state)
        })
    }
}

trait OptionInsert {
    type T;
    fn insert(&mut self, value: Self::T) -> &mut Self::T;
}

// TODO: Remove when MSRV is >= 1.53.0.
//
/// Trait implementation to support Rust version < 1.53.0.
///
/// This is taken [from STD], further license information can be found in the [rust-lang/rust
/// repository].
///
///
/// [from STD]: https://github.com/rust-lang/rust/blob/6e0b554619a3bb7e75b3334e97f191af20ef5d76/library/core/src/option.rs#L829-L858
/// [rust-lang/rust repository]: https://github.com/rust-lang/rust/blob/master/LICENSE-MIT
impl<T> OptionInsert for Option<T> {
    type T = T;

    fn insert(&mut self, value: T) -> &mut T {
        *self = Some(value);

        match self {
            Some(v) => v,
            // SAFETY: the code above just filled the option
            None => unsafe { std::hint::unreachable_unchecked() },
        }
    }
}
<commit_msg>Handle PTY EIO error for Rust 1.55+<commit_after>//! The main event loop which performs I/O on the pseudoterminal.

use std::borrow::Cow;
use std::collections::VecDeque;
use std::fs::File;
use std::io::{self, ErrorKind, Read, Write};
use std::marker::Send;
use std::sync::Arc;
use std::thread::JoinHandle;
use std::time::Instant;

use log::error;
#[cfg(not(windows))]
use mio::unix::UnixReady;
use mio::{self, Events, PollOpt, Ready};
use mio_extras::channel::{self, Receiver, Sender};

use crate::ansi;
use crate::event::{self, Event, EventListener};
use crate::sync::FairMutex;
use crate::term::{SizeInfo, Term};
use crate::thread;
use crate::tty;

/// Max bytes to read from the PTY before forced terminal synchronization.
const READ_BUFFER_SIZE: usize = 0x10_0000;

/// Max bytes to read from the PTY while the terminal is locked.
const MAX_LOCKED_READ: usize = u16::max_value() as usize;

/// Messages that may be sent to the `EventLoop`.
#[derive(Debug)]
pub enum Msg {
    /// Data that should be written to the PTY.
    Input(Cow<'static, [u8]>),

    /// Indicates that the `EventLoop` should shut down, as Alacritty is shutting down.
    Shutdown,

    /// Instruction to resize the PTY.
    Resize(SizeInfo),
}

/// The main event!.. loop.
///
/// Handles all the PTY I/O and runs the PTY parser which updates terminal
/// state.
pub struct EventLoop<T: tty::EventedPty, U: EventListener> {
    poll: mio::Poll,
    pty: T,
    rx: Receiver<Msg>,
    tx: Sender<Msg>,
    terminal: Arc<FairMutex<Term<U>>>,
    event_proxy: U,
    hold: bool,
    ref_test: bool,
}

/// Helper type which tracks how much of a buffer has been written.
struct Writing {
    source: Cow<'static, [u8]>,
    written: usize,
}

pub struct Notifier(pub Sender<Msg>);

impl event::Notify for Notifier {
    fn notify<B>(&self, bytes: B)
    where
        B: Into<Cow<'static, [u8]>>,
    {
        let bytes = bytes.into();
        // terminal hangs if we send 0 bytes through.
        if bytes.len() == 0 {
            return;
        }

        self.0.send(Msg::Input(bytes)).expect("send event loop msg");
    }
}

impl event::OnResize for Notifier {
    fn on_resize(&mut self, size: &SizeInfo) {
        self.0.send(Msg::Resize(*size)).expect("expected send event loop msg");
    }
}

/// All of the mutable state needed to run the event loop.
///
/// Contains list of items to write, current write state, etc. Anything that
/// would otherwise be mutated on the `EventLoop` goes here.
#[derive(Default)]
pub struct State {
    write_list: VecDeque<Cow<'static, [u8]>>,
    writing: Option<Writing>,
    parser: ansi::Processor,
}

impl State {
    #[inline]
    fn ensure_next(&mut self) {
        if self.writing.is_none() {
            self.goto_next();
        }
    }

    #[inline]
    fn goto_next(&mut self) {
        self.writing = self.write_list.pop_front().map(Writing::new);
    }

    #[inline]
    fn take_current(&mut self) -> Option<Writing> {
        self.writing.take()
    }

    #[inline]
    fn needs_write(&self) -> bool {
        self.writing.is_some() || !self.write_list.is_empty()
    }

    #[inline]
    fn set_current(&mut self, new: Option<Writing>) {
        self.writing = new;
    }
}

impl Writing {
    #[inline]
    fn new(c: Cow<'static, [u8]>) -> Writing {
        Writing { source: c, written: 0 }
    }

    #[inline]
    fn advance(&mut self, n: usize) {
        self.written += n;
    }

    #[inline]
    fn remaining_bytes(&self) -> &[u8] {
        &self.source[self.written..]
    }

    #[inline]
    fn finished(&self) -> bool {
        self.written >= self.source.len()
    }
}

impl<T, U> EventLoop<T, U>
where
    T: tty::EventedPty + event::OnResize + Send + 'static,
    U: EventListener + Send + 'static,
{
    /// Create a new event loop.
    pub fn new(
        terminal: Arc<FairMutex<Term<U>>>,
        event_proxy: U,
        pty: T,
        hold: bool,
        ref_test: bool,
    ) -> EventLoop<T, U> {
        let (tx, rx) = channel::channel();
        EventLoop {
            poll: mio::Poll::new().expect("create mio Poll"),
            pty,
            tx,
            rx,
            terminal,
            event_proxy,
            hold,
            ref_test,
        }
    }

    pub fn channel(&self) -> Sender<Msg> {
        self.tx.clone()
    }

    /// Drain the channel.
    ///
    /// Returns `false` when a shutdown message was received.
    fn drain_recv_channel(&mut self, state: &mut State) -> bool {
        while let Ok(msg) = self.rx.try_recv() {
            match msg {
                Msg::Input(input) => state.write_list.push_back(input),
                Msg::Shutdown => return false,
                Msg::Resize(size) => self.pty.on_resize(&size),
            }
        }

        true
    }

    /// Returns a `bool` indicating whether or not the event loop should continue running.
    #[inline]
    fn channel_event(&mut self, token: mio::Token, state: &mut State) -> bool {
        if !self.drain_recv_channel(state) {
            return false;
        }

        self.poll
            .reregister(&self.rx, token, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())
            .unwrap();

        true
    }

    #[inline]
    fn pty_read<X>(
        &mut self,
        state: &mut State,
        buf: &mut [u8],
        mut writer: Option<&mut X>,
    ) -> io::Result<()>
    where
        X: Write,
    {
        let mut unprocessed = 0;
        let mut processed = 0;

        // Reserve the next terminal lock for PTY reading.
        let _terminal_lease = Some(self.terminal.lease());
        let mut terminal = None;

        loop {
            // Read from the PTY.
            match self.pty.reader().read(&mut buf[unprocessed..]) {
                // This is received on Windows/macOS when no more data is readable from the PTY.
                Ok(0) if unprocessed == 0 => break,
                Ok(got) => unprocessed += got,
                Err(err) => match err.kind() {
                    ErrorKind::Interrupted | ErrorKind::WouldBlock => {
                        // Go back to mio if we're caught up on parsing and the PTY would block.
                        if unprocessed == 0 {
                            break;
                        }
                    },
                    _ => return Err(err),
                },
            }

            // Attempt to lock the terminal.
            let terminal = match &mut terminal {
                Some(terminal) => terminal,
                None => terminal.insert(match self.terminal.try_lock_unfair() {
                    // Force block if we are at the buffer size limit.
                    None if unprocessed >= READ_BUFFER_SIZE => self.terminal.lock_unfair(),
                    None => continue,
                    Some(terminal) => terminal,
                }),
            };

            // Write a copy of the bytes to the ref test file.
            if let Some(writer) = &mut writer {
                writer.write_all(&buf[..unprocessed]).unwrap();
            }

            // Parse the incoming bytes.
            for byte in &buf[..unprocessed] {
                state.parser.advance(&mut **terminal, *byte);
            }

            processed += unprocessed;
            unprocessed = 0;

            // Assure we're not blocking the terminal too long unnecessarily.
            if processed >= MAX_LOCKED_READ {
                break;
            }
        }

        // Queue terminal redraw unless all processed bytes were synchronized.
        if state.parser.sync_bytes_count() < processed && processed > 0 {
            self.event_proxy.send_event(Event::Wakeup);
        }

        Ok(())
    }

    #[inline]
    fn pty_write(&mut self, state: &mut State) -> io::Result<()> {
        state.ensure_next();

        'write_many: while let Some(mut current) = state.take_current() {
            'write_one: loop {
                match self.pty.writer().write(current.remaining_bytes()) {
                    Ok(0) => {
                        state.set_current(Some(current));
                        break 'write_many;
                    },
                    Ok(n) => {
                        current.advance(n);
                        if current.finished() {
                            state.goto_next();
                            break 'write_one;
                        }
                    },
                    Err(err) => {
                        state.set_current(Some(current));
                        match err.kind() {
                            ErrorKind::Interrupted | ErrorKind::WouldBlock => break 'write_many,
                            _ => return Err(err),
                        }
                    },
                }
            }
        }

        Ok(())
    }

    pub fn spawn(mut self) -> JoinHandle<(Self, State)> {
        thread::spawn_named("PTY reader", move || {
            let mut state = State::default();
            let mut buf = [0u8; READ_BUFFER_SIZE];

            let mut tokens = (0..).map(Into::into);

            let poll_opts = PollOpt::edge() | PollOpt::oneshot();

            let channel_token = tokens.next().unwrap();
            self.poll.register(&self.rx, channel_token, Ready::readable(), poll_opts).unwrap();

            // Register TTY through EventedRW interface.
            self.pty.register(&self.poll, &mut tokens, Ready::readable(), poll_opts).unwrap();

            let mut events = Events::with_capacity(1024);

            let mut pipe = if self.ref_test {
                Some(File::create("./alacritty.recording").expect("create alacritty recording"))
            } else {
                None
            };

            'event_loop: loop {
                // Wakeup the event loop when a synchronized update timeout was reached.
                let sync_timeout = state.parser.sync_timeout();
                let timeout = sync_timeout.map(|st| st.saturating_duration_since(Instant::now()));

                if let Err(err) = self.poll.poll(&mut events, timeout) {
                    match err.kind() {
                        ErrorKind::Interrupted => continue,
                        _ => panic!("EventLoop polling error: {:?}", err),
                    }
                }

                // Handle synchronized update timeout.
                if events.is_empty() {
                    state.parser.stop_sync(&mut *self.terminal.lock());
                    self.event_proxy.send_event(Event::Wakeup);
                    continue;
                }

                for event in events.iter() {
                    match event.token() {
                        token if token == channel_token => {
                            if !self.channel_event(channel_token, &mut state) {
                                break 'event_loop;
                            }
                        },

                        token if token == self.pty.child_event_token() => {
                            if let Some(tty::ChildEvent::Exited) = self.pty.next_child_event() {
                                if self.hold {
                                    // With hold enabled, make sure the PTY is drained.
                                    let _ = self.pty_read(&mut state, &mut buf, pipe.as_mut());
                                } else {
                                    // Without hold, shutdown the terminal.
                                    self.terminal.lock().exit();
                                }

                                self.event_proxy.send_event(Event::Wakeup);
                                break 'event_loop;
                            }
                        },

                        token
                            if token == self.pty.read_token()
                                || token == self.pty.write_token() =>
                        {
                            #[cfg(unix)]
                            if UnixReady::from(event.readiness()).is_hup() {
                                // Don't try to do I/O on a dead PTY.
                                continue;
                            }

                            if event.readiness().is_readable() {
                                if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut())
                                {
                                    // On Linux, a `read` on the master side of a PTY can fail
                                    // with `EIO` if the client side hangs up.  In that case,
                                    // just loop back round for the inevitable `Exited` event.
                                    // This sucks, but checking the process is either racy or
                                    // blocking.
                                    #[cfg(target_os = "linux")]
                                    if err.raw_os_error() == Some(libc::EIO) {
                                        continue;
                                    }

                                    error!("Error reading from PTY in event loop: {}", err);
                                    break 'event_loop;
                                }
                            }

                            if event.readiness().is_writable() {
                                if let Err(err) = self.pty_write(&mut state) {
                                    error!("Error writing to PTY in event loop: {}", err);
                                    break 'event_loop;
                                }
                            }
                        }
                        _ => (),
                    }
                }

                // Register write interest if necessary.
                let mut interest = Ready::readable();
                if state.needs_write() {
                    interest.insert(Ready::writable());
                }
                // Reregister with new interest.
                self.pty.reregister(&self.poll, interest, poll_opts).unwrap();
            }

            // The evented instances are not dropped here so deregister them explicitly.
            let _ = self.poll.deregister(&self.rx);
            let _ = self.pty.deregister(&self.poll);

            (self, state)
        })
    }
}

trait OptionInsert {
    type T;
    fn insert(&mut self, value: Self::T) -> &mut Self::T;
}

// TODO: Remove when MSRV is >= 1.53.0.
//
/// Trait implementation to support Rust version < 1.53.0.
///
/// This is taken [from STD], further license information can be found in the [rust-lang/rust
/// repository].
///
///
/// [from STD]: https://github.com/rust-lang/rust/blob/6e0b554619a3bb7e75b3334e97f191af20ef5d76/library/core/src/option.rs#L829-L858
/// [rust-lang/rust repository]: https://github.com/rust-lang/rust/blob/master/LICENSE-MIT
impl<T> OptionInsert for Option<T> {
    type T = T;

    fn insert(&mut self, value: T) -> &mut T {
        *self = Some(value);

        match self {
            Some(v) => v,
            // SAFETY: the code above just filled the option
            None => unsafe { std::hint::unreachable_unchecked() },
        }
    }
}
<|endoftext|>


<commit_before>use syntax::core::keywords::Keywords;
use syntax::core::tokens;
use syntax::core::tokens::Token;
use syntax::core::punctuation;
use syntax::core::punctuation::Punctuations;

pub trait Tokenizer {
    fn get_tok(&mut self) -> Token;
}

// A Lexer that keeps track of the current line and column position
// as well as the position in the char input stream.
pub struct Lexer {
    /*****

    pub status of line and column number deprecated, please use get_tok_line(), get_tok_column()

    ******/
    pub line_number: uint,
    pub column_number: uint,
    buffer_pos: uint,
    line_start: uint,
    input: String
}

impl Tokenizer for Lexer {
    // Parse the file where it left off and return the next token
    fn get_tok(&mut self) -> Token {
        // ToDo: More lexing!
        loop {
            if self.eof() {
                return tokens::EOF;
            }

            self.consume_whitespace();

            return match self.next_char() {
                // Find Keywords and Identifiers
                a if a.is_alphabetic() || a == '_' => self.consume_identifier(),

                e if self.eof() => tokens::EOF,

                // Find ints, floats, hex, and bin numeric values
                n if n.is_digit() => self.consume_numeric(),

                // Count tabs: \n\t*
                '\n' => self.consume_tabs(),

                // Error: Found tabs without preceeding newline
                '\t' => {
                    self.consume_char();

                    tokens::Error("Found an out of place tab.".to_string())
                },

                // Find single char punctuations
                '(' | ')' | '[' | ']' | '{' | '}' |
                '.' | ',' | ':' | '<' | '~' | '=' => {
                    // Dumb: cant do self.single_punc_token(self.consume_char()) due to borrowing
                    // But the following works.
                    let ch = self.consume_char();

                    self.single_punc_token(ch)
                },

                // Find multi-char(+=, -=, ..) punctuations or not
                '+' | '-' | '*' | '/' | '%' => {
                    let ch = self.consume_char();

                    match self.next_char() {
                        '=' => {
                            let ch2 = self.consume_char();

                            self.multi_punc_token([ch, ch2])
                        },
                         _  => self.single_punc_token(ch)
                    }
                },

                '>' => {
                    self.consume_char();

                    match self.next_char() {
                        '>' => self.consume_comment(),
                         _  => self.single_punc_token('>')
                    }
                },

                ch => tokens::Error(format!("Unknown character '{}'.", ch).to_string())
            };
        }
    }
}

impl Lexer {
    // Create a new lexer instance
    pub fn new<B: Buffer>(mut fileReader: B) -> Lexer {
        Lexer {
            line_number: 1,
            column_number: 1,
            buffer_pos: 0,
            line_start: 0,
            input: fileReader.read_to_string().unwrap()
        }
    }

    // ToDo: figure out a way to change this to take an index
    pub fn current_line(&mut self) -> String {
        let tmp = self.buffer_pos;
        let mut result = String::new();

        self.buffer_pos = self.line_start;

        result.push_str(self.consume_while(|ch| match ch {
            '\n' => false,
            _    => true
        }).as_slice());

        self.buffer_pos = tmp;

        result
    }

    fn current_slice(&mut self) -> &str {
        self.input.as_slice().slice_from(self.buffer_pos)
    }

    // Gets the next char and sets the position forward in the buffer
    fn consume_char(&mut self) -> char {
        let ch = self.next_char();

        self.buffer_pos += 1;
        self.column_number += 1;

        if ch == '\n' {
            self.line_start = self.buffer_pos;
            self.line_number += 1;
            self.column_number = 1;
        }

        ch
    }

    // Gets the next char
    fn next_char(&self) -> char {
        return self.input.as_slice().char_at(self.buffer_pos);
    }

    // Determine if we hit the inevitable End of File
    fn eof(&self) -> bool {
        return self.buffer_pos >= self.input.len();
    }

    // Thanks to mbrubeck of Mozilla for this consume_while fn as
    // well eof() and next_char() examples :)
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();

        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }

        result
    }

    // Single char puncuations: (, [, ., ...
    fn single_punc_token(&mut self, ch: char) -> Token {
        tokens::Punctuation(match ch {
            '(' => punctuation::ParenOpen,
            ')' => punctuation::ParenClose,
            '[' => punctuation::SBracketOpen,
            ']' => punctuation::SBracketClose,
            '{' => punctuation::CBracketOpen,
            '}' => punctuation::CBracketClose,
            '.' => punctuation::Period,
            ',' => punctuation::Comma,
            ':' => punctuation::Colon,
            '>' => punctuation::GreaterThan,
            '<' => punctuation::LessThan,
            '+' => punctuation::Plus,
            '-' => punctuation::Minus,
            '*' => punctuation::Asterisk,
            '/' => punctuation::Slash,
            '%' => punctuation::Percent,
            '~' => punctuation::Tilde,
            '=' => punctuation::Equals,

            // Should never get here:
              _ => punctuation::Period
        })
    }

    // Multi char punctuations: +=, -=, ...
    fn multi_punc_token(&mut self, vec: &[char]) -> Token {
        let string = String::from_chars(vec);
        let punct = from_str::<Punctuations>(string.as_slice()).unwrap();

        tokens::Punctuation(punct)
    }

    // Consume non newline whitespace
    fn consume_whitespace(&mut self) {
        self.consume_while(|ch| match ch {
            '\n'                   => false,
            '\t'                   => false,
            w if w.is_whitespace() => true,
            _                      => false
        });
    }

    // Identifiers: [a-zA-Z_][a-zA-z0-9_]*
    fn consume_identifier(&mut self) -> Token {
        // Lexer will only let you start with alpha or undescore,
        // so there is no need to check for numeric start
        let ident = self.consume_while(|ch| match ch {
            a if a.is_alphanumeric() => true,
            '_'                      => true,
             _                       => false
        });

        match from_str::<Keywords>(ident.as_slice()) {
            Some(key) => tokens::Keyword(key),
            None      => tokens::Identifier(ident)
        }
    }

    // Determines what type of number it is and call the appropriate fn
    fn consume_numeric(&mut self) -> Token {
        let mut result = String::new();

        if self.current_slice().starts_with("0x") {
            // Found hexadecimal: 0x[0-9a-fA-F_]+

            self.buffer_pos += 2;
            result.push_str("0x");

            // Cant do += for String, and push_str looks better than
            // result = result + self.consume...
            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' | 'a'..'f' | 'A'..'F' => true,
                 _                             => false
            }).as_slice());

            // ToDo: Get valid suffix for hex. Same as int?

        } else if self.current_slice().starts_with("0b") {
            // Found binary: 0b[01_]+

            self.buffer_pos += 2;
            result.push_str("0b");

            // Formatting the same as the hex case above.
            result.push_str(self.consume_while(|ch| match ch {
                '0' | '1' | '_' => true,
                 _              => false
            }).as_slice());

            // ToDo: Get valid suffix for bin. Same as int?

        } else {
            // Found int: [0-9]+ or float: [0-9]+.[0-9]+

            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' => true,
                 _       => false
            }).as_slice());

            match self.next_char() {
                // Float decimal point:
                '.' => {
                    result.push_char(self.consume_char());

                    let fractional = self.consume_while(|ch| match ch {
                        '0'..'9' => true,
                         _       => false
                    });

                    if fractional.as_slice() == "" {
                        return tokens::Error("Invalid floating point number.".to_string());

                    } else {
                        result.push_str(fractional.as_slice());
                    }

                    // Float suffixes:
                    // ToDo: find f32, f64?
                },

                // Int suffixes:
                // ToDo: will we need other int sizes?
                'i' | 'u' => {
                    result.push_char(self.consume_char());

                    // Ensure there are no additional alpha chars
                    if self.next_char().is_alphabetic() {
                        return tokens::Error("Invalid suffix.".to_string());
                    }

                },

                // Ensure there are no additional alpha chars
                c if c.is_alphabetic() => {
                    return tokens::Error("Invalid suffix".to_string());
                },

                // Presumably any other remaining char is valid, ie punctuation {,[ etc
                _ => ()
            };
        }

        match result.as_slice() {
            "0x" => tokens::Error("Invalid hex value.".to_string()),
            "0b" => tokens::Error("Invalid binary value.".to_string()),
             _   => tokens::Numeric(result)
        }
    }

    fn consume_comment(&mut self) -> Token {
        let mut result = String::new();

        // Consume 2nd '>'
        self.consume_char();

        if self.next_char() == '>' {
            // Multiline comments must end in <<< else error
            let mut sequence = 0u;

            // Consume 3rd '>'
            self.consume_char();

            result.push_str(self.consume_while(ref |ch| match ch {
                '<' => {
                    sequence += 1;

                    if sequence == 3 {
                        return false;
                    }
                    true
                },
                 _  => {
                     sequence = 0;
                     true
                 }
            }).as_slice());

            // ToDo: eof check/no <<< found -> error
        }
        else {

            // Single line comments eat up anything until newline or eof
            result.push_str(self.consume_while(|ch| match ch {
                '\n' => false,
                _ => true
            }).as_slice());
        }

        // ToDo: Finish this

        tokens::Comment(result)
    }

    fn consume_tabs(&mut self) -> Token {
        let mut count = 0;

        // Consume the newline token, count tabs
        self.consume_char();
        self.consume_while(ref |ch| match ch {
            '\t' => {
                count += 1;
                true
            },
             _   => false
        });

        tokens::Indent(count)
    }
}
<commit_msg>Added missing > char<commit_after>use syntax::core::keywords::Keywords;
use syntax::core::tokens;
use syntax::core::tokens::Token;
use syntax::core::punctuation;
use syntax::core::punctuation::Punctuations;

pub trait Tokenizer {
    fn get_tok(&mut self) -> Token;
}

// A Lexer that keeps track of the current line and column position
// as well as the position in the char input stream.
pub struct Lexer {
    /*****

    pub status of line and column number deprecated, please use get_tok_line(), get_tok_column()

    ******/
    pub line_number: uint,
    pub column_number: uint,
    buffer_pos: uint,
    line_start: uint,
    input: String
}

impl Tokenizer for Lexer {
    // Parse the file where it left off and return the next token
    fn get_tok(&mut self) -> Token {
        // ToDo: More lexing!
        loop {
            if self.eof() {
                return tokens::EOF;
            }

            self.consume_whitespace();

            return match self.next_char() {
                // Find Keywords and Identifiers
                a if a.is_alphabetic() || a == '_' => self.consume_identifier(),

                e if self.eof() => tokens::EOF,

                // Find ints, floats, hex, and bin numeric values
                n if n.is_digit() => self.consume_numeric(),

                // Count tabs: \n\t*
                '\n' => self.consume_tabs(),

                // Error: Found tabs without preceeding newline
                '\t' => {
                    self.consume_char();

                    tokens::Error("Found an out of place tab.".to_string())
                },

                // Find single char punctuations
                '(' | ')' | '[' | ']' | '{' | '}' |
                '.' | ',' | ':' | '<' | '>' | '~' | '=' => {
                    // Dumb: cant do self.single_punc_token(self.consume_char()) due to borrowing
                    // But the following works.
                    let ch = self.consume_char();

                    self.single_punc_token(ch)
                },

                // Find multi-char(+=, -=, ..) punctuations or not
                '+' | '-' | '*' | '/' | '%' => {
                    let ch = self.consume_char();

                    match self.next_char() {
                        '=' => {
                            let ch2 = self.consume_char();

                            self.multi_punc_token([ch, ch2])
                        },
                         _  => self.single_punc_token(ch)
                    }
                },

                '>' => {
                    self.consume_char();

                    match self.next_char() {
                        '>' => self.consume_comment(),
                         _  => self.single_punc_token('>')
                    }
                },

                ch => tokens::Error(format!("Unknown character '{}'.", ch).to_string())
            };
        }
    }
}

impl Lexer {
    // Create a new lexer instance
    pub fn new<B: Buffer>(mut fileReader: B) -> Lexer {
        Lexer {
            line_number: 1,
            column_number: 1,
            buffer_pos: 0,
            line_start: 0,
            input: fileReader.read_to_string().unwrap()
        }
    }

    // ToDo: figure out a way to change this to take an index
    pub fn current_line(&mut self) -> String {
        let tmp = self.buffer_pos;
        let mut result = String::new();

        self.buffer_pos = self.line_start;

        result.push_str(self.consume_while(|ch| match ch {
            '\n' => false,
            _    => true
        }).as_slice());

        self.buffer_pos = tmp;

        result
    }

    fn current_slice(&mut self) -> &str {
        self.input.as_slice().slice_from(self.buffer_pos)
    }

    // Gets the next char and sets the position forward in the buffer
    fn consume_char(&mut self) -> char {
        let ch = self.next_char();

        self.buffer_pos += 1;
        self.column_number += 1;

        if ch == '\n' {
            self.line_start = self.buffer_pos;
            self.line_number += 1;
            self.column_number = 1;
        }

        ch
    }

    // Gets the next char
    fn next_char(&self) -> char {
        return self.input.as_slice().char_at(self.buffer_pos);
    }

    // Determine if we hit the inevitable End of File
    fn eof(&self) -> bool {
        return self.buffer_pos >= self.input.len();
    }

    // Thanks to mbrubeck of Mozilla for this consume_while fn as
    // well eof() and next_char() examples :)
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();

        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }

        result
    }

    // Single char puncuations: (, [, ., ...
    fn single_punc_token(&mut self, ch: char) -> Token {
        tokens::Punctuation(match ch {
            '(' => punctuation::ParenOpen,
            ')' => punctuation::ParenClose,
            '[' => punctuation::SBracketOpen,
            ']' => punctuation::SBracketClose,
            '{' => punctuation::CBracketOpen,
            '}' => punctuation::CBracketClose,
            '.' => punctuation::Period,
            ',' => punctuation::Comma,
            ':' => punctuation::Colon,
            '>' => punctuation::GreaterThan,
            '<' => punctuation::LessThan,
            '+' => punctuation::Plus,
            '-' => punctuation::Minus,
            '*' => punctuation::Asterisk,
            '/' => punctuation::Slash,
            '%' => punctuation::Percent,
            '~' => punctuation::Tilde,
            '=' => punctuation::Equals,

            // Should never get here:
              _ => punctuation::Period
        })
    }

    // Multi char punctuations: +=, -=, ...
    fn multi_punc_token(&mut self, vec: &[char]) -> Token {
        let string = String::from_chars(vec);
        let punct = from_str::<Punctuations>(string.as_slice()).unwrap();

        tokens::Punctuation(punct)
    }

    // Consume non newline whitespace
    fn consume_whitespace(&mut self) {
        self.consume_while(|ch| match ch {
            '\n'                   => false,
            '\t'                   => false,
            w if w.is_whitespace() => true,
            _                      => false
        });
    }

    // Identifiers: [a-zA-Z_][a-zA-z0-9_]*
    fn consume_identifier(&mut self) -> Token {
        // Lexer will only let you start with alpha or undescore,
        // so there is no need to check for numeric start
        let ident = self.consume_while(|ch| match ch {
            a if a.is_alphanumeric() => true,
            '_'                      => true,
             _                       => false
        });

        match from_str::<Keywords>(ident.as_slice()) {
            Some(key) => tokens::Keyword(key),
            None      => tokens::Identifier(ident)
        }
    }

    // Determines what type of number it is and call the appropriate fn
    fn consume_numeric(&mut self) -> Token {
        let mut result = String::new();

        if self.current_slice().starts_with("0x") {
            // Found hexadecimal: 0x[0-9a-fA-F_]+

            self.buffer_pos += 2;
            result.push_str("0x");

            // Cant do += for String, and push_str looks better than
            // result = result + self.consume...
            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' | 'a'..'f' | 'A'..'F' => true,
                 _                             => false
            }).as_slice());

            // ToDo: Get valid suffix for hex. Same as int?

        } else if self.current_slice().starts_with("0b") {
            // Found binary: 0b[01_]+

            self.buffer_pos += 2;
            result.push_str("0b");

            // Formatting the same as the hex case above.
            result.push_str(self.consume_while(|ch| match ch {
                '0' | '1' | '_' => true,
                 _              => false
            }).as_slice());

            // ToDo: Get valid suffix for bin. Same as int?

        } else {
            // Found int: [0-9]+ or float: [0-9]+.[0-9]+

            result.push_str(self.consume_while(|ch| match ch {
                '0'..'9' => true,
                 _       => false
            }).as_slice());

            match self.next_char() {
                // Float decimal point:
                '.' => {
                    result.push_char(self.consume_char());

                    let fractional = self.consume_while(|ch| match ch {
                        '0'..'9' => true,
                         _       => false
                    });

                    if fractional.as_slice() == "" {
                        return tokens::Error("Invalid floating point number.".to_string());

                    } else {
                        result.push_str(fractional.as_slice());
                    }

                    // Float suffixes:
                    // ToDo: find f32, f64?
                },

                // Int suffixes:
                // ToDo: will we need other int sizes?
                'i' | 'u' => {
                    result.push_char(self.consume_char());

                    // Ensure there are no additional alpha chars
                    if self.next_char().is_alphabetic() {
                        return tokens::Error("Invalid suffix.".to_string());
                    }

                },

                // Ensure there are no additional alpha chars
                c if c.is_alphabetic() => {
                    return tokens::Error("Invalid suffix".to_string());
                },

                // Presumably any other remaining char is valid, ie punctuation {,[ etc
                _ => ()
            };
        }

        match result.as_slice() {
            "0x" => tokens::Error("Invalid hex value.".to_string()),
            "0b" => tokens::Error("Invalid binary value.".to_string()),
             _   => tokens::Numeric(result)
        }
    }

    fn consume_comment(&mut self) -> Token {
        let mut result = String::new();

        // Consume 2nd '>'
        self.consume_char();

        if self.next_char() == '>' {
            // Multiline comments must end in <<< else error
            let mut sequence = 0u;

            // Consume 3rd '>'
            self.consume_char();

            result.push_str(self.consume_while(ref |ch| match ch {
                '<' => {
                    sequence += 1;

                    if sequence == 3 {
                        return false;
                    }
                    true
                },
                 _  => {
                     sequence = 0;
                     true
                 }
            }).as_slice());

            // ToDo: eof check/no <<< found -> error
        }
        else {

            // Single line comments eat up anything until newline or eof
            result.push_str(self.consume_while(|ch| match ch {
                '\n' => false,
                _ => true
            }).as_slice());
        }

        // ToDo: Finish this

        tokens::Comment(result)
    }

    fn consume_tabs(&mut self) -> Token {
        let mut count = 0;

        // Consume the newline token, count tabs
        self.consume_char();
        self.consume_while(ref |ch| match ch {
            '\t' => {
                count += 1;
                true
            },
             _   => false
        });

        tokens::Indent(count)
    }
}
<|endoftext|>


<commit_before>use tensor::{Tensor, NumLimits, THVec, THVecGeneric, THDims};
use num::NumCast;

impl<T: NumLimits> THVec<T> {
    pub fn new(dims: Vec<usize>, data: Vec<T>) -> Self {
        THVec {
            dims: dims,
            data: data,
        }
    }
}
impl THVecGeneric {
    pub fn new(dims: Vec<usize>, data: Vec<i64>) -> Self {
        THVecGeneric {
            dims: dims,
            data: data,
        }
    }
}
impl THDims {
    fn new(dims: Vec<usize>) -> Self {
        THDims { dims: dims }
    }
}
impl<T: NumLimits> From<Vec<Vec<Vec<T>>>> for THVec<T> {
    fn from(input: Vec<Vec<Vec<T>>>) -> Self {
        let dims = vec![input.len(), input[0].len(), input[0][0].len()];
        let v = input
            .iter()
            .flat_map(|d| d.iter())
            .flat_map(|d| d.iter())
            .map(|d| *d)
            .collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<Vec<T>>> for THVec<T> {
    fn from(input: Vec<Vec<T>>) -> Self {
        let dims = vec![input.len(), input[0].len()];
        let v = input.iter().flat_map(|d| d.iter()).map(|d| *d).collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<T>> for THVec<T> {
    fn from(input: Vec<T>) -> Self {
        let dims = vec![input.len()];
        THVec::new(dims, input)
    }
}
impl<T: NumLimits> From<T> for THVec<T> {
    fn from(input: T) -> Self {
        let v = vec![input];
        THVec::new(vec![1], v)
    }
}
impl<T: NumLimits> From<T> for THVecGeneric {
    fn from(input: T) -> Self {
        let v: Vec<i64> = vec![<i64 as NumCast>::from(input).unwrap()];
        THVecGeneric::new(vec![1], v)
    }
}

#[allow(unused_variables)]
impl<T: NumLimits> From<()> for THVec<T> {
    fn from(input: ()) -> Self {
        THVec::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THVecGeneric {
    fn from(input: ()) -> Self {
        THVecGeneric::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THDims {
    fn from(input: ()) -> Self {
        THDims::new(vec![])
    }
}
impl<T: NumLimits> From<[usize; 2]> for THVec<T> {
    fn from(input: [usize; 2]) -> Self {
        THVec::new(input.to_vec(), vec![])
    }
}
impl<T: NumLimits> From<[usize; 4]> for THVec<T> {
    fn from(input: [usize; 4]) -> Self {
        THVec::new(input.to_vec(), vec![])
    }
}
impl<T: NumLimits> From<(usize, usize)> for THVec<T> {
    fn from(input: (usize, usize)) -> Self {
        THVec::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize, usize)> for THVecGeneric {
    fn from(input: (usize, usize)) -> Self {

        THVecGeneric::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize)> for THVecGeneric {
    fn from(input: (usize)) -> Self {

        THVecGeneric::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<(usize)> for THVec<T> {
    fn from(input: (usize)) -> Self {
        THVec::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<Vec<usize>> for THVec<T> {
    fn from(input: Vec<usize>) -> Self {
        THVec::new(input, vec![])
    }
}
impl From<Vec<usize>> for THVecGeneric {
    fn from(input: Vec<usize>) -> Self {
        THVecGeneric::new(input, vec![])
    }
}
impl From<Vec<usize>> for THDims {
    fn from(input: Vec<usize>) -> Self {
        THDims::new(input)
    }
}
impl<S: NumLimits, D: NumLimits> From<Tensor<S>> for THVec<D> {
    fn from(input: Tensor<S>) -> Self {
        unimplemented!()
    }
}
impl<T: NumLimits> From<Vec<THVec<T>>> for THVec<T> {
    fn from(input: Vec<THVec<T>>) -> Self {
        unimplemented!()
    }
}
impl<S: NumLimits, D: NumLimits> From<Vec<Tensor<S>>> for THVec<D> {
    fn from(input: Vec<Tensor<S>>) -> Self {
        let mut d: Vec<D> = Vec::with_capacity(input.len() * input[0].len());
        let len = input[0].len();
        let mut tmp: Vec<S> = Vec::with_capacity(len);
        unsafe {
            d.set_len(input.len() * input[0].len());
            tmp.set_len(len);
        }
        for i in 0..input.len() {
            input[i].get_storage(&mut tmp, len);
            for j in 0..len {
                unsafe {
                    *(d.get_unchecked_mut(i * len + j)) = <D as ::num::NumCast>::from(tmp[j])
                        .unwrap();
                }
            }
        }
        let mut sizes = input[0].size();
        let mut dims = vec![input.len()];
        dims.append(&mut sizes);
        THVec::new(dims, d)
    }
}
impl From<THVecGeneric> for THVec<u8> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<u8> = input
            .data
            .iter()
            .map(|t| <u8 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<f32> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<f32> = input
            .data
            .iter()
            .map(|t| <f32 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<i64> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<i64> = input
            .data
            .iter()
            .map(|t| <i64 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}

impl<T: NumLimits> From<THVec<T>> for THDims {
    fn from(input: THVec<T>) -> Self {
        THDims::new(input.dims.clone())
    }
}
impl From<THVecGeneric> for THDims {
    fn from(input: THVecGeneric) -> Self {
        THDims::new(input.dims.clone())
    }
}

trait TensorNew<T: NumLimits> {
    fn tensor_new(arg: THDims) -> Tensor<T>;
}

impl<T: NumLimits> TensorNew<T> for Tensor<T> {
    #[allow(unused_variables)]
    default fn tensor_new(arg: THDims) -> Tensor<T> {
        unreachable!()
    }
}

impl TensorNew<u8> for Tensor<u8> {
    fn tensor_new(arg: THDims) -> Tensor<u8> {
        let t = ::RcMutNew(::tensor::ByteTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<i64> for Tensor<i64> {
    fn tensor_new(arg: THDims) -> Tensor<i64> {
        let t = ::RcMutNew(::tensor::LongTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f32> for Tensor<f32> {
    fn tensor_new(arg: THDims) -> Tensor<f32> {
        let t = ::RcMutNew(::tensor::FloatTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f64> for Tensor<f64> {
    fn tensor_new(arg: THDims) -> Tensor<f64> {
        let t = ::RcMutNew(::tensor::DoubleTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}

pub fn byte_tensor<T>(arg: T) -> Tensor<u8>
    where T: Into<THVec<u8>>
{
    tensor(arg)
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64>
    where T: Into<THVec<i64>>
{
    tensor(arg)
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32>
    where T: Into<THVec<f32>>
{
    tensor(arg)
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64>
    where T: Into<THVec<f64>>
{
    tensor(arg)
}
pub fn tensor<S, T>(arg: S) -> Tensor<T>
    where T: NumLimits,
          S: Into<THVec<T>>
{
    let t: THVec<T> = arg.into();
    Tensor::tensor_new(t.into())
}
<commit_msg>set storage on new tensor if data len > 0<commit_after>use tensor::{Tensor, NumLimits, THVec, THVecGeneric, THDims};
use num::NumCast;

impl<T: NumLimits> THVec<T> {
    pub fn new(dims: Vec<usize>, data: Vec<T>) -> Self {
        THVec {
            dims: dims,
            data: data,
        }
    }
}
impl THVecGeneric {
    pub fn new(dims: Vec<usize>, data: Vec<i64>) -> Self {
        THVecGeneric {
            dims: dims,
            data: data,
        }
    }
}
impl THDims {
    fn new(dims: Vec<usize>) -> Self {
        THDims { dims: dims }
    }
}
impl<T: NumLimits> From<Vec<Vec<Vec<T>>>> for THVec<T> {
    fn from(input: Vec<Vec<Vec<T>>>) -> Self {
        let dims = vec![input.len(), input[0].len(), input[0][0].len()];
        let v = input
            .iter()
            .flat_map(|d| d.iter())
            .flat_map(|d| d.iter())
            .map(|d| *d)
            .collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<Vec<T>>> for THVec<T> {
    fn from(input: Vec<Vec<T>>) -> Self {
        let dims = vec![input.len(), input[0].len()];
        let v = input.iter().flat_map(|d| d.iter()).map(|d| *d).collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<T>> for THVec<T> {
    fn from(input: Vec<T>) -> Self {
        let dims = vec![input.len()];
        THVec::new(dims, input)
    }
}
impl<T: NumLimits> From<T> for THVec<T> {
    fn from(input: T) -> Self {
        let v = vec![input];
        THVec::new(vec![1], v)
    }
}
impl<T: NumLimits> From<T> for THVecGeneric {
    fn from(input: T) -> Self {
        let v: Vec<i64> = vec![<i64 as NumCast>::from(input).unwrap()];
        THVecGeneric::new(vec![1], v)
    }
}

#[allow(unused_variables)]
impl<T: NumLimits> From<()> for THVec<T> {
    fn from(input: ()) -> Self {
        THVec::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THVecGeneric {
    fn from(input: ()) -> Self {
        THVecGeneric::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THDims {
    fn from(input: ()) -> Self {
        THDims::new(vec![])
    }
}
impl<T: NumLimits> From<[usize; 2]> for THVec<T> {
    fn from(input: [usize; 2]) -> Self {
        THVec::new(input.to_vec(), vec![])
    }
}
impl<T: NumLimits> From<[usize; 4]> for THVec<T> {
    fn from(input: [usize; 4]) -> Self {
        THVec::new(input.to_vec(), vec![])
    }
}
impl<T: NumLimits> From<(usize, usize)> for THVec<T> {
    fn from(input: (usize, usize)) -> Self {
        THVec::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize, usize)> for THVecGeneric {
    fn from(input: (usize, usize)) -> Self {

        THVecGeneric::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize)> for THVecGeneric {
    fn from(input: (usize)) -> Self {

        THVecGeneric::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<(usize)> for THVec<T> {
    fn from(input: (usize)) -> Self {
        THVec::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<Vec<usize>> for THVec<T> {
    fn from(input: Vec<usize>) -> Self {
        THVec::new(input, vec![])
    }
}
impl From<Vec<usize>> for THVecGeneric {
    fn from(input: Vec<usize>) -> Self {
        THVecGeneric::new(input, vec![])
    }
}
impl From<Vec<usize>> for THDims {
    fn from(input: Vec<usize>) -> Self {
        THDims::new(input)
    }
}
impl<S: NumLimits, D: NumLimits> From<Tensor<S>> for THVec<D> {
    fn from(input: Tensor<S>) -> Self {
        unimplemented!()
    }
}
impl<T: NumLimits> From<Vec<THVec<T>>> for THVec<T> {
    fn from(input: Vec<THVec<T>>) -> Self {
        unimplemented!()
    }
}
impl<S: NumLimits, D: NumLimits> From<Vec<Tensor<S>>> for THVec<D> {
    fn from(input: Vec<Tensor<S>>) -> Self {
        let mut d: Vec<D> = Vec::with_capacity(input.len() * input[0].len());
        let len = input[0].len();
        let mut tmp: Vec<S> = Vec::with_capacity(len);
        unsafe {
            d.set_len(input.len() * input[0].len());
            tmp.set_len(len);
        }
        for i in 0..input.len() {
            input[i].get_storage(&mut tmp, len);
            for j in 0..len {
                unsafe {
                    *(d.get_unchecked_mut(i * len + j)) = <D as ::num::NumCast>::from(tmp[j])
                        .unwrap();
                }
            }
        }
        let mut sizes = input[0].size();
        let mut dims = vec![input.len()];
        dims.append(&mut sizes);
        THVec::new(dims, d)
    }
}
impl From<THVecGeneric> for THVec<u8> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<u8> = input
            .data
            .iter()
            .map(|t| <u8 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<f32> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<f32> = input
            .data
            .iter()
            .map(|t| <f32 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<i64> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<i64> = input
            .data
            .iter()
            .map(|t| <i64 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}

impl<T: NumLimits> From<THVec<T>> for THDims {
    fn from(input: THVec<T>) -> Self {
        THDims::new(input.dims.clone())
    }
}
impl From<THVecGeneric> for THDims {
    fn from(input: THVecGeneric) -> Self {
        THDims::new(input.dims.clone())
    }
}

trait TensorNew<T: NumLimits> {
    fn tensor_new(arg: THDims) -> Tensor<T>;
}

impl<T: NumLimits> TensorNew<T> for Tensor<T> {
    #[allow(unused_variables)]
    default fn tensor_new(arg: THDims) -> Tensor<T> {
        unreachable!()
    }
}

impl TensorNew<u8> for Tensor<u8> {
    fn tensor_new(arg: THDims) -> Tensor<u8> {
        let t = ::RcMutNew(::tensor::ByteTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<i64> for Tensor<i64> {
    fn tensor_new(arg: THDims) -> Tensor<i64> {
        let t = ::RcMutNew(::tensor::LongTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f32> for Tensor<f32> {
    fn tensor_new(arg: THDims) -> Tensor<f32> {
        let t = ::RcMutNew(::tensor::FloatTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f64> for Tensor<f64> {
    fn tensor_new(arg: THDims) -> Tensor<f64> {
        let t = ::RcMutNew(::tensor::DoubleTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}

pub fn byte_tensor<T>(arg: T) -> Tensor<u8>
    where T: Into<THVec<u8>>
{
    tensor(arg)
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64>
    where T: Into<THVec<i64>>
{
    tensor(arg)
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32>
    where T: Into<THVec<f32>>
{
    tensor(arg)
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64>
    where T: Into<THVec<f64>>
{
    tensor(arg)
}
pub fn tensor<S, T>(arg: S) -> Tensor<T>
    where T: NumLimits,
          S: Into<THVec<T>>
{
    let t: THVec<T> = arg.into();
    let dims = t.dims.clone().into();
    let mut out = Tensor::tensor_new(dims);
    if t.data.len() > 0 {
        out.set_storage(t.data);
    }
    out
}
<|endoftext|>


<commit_before>use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    let target = env::var("TARGET").expect("TARGET was not set");

    if cfg!(feature = "llvm-libunwind")
        && ((target.contains("linux") && !target.contains("musl")) || target.contains("fuchsia"))
    {
        // Build the unwinding from libunwind C/C++ source code.
        llvm_libunwind::compile();
    } else if target.contains("linux") {
        if target.contains("musl") {
            // linking for musl is handled in lib.rs
            llvm_libunwind::compile();
        } else if !target.contains("android") {
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("rumprun") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("netbsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("openbsd") {
        if target.contains("sparc64") {
            println!("cargo:rustc-link-lib=gcc");
        } else {
            println!("cargo:rustc-link-lib=c++abi");
        }
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("illumos") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") {
        println!("cargo:rustc-link-lib=gcc_pic");
    } else if target.contains("pc-windows-gnu") {
        // This is handled in the target spec with late_link_args_[static|dynamic]

        // cfg!(bootstrap) doesn't work in build scripts
        if env::var("RUSTC_STAGE").ok() == Some("0".to_string()) {
            println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
            println!("cargo:rustc-link-lib=static-nobundle=pthread");
        }
    } else if target.contains("uwp-windows-gnu") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("haiku") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("redox") {
        // redox is handled in lib.rs
    } else if target.contains("cloudabi") {
        println!("cargo:rustc-link-lib=unwind");
    }
}

mod llvm_libunwind {
    use std::env;
    use std::path::Path;

    /// Compile the libunwind C/C++ source code.
    pub fn compile() {
        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
        let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
        let cfg = &mut cc::Build::new();

        cfg.cpp(true);
        cfg.cpp_set_stdlib(None);
        cfg.warnings(false);

        // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
        if target_endian_little {
            cfg.define("__LITTLE_ENDIAN__", Some("1"));
        }

        if target_env == "msvc" {
            // Don't pull in extra libraries on MSVC
            cfg.flag("/Zl");
            cfg.flag("/EHsc");
            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
        } else {
            cfg.flag("-std=c99");
            cfg.flag("-std=c++11");
            cfg.flag("-nostdinc++");
            cfg.flag("-fno-exceptions");
            cfg.flag("-fno-rtti");
            cfg.flag("-fstrict-aliasing");
            cfg.flag("-funwind-tables");
        }

        let mut unwind_sources = vec![
            "Unwind-EHABI.cpp",
            "Unwind-seh.cpp",
            "Unwind-sjlj.c",
            "UnwindLevel1-gcc-ext.c",
            "UnwindLevel1.c",
            "UnwindRegistersRestore.S",
            "UnwindRegistersSave.S",
            "libunwind.cpp",
        ];

        if target_vendor == "apple" {
            unwind_sources.push("Unwind_AppleExtras.cpp");
        }

        let root = Path::new("../llvm-project/libunwind");
        cfg.include(root.join("include"));
        for src in unwind_sources {
            cfg.file(root.join("src").join(src));
        }

        if target_env == "musl" {
            // use the same C compiler command to compile C++ code so we do not need to setup the
            // C++ compiler env variables on the builders
            cfg.cpp(false);
            // linking for musl is handled in lib.rs
            cfg.cargo_metadata(false);
            println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
        }

        cfg.compile("unwind");
    }
}
<commit_msg>Use -fvisibility=hidden for libunwind<commit_after>use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    let target = env::var("TARGET").expect("TARGET was not set");

    if cfg!(feature = "llvm-libunwind")
        && ((target.contains("linux") && !target.contains("musl")) || target.contains("fuchsia"))
    {
        // Build the unwinding from libunwind C/C++ source code.
        llvm_libunwind::compile();
    } else if target.contains("linux") {
        if target.contains("musl") {
            // linking for musl is handled in lib.rs
            llvm_libunwind::compile();
        } else if !target.contains("android") {
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("rumprun") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("netbsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("openbsd") {
        if target.contains("sparc64") {
            println!("cargo:rustc-link-lib=gcc");
        } else {
            println!("cargo:rustc-link-lib=c++abi");
        }
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("illumos") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") {
        println!("cargo:rustc-link-lib=gcc_pic");
    } else if target.contains("pc-windows-gnu") {
        // This is handled in the target spec with late_link_args_[static|dynamic]

        // cfg!(bootstrap) doesn't work in build scripts
        if env::var("RUSTC_STAGE").ok() == Some("0".to_string()) {
            println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
            println!("cargo:rustc-link-lib=static-nobundle=pthread");
        }
    } else if target.contains("uwp-windows-gnu") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("haiku") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("redox") {
        // redox is handled in lib.rs
    } else if target.contains("cloudabi") {
        println!("cargo:rustc-link-lib=unwind");
    }
}

mod llvm_libunwind {
    use std::env;
    use std::path::Path;

    /// Compile the libunwind C/C++ source code.
    pub fn compile() {
        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
        let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
        let cfg = &mut cc::Build::new();

        cfg.cpp(true);
        cfg.cpp_set_stdlib(None);
        cfg.warnings(false);

        // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
        if target_endian_little {
            cfg.define("__LITTLE_ENDIAN__", Some("1"));
        }

        if target_env == "msvc" {
            // Don't pull in extra libraries on MSVC
            cfg.flag("/Zl");
            cfg.flag("/EHsc");
            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
        } else {
            cfg.flag("-std=c99");
            cfg.flag("-std=c++11");
            cfg.flag("-nostdinc++");
            cfg.flag("-fno-exceptions");
            cfg.flag("-fno-rtti");
            cfg.flag("-fstrict-aliasing");
            cfg.flag("-funwind-tables");
            cfg.flag("-fvisibility=hidden");
        }

        let mut unwind_sources = vec![
            "Unwind-EHABI.cpp",
            "Unwind-seh.cpp",
            "Unwind-sjlj.c",
            "UnwindLevel1-gcc-ext.c",
            "UnwindLevel1.c",
            "UnwindRegistersRestore.S",
            "UnwindRegistersSave.S",
            "libunwind.cpp",
        ];

        if target_vendor == "apple" {
            unwind_sources.push("Unwind_AppleExtras.cpp");
        }

        let root = Path::new("../llvm-project/libunwind");
        cfg.include(root.join("include"));
        for src in unwind_sources {
            cfg.file(root.join("src").join(src));
        }

        if target_env == "musl" {
            // use the same C compiler command to compile C++ code so we do not need to setup the
            // C++ compiler env variables on the builders
            cfg.cpp(false);
            // linking for musl is handled in lib.rs
            cfg.cargo_metadata(false);
            println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
        }

        cfg.compile("unwind");
    }
}
<|endoftext|>


<commit_before>use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    let target = env::var("TARGET").expect("TARGET was not set");

    if cfg!(feature = "llvm-libunwind") &&
        (target.contains("linux") ||
         target.contains("fuchsia")) {
        // Build the unwinding from libunwind C/C++ source code.
        #[cfg(feature = "llvm-libunwind")]
        llvm_libunwind::compile();
    } else if target.contains("linux") {
        if target.contains("musl") {
            // musl is handled in lib.rs
        } else if !target.contains("android") {
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("rumprun") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("netbsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("openbsd") {
        println!("cargo:rustc-link-lib=c++abi");
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") {
        println!("cargo:rustc-link-lib=gcc_pic");
    } else if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("haiku") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("redox") {
        println!("cargo:rustc-link-lib=gcc");
    } else if target.contains("cloudabi") {
        println!("cargo:rustc-link-lib=unwind");
    }
}

#[cfg(feature = "llvm-libunwind")]
mod llvm_libunwind {
    use std::env;
    use std::path::Path;

    /// Compile the libunwind C/C++ source code.
    pub fn compile() {
        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
        let cfg = &mut cc::Build::new();

        cfg.cpp(true);
        cfg.cpp_set_stdlib(None);
        cfg.warnings(false);

        if target_env == "msvc" {
            // Don't pull in extra libraries on MSVC
            cfg.flag("/Zl");
            cfg.flag("/EHsc");
            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
        } else {
            cfg.flag("-std=c99");
            cfg.flag("-std=c++11");
            cfg.flag("-nostdinc++");
            if cfg.is_flag_supported("-funwind-tables").unwrap_or_default() &&
               cfg.is_flag_supported("-fno-exceptions").unwrap_or_default() {
                cfg.flag("-funwind-tables");
                cfg.flag("-fno-exceptions");
            }
            cfg.flag("-fno-rtti");
            cfg.flag("-fstrict-aliasing");
        }

        let mut unwind_sources = vec![
            "Unwind-EHABI.cpp",
            "Unwind-seh.cpp",
            "Unwind-sjlj.c",
            "UnwindLevel1-gcc-ext.c",
            "UnwindLevel1.c",
            "UnwindRegistersRestore.S",
            "UnwindRegistersSave.S",
            "libunwind.cpp",
        ];

        if target_vendor == "apple" {
            unwind_sources.push("Unwind_AppleExtras.cpp");
        }

        let root = Path::new("../llvm-project/libunwind");
        cfg.include(root.join("include"));
        for src in unwind_sources {
            cfg.file(root.join("src").join(src));
        }

        cfg.compile("unwind");
    }
}
<commit_msg>Set -funwind-tables and -fno-exceptions unconditionally for LLVM's libunwind<commit_after>use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    let target = env::var("TARGET").expect("TARGET was not set");

    if cfg!(feature = "llvm-libunwind") &&
        (target.contains("linux") ||
         target.contains("fuchsia")) {
        // Build the unwinding from libunwind C/C++ source code.
        #[cfg(feature = "llvm-libunwind")]
        llvm_libunwind::compile();
    } else if target.contains("linux") {
        if target.contains("musl") {
            // musl is handled in lib.rs
        } else if !target.contains("android") {
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("rumprun") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("netbsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("openbsd") {
        println!("cargo:rustc-link-lib=c++abi");
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") {
        println!("cargo:rustc-link-lib=gcc_pic");
    } else if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("haiku") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("redox") {
        println!("cargo:rustc-link-lib=gcc");
    } else if target.contains("cloudabi") {
        println!("cargo:rustc-link-lib=unwind");
    }
}

#[cfg(feature = "llvm-libunwind")]
mod llvm_libunwind {
    use std::env;
    use std::path::Path;

    /// Compile the libunwind C/C++ source code.
    pub fn compile() {
        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
        let cfg = &mut cc::Build::new();

        cfg.cpp(true);
        cfg.cpp_set_stdlib(None);
        cfg.warnings(false);

        if target_env == "msvc" {
            // Don't pull in extra libraries on MSVC
            cfg.flag("/Zl");
            cfg.flag("/EHsc");
            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
        } else {
            cfg.flag("-std=c99");
            cfg.flag("-std=c++11");
            cfg.flag("-nostdinc++");
            cfg.flag("-fno-exceptions");
            cfg.flag("-fno-rtti");
            cfg.flag("-fstrict-aliasing");
            cfg.flag("-funwind-tables");
        }

        let mut unwind_sources = vec![
            "Unwind-EHABI.cpp",
            "Unwind-seh.cpp",
            "Unwind-sjlj.c",
            "UnwindLevel1-gcc-ext.c",
            "UnwindLevel1.c",
            "UnwindRegistersRestore.S",
            "UnwindRegistersSave.S",
            "libunwind.cpp",
        ];

        if target_vendor == "apple" {
            unwind_sources.push("Unwind_AppleExtras.cpp");
        }

        let root = Path::new("../llvm-project/libunwind");
        cfg.include(root.join("include"));
        for src in unwind_sources {
            cfg.file(root.join("src").join(src));
        }

        cfg.compile("unwind");
    }
}
<|endoftext|>


<commit_before>use hyper::Client;
use hyper::client::Body;
use hyper::client::response::Response;
use discover;
use rustc_serialize::json;
use rustc_serialize::json::Json;
use rustc_serialize::{Decodable};
use errors::HueError;
use errors::AppError;
use regex::Regex;
use std::str::FromStr;

#[derive(Debug,Copy,Clone,RustcDecodable)]
pub struct LightState {
    pub on: bool,
    pub bri: u8,
    pub hue: u16,
    pub sat: u8,
    pub ct: Option<u16>,
}

#[derive(Debug,Clone,RustcDecodable)]
pub struct Light {
    pub name: String,
    pub modelid: String,
    pub swversion: String,
    pub uniqueid: String,
    pub state: LightState,
}

#[derive(Debug,Clone)]
pub struct IdentifiedLight {
    pub id: usize,
    pub light: Light,
}

#[derive(Debug,Clone,Copy,RustcEncodable,RustcDecodable)]
pub struct CommandLight {
    pub on:Option<bool>,
    pub bri:Option<u8>,
    pub hue:Option<u16>,
    pub sat:Option<u8>,
    pub ct:Option<u16>,
    pub transitiontime:Option<u16>,
}

impl CommandLight {
    pub fn empty() -> CommandLight {
        CommandLight { on:None, bri:None, hue:None, sat:None, transitiontime:None, ct:None }
    }
    pub fn on() -> CommandLight {
        CommandLight { on:Some(true), ..CommandLight::empty() }
    }
    pub fn off() -> CommandLight {
        CommandLight { on:Some(false), ..CommandLight::empty() }
    }
    pub fn with_bri(&self, b:u8) -> CommandLight {
        CommandLight { bri:Some(b), ..*self }
    }
    pub fn with_hue(&self, h:u16) -> CommandLight {
        CommandLight { hue:Some(h), ..*self }
    }
    pub fn with_sat(&self, s:u8) -> CommandLight {
        CommandLight { sat:Some(s), ..*self }
    }
    pub fn with_ct(&self, c:u16) -> CommandLight {
        CommandLight { ct:Some(c), ..*self }
    }
}

#[derive(Debug)]
pub struct Bridge {
    ip: String,
    username: Option<String>,
}

impl Bridge {
    #[allow(dead_code)]
    pub fn discover() -> Option<Bridge> {
        discover::discover_hue_bridge().ok().map( |i| Bridge{ ip:i, username:None } )
    }

    pub fn discover_required() -> Bridge {
        Bridge::discover().unwrap_or_else( || panic!("No bridge found!") )
    }

    pub fn with_user(self, username:String) -> Bridge {
        Bridge{ username: Some(username), ..self }
    }

    pub fn register_user(&self, devicetype:&str, username:&str) -> Result<Json,HueError> {
        if username.len() < 10 || username.len() > 40 {
            return HueError::wrap("username must be between 10 and 40 characters")
        }
        #[derive(RustcDecodable, RustcEncodable)]
        struct PostApi {
            devicetype: String,
            username:String
        }
        let obtain = PostApi {
            devicetype:devicetype.to_string(),
            username:username.to_string()
        };
        let body = try!(json::encode(&obtain));
        let client = Client::new();
        let url = format!("http://{}/api", self.ip);
        let mut resp = try!(client.post(&url[..])
            .body(Body::BufBody(body.as_bytes(), body.as_bytes().len())).send());
        self.parse_write_resp(&mut resp)
    }

    pub fn get_all_lights(&self) -> Result<Vec<IdentifiedLight>,HueError> {
        let url = format!("http://{}/api/{}/lights",
            self.ip, self.username.clone().unwrap());
        let client = Client::new();
        let mut resp = try!(client.get(&url[..]).send());
        let json = try!(json::Json::from_reader(&mut resp));
        let json_object = try!(json.as_object().
            ok_or(HueError::ProtocolError("malformed bridge response".to_string())));
        let mut lights:Vec<IdentifiedLight> = try!(
            json_object.iter().map( |(k,v)| -> Result<IdentifiedLight,HueError> {
                let id:usize = try!(usize::from_str(k));
                let mut decoder = json::Decoder::new(v.clone());
                let light = try!(<Light as Decodable>::decode(&mut decoder));
                Ok(IdentifiedLight{ id: id, light: light })
        }).collect());
        lights.sort_by( |a,b| a.id.cmp(&b.id) );
        Ok(lights)
    }

    pub fn set_light_state(&self, light:usize, command:CommandLight) -> Result<Json, HueError> {
        let url = format!("http://{}/api/{}/lights/{}/state",
            self.ip, self.username.clone().unwrap(), light);
        let body = try!(json::encode(&command));
        let re1 = Regex::new("\"[a-z]*\":null").unwrap();
        let cleaned1 = re1.replace_all(&body,"");
        let re2 = Regex::new(",+").unwrap();
        let cleaned2 = re2.replace_all(&cleaned1,",");
        let re3 = Regex::new(",\\}").unwrap();
        let cleaned3 = re3.replace_all(&cleaned2,"}");
        let re3 = Regex::new("\\{,").unwrap();
        let cleaned4 = re3.replace_all(&cleaned3,"{");
        let client = Client::new();
        let mut resp = try!(client.put(&url[..])
            .body(Body::BufBody(cleaned4.as_bytes(), cleaned4.as_bytes().len())).send());
        self.parse_write_resp(&mut resp)
    }

    fn parse_write_resp(&self, resp:&mut Response) -> Result<Json,HueError> {
        let json = try!(json::Json::from_reader(resp));
        let objects = try!(json.as_array()
            .ok_or(HueError::ProtocolError("expected array".to_string())));
        if objects.len() == 0 {
            return Err(HueError::ProtocolError("expected non-empty array".to_string()));
        }
        let object = try!(objects[0].as_object()
            .ok_or(HueError::ProtocolError("expected first item to be an object".to_string())));
        let obj = object.get(&"error".to_string()).and_then( |o| o.as_object() );
        match obj {
            Some(e) => {
                let error = e.clone();
                let mut decoder = json::Decoder::new(json::Json::Object(error));
                let actual_error = try!(AppError::dec(&mut decoder));
                //println!("actual: {:?}",actual_error);
                Err(HueError::BridgeError(actual_error))
            },
            None => Ok(json.clone())
        }
    }
}
<commit_msg>Remove unnecessary &'s<commit_after>use hyper::Client;
use hyper::client::Body;
use hyper::client::response::Response;
use discover;
use rustc_serialize::json;
use rustc_serialize::json::Json;
use rustc_serialize::{Decodable};
use errors::HueError;
use errors::AppError;
use regex::Regex;
use std::str::FromStr;

#[derive(Debug,Copy,Clone,RustcDecodable)]
pub struct LightState {
    pub on: bool,
    pub bri: u8,
    pub hue: u16,
    pub sat: u8,
    pub ct: Option<u16>,
}

#[derive(Debug,Clone,RustcDecodable)]
pub struct Light {
    pub name: String,
    pub modelid: String,
    pub swversion: String,
    pub uniqueid: String,
    pub state: LightState,
}

#[derive(Debug,Clone)]
pub struct IdentifiedLight {
    pub id: usize,
    pub light: Light,
}

#[derive(Debug,Clone,Copy,RustcEncodable,RustcDecodable)]
pub struct CommandLight {
    pub on:Option<bool>,
    pub bri:Option<u8>,
    pub hue:Option<u16>,
    pub sat:Option<u8>,
    pub ct:Option<u16>,
    pub transitiontime:Option<u16>,
}

impl CommandLight {
    pub fn empty() -> CommandLight {
        CommandLight { on:None, bri:None, hue:None, sat:None, transitiontime:None, ct:None }
    }
    pub fn on() -> CommandLight {
        CommandLight { on:Some(true), ..CommandLight::empty() }
    }
    pub fn off() -> CommandLight {
        CommandLight { on:Some(false), ..CommandLight::empty() }
    }
    pub fn with_bri(self, b:u8) -> CommandLight {
        CommandLight { bri:Some(b), ..self }
    }
    pub fn with_hue(self, h:u16) -> CommandLight {
        CommandLight { hue:Some(h), ..self }
    }
    pub fn with_sat(self, s:u8) -> CommandLight {
        CommandLight { sat:Some(s), ..self }
    }
    pub fn with_ct(self, c:u16) -> CommandLight {
        CommandLight { ct:Some(c), ..self }
    }
}

#[derive(Debug)]
pub struct Bridge {
    ip: String,
    username: Option<String>,
}

impl Bridge {
    #[allow(dead_code)]
    pub fn discover() -> Option<Bridge> {
        discover::discover_hue_bridge().ok().map( |i| Bridge{ ip:i, username:None } )
    }

    pub fn discover_required() -> Bridge {
        Bridge::discover().unwrap_or_else( || panic!("No bridge found!") )
    }

    pub fn with_user(self, username:String) -> Bridge {
        Bridge{ username: Some(username), ..self }
    }

    pub fn register_user(&self, devicetype:&str, username:&str) -> Result<Json,HueError> {
        if username.len() < 10 || username.len() > 40 {
            return HueError::wrap("username must be between 10 and 40 characters")
        }
        #[derive(RustcDecodable, RustcEncodable)]
        struct PostApi {
            devicetype: String,
            username:String
        }
        let obtain = PostApi {
            devicetype:devicetype.to_string(),
            username:username.to_string()
        };
        let body = try!(json::encode(&obtain));
        let client = Client::new();
        let url = format!("http://{}/api", self.ip);
        let mut resp = try!(client.post(&url[..])
            .body(Body::BufBody(body.as_bytes(), body.as_bytes().len())).send());
        self.parse_write_resp(&mut resp)
    }

    pub fn get_all_lights(&self) -> Result<Vec<IdentifiedLight>,HueError> {
        let url = format!("http://{}/api/{}/lights",
            self.ip, self.username.clone().unwrap());
        let client = Client::new();
        let mut resp = try!(client.get(&url[..]).send());
        let json = try!(json::Json::from_reader(&mut resp));
        let json_object = try!(json.as_object().
            ok_or(HueError::ProtocolError("malformed bridge response".to_string())));
        let mut lights:Vec<IdentifiedLight> = try!(
            json_object.iter().map( |(k,v)| -> Result<IdentifiedLight,HueError> {
                let id:usize = try!(usize::from_str(k));
                let mut decoder = json::Decoder::new(v.clone());
                let light = try!(<Light as Decodable>::decode(&mut decoder));
                Ok(IdentifiedLight{ id: id, light: light })
        }).collect());
        lights.sort_by( |a,b| a.id.cmp(&b.id) );
        Ok(lights)
    }

    pub fn set_light_state(&self, light:usize, command:CommandLight) -> Result<Json, HueError> {
        let url = format!("http://{}/api/{}/lights/{}/state",
            self.ip, self.username.clone().unwrap(), light);
        let body = try!(json::encode(&command));
        let re1 = Regex::new("\"[a-z]*\":null").unwrap();
        let cleaned1 = re1.replace_all(&body,"");
        let re2 = Regex::new(",+").unwrap();
        let cleaned2 = re2.replace_all(&cleaned1,",");
        let re3 = Regex::new(",\\}").unwrap();
        let cleaned3 = re3.replace_all(&cleaned2,"}");
        let re3 = Regex::new("\\{,").unwrap();
        let cleaned4 = re3.replace_all(&cleaned3,"{");
        let client = Client::new();
        let mut resp = try!(client.put(&url[..])
            .body(Body::BufBody(cleaned4.as_bytes(), cleaned4.as_bytes().len())).send());
        self.parse_write_resp(&mut resp)
    }

    fn parse_write_resp(&self, resp:&mut Response) -> Result<Json,HueError> {
        let json = try!(json::Json::from_reader(resp));
        let objects = try!(json.as_array()
            .ok_or(HueError::ProtocolError("expected array".to_string())));
        if objects.len() == 0 {
            return Err(HueError::ProtocolError("expected non-empty array".to_string()));
        }
        let object = try!(objects[0].as_object()
            .ok_or(HueError::ProtocolError("expected first item to be an object".to_string())));
        let obj = object.get(&"error".to_string()).and_then( |o| o.as_object() );
        match obj {
            Some(e) => {
                let error = e.clone();
                let mut decoder = json::Decoder::new(json::Json::Object(error));
                let actual_error = try!(AppError::dec(&mut decoder));
                //println!("actual: {:?}",actual_error);
                Err(HueError::BridgeError(actual_error))
            },
            None => Ok(json.clone())
        }
    }
}
<|endoftext|>