<commit_before>use std::sync::{
    atomic::{AtomicBool, Ordering},
    mpsc, Arc,
};

#[cfg(not(target_os = "redox"))]
use std::thread;

use super::MouseState;
use crate::{
    event::{ButtonState, Key, KeyEvent, MouseButton, MouseEvent},
    render::RenderContext2D,
    window_adapter::WindowAdapter,
    WindowRequest,
};

#[cfg(not(target_os = "redox"))]
use sdl2::event;

use orbclient::Renderer;

#[cfg(not(target_os = "redox"))]
use raw_window_handle::HasRawWindowHandle;

use orbtk_utils::Point;

/// Represents a wrapper for a orbclient window. It handles events, propagate them to
/// the window adapter and handles the update and render pipeline.
pub struct Window
where
    A: WindowAdapter,
{
    window: orbclient::Window,
    adapter: A,
    render_context: RenderContext2D,
    request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    //window_state: WindowState,
    mouse: MouseState,
    update: bool,
    redraw: Arc<AtomicBool>,
    close: bool,
    has_clipboard_update: bool,
    #[cfg(not(target_os = "redox"))]
    _sdl2_sync_thread: Option<thread::JoinHandle<()>>,
}

// internal method to sync if OrbClient backend is sdl2
#[cfg(not(target_os = "redox"))]
fn init_sync(
    window: &orbclient::Window,
    receiver: mpsc::Receiver<WindowRequest>,
) -> (mpsc::Receiver<WindowRequest>, thread::JoinHandle<()>) {
    let (internal_sender, internal_receiver) = mpsc::channel();

    let event_sender = window.event_sender();
    let id = window.id();

    let _sdl2_sync_thread = thread::spawn(move || loop {
        for request in receiver.iter() {
            let _ = internal_sender.send(request.clone());
            if request == WindowRequest::Redraw {
                let _ = event_sender.push_event(event::Event::Window {
                    window_id: id,
                    timestamp: 0,
                    win_event: event::WindowEvent::None,
                });
            }
        }
    });

    (internal_receiver, _sdl2_sync_thread)
}

impl Window
where
    A: WindowAdapter,
{
    #[cfg(target_os = "redox")]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        Window {
            window,
            adapter,
            render_context,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw: Arc::new(AtomicBool::new(true)),
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        let mut adapter = adapter;
        let redraw: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));

        adapter.set_raw_window_handle(window.raw_window_handle());

        let (request_receiver, _sdl2_sync_thread) = {
            if let Some(receiver) = request_receiver {
                let (rec, sync) = init_sync(&window, receiver);
                (Some(rec), Some(sync))
            } else {
                (None, None)
            }
        };

        Window {
            window,
            adapter,
            render_context,
            _sdl2_sync_thread,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw,
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    fn has_clipboard_update(&self) -> bool {
        self.has_clipboard_update
    }

    // todo: workaround until clipboard update events available on orbital
    #[cfg(target_os = "redox")]
    fn has_clipboard_update(&self) -> bool {
        true
    }
}

#[cfg(not(target_os = "redox"))]
unsafe impl raw_window_handle::HasRawWindowHandle for Window
where
    A: WindowAdapter,
{
    fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
        self.window.raw_window_handle()
    }
}

