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

use std::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT |
    event_type::EPOLLERR |
    event_type::EPOLLHUP);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                trace!("New connection received");
                // Create new socket
                match NbetStream::new(stream) {
                    Ok(nb_stream) => {
                        let socket = Socket::new(nb_stream);
                        let socket_ptr;
                        // Add to master list
                        { // Begin Mutex lock
                            let mut guard = match sockets.lock() {
                                Ok(guard) => guard,
                                Err(poisoned) => {
                                    warn!("SocketList Mutex failed, using anyway...");
                                    poisoned.into_inner()
                                }
                            };
                            let socket_list = guard.deref_mut();
                            socket_list.push_back(socket.clone());
                            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
                        } // End Mutex lock

                        // Add to epoll
                        let sfd = socket.raw_fd();
                        let mut event = EpollEvent {
                            data: socket_ptr as u64,
                            events: EVENTS
                        };
                        match epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event) {
                            Ok(()) => {
                                trace!("New socket added to epoll list");
                                trace!("socket.id: {}", socket.id());
                                trace!("epfd: {}", epfd);
                                trace!("fd: {}", sfd);
                            },
                            Err(e) => warn!("Epoll CtrlError during add: {}", e)
                        };
                    }
                    Err(e) => warn!("Error creating nbstream: {}", e)
                }
            }
            Err(e) => warn!("Error encountered during TCP connection: {}", e)
        }
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP | event_type::EPOLLERR;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            trace!("Received drop event");
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd to epoll watch list
                            //
                            // Rust's TcpStream clone method makes use of the F_DUPFD flag
                            // for duplicating file descriptors. This means the fd we just read
                            // from and/or the original fd added to epoll for this stream cannot
                            // be used to MOD, or DEL and ADD again, in order to re-register for
                            // the same events, with the same fd.
                            // The originally added fd is essentially invalid at this point, but
                            // lucky for us, Rust sets the CLOEXEC flag for fds, which means that
                            // the system will clean them up when they go out of scope. Also,
                            // epoll removes fds when the system clears them, so we should be OK
                            // from any internal fd leaks here. All we really care about, is if
                            // we receive the EEXIST from the call. In this case, we must apply
                            // the adjustment as a MOD
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::ADD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    if e == CtlError::EEXIST {
                                        trace!("Fd already exists in epoll, trying ctl::MOD");
                                        match epoll::ctl(t_epfd.clone(), ctl_op::MOD, socketfd,
                                            &mut event) {
                                            Ok(_) => trace!("Socket back in epoll list with mod"),
                                            Err(_) => {
                                                warn!("Error modifying socket in epoll...")
                                            }
                                        };
                                    } else {
                                        warn!("Epoll CtrlError during mod: {}", e);
                                        warn!("s.id: {}", s_id);
                                        warn!("epfd: {}", t_epfd.clone());
                                        warn!("fd: {}", socketfd);
                                    }
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<commit_msg>Refactored epolloop::listen function<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT |
    event_type::EPOLLERR |
    event_type::EPOLLHUP);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for connection in listener.incoming() {
        if connection.is_err() {
            warn!("Error encountered during TCP connection: {}", connection.unwrap_err());
            continue;
        }

        let result = NbetStream::new(connection.unwrap());
        if result.is_err() {
            warn!("Error creating nbstream: {:?}", result.unwrap_err());
            continue;
        }

        let socket_ptr;
        let socket = Socket::new(result.unwrap());
        { // Begin Mutex lock
            let mut guard = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            let socket_list = guard.deref_mut();
            socket_list.push_back(socket.clone());
            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
        } // End Mutex lock

        // Add to epoll
        let sfd = socket.raw_fd();
        let mut event = EpollEvent {
            data: socket_ptr as u64,
            events: EVENTS
        };
        let _ = epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event).map_err(|e| {
            error!("CtrlError during add: {}", e);
        });
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP | event_type::EPOLLERR;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            trace!("Received drop event");
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd to epoll watch list
                            //
                            // Rust's TcpStream clone method makes use of the F_DUPFD flag
                            // for duplicating file descriptors. This means the fd we just read
                            // from and/or the original fd added to epoll for this stream cannot
                            // be used to MOD, or DEL and ADD again, in order to re-register for
                            // the same events, with the same fd.
                            // The originally added fd is essentially invalid at this point, but
                            // lucky for us, Rust sets the CLOEXEC flag for fds, which means that
                            // the system will clean them up when they go out of scope. Also,
                            // epoll removes fds when the system clears them, so we should be OK
                            // from any internal fd leaks here. All we really care about, is if
                            // we receive the EEXIST from the call. In this case, we must apply
                            // the adjustment as a MOD
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::ADD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    if e == CtlError::EEXIST {
                                        trace!("Fd already exists in epoll, trying ctl::MOD");
                                        match epoll::ctl(t_epfd.clone(), ctl_op::MOD, socketfd,
                                            &mut event) {
                                            Ok(_) => trace!("Socket back in epoll list with mod"),
                                            Err(_) => {
                                                warn!("Error modifying socket in epoll...")
                                            }
                                        };
                                    } else {
                                        warn!("Epoll CtrlError during mod: {}", e);
                                        warn!("s.id: {}", s_id);
                                        warn!("epfd: {}", t_epfd.clone());
                                        warn!("fd: {}", socketfd);
                                    }
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::ffi::OsString;

use common::ui::UI;
use hcore::crypto::CACHE_KEY_PATH_ENV_VAR;
use hcore::env as henv;
use hcore::fs::CACHE_KEY_PATH;
use hcore::os::users;

use config;
use error::Result;

pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
    // If the `$HAB_ORIGIN` environment variable is not present, then see if a default is set in
    // the CLI config. If so, set it as the `$HAB_ORIGIN` environment variable for the `hab-studio`
    // or `docker` execv call.
    if henv::var("HAB_ORIGIN").is_err() {
        let config = try!(config::load_with_sudo_user());
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    // If the `$HAB_CACHE_KEY_PATH` environment variable is not present, check if we are running
    // under a `sudo` invocation. If so, determine the non-root user that issued the command in
    // order to set their key cache location in the environment variable. This is done so that the
    // `hab-studio` command will find the correct key cache or so that the correct directory will
    // be volume mounted when used with Docker.
    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        if let Some(sudo_user) = henv::sudo_user() {
            if let Some(home) = users::get_home_for_user(&sudo_user) {
                let cache_key_path = home.join(format!(".{}", CACHE_KEY_PATH));
                debug!("Setting cache_key_path for SUDO_USER={} to: {}",
                       &sudo_user,
                       cache_key_path.display());
                env::set_var(CACHE_KEY_PATH_ENV_VAR, cache_key_path);
                // Prevent any inner `hab` invocations from triggering similar logic: we will be
                // operating in the context `hab-studio` which is running with rootlike privileges.
                env::remove_var("SUDO_USER");
            }
        }
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use common::ui::UI;
    use hcore::crypto::{init, default_cache_key_path};
    use hcore::env as henv;
    use hcore::fs::find_command;
    use hcore::package::PackageIdent;

    use error::{Error, Result};
    use exec;

    const STUDIO_CMD: &'static str = "hab-studio";
    const STUDIO_CMD_ENVVAR: &'static str = "HAB_STUDIO_BINARY";
    const STUDIO_PACKAGE_IDENT: &'static str = "core/hab-studio";

    pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let command = match henv::var(STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let ident = try!(PackageIdent::from_str(STUDIO_PACKAGE_IDENT));
                try!(exec::command_from_pkg(ui,
                                            STUDIO_CMD,
                                            &ident,
                                            &default_cache_key_path(None),
                                            0))
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            try!(exec::exec_command(cmd, args));
        } else {
            return Err(Error::ExecCommandNotFound(command.to_string_lossy().into_owned()));
        }
        Ok(())
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use std::env;
    use std::ffi::OsString;

    use common::ui::UI;
    use hcore::crypto::default_cache_key_path;
    use hcore::env as henv;
    use hcore::fs::{CACHE_KEY_PATH, find_command};

    use VERSION;
    use error::{Error, Result};
    use exec;

    const DOCKER_CMD: &'static str = "docker";
    const DOCKER_CMD_ENVVAR: &'static str = "HAB_DOCKER_BINARY";

    const DOCKER_IMAGE: &'static str = "habitat-docker-registry.bintray.io/studio";
    const DOCKER_IMAGE_ENVVAR: &'static str = "HAB_DOCKER_STUDIO_IMAGE";

    pub fn start(_ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let docker = henv::var(DOCKER_CMD_ENVVAR).unwrap_or(DOCKER_CMD.to_string());
        let image = henv::var(DOCKER_IMAGE_ENVVAR)
            .unwrap_or(format!("{}:{}", DOCKER_IMAGE, VERSION));

        let cmd = match find_command(&docker) {
            Some(cmd) => cmd,
            None => return Err(Error::ExecCommandNotFound(docker.to_string())),
        };

        let mut cmd_args: Vec<OsString> = vec!["run".into(),
                                               "--rm".into(),
                                               "--tty".into(),
                                               "--interactive".into(),
                                               "--privileged".into()];
        let env_vars = vec!["HAB_DEPOT_URL", "HAB_ORIGIN", "http_proxy", "https_proxy"];
        for var in env_vars {
            if let Ok(val) = henv::var(var) {
                debug!("Propagating environment variable into container: {}={}",
                       var,
                       val);
                cmd_args.push("--env".into());
                cmd_args.push(format!("{}={}", var, val).into());
            }
        }
        cmd_args.push("--volume".into());
        cmd_args.push("/var/run/docker.sock:/var/run/docker.sock".into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/{}",
                              default_cache_key_path(None).to_string_lossy(),
                              CACHE_KEY_PATH)
            .into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/src", env::current_dir().unwrap().to_string_lossy()).into());
        cmd_args.push(image.into());
        cmd_args.extend_from_slice(args.as_slice());

        for var in vec!["http_proxy", "https_proxy"] {
            if let Ok(_) = henv::var(var) {
                debug!("Unsetting proxy environment variable '{}' before calling `{}'",
                       var,
                       docker);
                env::remove_var(var);
            }
        }

        exec::exec_command(cmd, cmd_args)
    }
}
<commit_msg>Fix issue entering studios in release versions of hab<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::ffi::OsString;

use common::ui::UI;
use hcore::crypto::CACHE_KEY_PATH_ENV_VAR;
use hcore::env as henv;
use hcore::fs::CACHE_KEY_PATH;
use hcore::os::users;

use config;
use error::Result;
use VERSION;

pub const DOCKER_IMAGE: &'static str = "habitat-docker-registry.bintray.io/studio";
const DOCKER_CMD: &'static str = "docker";
const DOCKER_CMD_ENVVAR: &'static str = "HAB_DOCKER_BINARY";
const DOCKER_IMAGE_ENVVAR: &'static str = "HAB_DOCKER_STUDIO_IMAGE";

pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
    // If the `$HAB_ORIGIN` environment variable is not present, then see if a default is set in
    // the CLI config. If so, set it as the `$HAB_ORIGIN` environment variable for the `hab-studio`
    // or `docker` execv call.
    if henv::var("HAB_ORIGIN").is_err() {
        let config = try!(config::load_with_sudo_user());
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    // If the `$HAB_CACHE_KEY_PATH` environment variable is not present, check if we are running
    // under a `sudo` invocation. If so, determine the non-root user that issued the command in
    // order to set their key cache location in the environment variable. This is done so that the
    // `hab-studio` command will find the correct key cache or so that the correct directory will
    // be volume mounted when used with Docker.
    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        if let Some(sudo_user) = henv::sudo_user() {
            if let Some(home) = users::get_home_for_user(&sudo_user) {
                let cache_key_path = home.join(format!(".{}", CACHE_KEY_PATH));
                debug!("Setting cache_key_path for SUDO_USER={} to: {}",
                       &sudo_user,
                       cache_key_path.display());
                env::set_var(CACHE_KEY_PATH_ENV_VAR, cache_key_path);
                // Prevent any inner `hab` invocations from triggering similar logic: we will be
                // operating in the context `hab-studio` which is running with rootlike privileges.
                env::remove_var("SUDO_USER");
            }
        }
    }

    inner::start(ui, args)
}

/// Retrieves the
pub fn image_identifier() -> String {
    let version: Vec<&str> = VERSION.split("/").collect();
    henv::var(DOCKER_IMAGE_ENVVAR).unwrap_or(format!("{}:{}", DOCKER_IMAGE, version[0]))
}

#[cfg(test)]
mod tests {
    use super::*;
    use VERSION;

    #[test]
    fn retrieve_image_identifier() {
        assert_eq!(image_identifier(), format!("{}:{}", DOCKER_IMAGE, VERSION));
    }
}

#[cfg(target_os = "linux")]
mod inner {
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use common::ui::UI;
    use hcore::crypto::{init, default_cache_key_path};
    use hcore::env as henv;
    use hcore::fs::find_command;
    use hcore::package::PackageIdent;

    use error::{Error, Result};
    use exec;

    const STUDIO_CMD: &'static str = "hab-studio";
    const STUDIO_CMD_ENVVAR: &'static str = "HAB_STUDIO_BINARY";
    const STUDIO_PACKAGE_IDENT: &'static str = "core/hab-studio";

    pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let command = match henv::var(STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let ident = try!(PackageIdent::from_str(STUDIO_PACKAGE_IDENT));
                try!(exec::command_from_pkg(ui,
                                            STUDIO_CMD,
                                            &ident,
                                            &default_cache_key_path(None),
                                            0))
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            try!(exec::exec_command(cmd, args));
        } else {
            return Err(Error::ExecCommandNotFound(command.to_string_lossy().into_owned()));
        }
        Ok(())
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use std::env;
    use std::ffi::OsString;

    use common::ui::UI;
    use hcore::crypto::default_cache_key_path;
    use hcore::env as henv;
    use hcore::fs::{CACHE_KEY_PATH, find_command};

    use error::{Error, Result};
    use exec;
    use super::{DOCKER_CMD, DOCKER_CMD_ENVVAR, image_identifier};

    pub fn start(_ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let docker = henv::var(DOCKER_CMD_ENVVAR).unwrap_or(DOCKER_CMD.to_string());

        let cmd = match find_command(&docker) {
            Some(cmd) => cmd,
            None => return Err(Error::ExecCommandNotFound(docker.to_string())),
        };

        let mut cmd_args: Vec<OsString> = vec!["run".into(),
                                               "--rm".into(),
                                               "--tty".into(),
                                               "--interactive".into(),
                                               "--privileged".into()];
        let env_vars = vec!["HAB_DEPOT_URL", "HAB_ORIGIN", "http_proxy", "https_proxy"];
        for var in env_vars {
            if let Ok(val) = henv::var(var) {
                debug!("Propagating environment variable into container: {}={}",
                       var,
                       val);
                cmd_args.push("--env".into());
                cmd_args.push(format!("{}={}", var, val).into());
            }
        }
        cmd_args.push("--volume".into());
        cmd_args.push("/var/run/docker.sock:/var/run/docker.sock".into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/{}",
                              default_cache_key_path(None).to_string_lossy(),
                              CACHE_KEY_PATH)
            .into());
        cmd_args.push("--volume".into());
        cmd_args.push(format!("{}:/src", env::current_dir().unwrap().to_string_lossy()).into());
        cmd_args.push(image_identifier().into());
        cmd_args.extend_from_slice(args.as_slice());

        for var in vec!["http_proxy", "https_proxy"] {
            if let Ok(_) = henv::var(var) {
                debug!("Unsetting proxy environment variable '{}' before calling `{}'",
                       var,
                       docker);
                env::remove_var(var);
            }
        }

        exec::exec_command(cmd, cmd_args)
    }
}
<|endoftext|>


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

use smallvec::SmallVec;
use webgpu::wgpu::{
    hub::IdentityManager,
    id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
    Backend,
};

#[derive(Debug)]
pub struct IdentityHub {
    adapters: IdentityManager,
    devices: IdentityManager,
    buffers: IdentityManager,
    bind_group_layouts: IdentityManager,
    pipeline_layouts: IdentityManager,
    backend: Backend,
}

impl IdentityHub {
    fn new(backend: Backend) -> Self {
        IdentityHub {
            adapters: IdentityManager::default(),
            devices: IdentityManager::default(),
            buffers: IdentityManager::default(),
            bind_group_layouts: IdentityManager::default(),
            pipeline_layouts: IdentityManager::default(),
            backend,
        }
    }

    fn create_adapter_id(&mut self) -> AdapterId {
        self.adapters.alloc(self.backend)
    }

    fn create_device_id(&mut self) -> DeviceId {
        self.devices.alloc(self.backend)
    }

    fn create_buffer_id(&mut self) -> BufferId {
        self.buffers.alloc(self.backend)
    }

    fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
        self.bind_group_layouts.alloc(self.backend)
    }

    fn create_pipeline_layout_id(&mut self) -> PipelineLayoutId {
        self.pipeline_layouts.alloc(self.backend)
    }
}