impl Window
where
    A: WindowAdapter,
{
    /// Check if the window is open.
    pub fn is_open(&self) -> bool {
        !self.close
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            position: Point::new(self.mouse.mouse_pos.0 as f64, self.mouse.mouse_pos.1 as f64),
            button,
            state,
        });
    }

    fn push_key_event(&mut self, key_event: orbclient::KeyEvent) {
        let mut key = Key::from(key_event.character);
        let state = {
            if key_event.pressed {
                ButtonState::Down
            } else {
                ButtonState::Up
            }
        };

        let text = {
            if key_event.character != '\0'
                && key_event.character != '\n'
                && key_event.character != '\u{1b}'
            {
                key_event.character.to_string()
            } else {
                match key_event.scancode {
                    orbclient::K_BKSP => key = Key::Backspace,
                    orbclient::K_LEFT => key = Key::Left,
                    orbclient::K_RIGHT => key = Key::Right,
                    orbclient::K_UP => key = Key::Up,
                    orbclient::K_DOWN => key = Key::Down,
                    orbclient::K_DEL => key = Key::Delete,
                    orbclient::K_ENTER => key = Key::Enter,
                    orbclient::K_CTRL => key = Key::Control,
                    orbclient::K_LEFT_SHIFT => key = Key::ShiftL,
                    orbclient::K_RIGHT_SHIFT => key = Key::ShiftR,
                    orbclient::K_ALT => key = Key::Alt,
                    orbclient::K_ESC => key = Key::Escape,
                    orbclient::K_CAPS => key = Key::CapsLock,
                    orbclient::K_HOME => {
                        key = Key::Home;
                    }
                    _ => key = Key::Unknown,
                };
                String::default()
            }
        };

        self.adapter.key_event(KeyEvent { key, text, state });
    }

    /// Updates the clipboard.
    pub fn update_clipboard(&mut self) {
        let mut clipboard_value = if self.has_clipboard_update() {
            self.has_clipboard_update = false;
            Some(self.window.clipboard())
        } else {
            None
        };

        self.adapter.clipboard_update(&mut clipboard_value);

        if let Some(value) = clipboard_value {
            self.window.set_clipboard(value.as_str());
        }
    }

    /// Drain events and propagate the events to the adapter.
    pub fn drain_events(&mut self) {
        for event in self.window.events() {
            match event.to_option() {
                orbclient::EventOption::Key(event) => {
                    self.push_key_event(event);
                    self.update = true;
                }
                orbclient::EventOption::TextInput(event) => {
                    self.adapter.text_input(event.character.to_string());
                    self.update = true;
                }
                orbclient::EventOption::Mouse(event) => {
                    self.mouse.mouse_pos = (event.x as f32, event.y as f32);
                    self.adapter.mouse(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::MouseRelative(_) => {}
                orbclient::EventOption::ClipboardUpdate(_) => {
                    self.has_clipboard_update = true;
                }
                orbclient::EventOption::Button(event) => {
                    if event.left != self.mouse.button_left {
                        if event.left {
                            self.push_mouse_event(true, MouseButton::Left);
                        } else {
                            self.push_mouse_event(false, MouseButton::Left);
                        }
                        self.mouse.button_left = event.left;
                        self.update = true;
                    }

                    if event.middle != self.mouse.button_middle {
                        if event.middle {
                            self.push_mouse_event(true, MouseButton::Middle);
                        } else {
                            self.push_mouse_event(false, MouseButton::Middle);
                        }
                        self.mouse.button_middle = event.middle;
                        self.update = true;
                    }

                    if event.right != self.mouse.button_right {
                        if event.right {
                            self.push_mouse_event(true, MouseButton::Right);
                        } else {
                            self.push_mouse_event(false, MouseButton::Right);
                        }
                        self.mouse.button_right = event.right;
                        self.update = true;
                    }
                }
                orbclient::EventOption::Scroll(event) => {
                    self.adapter.scroll(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::Quit(_) => {
                    self.close = true;
                    self.update = true
                }
                orbclient::EventOption::Focus(_) => {}
                orbclient::EventOption::Move(_) => {}
                orbclient::EventOption::Resize(event) => {
                    self.adapter.resize(event.width as f64, event.height as f64);
                    self.render_context
                        .resize(event.width as f64, event.height as f64);
                    self.update = true;
                    self.redraw.store(true, Ordering::Relaxed);
                }
                orbclient::EventOption::Screen(_) => {}
                orbclient::EventOption::Clipboard(_) => {}
                orbclient::EventOption::Drop(event) => {
                    self.window.sync_path();
                    if let Some(text) = self.window.pop_drop_content() {
                        if event.kind == orbclient::DROP_FILE {
                            self.adapter.file_drop_event(text);
                        } else {
                            self.adapter.text_drop_event(text);
                        }
                    }
                }
                orbclient::EventOption::Unknown(_) => {}
                orbclient::EventOption::None => {}
            }
        }
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        if let Some(request_receiver) = &self.request_receiver {
            for request in request_receiver.try_iter() {
                match request {
                    WindowRequest::Redraw => {
                        if !self.update && !self.redraw.load(Ordering::Relaxed) {
                            self.update = true;
                            self.redraw.store(true, Ordering::Relaxed)
                        }
                    }
                    WindowRequest::ChangeTitle(title) => {
                        self.window.set_title(title.as_str());
                        self.update = true;
                        self.redraw.store(true, Ordering::Relaxed)
                    }
                    WindowRequest::Close => {
                        self.close = true;
                    }
                }
            }
        }
    }

    /// Runs update on the adapter.
    pub fn update(&mut self) {
        //super::CONSOLE.time("complete");
        if !self.update {
            return;
        }
        self.adapter.run(&mut self.render_context);
        self.update = false;
        self.redraw.store(true, Ordering::Relaxed)
    }

    /// Swaps the current frame buffer.
    pub fn render(&mut self) {
        if self.redraw.load(Ordering::Relaxed) {
            let color_data: Vec<orbclient::Color> = self
                .render_context
                .data()
                .iter()
                .map(|v| orbclient::Color { data: *v })
                .collect();

            if color_data.len() == self.window.data().len() {
                self.window
                    .data_mut()
                    .clone_from_slice(color_data.as_slice());

                // CONSOLE.time_end("render");
                self.redraw.store(false, Ordering::Relaxed)
                //super::CONSOLE.time_end("complete");
            }
        }

        self.window.sync();
    }
}
<commit_msg>render performance improvement on orbclient<commit_after>use std::sync::{
    atomic::{AtomicBool, Ordering},
    mpsc, Arc,
};

#[cfg(not(target_os = "redox"))]
use std::thread;

use super::MouseState;
use crate::{
    event::{ButtonState, Key, KeyEvent, MouseButton, MouseEvent},
    render::RenderContext2D,
    window_adapter::WindowAdapter,
    WindowRequest,
};

#[cfg(not(target_os = "redox"))]
use sdl2::event;

use orbclient::Renderer;

#[cfg(not(target_os = "redox"))]
use raw_window_handle::HasRawWindowHandle;

use orbtk_utils::Point;

/// Represents a wrapper for a orbclient window. It handles events, propagate them to
/// the window adapter and handles the update and render pipeline.
pub struct Window
where
    A: WindowAdapter,
{
    window: orbclient::Window,
    adapter: A,
    render_context: RenderContext2D,
    request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    //window_state: WindowState,
    mouse: MouseState,
    update: bool,
    redraw: Arc<AtomicBool>,
    close: bool,
    has_clipboard_update: bool,
    #[cfg(not(target_os = "redox"))]
    _sdl2_sync_thread: Option<thread::JoinHandle<()>>,
}

// internal method to sync if OrbClient backend is sdl2
#[cfg(not(target_os = "redox"))]
fn init_sync(
    window: &orbclient::Window,
    receiver: mpsc::Receiver<WindowRequest>,
) -> (mpsc::Receiver<WindowRequest>, thread::JoinHandle<()>) {
    let (internal_sender, internal_receiver) = mpsc::channel();

    let event_sender = window.event_sender();
    let id = window.id();

    let _sdl2_sync_thread = thread::spawn(move || loop {
        for request in receiver.iter() {
            let _ = internal_sender.send(request.clone());
            if request == WindowRequest::Redraw {
                let _ = event_sender.push_event(event::Event::Window {
                    window_id: id,
                    timestamp: 0,
                    win_event: event::WindowEvent::None,
                });
            }
        }
    });

    (internal_receiver, _sdl2_sync_thread)
}

impl Window
where
    A: WindowAdapter,
{
    #[cfg(target_os = "redox")]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        Window {
            window,
            adapter,
            render_context,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw: Arc::new(AtomicBool::new(true)),
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        let mut adapter = adapter;
        let redraw: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));

        adapter.set_raw_window_handle(window.raw_window_handle());

        let (request_receiver, _sdl2_sync_thread) = {
            if let Some(receiver) = request_receiver {
                let (rec, sync) = init_sync(&window, receiver);
                (Some(rec), Some(sync))
            } else {
                (None, None)
            }
        };

        Window {
            window,
            adapter,
            render_context,
            _sdl2_sync_thread,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw,
            close: false,
            has_clipboard_update: true,
        }
    }

    #[cfg(not(target_os = "redox"))]
    fn has_clipboard_update(&self) -> bool {
        self.has_clipboard_update
    }

    // todo: workaround until clipboard update events available on orbital
    #[cfg(target_os = "redox")]
    fn has_clipboard_update(&self) -> bool {
        true
    }
}

#[cfg(not(target_os = "redox"))]
unsafe impl raw_window_handle::HasRawWindowHandle for Window
where
    A: WindowAdapter,
{
    fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
        self.window.raw_window_handle()
    }
}

impl Window
where
    A: WindowAdapter,
{
    /// Check if the window is open.
    pub fn is_open(&self) -> bool {
        !self.close
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            position: Point::new(self.mouse.mouse_pos.0 as f64, self.mouse.mouse_pos.1 as f64),
            button,
            state,
        });
    }

    fn push_key_event(&mut self, key_event: orbclient::KeyEvent) {
        let mut key = Key::from(key_event.character);
        let state = {
            if key_event.pressed {
                ButtonState::Down
            } else {
                ButtonState::Up
            }
        };

        let text = {
            if key_event.character != '\0'
                && key_event.character != '\n'
                && key_event.character != '\u{1b}'
            {
                key_event.character.to_string()
            } else {
                match key_event.scancode {
                    orbclient::K_BKSP => key = Key::Backspace,
                    orbclient::K_LEFT => key = Key::Left,
                    orbclient::K_RIGHT => key = Key::Right,
                    orbclient::K_UP => key = Key::Up,
                    orbclient::K_DOWN => key = Key::Down,
                    orbclient::K_DEL => key = Key::Delete,
                    orbclient::K_ENTER => key = Key::Enter,
                    orbclient::K_CTRL => key = Key::Control,
                    orbclient::K_LEFT_SHIFT => key = Key::ShiftL,
                    orbclient::K_RIGHT_SHIFT => key = Key::ShiftR,
                    orbclient::K_ALT => key = Key::Alt,
                    orbclient::K_ESC => key = Key::Escape,
                    orbclient::K_CAPS => key = Key::CapsLock,
                    orbclient::K_HOME => {
                        key = Key::Home;
                    }
                    _ => key = Key::Unknown,
                };
                String::default()
            }
        };

        self.adapter.key_event(KeyEvent { key, text, state });
    }

    /// Updates the clipboard.
    pub fn update_clipboard(&mut self) {
        let mut clipboard_value = if self.has_clipboard_update() {
            self.has_clipboard_update = false;
            Some(self.window.clipboard())
        } else {
            None
        };

        self.adapter.clipboard_update(&mut clipboard_value);

        if let Some(value) = clipboard_value {
            self.window.set_clipboard(value.as_str());
        }
    }

    /// Drain events and propagate the events to the adapter.
    pub fn drain_events(&mut self) {
        for event in self.window.events() {
            match event.to_option() {
                orbclient::EventOption::Key(event) => {
                    self.push_key_event(event);
                    self.update = true;
                }
                orbclient::EventOption::TextInput(event) => {
                    self.adapter.text_input(event.character.to_string());
                    self.update = true;
                }
                orbclient::EventOption::Mouse(event) => {
                    self.mouse.mouse_pos = (event.x as f32, event.y as f32);
                    self.adapter.mouse(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::MouseRelative(_) => {}
                orbclient::EventOption::ClipboardUpdate(_) => {
                    self.has_clipboard_update = true;
                }
                orbclient::EventOption::Button(event) => {
                    if event.left != self.mouse.button_left {
                        if event.left {
                            self.push_mouse_event(true, MouseButton::Left);
                        } else {
                            self.push_mouse_event(false, MouseButton::Left);
                        }
                        self.mouse.button_left = event.left;
                        self.update = true;
                    }

                    if event.middle != self.mouse.button_middle {
                        if event.middle {
                            self.push_mouse_event(true, MouseButton::Middle);
                        } else {
                            self.push_mouse_event(false, MouseButton::Middle);
                        }
                        self.mouse.button_middle = event.middle;
                        self.update = true;
                    }

                    if event.right != self.mouse.button_right {
                        if event.right {
                            self.push_mouse_event(true, MouseButton::Right);
                        } else {
                            self.push_mouse_event(false, MouseButton::Right);
                        }
                        self.mouse.button_right = event.right;
                        self.update = true;
                    }
                }
                orbclient::EventOption::Scroll(event) => {
                    self.adapter.scroll(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::Quit(_) => {
                    self.close = true;
                    self.update = true
                }
                orbclient::EventOption::Focus(_) => {}
                orbclient::EventOption::Move(_) => {}
                orbclient::EventOption::Resize(event) => {
                    self.adapter.resize(event.width as f64, event.height as f64);
                    self.render_context
                        .resize(event.width as f64, event.height as f64);
                    self.update = true;
                    self.redraw.store(true, Ordering::Relaxed);
                }
                orbclient::EventOption::Screen(_) => {}
                orbclient::EventOption::Clipboard(_) => {}
                orbclient::EventOption::Drop(event) => {
                    self.window.sync_path();
                    if let Some(text) = self.window.pop_drop_content() {
                        if event.kind == orbclient::DROP_FILE {
                            self.adapter.file_drop_event(text);
                        } else {
                            self.adapter.text_drop_event(text);
                        }
                    }
                }
                orbclient::EventOption::Unknown(_) => {}
                orbclient::EventOption::None => {}
            }
        }
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        if let Some(request_receiver) = &self.request_receiver {
            for request in request_receiver.try_iter() {
                match request {
                    WindowRequest::Redraw => {
                        if !self.update && !self.redraw.load(Ordering::Relaxed) {
                            self.update = true;
                            self.redraw.store(true, Ordering::Relaxed)
                        }
                    }
                    WindowRequest::ChangeTitle(title) => {
                        self.window.set_title(title.as_str());
                        self.update = true;
                        self.redraw.store(true, Ordering::Relaxed)
                    }
                    WindowRequest::Close => {
                        self.close = true;
                    }
                }
            }
        }
    }

    /// Runs update on the adapter.
    pub fn update(&mut self) {
        //super::CONSOLE.time("complete");
        if !self.update {
            return;
        }
        self.adapter.run(&mut self.render_context);
        self.update = false;
        self.redraw.store(true, Ordering::Relaxed)
    }

    /// Swaps the current frame buffer.
    pub fn render(&mut self) {
        if self.redraw.load(Ordering::Relaxed) {
            let bytes = self.render_context.data_u8_mut();
            let color_data = unsafe {
                std::slice::from_raw_parts_mut(
                    bytes.as_mut_ptr() as *mut orbclient::Color,
                    bytes.len() / std::mem::size_of::<orbclient::Color>(),
                )
            };

            if color_data.len() == self.window.data().len() {
                self.window.data_mut().clone_from_slice(color_data);

                // CONSOLE.time_end("render");
                self.redraw.store(false, Ordering::Relaxed)
                //super::CONSOLE.time_end("complete");
            }
        }

        self.window.sync();
    }
}
<|endoftext|>


<commit_before>use std::env;

fn is_palindrome(ch_vec: Vec<&str>) -> bool {
    let ch_vec_2 = ch_vec.to_vec();
    ch_vec.reverse();
    return (ch_vec == ch_vec_2);
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let input = &args[1];
    let ch_vec: Vec<&str> = input.split("").collect();
    let is_pal = is_palindrome(ch_vec);
    println!("Is {} a palindrome? {}", input, is_pal);
    // if is_pal {
    //     for combo in ch_vec.permutations() {
    //         if is_palindrome(combo) {
    //             let combo_str =
    //             println!("A palindromic form of {} is {}", input, combo);
    //             break;
    //         }
    //     }
    // }
}
<commit_msg>Rust is hard, permutations is unstable, will try  later<commit_after>use std::env;

fn is_palindrome(ch_vec: Vec<&str>) -> bool {
    let mut ch_vec_1 = ch_vec.to_vec();
    let ch_vec_2 = ch_vec.to_vec();
    ch_vec_1.reverse();
    return ch_vec_1 == ch_vec_2;
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let input = &args[1];
    let ch_vec: Vec<&str> = input.split("").collect();
    let is_pal = is_palindrome(ch_vec);
    println!("Is {} a palindrome? {}", input, is_pal);
    if is_pal {
        // stuff here, will do later
    }
}
<|endoftext|>


<commit_before>extern crate cc;
extern crate build_helper;

use std::process::Command;
use std::env;
use std::path::{PathBuf, Path};

use build_helper::output;

fn detect_llvm_link() -> (&'static str, &'static str) {
    // Force the link mode we want, preferring static by default, but
    // possibly overridden by `configure --enable-llvm-link-shared`.
    if env::var_os("LLVM_LINK_SHARED").is_some() {
        ("dylib", "--link-shared")
    } else {
        ("static", "--link-static")
    }
}

fn main() {
    if env::var_os("RUST_CHECK").is_some() {
        // If we're just running `check`, there's no need for LLVM to be built.
        println!("cargo:rerun-if-env-changed=RUST_CHECK");
        return;
    }

    let target = env::var("TARGET").expect("TARGET was not set");
    let llvm_config = env::var_os("LLVM_CONFIG")
        .map(PathBuf::from)
        .unwrap_or_else(|| {
            if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
                let to_test = dir.parent()
                    .unwrap()
                    .parent()
                    .unwrap()
                    .join(&target)
                    .join("llvm/bin/llvm-config");
                if Command::new(&to_test).output().is_ok() {
                    return to_test;
                }
            }
            PathBuf::from("llvm-config")
        });

    println!("cargo:rerun-if-changed={}", llvm_config.display());
    println!("cargo:rerun-if-env-changed=LLVM_CONFIG");

    // Test whether we're cross-compiling LLVM. This is a pretty rare case
    // currently where we're producing an LLVM for a different platform than
    // what this build script is currently running on.
    //
    // In that case, there's no guarantee that we can actually run the target,
    // so the build system works around this by giving us the LLVM_CONFIG for
    // the host platform. This only really works if the host LLVM and target
    // LLVM are compiled the same way, but for us that's typically the case.
    //
    // We *want* detect this cross compiling situation by asking llvm-config
    // what it's host-target is. If that's not the TARGET, then we're cross
    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
    // tricks us into thinking we're doing a cross build when we aren't, so
    // havoc ensues.
    //
    // In any case, if we're cross compiling, this generally just means that we
    // can't trust all the output of llvm-config becaues it might be targeted
    // for the host rather than the target. As a result a bunch of blocks below
    // are gated on `if !is_crossed`
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    let is_crossed = target != host;

    let mut optional_components =
        vec!["x86", "arm", "aarch64", "amdgpu", "mips", "powerpc",
             "systemz", "jsbackend", "webassembly", "msp430", "sparc", "nvptx"];

    let mut version_cmd = Command::new(&llvm_config);
    version_cmd.arg("--version");
    let version_output = output(&mut version_cmd);
    let mut parts = version_output.split('.').take(2)
        .filter_map(|s| s.parse::<u32>().ok());
    let (major, _minor) =
        if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
            (major, minor)
        } else {
            (3, 9)
        };

    if major > 3 {
        optional_components.push("hexagon");
    }

    if major > 6 {
        optional_components.push("riscv");
    }

    // FIXME: surely we don't need all these components, right? Stuff like mcjit
    //        or interpreter the compiler itself never uses.
    let required_components = &["ipo",
                                "bitreader",
                                "bitwriter",
                                "linker",
                                "asmparser",
                                "mcjit",
                                "lto",
                                "interpreter",
                                "instrumentation"];

    let components = output(Command::new(&llvm_config).arg("--components"));
    let mut components = components.split_whitespace().collect::<Vec<_>>();
    components.retain(|c| optional_components.contains(c) || required_components.contains(c));

    for component in required_components {
        if !components.contains(component) {
            panic!("require llvm component {} but wasn't found", component);
        }
    }

    for component in components.iter() {
        println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
    }

    // Link in our own LLVM shims, compiled with the same flags as LLVM
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--cxxflags");
    let cxxflags = output(&mut cmd);
    let mut cfg = cc::Build::new();
    cfg.warnings(false);
    for flag in cxxflags.split_whitespace() {
        // Ignore flags like `-m64` when we're doing a cross build
        if is_crossed && flag.starts_with("-m") {
            continue;
        }

        if flag.starts_with("-flto") {
            continue;
        }

        // -Wdate-time is not supported by the netbsd cross compiler
        if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
            continue;
        }

        cfg.flag(flag);
    }

    for component in &components {
        let mut flag = String::from("LLVM_COMPONENT_");
        flag.push_str(&component.to_uppercase());
        cfg.define(&flag, None);
    }

    println!("cargo:rerun-if-changed-env=LLVM_RUSTLLVM");
    if env::var_os("LLVM_RUSTLLVM").is_some() {
        cfg.define("LLVM_RUSTLLVM", None);
    }

    build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm"));
    cfg.file("../rustllvm/PassWrapper.cpp")
       .file("../rustllvm/RustWrapper.cpp")
       .file("../rustllvm/ArchiveWrapper.cpp")
       .file("../rustllvm/Linker.cpp")
       .cpp(true)
       .cpp_link_stdlib(None) // we handle this below
       .compile("rustllvm");

    let (llvm_kind, llvm_link_arg) = detect_llvm_link();

    // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then
    // we don't pick up system libs because unfortunately they're for the host
    // of llvm-config, not the target that we're attempting to link.
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--libs");

    if !is_crossed {
        cmd.arg("--system-libs");
    }
    cmd.args(&components);

    for lib in output(&mut cmd).split_whitespace() {
        let name = if lib.starts_with("-l") {
            &lib[2..]
        } else if lib.starts_with("-") {
            &lib[1..]
        } else if Path::new(lib).exists() {
            // On MSVC llvm-config will print the full name to libraries, but
            // we're only interested in the name part
            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
            name.trim_end_matches(".lib")
        } else if lib.ends_with(".lib") {
            // Some MSVC libraries just come up with `.lib` tacked on, so chop
            // that off
            lib.trim_end_matches(".lib")
        } else {
            continue;
        };

        // Don't need or want this library, but LLVM's CMake build system
        // doesn't provide a way to disable it, so filter it here even though we
        // may or may not have built it. We don't reference anything from this
        // library and it otherwise may just pull in extra dependencies on
        // libedit which we don't want
        if name == "LLVMLineEditor" {
            continue;
        }

        let kind = if name.starts_with("LLVM") {
            llvm_kind
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, name);
    }

    // LLVM ldflags
    //
    // If we're a cross-compile of LLVM then unfortunately we can't trust these
    // ldflags (largely where all the LLVM libs are located). Currently just
    // hack around this by replacing the host triple with the target and pray
    // that those -L directories are the same!
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--ldflags");
    for lib in output(&mut cmd).split_whitespace() {
        if lib.starts_with("-LIBPATH:") {
            println!("cargo:rustc-link-search=native={}", &lib[9..]);
        } else if is_crossed {
            if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}",
                         lib[2..].replace(&host, &target));
            }
        } else if lib.starts_with("-l") {
            println!("cargo:rustc-link-lib={}", &lib[2..]);
        } else if lib.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &lib[2..]);
        }
    }

    let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP");
    let llvm_use_libcxx = env::var_os("LLVM_USE_LIBCXX");

    let stdcppname = if target.contains("openbsd") {
        // llvm-config on OpenBSD doesn't mention stdlib=libc++
        "c++"
    } else if target.contains("freebsd") {
        "c++"
    } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
        // NetBSD uses a separate library when relocation is required
        "stdc++_pic"
    } else if llvm_use_libcxx.is_some() {
        "c++"
    } else {
        "stdc++"
    };

    // C++ runtime library
    if !target.contains("msvc") {
        if let Some(s) = llvm_static_stdcpp {
            assert!(!cxxflags.contains("stdlib=libc++"));
            let path = PathBuf::from(s);
            println!("cargo:rustc-link-search=native={}",
                     path.parent().unwrap().display());
            println!("cargo:rustc-link-lib=static={}", stdcppname);
        } else if cxxflags.contains("stdlib=libc++") {
            println!("cargo:rustc-link-lib=c++");
        } else {
            println!("cargo:rustc-link-lib={}", stdcppname);
        }
    }

    // LLVM requires symbols from this library, but apparently they're not printed
    // during llvm-config?
    if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
        println!("cargo:rustc-link-lib=dylib=uuid");
    }
}
<commit_msg>librustc_llvm: default to libc++ for darwin<commit_after>extern crate cc;
extern crate build_helper;