#[derive(Debug)]
pub struct Identities {
    surface: IdentityManager,
    #[cfg(any(target_os = "linux", target_os = "windows"))]
    vk_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx12_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx11_hub: IdentityHub,
    #[cfg(any(target_os = "ios", target_os = "macos"))]
    metal_hub: IdentityHub,
    dummy_hub: IdentityHub,
}

impl Identities {
    pub fn new() -> Self {
        Identities {
            surface: IdentityManager::default(),
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            vk_hub: IdentityHub::new(Backend::Vulkan),
            #[cfg(target_os = "windows")]
            dx12_hub: IdentityHub::new(Backend::Dx12),
            #[cfg(target_os = "windows")]
            dx11_hub: IdentityHub::new(Backend::Dx11),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            metal_hub: IdentityHub::new(Backend::Metal),
            dummy_hub: IdentityHub::new(Backend::Empty),
        }
    }

    fn hubs(&mut self) -> Vec<&mut IdentityHub> {
        vec![
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            &mut self.vk_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx12_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx11_hub,
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            &mut self.metal_hub,
            &mut self.dummy_hub,
        ]
    }

    pub fn create_device_id(&mut self, backend: Backend) -> DeviceId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_device_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_device_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_device_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_device_id(),
            _ => self.dummy_hub.create_device_id(),
        }
    }

    pub fn create_adapter_ids(&mut self) -> SmallVec<[AdapterId; 4]> {
        let mut ids = SmallVec::new();
        for hub in self.hubs() {
            ids.push(hub.create_adapter_id())
        }
        ids
    }

    pub fn create_buffer_id(&mut self, backend: Backend) -> BufferId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_buffer_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_buffer_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_buffer_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_buffer_id(),
            _ => self.dummy_hub.create_buffer_id(),
        }
    }

    pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_bind_group_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_bind_group_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_bind_group_layout_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_bind_group_layout_id(),
            _ => self.dummy_hub.create_bind_group_layout_id(),
        }
    }

    pub fn create_pipeline_layout_id(&mut self, backend: Backend) -> PipelineLayoutId {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => self.vk_hub.create_pipeline_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx12 => self.dx12_hub.create_pipeline_layout_id(),
            #[cfg(target_os = "windows")]
            Backend::Dx11 => self.dx11_hub.create_pipeline_layout_id(),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => self.metal_hub.create_pipeline_layout_id(),
            _ => self.dummy_hub.create_pipeline_layout_id(),
        }
    }
}
<commit_msg>Auto merge of #25648 - szeged:identity_backend_select, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use smallvec::SmallVec;
use webgpu::wgpu::{
    hub::IdentityManager,
    id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
    Backend,
};

#[derive(Debug)]
pub struct IdentityHub {
    adapters: IdentityManager,
    devices: IdentityManager,
    buffers: IdentityManager,
    bind_group_layouts: IdentityManager,
    pipeline_layouts: IdentityManager,
    backend: Backend,
}

impl IdentityHub {
    fn new(backend: Backend) -> Self {
        IdentityHub {
            adapters: IdentityManager::default(),
            devices: IdentityManager::default(),
            buffers: IdentityManager::default(),
            bind_group_layouts: IdentityManager::default(),
            pipeline_layouts: IdentityManager::default(),
            backend,
        }
    }

    fn create_adapter_id(&mut self) -> AdapterId {
        self.adapters.alloc(self.backend)
    }

    fn create_device_id(&mut self) -> DeviceId {
        self.devices.alloc(self.backend)
    }

    fn create_buffer_id(&mut self) -> BufferId {
        self.buffers.alloc(self.backend)
    }

    fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
        self.bind_group_layouts.alloc(self.backend)
    }

    fn create_pipeline_layout_id(&mut self) -> PipelineLayoutId {
        self.pipeline_layouts.alloc(self.backend)
    }
}

#[derive(Debug)]
pub struct Identities {
    surface: IdentityManager,
    #[cfg(any(target_os = "linux", target_os = "windows"))]
    vk_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx12_hub: IdentityHub,
    #[cfg(target_os = "windows")]
    dx11_hub: IdentityHub,
    #[cfg(any(target_os = "ios", target_os = "macos"))]
    metal_hub: IdentityHub,
    dummy_hub: IdentityHub,
}

impl Identities {
    pub fn new() -> Self {
        Identities {
            surface: IdentityManager::default(),
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            vk_hub: IdentityHub::new(Backend::Vulkan),
            #[cfg(target_os = "windows")]
            dx12_hub: IdentityHub::new(Backend::Dx12),
            #[cfg(target_os = "windows")]
            dx11_hub: IdentityHub::new(Backend::Dx11),
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            metal_hub: IdentityHub::new(Backend::Metal),
            dummy_hub: IdentityHub::new(Backend::Empty),
        }
    }

    fn select(&mut self, backend: Backend) -> &mut IdentityHub {
        match backend {
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            Backend::Vulkan => &mut self.vk_hub,
            #[cfg(target_os = "windows")]
            Backend::Dx12 => &mut self.dx12_hub,
            #[cfg(target_os = "windows")]
            Backend::Dx11 => &mut self.dx11_hub,
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            Backend::Metal => &mut self.metal_hub,
            _ => &mut self.dummy_hub,
        }
    }

    fn hubs(&mut self) -> Vec<&mut IdentityHub> {
        vec![
            #[cfg(any(target_os = "linux", target_os = "windows"))]
            &mut self.vk_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx12_hub,
            #[cfg(target_os = "windows")]
            &mut self.dx11_hub,
            #[cfg(any(target_os = "ios", target_os = "macos"))]
            &mut self.metal_hub,
            &mut self.dummy_hub,
        ]
    }