use std::process::Command;
use std::env;
use std::path::{PathBuf, Path};

use build_helper::output;

fn detect_llvm_link() -> (&'static str, &'static str) {
    // Force the link mode we want, preferring static by default, but
    // possibly overridden by `configure --enable-llvm-link-shared`.
    if env::var_os("LLVM_LINK_SHARED").is_some() {
        ("dylib", "--link-shared")
    } else {
        ("static", "--link-static")
    }
}

fn main() {
    if env::var_os("RUST_CHECK").is_some() {
        // If we're just running `check`, there's no need for LLVM to be built.
        println!("cargo:rerun-if-env-changed=RUST_CHECK");
        return;
    }

    let target = env::var("TARGET").expect("TARGET was not set");
    let llvm_config = env::var_os("LLVM_CONFIG")
        .map(PathBuf::from)
        .unwrap_or_else(|| {
            if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
                let to_test = dir.parent()
                    .unwrap()
                    .parent()
                    .unwrap()
                    .join(&target)
                    .join("llvm/bin/llvm-config");
                if Command::new(&to_test).output().is_ok() {
                    return to_test;
                }
            }
            PathBuf::from("llvm-config")
        });

    println!("cargo:rerun-if-changed={}", llvm_config.display());
    println!("cargo:rerun-if-env-changed=LLVM_CONFIG");

    // Test whether we're cross-compiling LLVM. This is a pretty rare case
    // currently where we're producing an LLVM for a different platform than
    // what this build script is currently running on.
    //
    // In that case, there's no guarantee that we can actually run the target,
    // so the build system works around this by giving us the LLVM_CONFIG for
    // the host platform. This only really works if the host LLVM and target
    // LLVM are compiled the same way, but for us that's typically the case.
    //
    // We *want* detect this cross compiling situation by asking llvm-config
    // what it's host-target is. If that's not the TARGET, then we're cross
    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
    // tricks us into thinking we're doing a cross build when we aren't, so
    // havoc ensues.
    //
    // In any case, if we're cross compiling, this generally just means that we
    // can't trust all the output of llvm-config becaues it might be targeted
    // for the host rather than the target. As a result a bunch of blocks below
    // are gated on `if !is_crossed`
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    let is_crossed = target != host;

    let mut optional_components =
        vec!["x86", "arm", "aarch64", "amdgpu", "mips", "powerpc",
             "systemz", "jsbackend", "webassembly", "msp430", "sparc", "nvptx"];

    let mut version_cmd = Command::new(&llvm_config);
    version_cmd.arg("--version");
    let version_output = output(&mut version_cmd);
    let mut parts = version_output.split('.').take(2)
        .filter_map(|s| s.parse::<u32>().ok());
    let (major, _minor) =
        if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
            (major, minor)
        } else {
            (3, 9)
        };

    if major > 3 {
        optional_components.push("hexagon");
    }

    if major > 6 {
        optional_components.push("riscv");
    }

    // FIXME: surely we don't need all these components, right? Stuff like mcjit
    //        or interpreter the compiler itself never uses.
    let required_components = &["ipo",
                                "bitreader",
                                "bitwriter",
                                "linker",
                                "asmparser",
                                "mcjit",
                                "lto",
                                "interpreter",
                                "instrumentation"];

    let components = output(Command::new(&llvm_config).arg("--components"));
    let mut components = components.split_whitespace().collect::<Vec<_>>();
    components.retain(|c| optional_components.contains(c) || required_components.contains(c));

    for component in required_components {
        if !components.contains(component) {
            panic!("require llvm component {} but wasn't found", component);
        }
    }

    for component in components.iter() {
        println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
    }

    // Link in our own LLVM shims, compiled with the same flags as LLVM
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--cxxflags");
    let cxxflags = output(&mut cmd);
    let mut cfg = cc::Build::new();
    cfg.warnings(false);
    for flag in cxxflags.split_whitespace() {
        // Ignore flags like `-m64` when we're doing a cross build
        if is_crossed && flag.starts_with("-m") {
            continue;
        }

        if flag.starts_with("-flto") {
            continue;
        }

        // -Wdate-time is not supported by the netbsd cross compiler
        if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
            continue;
        }

        cfg.flag(flag);
    }

    for component in &components {
        let mut flag = String::from("LLVM_COMPONENT_");
        flag.push_str(&component.to_uppercase());
        cfg.define(&flag, None);
    }

    println!("cargo:rerun-if-changed-env=LLVM_RUSTLLVM");
    if env::var_os("LLVM_RUSTLLVM").is_some() {
        cfg.define("LLVM_RUSTLLVM", None);
    }

    build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm"));
    cfg.file("../rustllvm/PassWrapper.cpp")
       .file("../rustllvm/RustWrapper.cpp")
       .file("../rustllvm/ArchiveWrapper.cpp")
       .file("../rustllvm/Linker.cpp")
       .cpp(true)
       .cpp_link_stdlib(None) // we handle this below
       .compile("rustllvm");

    let (llvm_kind, llvm_link_arg) = detect_llvm_link();

    // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then
    // we don't pick up system libs because unfortunately they're for the host
    // of llvm-config, not the target that we're attempting to link.
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--libs");

    if !is_crossed {
        cmd.arg("--system-libs");
    }
    cmd.args(&components);

    for lib in output(&mut cmd).split_whitespace() {
        let name = if lib.starts_with("-l") {
            &lib[2..]
        } else if lib.starts_with("-") {
            &lib[1..]
        } else if Path::new(lib).exists() {
            // On MSVC llvm-config will print the full name to libraries, but
            // we're only interested in the name part
            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
            name.trim_end_matches(".lib")
        } else if lib.ends_with(".lib") {
            // Some MSVC libraries just come up with `.lib` tacked on, so chop
            // that off
            lib.trim_end_matches(".lib")
        } else {
            continue;
        };

        // Don't need or want this library, but LLVM's CMake build system
        // doesn't provide a way to disable it, so filter it here even though we
        // may or may not have built it. We don't reference anything from this
        // library and it otherwise may just pull in extra dependencies on
        // libedit which we don't want
        if name == "LLVMLineEditor" {
            continue;
        }

        let kind = if name.starts_with("LLVM") {
            llvm_kind
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, name);
    }

    // LLVM ldflags
    //
    // If we're a cross-compile of LLVM then unfortunately we can't trust these
    // ldflags (largely where all the LLVM libs are located). Currently just
    // hack around this by replacing the host triple with the target and pray
    // that those -L directories are the same!
    let mut cmd = Command::new(&llvm_config);
    cmd.arg(llvm_link_arg).arg("--ldflags");
    for lib in output(&mut cmd).split_whitespace() {
        if lib.starts_with("-LIBPATH:") {
            println!("cargo:rustc-link-search=native={}", &lib[9..]);
        } else if is_crossed {
            if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}",
                         lib[2..].replace(&host, &target));
            }
        } else if lib.starts_with("-l") {
            println!("cargo:rustc-link-lib={}", &lib[2..]);
        } else if lib.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &lib[2..]);
        }
    }

    let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP");
    let llvm_use_libcxx = env::var_os("LLVM_USE_LIBCXX");

    let stdcppname = if target.contains("openbsd") {
        // llvm-config on OpenBSD doesn't mention stdlib=libc++
        "c++"
    } else if target.contains("freebsd") {
        "c++"
    } else if target.contains("darwin") {
        "c++"
    } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
        // NetBSD uses a separate library when relocation is required
        "stdc++_pic"
    } else if llvm_use_libcxx.is_some() {
        "c++"
    } else {
        "stdc++"
    };

    // C++ runtime library
    if !target.contains("msvc") {
        if let Some(s) = llvm_static_stdcpp {
            assert!(!cxxflags.contains("stdlib=libc++"));
            let path = PathBuf::from(s);
            println!("cargo:rustc-link-search=native={}",
                     path.parent().unwrap().display());
            println!("cargo:rustc-link-lib=static={}", stdcppname);
        } else if cxxflags.contains("stdlib=libc++") {
            println!("cargo:rustc-link-lib=c++");
        } else {
            println!("cargo:rustc-link-lib={}", stdcppname);
        }
    }

    // LLVM requires symbols from this library, but apparently they're not printed
    // during llvm-config?
    if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
        println!("cargo:rustc-link-lib=dylib=uuid");
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix #2: Implement functionality for get_file_size() function<commit_after><|endoftext|>