    pub fn create_device_id(&mut self, backend: Backend) -> DeviceId {
        self.select(backend).create_device_id()
    }

    pub fn create_adapter_ids(&mut self) -> SmallVec<[AdapterId; 4]> {
        let mut ids = SmallVec::new();
        for hub in self.hubs() {
            ids.push(hub.create_adapter_id())
        }
        ids
    }

    pub fn create_buffer_id(&mut self, backend: Backend) -> BufferId {
        self.select(backend).create_buffer_id()
    }

    pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
        self.select(backend).create_bind_group_layout_id()
    }

    pub fn create_pipeline_layout_id(&mut self, backend: Backend) -> PipelineLayoutId {
        self.select(backend).create_pipeline_layout_id()
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::convert::TryFrom;
use std::fmt;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Span {
    pub start: u32,
    pub end: u32,
}

impl Span {
    pub fn empty() -> Self {
        Self { start: 0, end: 0 }
    }

    pub fn new(start: u32, end: u32) -> Self {
        debug_assert!(start <= end);
        Self { start, end }
    }

    pub fn from_usize(start: usize, end: usize) -> Self {
        Self::new(u32::try_from(start).unwrap(), u32::try_from(end).unwrap())
    }

    pub fn as_usize(self) -> (usize, usize) {
        (self.start as usize, self.end as usize)
    }

    pub fn contains(self, subspan: Span) -> bool {
        subspan.start >= self.start && subspan.start < self.end && subspan.end <= self.end
    }

    pub fn to_range(
        self,
        source: &str,
        line_offset: usize,
        character_offset: usize,
    ) -> lsp_types::Range {
        let start = self.start as usize;
        let end = self.end as usize;
        // Zero-indexed line offset in the document
        let mut line = line_offset;
        // Zero-indexed character offset on the line
        let mut character = character_offset;
        let mut start_position = lsp_types::Position::default();
        let mut end_position = lsp_types::Position::default();
        let mut chars = source.chars().enumerate().peekable();

        while let Some((index, chr)) = chars.next() {
            let is_newline = match chr {
                // Line terminators: https://www.ecma-international.org/ecma-262/#sec-line-terminators
                '\u{000A}' | '\u{000D}' | '\u{2028}' | '\u{2029}' => match (chr, chars.peek()) {
                    // <CLRF>
                    ('\u{000D}', Some((_, '\u{000D}'))) => false,
                    _ => true,
                },
                _ => false,
            };

            if is_newline {
                // New line, increment the line offset and reset the
                // character offset.
                line += 1;
                character = 0;
            }
            if index == start {
                start_position = lsp_types::Position::new(line as u64, character as u64);
            }
            if index == end {
                end_position = lsp_types::Position::new(line as u64, character as u64);
                break;
            }
            // Make sure to only increment the character offset if this
            // isn't a newline.
            if !is_newline {
                character += 1;
            }
        }
        lsp_types::Range::new(start_position, end_position)
    }
}

impl fmt::Debug for Span {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{}:{}", self.start, self.end)
    }
}

impl From<std::ops::Range<usize>> for Span {
    fn from(range: std::ops::Range<usize>) -> Self {
        Span::from_usize(range.start, range.end)
    }
}

#[cfg(test)]
mod test {
    use super::Span;
    #[test]
    fn span_contains() {
        let outer_span = Span::new(1, 10);
        let overflow_right_start_span = Span::new(10, 10);
        let overflow_right_end_span = Span::new(1, 11);
        let overflow_left_span_start = Span::new(0, 10);

        assert!(outer_span.contains(outer_span), "A span contains itself");
        assert!(
            !outer_span.contains(overflow_right_start_span),
            "A span doesn't contain a subspan whose start is equal to the end of the current span"
        );
        assert!(
            !outer_span.contains(overflow_right_end_span),
            "A span doesn't contain a subspan whose end is greater than the end of the current span"
        );
        assert!(
            !outer_span.contains(overflow_left_span_start),
            "A span doesn't contain a subspan whose start is less than the start of the current span",
        );
    }
}
<commit_msg>Fix clippy errors in common<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::convert::TryFrom;
use std::fmt;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Span {
    pub start: u32,
    pub end: u32,
}

impl Span {
    pub fn empty() -> Self {
        Self { start: 0, end: 0 }
    }

    pub fn new(start: u32, end: u32) -> Self {
        debug_assert!(start <= end);
        Self { start, end }
    }

    pub fn from_usize(start: usize, end: usize) -> Self {
        Self::new(u32::try_from(start).unwrap(), u32::try_from(end).unwrap())
    }

    pub fn as_usize(self) -> (usize, usize) {
        (self.start as usize, self.end as usize)
    }

    // clippy suggest to use `subspan.start < self.start` :-)
    #[allow(clippy::suspicious_operation_groupings)]
    pub fn contains(self, subspan: Span) -> bool {
        subspan.start >= self.start && subspan.start < self.end && subspan.end <= self.end
    }

    pub fn to_range(
        self,
        source: &str,
        line_offset: usize,
        character_offset: usize,
    ) -> lsp_types::Range {
        let start = self.start as usize;
        let end = self.end as usize;
        // Zero-indexed line offset in the document
        let mut line = line_offset;
        // Zero-indexed character offset on the line
        let mut character = character_offset;
        let mut start_position = lsp_types::Position::default();
        let mut end_position = lsp_types::Position::default();
        let mut chars = source.chars().enumerate().peekable();

        while let Some((index, chr)) = chars.next() {
            let is_newline = match chr {
                // Line terminators: https://www.ecma-international.org/ecma-262/#sec-line-terminators
                '\u{000A}' | '\u{000D}' | '\u{2028}' | '\u{2029}' => {
                    // <CLRF>
                    !matches!((chr, chars.peek()), ('\u{000D}', Some((_, '\u{000D}'))))
                }
                _ => false,
            };

            if is_newline {
                // New line, increment the line offset and reset the
                // character offset.
                line += 1;
                character = 0;
            }
            if index == start {
                start_position = lsp_types::Position::new(line as u64, character as u64);
            }
            if index == end {
                end_position = lsp_types::Position::new(line as u64, character as u64);
                break;
            }
            // Make sure to only increment the character offset if this
            // isn't a newline.
            if !is_newline {
                character += 1;
            }
        }
        lsp_types::Range::new(start_position, end_position)
    }
}

impl fmt::Debug for Span {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{}:{}", self.start, self.end)
    }
}

impl From<std::ops::Range<usize>> for Span {
    fn from(range: std::ops::Range<usize>) -> Self {
        Span::from_usize(range.start, range.end)
    }
}

#[cfg(test)]
mod test {
    use super::Span;
    #[test]
    fn span_contains() {
        let outer_span = Span::new(1, 10);
        let overflow_right_start_span = Span::new(10, 10);
        let overflow_right_end_span = Span::new(1, 11);
        let overflow_left_span_start = Span::new(0, 10);

        assert!(outer_span.contains(outer_span), "A span contains itself");
        assert!(
            !outer_span.contains(overflow_right_start_span),
            "A span doesn't contain a subspan whose start is equal to the end of the current span"
        );
        assert!(
            !outer_span.contains(overflow_right_end_span),
            "A span doesn't contain a subspan whose end is greater than the end of the current span"
        );
        assert!(
            !outer_span.contains(overflow_left_span_start),
            "A span doesn't contain a subspan whose start is less than the start of the current span",
        );
    }
}
<|endoftext|>


<commit_before>use theme::theme::{Theme, ParseThemeError};
use theme::settings::*;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::io::{Error as IoError, BufReader};
use walkdir::WalkDir;
use std::io::{self};
use std::fs::File;
use walkdir;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThemeSet {
  themes: BTreeMap<String, Theme>,
}

#[derive(Debug)]
pub enum ThemeSetError {
    WalkDir(walkdir::Error),
    Io(io::Error),
    ParseTheme(ParseThemeError),
    ReadSettings(SettingsError),
}

impl From<SettingsError> for ThemeSetError {
    fn from(error: SettingsError) -> ThemeSetError {
        ThemeSetError::ReadSettings(error)
    }
}

impl From<IoError> for ThemeSetError {
    fn from(error: IoError) -> ThemeSetError {
        ThemeSetError::Io(error)
    }
}

impl From<ParseThemeError> for ThemeSetError {
    fn from(error: ParseThemeError) -> ThemeSetError {
        ThemeSetError::ParseTheme(error)
    }
}

impl ThemeSet {
    /// Returns all the themes found in a folder, good for enumerating before loading one with get_theme
    pub fn discover_theme_paths<P: AsRef<Path>>(folder: P) -> Result<Vec<PathBuf>, ThemeSetError> {
      let mut themes = Vec::new();
      for entry in WalkDir::new(folder) {
          let entry = try!(entry.map_err(|e| ThemeSetError::WalkDir(e)));
          if entry.path().extension().map(|e| e == "tmTheme").unwrap_or(false) {
              themes.push(entry.path().to_owned());
          }
      }
      Ok(themes)
    }

    fn read_file(path: &Path) -> Result<BufReader<File>, ThemeSetError> {
      let reader = try!(File::open(path));
      Ok(BufReader::new(reader))
    }

    fn read_plist(path: &Path) -> Result<Settings, ThemeSetError> {
      Ok(try!(read_plist(try!(Self::read_file(path)))))
    }

    /// Loads a theme given a path to a .tmTheme file
    pub fn get_theme<P: AsRef<Path>>(path: P) -> Result<Theme, ThemeSetError> {
      Ok(try!(Theme::parse_settings(try!(Self::read_plist(path.as_ref())))))
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn can_parse_common_themes() {
        use theme_set::ThemeSet;
        use theme::style::Color;
        let theme_paths = ThemeSet::discover_theme_paths("testdata/themes.tmbundle").unwrap();
        for theme_path in theme_paths.iter() {
            println!("{:?}", theme_path);
            ThemeSet::get_theme(theme_path).unwrap();
        }

        let theme = ThemeSet::get_theme("testdata/themes.tmbundle/Themes/Amy.tmTheme").unwrap();
        assert_eq!(theme.name.unwrap(), "Amy");
        assert_eq!(theme.settings.selection.unwrap(),
                   Color {
                       r: 0x80,
                       g: 0x00,
                       b: 0x00,
                       a: 0x80,
                   });
        assert_eq!(theme.scopes[0].style.foreground.unwrap(),
                   Color {
                       r: 0x40,
                       g: 0x40,
                       b: 0x80,
                       a: 0xFF,
                   });
        // assert!(false);
    }
}
<commit_msg>Load all themes in folder<commit_after>use theme::theme::{Theme, ParseThemeError};
use theme::settings::*;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::io::{Error as IoError, BufReader};
use walkdir::WalkDir;
use std::io::{self};
use std::fs::File;
use walkdir;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThemeSet {
  themes: BTreeMap<String, Theme>,
}

#[derive(Debug)]
pub enum ThemeSetError {
    WalkDir(walkdir::Error),
    Io(io::Error),
    ParseTheme(ParseThemeError),
    ReadSettings(SettingsError),
    BadPath,
}

impl From<SettingsError> for ThemeSetError {
    fn from(error: SettingsError) -> ThemeSetError {
        ThemeSetError::ReadSettings(error)
    }
}

impl From<IoError> for ThemeSetError {
    fn from(error: IoError) -> ThemeSetError {
        ThemeSetError::Io(error)
    }
}

impl From<ParseThemeError> for ThemeSetError {
    fn from(error: ParseThemeError) -> ThemeSetError {
        ThemeSetError::ParseTheme(error)
    }
}

impl ThemeSet {
    /// Returns all the themes found in a folder, good for enumerating before loading one with get_theme
    pub fn discover_theme_paths<P: AsRef<Path>>(folder: P) -> Result<Vec<PathBuf>, ThemeSetError> {
      let mut themes = Vec::new();
      for entry in WalkDir::new(folder) {
          let entry = try!(entry.map_err(|e| ThemeSetError::WalkDir(e)));
          if entry.path().extension().map(|e| e == "tmTheme").unwrap_or(false) {
              themes.push(entry.path().to_owned());
          }
      }
      Ok(themes)
    }