<commit_before><commit_msg>Move more stuff out into functions<commit_after><|endoftext|>


<commit_before><commit_msg>Properly chain together reading chars and tokens<commit_after><|endoftext|>


<commit_before><commit_msg>Remove extra newline<commit_after><|endoftext|>


<commit_before><commit_msg>Fixing printing of http request content<commit_after><|endoftext|>


<commit_before><commit_msg>Add fast encoding<commit_after><|endoftext|>


<commit_before><commit_msg>Specify local ip<commit_after><|endoftext|>


<commit_before><commit_msg>Reading in a few fields from the header. This will all be properly modularized once it works well.<commit_after><|endoftext|>


<commit_before><commit_msg>Don't crash on pings, show log message instead<commit_after><|endoftext|>


<commit_before>use super::super::{Coord, Grid, X, Y};
use super::*;
use grid_loop::{Edge, GridLoop, GridLoopField};
use std::cmp;

#[derive(Clone)]
pub struct Field {
    grid_loop: GridLoop,
    clue: Grid<Clue>,
    cell: Grid<Cell>,
}

const FOUR_NEIGHBORS: [(i32, i32); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];

impl Field {
    pub fn new(clue: Grid<Clue>) -> Field {
        let height = clue.height();
        let width = clue.width();

        let mut cell = Grid::new(height, width, Cell::Undecided);
        let mut grid_loop = GridLoop::new(height - 1, width - 1);

        {
            let mut handle = GridLoop::get_handle(&mut grid_loop);
            for y in 0..height {
                for x in 0..width {
                    let c = clue[(Y(y), X(x))];
                    if c != Clue::NoClue {
                        cell[(Y(y), X(x))] = Cell::Clue;
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 - 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 + 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 - 1)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 + 1)), Edge::Blank);
                    }
                }
            }
        }
        Field {
            grid_loop,
            clue,
            cell,
        }
    }
    pub fn height(&self) -> i32 {
        self.clue.height()
    }
    pub fn width(&self) -> i32 {
        self.clue.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.grid_loop.inconsistent()
    }
    pub fn set_inconsistent(&mut self) {
        self.grid_loop.set_inconsistent()
    }
    pub fn fully_solved(&self) -> bool {
        self.grid_loop.fully_solved()
    }
    pub fn get_cell(&self, cd: Coord) -> Cell {
        self.cell[cd]
    }
    pub fn get_cell_safe(&self, cd: Coord) -> Cell {
        if self.cell.is_valid_coord(cd) {
            self.cell[cd]
        } else {
            // The outside of the field can be identified with a (meaningless) clue
            Cell::Clue
        }
    }
    pub fn get_edge(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge(cd)
    }
    pub fn get_edge_safe(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge_safe(cd)
    }

    pub fn set_cell(&mut self, cd: Coord, v: Cell) {
        let mut handle = GridLoop::get_handle(self);
        handle.set_cell_internal(cd, v);
    }
    pub fn check_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut handle = GridLoop::get_handle(self);
        for y in 0..height {
            for x in 0..width {
                GridLoop::check(&mut *handle, (Y(y * 2), X(x * 2)));
            }
        }
    }

    fn set_cell_internal(&mut self, cd: Coord, v: Cell) {
        let current = self.cell[cd];
        if current != Cell::Undecided {
            if current != v {
                self.set_inconsistent();
            }
            return;
        }

        self.cell[cd] = v;
        let (Y(y), X(x)) = cd;
        match v {
            Cell::Undecided => (),
            Cell::Clue => (), // don't do this!
            Cell::Line => GridLoop::check(self, (Y(y * 2), X(x * 2))),
            Cell::Blocked => for &(dy, dx) in &FOUR_NEIGHBORS {
                if self.get_cell_safe((Y(y + dy), X(x + dx))) != Cell::Clue {
                    self.set_cell_internal((Y(y + dy), X(x + dx)), Cell::Line);
                }
                GridLoop::decide_edge(self, (Y(y * 2 + dy), X(x * 2 + dx)), Edge::Blank);
            },
        }
    }
    fn inspect_clue(&mut self, cell_cd: Coord) {
        let (Y(y), X(x)) = cell_cd;
        let clue = self.clue[cell_cd];
        let (dy, dx, mut n) = match clue {
            Clue::NoClue | Clue::Empty => return,
            Clue::Up(n) => (-1, 0, n),
            Clue::Left(n) => (0, -1, n),
            Clue::Right(n) => (0, 1, n),
            Clue::Down(n) => (1, 0, n),
        };
        let mut involving_cells = 0;
        {
            let mut y = y + dy;
            let mut x = x + dx;
            while self.clue.is_valid_coord((Y(y), X(x))) {
                let c = self.clue[(Y(y), X(x))];
                if c.same_shape(clue) {
                    n -= c.clue_number();
                    break;
                }
                y += dy;
                x += dx;
                involving_cells += 1;
            }
        }
        let mut dp_left = vec![(0, 0); (involving_cells + 1) as usize];
        let mut dp_right = vec![(0, 0); (involving_cells + 1) as usize];

        for i in 0..involving_cells {
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_left[(i + 1) as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_left[i as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let i = involving_cells - 1 - i;
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_right[i as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_right[(i + 1) as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let (_, left_hi) = dp_left[i as usize];
            let (_, right_hi) = dp_right[(i + 1) as usize];

            if left_hi + right_hi < n - 1 {
                self.set_inconsistent();
                return;
            } else if left_hi + right_hi == n - 1 {
                self.set_cell_internal((Y(y + dy * (i + 1)), X(x + dx * (i + 1))), Cell::Blocked);
            }
        }
    }
}

impl GridLoopField for Field {
    fn grid_loop(&mut self) -> &mut GridLoop {
        &mut self.grid_loop
    }
    fn check_neighborhood(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 0 {
            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));
        } else {
            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));
        }
    }
    fn inspect(&mut self, cd: Coord) {
        let (Y(y), X(x)) = cd;
        if !(y % 2 == 0 && x % 2 == 0) {
            return;
        }
        let cell = self.get_cell((Y(y / 2), X(x / 2)));
        if cell == Cell::Line || cell == Cell::Undecided {
            let (n_line, n_undecided) = self.grid_loop.neighbor_summary(cd);

            if cell == Cell::Line {
                if n_line + n_undecided <= 1 {
                    self.set_inconsistent();
                    return;
                } else if n_line + n_undecided <= 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) != Edge::Blank {
                            GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                        }
                    }
                }
            } else {
                if n_line == 0 && n_undecided == 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) == Edge::Undecided {
                            self.set_cell_internal((Y(y / 2 + dy), X(x / 2 + dx)), Cell::Line);
                        }
                    }
                }
            }
        } else if cell == Cell::Clue {
            self.inspect_clue((Y(y / 2), X(x / 2)));
        }
    }
}

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

    #[test]
    fn test_yajilin_clue() {
        let mut problem = Grid::new(5, 5, Clue::NoClue);
        problem[(Y(2), X(1))] = Clue::Right(2);

        let mut field = Field::new(problem);
        field.check_all_cell();

        assert_eq!(field.inconsistent(), false);
        assert_eq!(field.fully_solved(), true);
        assert_eq!(field.get_cell((Y(2), X(2))), Cell::Blocked);
        assert_eq!(field.get_cell((Y(2), X(4))), Cell::Blocked);
        assert_eq!(field.get_edge((Y(3), X(6))), Edge::Line);
        assert_eq!(field.get_edge((Y(5), X(6))), Edge::Line);
        assert_eq!(field.get_edge((Y(2), X(3))), Edge::Line);
        assert_eq!(field.get_edge((Y(3), X(0))), Edge::Line);
    }
}
<commit_msg>Yajilin: consider lower bounds of block cells in inspect_clue<commit_after>use super::super::{Coord, Grid, X, Y};
use super::*;
use grid_loop::{Edge, GridLoop, GridLoopField};
use std::cmp;

#[derive(Clone)]
pub struct Field {
    grid_loop: GridLoop,
    clue: Grid<Clue>,
    cell: Grid<Cell>,
}

const FOUR_NEIGHBORS: [(i32, i32); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];

impl Field {
    pub fn new(clue: Grid<Clue>) -> Field {
        let height = clue.height();
        let width = clue.width();

        let mut cell = Grid::new(height, width, Cell::Undecided);
        let mut grid_loop = GridLoop::new(height - 1, width - 1);

        {
            let mut handle = GridLoop::get_handle(&mut grid_loop);
            for y in 0..height {
                for x in 0..width {
                    let c = clue[(Y(y), X(x))];
                    if c != Clue::NoClue {
                        cell[(Y(y), X(x))] = Cell::Clue;
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 - 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 + 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 - 1)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 + 1)), Edge::Blank);
                    }
                }
            }
        }
        Field {
            grid_loop,
            clue,
            cell,
        }
    }
    pub fn height(&self) -> i32 {
        self.clue.height()
    }
    pub fn width(&self) -> i32 {
        self.clue.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.grid_loop.inconsistent()
    }
    pub fn set_inconsistent(&mut self) {
        self.grid_loop.set_inconsistent()
    }
    pub fn fully_solved(&self) -> bool {
        self.grid_loop.fully_solved()
    }
    pub fn get_cell(&self, cd: Coord) -> Cell {
        self.cell[cd]
    }
    pub fn get_cell_safe(&self, cd: Coord) -> Cell {
        if self.cell.is_valid_coord(cd) {
            self.cell[cd]
        } else {
            // The outside of the field can be identified with a (meaningless) clue
            Cell::Clue
        }
    }
    pub fn get_edge(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge(cd)
    }
    pub fn get_edge_safe(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge_safe(cd)
    }

    pub fn set_cell(&mut self, cd: Coord, v: Cell) {
        let mut handle = GridLoop::get_handle(self);
        handle.set_cell_internal(cd, v);
    }
    pub fn check_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut handle = GridLoop::get_handle(self);
        for y in 0..height {
            for x in 0..width {
                GridLoop::check(&mut *handle, (Y(y * 2), X(x * 2)));
            }
        }
    }

    fn set_cell_internal(&mut self, cd: Coord, v: Cell) {
        let current = self.cell[cd];
        if current != Cell::Undecided {
            if current != v {
                self.set_inconsistent();
            }
            return;
        }

        self.cell[cd] = v;
        let (Y(y), X(x)) = cd;
        match v {
            Cell::Undecided => (),
            Cell::Clue => (), // don't do this!
            Cell::Line => GridLoop::check(self, (Y(y * 2), X(x * 2))),
            Cell::Blocked => for &(dy, dx) in &FOUR_NEIGHBORS {
                if self.get_cell_safe((Y(y + dy), X(x + dx))) != Cell::Clue {
                    self.set_cell_internal((Y(y + dy), X(x + dx)), Cell::Line);
                }
                GridLoop::decide_edge(self, (Y(y * 2 + dy), X(x * 2 + dx)), Edge::Blank);
            },
        }
    }
    fn inspect_clue(&mut self, cell_cd: Coord) {
        let (Y(y), X(x)) = cell_cd;
        let clue = self.clue[cell_cd];
        let (dy, dx, mut n) = match clue {
            Clue::NoClue | Clue::Empty => return,
            Clue::Up(n) => (-1, 0, n),
            Clue::Left(n) => (0, -1, n),
            Clue::Right(n) => (0, 1, n),
            Clue::Down(n) => (1, 0, n),
        };
        let mut involving_cells = 0;
        {
            let mut y = y + dy;
            let mut x = x + dx;
            while self.clue.is_valid_coord((Y(y), X(x))) {
                let c = self.clue[(Y(y), X(x))];
                if c.same_shape(clue) {
                    n -= c.clue_number();
                    break;
                }
                y += dy;
                x += dx;
                involving_cells += 1;
            }
        }
        let mut dp_left = vec![(0, 0); (involving_cells + 1) as usize];
        let mut dp_right = vec![(0, 0); (involving_cells + 1) as usize];

        for i in 0..involving_cells {
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_left[(i + 1) as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_left[i as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let i = involving_cells - 1 - i;
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_right[i as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_right[(i + 1) as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let (left_lo, left_hi) = dp_left[i as usize];
            let (right_lo, right_hi) = dp_right[(i + 1) as usize];

            if left_hi + right_hi < n - 1 {
                self.set_inconsistent();
                return;
            } else if left_hi + right_hi == n - 1 {
                self.set_cell_internal((Y(y + dy * (i + 1)), X(x + dx * (i + 1))), Cell::Blocked);
            }

            if left_lo + right_lo > n {
                self.set_inconsistent();
                return;
            } else if left_lo + right_lo == n {
                self.set_cell_internal((Y(y + dy * (i + 1)), X(x + dx * (i + 1))), Cell::Line);
            }
        }
    }
}

impl GridLoopField for Field {
    fn grid_loop(&mut self) -> &mut GridLoop {
        &mut self.grid_loop
    }
    fn check_neighborhood(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 0 {
            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));
        } else {
            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));
        }
    }
    fn inspect(&mut self, cd: Coord) {
        let (Y(y), X(x)) = cd;
        if !(y % 2 == 0 && x % 2 == 0) {
            return;
        }
        let cell = self.get_cell((Y(y / 2), X(x / 2)));
        if cell == Cell::Line || cell == Cell::Undecided {
            let (n_line, n_undecided) = self.grid_loop.neighbor_summary(cd);

            if cell == Cell::Line {
                if n_line + n_undecided <= 1 {
                    self.set_inconsistent();
                    return;
                } else if n_line + n_undecided <= 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) != Edge::Blank {
                            GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                        }
                    }
                }
            } else {
                if n_line == 0 && n_undecided == 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) == Edge::Undecided {
                            self.set_cell_internal((Y(y / 2 + dy), X(x / 2 + dx)), Cell::Line);
                        }
                    }
                }
            }
        } else if cell == Cell::Clue {
            self.inspect_clue((Y(y / 2), X(x / 2)));
        }
    }
}

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

    #[test]
    fn test_yajilin_clue() {
        {
            // Loop must not pass through clue cells
            let mut problem = Grid::new(5, 5, Clue::NoClue);
            problem[(Y(0), X(0))] = Clue::Right(1);

            let mut field = Field::new(problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_edge((Y(0), X(1))), Edge::Blank);
            assert_eq!(field.get_edge((Y(1), X(0))), Edge::Blank);
        }
        {
            // 0 block cells
            let mut problem = Grid::new(5, 7, Clue::NoClue);
            problem[(Y(0), X(3))] = Clue::Right(0);

            let mut field = Field::new(problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_cell((Y(0), X(4))), Cell::Line);
            assert_eq!(field.get_cell((Y(0), X(5))), Cell::Line);
            assert_eq!(field.get_cell((Y(0), X(6))), Cell::Line);
            assert_eq!(field.get_edge((Y(1), X(8))), Edge::Line);
        }
        {
            // 2 block cells in 3 consecutive cells
            let mut problem = Grid::new(5, 5, Clue::NoClue);
            problem[(Y(2), X(1))] = Clue::Right(2);

            let mut field = Field::new(problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.fully_solved(), true);
            assert_eq!(field.get_cell((Y(2), X(2))), Cell::Blocked);
            assert_eq!(field.get_cell((Y(2), X(4))), Cell::Blocked);
            assert_eq!(field.get_edge((Y(3), X(6))), Edge::Line);
            assert_eq!(field.get_edge((Y(5), X(6))), Edge::Line);
            assert_eq!(field.get_edge((Y(2), X(3))), Edge::Line);
            assert_eq!(field.get_edge((Y(3), X(0))), Edge::Line);
        }
    }
}
<|endoftext|>