    fn read_file(path: &Path) -> Result<BufReader<File>, ThemeSetError> {
      let reader = try!(File::open(path));
      Ok(BufReader::new(reader))
    }

    fn read_plist(path: &Path) -> Result<Settings, ThemeSetError> {
      Ok(try!(read_plist(try!(Self::read_file(path)))))
    }

    /// Loads a theme given a path to a .tmTheme file
    pub fn get_theme<P: AsRef<Path>>(path: P) -> Result<Theme, ThemeSetError> {
      Ok(try!(Theme::parse_settings(try!(Self::read_plist(path.as_ref())))))
    }

    /// Loads all the themes in a folder
    pub fn load_from_folder<P: AsRef<Path>>(folder: P) -> Result<ThemeSet, ThemeSetError> {
        let paths = try!(Self::discover_theme_paths(folder));
        let mut map = BTreeMap::new();
        for p in paths.iter() {
            let theme = try!(Self::get_theme(p));
            let basename = try!(p.file_stem().and_then(|x| x.to_str()).ok_or(ThemeSetError::BadPath));
            map.insert(basename.to_owned(), theme);
        }
        Ok(ThemeSet { themes: map })
    }
}

#[cfg(test)]
mod tests {
    use theme_set::ThemeSet;
    #[test]
    fn can_parse_common_themes() {
        use theme::style::Color;
        let themes = ThemeSet::load_from_folder("testdata").unwrap();
        let all_themes: Vec<&str> = themes.themes.keys().map(|x| &**x).collect();
        println!("{:?}", all_themes);

        let theme = ThemeSet::get_theme("testdata/themes.tmbundle/Themes/Amy.tmTheme").unwrap();
        assert_eq!(theme.name.unwrap(), "Amy");
        assert_eq!(theme.settings.selection.unwrap(),
                   Color {
                       r: 0x80,
                       g: 0x00,
                       b: 0x00,
                       a: 0x80,
                   });
        assert_eq!(theme.scopes[0].style.foreground.unwrap(),
                   Color {
                       r: 0x40,
                       g: 0x40,
                       b: 0x80,
                       a: 0xFF,
                   });
        // assert!(false);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

extern crate libc;

use partition::TxSize;
use partition::TxType;

// In libaom, functions that have more than one specialization use function
// pointers, so we need to declare them as static fields and call them
// indirectly. Otherwise, we call SSE or C variants directly. To fully
// understand what's going on here you should first understand the Perl code
// in libaom that generates these function bindings.

extern {
  fn av1_fht4x4_sse2(
    input: *const i16, output: *mut i32, stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  static av1_inv_txfm2d_add_4x4: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  );
  fn av1_fht8x8_sse2(
    input: *const i16, output: *mut i32, stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  static av1_inv_txfm2d_add_8x8: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  ) -> ();
  static av1_fht16x16: extern fn(
    input: *const i16,
    output: *mut i32,
    stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  static av1_inv_txfm2d_add_16x16: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  );
  fn av1_inv_txfm2d_add_16x16_c(
    input: *const i32, output: *mut u16, stride: libc::c_int,
    tx_type: libc::c_int, bd: libc::c_int
  );
  static av1_fht32x32: extern fn(
    input: *const i16,
    output: *mut i32,
    stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  static av1_inv_txfm2d_add_32x32: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  );
}

pub fn forward_transform(
  input: &[i16], output: &mut [i32], stride: usize, tx_size: TxSize,
  tx_type: TxType
) {
  match tx_size {
    TxSize::TX_4X4 => fht4x4(input, output, stride, tx_type),
    TxSize::TX_8X8 => fht8x8(input, output, stride, tx_type),
    TxSize::TX_16X16 => fht16x16(input, output, stride, tx_type),
    TxSize::TX_32X32 => fht32x32(input, output, stride, tx_type),
    _ => panic!("unimplemented tx size")
  }
}

pub fn inverse_transform_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_size: TxSize,
  tx_type: TxType
) {
  match tx_size {
    TxSize::TX_4X4 => iht4x4_add(input, output, stride, tx_type),
    TxSize::TX_8X8 => iht8x8_add(input, output, stride, tx_type),
    TxSize::TX_16X16 => iht16x16_add(input, output, stride, tx_type),
    TxSize::TX_32X32 => iht32x32_add(input, output, stride, tx_type),
    _ => panic!("unimplemented tx size")
  }
}

fn fht4x4(input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType) {
  unsafe {
    av1_fht4x4_sse2(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht4x4_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_inv_txfm2d_add_4x4(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      tx_type as libc::c_int,
      8
    );
  }
}

fn fht8x8(input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType) {
  unsafe {
    av1_fht8x8_sse2(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht8x8_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_inv_txfm2d_add_8x8(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      tx_type as libc::c_int,
      8
    );
  }
}

fn fht16x16(
  input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_fht16x16(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht16x16_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    if tx_type < TxType::IDTX {
      // SSE C code asserts for transform types beyond TxType::IDTX.
      av1_inv_txfm2d_add_16x16(
        input.as_ptr(),
        output.as_mut_ptr(),
        stride as libc::c_int,
        tx_type as libc::c_int,
        8
      );
    } else {
      av1_inv_txfm2d_add_16x16_c(
        input.as_ptr(),
        output.as_mut_ptr(),
        stride as libc::c_int,
        tx_type as libc::c_int,
        8
      );
    }
  }
}

fn fht32x32(
  input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_fht32x32(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht32x32_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_inv_txfm2d_add_32x32(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      tx_type as libc::c_int,
      8
    );
  }
}
<commit_msg>Use target_feature to fallback to C when sse2 is not available<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

extern crate libc;

use partition::TxSize;
use partition::TxType;

// In libaom, functions that have more than one specialization use function
// pointers, so we need to declare them as static fields and call them
// indirectly. Otherwise, we call SSE or C variants directly. To fully
// understand what's going on here you should first understand the Perl code
// in libaom that generates these function bindings.

#[cfg(target_feature = "sse2")]
extern {
  fn av1_fht4x4_sse2(
    input: *const i16, output: *mut i32, stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  fn av1_fht8x8_sse2(
    input: *const i16, output: *mut i32, stride: libc::c_int,
    tx_type: *const libc::c_int
  );
}

#[cfg(target_feature = "sse2")]
use self::av1_fht4x4_sse2 as av1_fht4x4;
#[cfg(target_feature = "sse2")]
use self::av1_fht8x8_sse2 as av1_fht8x8;

#[cfg(not(target_feature = "sse2"))]
extern {
  fn av1_fht4x4_c(
    input: *const i16, output: *mut i32, stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  fn av1_fht8x8_c(
    input: *const i16, output: *mut i32, stride: libc::c_int,
    tx_type: *const libc::c_int
  );
}

#[cfg(not(target_feature = "sse2"))]
use self::av1_fht4x4_c as av1_fht4x4;
#[cfg(not(target_feature = "sse2"))]
use self::av1_fht8x8_c as av1_fht8x8;

extern {
  static av1_inv_txfm2d_add_4x4: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  );

  static av1_inv_txfm2d_add_8x8: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  ) -> ();
  static av1_fht16x16: extern fn(
    input: *const i16,
    output: *mut i32,
    stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  static av1_inv_txfm2d_add_16x16: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  );
  fn av1_inv_txfm2d_add_16x16_c(
    input: *const i32, output: *mut u16, stride: libc::c_int,
    tx_type: libc::c_int, bd: libc::c_int
  );
  static av1_fht32x32: extern fn(
    input: *const i16,
    output: *mut i32,
    stride: libc::c_int,
    tx_type: *const libc::c_int
  );
  static av1_inv_txfm2d_add_32x32: extern fn(
    input: *const i32,
    output: *mut u16,
    stride: libc::c_int,
    tx_type: libc::c_int,
    bd: libc::c_int
  );
}

pub fn forward_transform(
  input: &[i16], output: &mut [i32], stride: usize, tx_size: TxSize,
  tx_type: TxType
) {
  match tx_size {
    TxSize::TX_4X4 => fht4x4(input, output, stride, tx_type),
    TxSize::TX_8X8 => fht8x8(input, output, stride, tx_type),
    TxSize::TX_16X16 => fht16x16(input, output, stride, tx_type),
    TxSize::TX_32X32 => fht32x32(input, output, stride, tx_type),
    _ => panic!("unimplemented tx size")
  }
}

pub fn inverse_transform_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_size: TxSize,
  tx_type: TxType
) {
  match tx_size {
    TxSize::TX_4X4 => iht4x4_add(input, output, stride, tx_type),
    TxSize::TX_8X8 => iht8x8_add(input, output, stride, tx_type),
    TxSize::TX_16X16 => iht16x16_add(input, output, stride, tx_type),
    TxSize::TX_32X32 => iht32x32_add(input, output, stride, tx_type),
    _ => panic!("unimplemented tx size")
  }
}

fn fht4x4(input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType) {
  unsafe {
    av1_fht4x4(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht4x4_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_inv_txfm2d_add_4x4(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      tx_type as libc::c_int,
      8
    );
  }
}

fn fht8x8(input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType) {
  unsafe {
    av1_fht8x8(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht8x8_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_inv_txfm2d_add_8x8(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      tx_type as libc::c_int,
      8
    );
  }
}

fn fht16x16(
  input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_fht16x16(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht16x16_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    if tx_type < TxType::IDTX {
      // SSE C code asserts for transform types beyond TxType::IDTX.
      av1_inv_txfm2d_add_16x16(
        input.as_ptr(),
        output.as_mut_ptr(),
        stride as libc::c_int,
        tx_type as libc::c_int,
        8
      );
    } else {
      av1_inv_txfm2d_add_16x16_c(
        input.as_ptr(),
        output.as_mut_ptr(),
        stride as libc::c_int,
        tx_type as libc::c_int,
        8
      );
    }
  }
}

fn fht32x32(
  input: &[i16], output: &mut [i32], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_fht32x32(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      &(tx_type as i32) as *const libc::c_int
    );
  }
}

fn iht32x32_add(
  input: &[i32], output: &mut [u16], stride: usize, tx_type: TxType
) {
  unsafe {
    av1_inv_txfm2d_add_32x32(
      input.as_ptr(),
      output.as_mut_ptr(),
      stride as libc::c_int,
      tx_type as libc::c_int,
      8
    );
  }
}
<|endoftext|>


<commit_before><commit_msg>break up SmallEnemySpec<commit_after><|endoftext|>