<commit_before>extern crate base32;
extern crate oath;

use oath::{totp_raw_now, HashType};

use std::env;

fn main() {
    println!("{:?}", totp_raw_now(base32::decode(base32::Alphabet::RFC4648{ padding: false }, &env::args().nth(1).unwrap()).unwrap().as_ref(), 6, 0, 30, &HashType::SHA1));
}
<commit_msg>totpcli: add padding<commit_after>extern crate base32;
extern crate oath;

use oath::{totp_raw_now, HashType};

use std::env;

fn main() {
    println!("{:06}", totp_raw_now(base32::decode(base32::Alphabet::RFC4648{ padding: false }, &env::args().nth(1).unwrap()).unwrap().as_ref(), 6, 0, 30, &HashType::SHA1));
}
<|endoftext|>


<commit_before><commit_msg>Refactor the macros in spec<commit_after><|endoftext|>


<commit_before><commit_msg>Implement SetIntro/SetElim in terms of tries<commit_after><|endoftext|>


<commit_before>use crate::utils::paths::{FUTURE_CORE, FUTURE_FROM_GENERATOR, FUTURE_STD};
use crate::utils::{match_function_call, match_path, snippet_block, snippet_opt, span_lint_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericBound, HirId, IsAsync,
    ItemKind, TraitRef, Ty, TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** It checks for manual implementations of `async` functions.
    ///
    /// **Why is this bad?** It's more idiomatic to use the dedicated syntax.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// use std::future::Future;
    ///
    /// fn foo() -> Future<Output = i32> { async { 42 } }
    /// ```
    /// Use instead:
    /// ```rust
    /// use std::future::Future;
    ///
    /// async fn foo() -> i32 { 42 }
    /// ```
    pub MANUAL_ASYNC_FN,
    style,
    "manual implementations of `async` functions can be simplified using the dedicated syntax"
}

declare_lint_pass!(ManualAsyncFn => [MANUAL_ASYNC_FN]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ManualAsyncFn {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        span: Span,
        _: HirId,
    ) {
        if_chain! {
            if let Some(header) = kind.header();
            if let IsAsync::NotAsync = header.asyncness;
            // Check that this function returns `impl Future`
            if let FnRetTy::Return(ret_ty) = decl.output;
            if let Some(trait_ref) = future_trait_ref(cx, ret_ty);
            if let Some(output) = future_output_ty(trait_ref);
            // Check that the body of the function consists of one async block
            if let ExprKind::Block(block, _) = body.value.kind;
            if block.stmts.is_empty();
            if let Some(closure_body) = desugared_async_block(cx, block);
            then {
                let header_span = span.with_hi(ret_ty.span.hi());

                span_lint_and_then(
                    cx,
                    MANUAL_ASYNC_FN,
                    header_span,
                    "this function can be simplified using async syntax",
                    |diag| {
                        if_chain! {
                            if let Some(header_snip) = snippet_opt(cx, header_span);
                            if let Some(ret_pos) = header_snip.rfind("->");
                            if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
                            then {
                                let help = format!("make the function `async` and {}", ret_sugg);
                                diag.span_suggestion(
                                    header_span,
                                    &help,
                                    format!("async {}{}", &header_snip[..ret_pos], ret_snip),
                                    Applicability::MachineApplicable
                                );

                                let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
                                diag.span_suggestion(
                                    block.span,
                                    "move the body of the async block to the enclosing function",
                                    body_snip.to_string(),
                                    Applicability::MachineApplicable
                                );
                            }
                        }
                    },
                );
            }
        }
    }
}

fn future_trait_ref<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &'tcx Ty<'tcx>) -> Option<&'tcx TraitRef<'tcx>> {
    if_chain! {
        if let TyKind::Def(item_id, _) = ty.kind;
        let item = cx.tcx.hir().item(item_id.id);
        if let ItemKind::OpaqueTy(opaque) = &item.kind;
        if opaque.bounds.len() == 1;
        if let GenericBound::Trait(poly, _) = &opaque.bounds[0];
        let path = poly.trait_ref.path;
        if match_path(&path, &FUTURE_CORE) || match_path(&path, &FUTURE_STD);
        then {
            return Some(&poly.trait_ref);
        }
    }

    None
}

fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
    if_chain! {
        if let Some(segment) = trait_ref.path.segments.last();
        if let Some(args) = segment.args;
        if args.bindings.len() == 1;
        let binding = &args.bindings[0];
        if binding.ident.as_str() == "Output";
        if let TypeBindingKind::Equality{ty: output} = binding.kind;
        then {
            return Some(output)
        }
    }

    None
}

fn desugared_async_block<'tcx>(cx: &LateContext<'_, 'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
    if_chain! {
        if let Some(block_expr) = block.expr;
        if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
        if args.len() == 1;
        if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0];
        let closure_body = cx.tcx.hir().body(body_id);
        if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind;
        then {
            return Some(closure_body);
        }
    }

    None
}

fn suggested_ret(cx: &LateContext<'_, '_>, output: &Ty<'_>) -> Option<(&'static str, String)> {
    match output.kind {
        TyKind::Tup(tys) if tys.is_empty() => {
            let sugg = "remove the return type";
            Some((sugg, "".into()))
        },
        _ => {
            let sugg = "return the output of the future directly";
            snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip)))
        },
    }
}
<commit_msg>Fix doc comment in lint declaration<commit_after>use crate::utils::paths::{FUTURE_CORE, FUTURE_FROM_GENERATOR, FUTURE_STD};
use crate::utils::{match_function_call, match_path, snippet_block, snippet_opt, span_lint_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericBound, HirId, IsAsync,
    ItemKind, TraitRef, Ty, TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** It checks for manual implementations of `async` functions.
    ///
    /// **Why is this bad?** It's more idiomatic to use the dedicated syntax.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// use std::future::Future;
    ///
    /// fn foo() -> impl Future<Output = i32> { async { 42 } }
    /// ```
    /// Use instead:
    /// ```rust
    /// use std::future::Future;
    ///
    /// async fn foo() -> i32 { 42 }
    /// ```
    pub MANUAL_ASYNC_FN,
    style,
    "manual implementations of `async` functions can be simplified using the dedicated syntax"
}

declare_lint_pass!(ManualAsyncFn => [MANUAL_ASYNC_FN]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ManualAsyncFn {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        span: Span,
        _: HirId,
    ) {
        if_chain! {
            if let Some(header) = kind.header();
            if let IsAsync::NotAsync = header.asyncness;
            // Check that this function returns `impl Future`
            if let FnRetTy::Return(ret_ty) = decl.output;
            if let Some(trait_ref) = future_trait_ref(cx, ret_ty);
            if let Some(output) = future_output_ty(trait_ref);
            // Check that the body of the function consists of one async block
            if let ExprKind::Block(block, _) = body.value.kind;
            if block.stmts.is_empty();
            if let Some(closure_body) = desugared_async_block(cx, block);
            then {
                let header_span = span.with_hi(ret_ty.span.hi());

                span_lint_and_then(
                    cx,
                    MANUAL_ASYNC_FN,
                    header_span,
                    "this function can be simplified using async syntax",
                    |diag| {
                        if_chain! {
                            if let Some(header_snip) = snippet_opt(cx, header_span);
                            if let Some(ret_pos) = header_snip.rfind("->");
                            if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
                            then {
                                let help = format!("make the function `async` and {}", ret_sugg);
                                diag.span_suggestion(
                                    header_span,
                                    &help,
                                    format!("async {}{}", &header_snip[..ret_pos], ret_snip),
                                    Applicability::MachineApplicable
                                );

                                let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
                                diag.span_suggestion(
                                    block.span,
                                    "move the body of the async block to the enclosing function",
                                    body_snip.to_string(),
                                    Applicability::MachineApplicable
                                );
                            }
                        }
                    },
                );
            }
        }
    }
}

fn future_trait_ref<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &'tcx Ty<'tcx>) -> Option<&'tcx TraitRef<'tcx>> {
    if_chain! {
        if let TyKind::Def(item_id, _) = ty.kind;
        let item = cx.tcx.hir().item(item_id.id);
        if let ItemKind::OpaqueTy(opaque) = &item.kind;
        if opaque.bounds.len() == 1;
        if let GenericBound::Trait(poly, _) = &opaque.bounds[0];
        let path = poly.trait_ref.path;
        if match_path(&path, &FUTURE_CORE) || match_path(&path, &FUTURE_STD);
        then {
            return Some(&poly.trait_ref);
        }
    }

    None
}

fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
    if_chain! {
        if let Some(segment) = trait_ref.path.segments.last();
        if let Some(args) = segment.args;
        if args.bindings.len() == 1;
        let binding = &args.bindings[0];
        if binding.ident.as_str() == "Output";
        if let TypeBindingKind::Equality{ty: output} = binding.kind;
        then {
            return Some(output)
        }
    }

    None
}

fn desugared_async_block<'tcx>(cx: &LateContext<'_, 'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
    if_chain! {
        if let Some(block_expr) = block.expr;
        if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
        if args.len() == 1;
        if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0];
        let closure_body = cx.tcx.hir().body(body_id);
        if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind;
        then {
            return Some(closure_body);
        }
    }

    None
}

fn suggested_ret(cx: &LateContext<'_, '_>, output: &Ty<'_>) -> Option<(&'static str, String)> {
    match output.kind {
        TyKind::Tup(tys) if tys.is_empty() => {
            let sugg = "remove the return type";
            Some((sugg, "".into()))
        },
        _ => {
            let sugg = "return the output of the future directly";
            snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip)))
        },
    }
}
<|endoftext|>