<commit_before>extern crate minifb;
extern crate bgfx;
extern crate viewdock;
extern crate renderer;

mod window;
mod keys;

use renderer::Renderer;
use core::view_plugins::ViewPlugins;
use core::backend_plugin::{BackendHandle, BackendPlugins};
use core::session::Sessions;
use settings::Settings;
use self::window::Window;
use self::keys::KeyCharCallback;
use menu::{MENU_FILE_BACKEND_START, MENU_FILE_BACKEND_END};
use project::Project;

const WIDTH: i32 = 1280;
const HEIGHT: i32 = 800;

/// ! Windows keeps track of all different windows that are present with in the application
/// ! There are several ways windows can be created:
/// !
/// ! 1. User opens a new window using a shortcut or menu selection.
/// ! 2. User "undocks" a view from an existing window giving it it's own floating window.
/// ! 3. etc

pub struct Windows {
    /// All the windows being tracked
    windows: Vec<Window>,
    current: usize,
    renderer: Renderer,
}

impl Windows {
    pub fn new() -> Windows {
        Windows {
            windows: Vec::new(),
            renderer: Renderer::new(),
            current: 0,
        }
    }

    /// Create a default window which will only be created if there are no other
    pub fn create_default(&mut self, settings: &Settings, backend_plugins: Vec<String>) {
        if self.windows.len() > 0 {
            return;
        }

        let window = self.create_window_with_menus(settings, backend_plugins)
            .expect("Unable to create window");

        keys::setup_imgui_key_mappings();

        self.windows.push(window)
    }

    pub fn create_window(&mut self, width: usize, height: usize) -> minifb::Result<Window> {
        let win = try!(Window::new(width, height));
        // TODO: Return correctly
        self.renderer
            .setup_window(win.win.get_window_handle(), width as u16, height as u16)
            .unwrap();
        Ok(win)
    }

    pub fn create_window_with_menus(&mut self,
                                    settings: &Settings,
                                    backend_plugins: Vec<String>)
                                    -> minifb::Result<Window> {
        let width = settings.get_int("window_size", "width").unwrap_or(WIDTH) as usize;
        let height = settings.get_int("window_size", "height").unwrap_or(HEIGHT) as usize;

        let mut window = try!(self.create_window(width, height));

        window.win.set_input_callback(Box::new(KeyCharCallback {}));

        Self::add_backend_menus(&mut window, backend_plugins);

        // TODO: Figure check result of add_menu
        window.win.add_menu(&window.menu.file_menu);
        window.win.add_menu(&window.menu.debug_menu);

        Ok(window)
    }

    pub fn update(&mut self,
                  sessions: &mut Sessions,
                  view_plugins: &mut ViewPlugins,
                  backend_plugins: &mut BackendPlugins) {
        for win in &mut self.windows {
            win.pre_update();
        }

        self.renderer.pre_update();

        for i in (0..self.windows.len()).rev() {
            self.windows[i].update(sessions, view_plugins, backend_plugins);
            self.renderer.update_size(self.windows[i].win.get_size());

            if !self.windows[i].win.is_open() {
                // TODO: Support more than one window
                self.save_project("data/current_project.json",
                                  sessions,
                                  backend_plugins,
                                  view_plugins);
                self.windows.swap_remove(i);
            }
        }

        self.renderer.post_update();
    }

    pub fn get_current(&mut self) -> &mut Window {
        let current = self.current;
        &mut self.windows[current]
    }

    fn add_backend_menus(window: &mut Window, backend_plugins: Vec<String>) {
        // Build menu with all the backend plugins
        let mut backend_menus = minifb::Menu::new("").unwrap();

        for (i, name) in backend_plugins.iter().enumerate() {
            let id = MENU_FILE_BACKEND_START + i;

            if id >= MENU_FILE_BACKEND_END {
                panic!("Maximum number of backends reached {}",
                       MENU_FILE_BACKEND_END - MENU_FILE_BACKEND_START);
            }

            backend_menus.add_item(&name, id).build();
        }

        window.menu.file_menu.add_sub_menu("New Project...", &backend_menus);
    }

    /// Checks if application should exit (all window instances closed)
    pub fn should_exit(&self) -> bool {
        self.windows.is_empty()
    }

    /// Save the state of the windows (usually done when exiting the application)
    pub fn save_project(&mut self,
                        filename: &str,
                        sessions: &mut Sessions,
                        backend_plugins: &mut BackendPlugins,
                        view_plugins: &mut ViewPlugins) {
        // TODO: This only supports one window for now
        if self.windows.len() == 1 {
            println!("save layout");
            let layout = self.windows[0].layout_to_string(view_plugins);
            let mut backend_name = "".to_owned();
            let mut backend_data = None;

            if let Some(backend) = backend_plugins.get_backend(sessions.get_current().backend) {
                let t = backend.get_plugin_data();
                backend_name = t.0;
                backend_data = t.1;
            }

            let p = Project {
                backend_name: backend_name,
                backend_data: backend_data,
                layout_data: layout,
            };

            // TODO: Proper error handling
            p.save(filename).unwrap();
        }
    }

    /// Load the state of all the views from a previous run
    pub fn init(&mut self,
                layout_data: &str,
                view_plugins: &mut ViewPlugins,
                backend: Option<BackendHandle>,
                backend_plugins: &mut BackendPlugins) {
        // TODO: This only supports one window for now
        if self.windows.len() == 1 {
            // TODO: Proper error handling here (loading is ok to fail though)
            let _ = self.windows[0].init_layout(layout_data, view_plugins);

            if let Some(backend) = backend {
                if let Some(menu) =
                       backend_plugins.get_menu(backend, self.windows[0].menu_id_offset) {
                    self.windows[0].win.add_menu(&(*menu));
                    self.windows[0].menu_id_offset += 1000;
                }
            }
        }
    }
}
<commit_msg>Fixed menu name for "New project..." sub-menu. (#291)<commit_after>extern crate minifb;
extern crate bgfx;
extern crate viewdock;
extern crate renderer;

mod window;
mod keys;

use renderer::Renderer;
use core::view_plugins::ViewPlugins;
use core::backend_plugin::{BackendHandle, BackendPlugins};
use core::session::Sessions;
use settings::Settings;
use self::window::Window;
use self::keys::KeyCharCallback;
use menu::{MENU_FILE_BACKEND_START, MENU_FILE_BACKEND_END};
use project::Project;

const WIDTH: i32 = 1280;
const HEIGHT: i32 = 800;

/// ! Windows keeps track of all different windows that are present with in the application
/// ! There are several ways windows can be created:
/// !
/// ! 1. User opens a new window using a shortcut or menu selection.
/// ! 2. User "undocks" a view from an existing window giving it it's own floating window.
/// ! 3. etc

pub struct Windows {
    /// All the windows being tracked
    windows: Vec<Window>,
    current: usize,
    renderer: Renderer,
}

impl Windows {
    pub fn new() -> Windows {
        Windows {
            windows: Vec::new(),
            renderer: Renderer::new(),
            current: 0,
        }
    }

    /// Create a default window which will only be created if there are no other
    pub fn create_default(&mut self, settings: &Settings, backend_plugins: Vec<String>) {
        if self.windows.len() > 0 {
            return;
        }

        let window = self.create_window_with_menus(settings, backend_plugins)
            .expect("Unable to create window");

        keys::setup_imgui_key_mappings();

        self.windows.push(window)
    }

    pub fn create_window(&mut self, width: usize, height: usize) -> minifb::Result<Window> {
        let win = try!(Window::new(width, height));
        // TODO: Return correctly
        self.renderer
            .setup_window(win.win.get_window_handle(), width as u16, height as u16)
            .unwrap();
        Ok(win)
    }

    pub fn create_window_with_menus(&mut self,
                                    settings: &Settings,
                                    backend_plugins: Vec<String>)
                                    -> minifb::Result<Window> {
        let width = settings.get_int("window_size", "width").unwrap_or(WIDTH) as usize;
        let height = settings.get_int("window_size", "height").unwrap_or(HEIGHT) as usize;

        let mut window = try!(self.create_window(width, height));

        window.win.set_input_callback(Box::new(KeyCharCallback {}));

        Self::add_backend_menus(&mut window, backend_plugins);

        // TODO: Figure check result of add_menu
        window.win.add_menu(&window.menu.file_menu);
        window.win.add_menu(&window.menu.debug_menu);

        Ok(window)
    }

    pub fn update(&mut self,
                  sessions: &mut Sessions,
                  view_plugins: &mut ViewPlugins,
                  backend_plugins: &mut BackendPlugins) {
        for win in &mut self.windows {
            win.pre_update();
        }

        self.renderer.pre_update();

        for i in (0..self.windows.len()).rev() {
            self.windows[i].update(sessions, view_plugins, backend_plugins);
            self.renderer.update_size(self.windows[i].win.get_size());

            if !self.windows[i].win.is_open() {
                // TODO: Support more than one window
                self.save_project("data/current_project.json",
                                  sessions,
                                  backend_plugins,
                                  view_plugins);
                self.windows.swap_remove(i);
            }
        }

        self.renderer.post_update();
    }

    pub fn get_current(&mut self) -> &mut Window {
        let current = self.current;
        &mut self.windows[current]
    }

    fn add_backend_menus(window: &mut Window, backend_plugins: Vec<String>) {
        // Build menu with all the backend plugins
        let mut backend_menus = minifb::Menu::new("New Project...").unwrap();

        for (i, name) in backend_plugins.iter().enumerate() {
            let id = MENU_FILE_BACKEND_START + i;

            if id >= MENU_FILE_BACKEND_END {
                panic!("Maximum number of backends reached {}",
                       MENU_FILE_BACKEND_END - MENU_FILE_BACKEND_START);
            }

            backend_menus.add_item(&name, id).build();
        }

        window.menu.file_menu.add_sub_menu("New Project...", &backend_menus);
    }

    /// Checks if application should exit (all window instances closed)
    pub fn should_exit(&self) -> bool {
        self.windows.is_empty()
    }

    /// Save the state of the windows (usually done when exiting the application)
    pub fn save_project(&mut self,
                        filename: &str,
                        sessions: &mut Sessions,
                        backend_plugins: &mut BackendPlugins,
                        view_plugins: &mut ViewPlugins) {
        // TODO: This only supports one window for now
        if self.windows.len() == 1 {
            println!("save layout");
            let layout = self.windows[0].layout_to_string(view_plugins);
            let mut backend_name = "".to_owned();
            let mut backend_data = None;

            if let Some(backend) = backend_plugins.get_backend(sessions.get_current().backend) {
                let t = backend.get_plugin_data();
                backend_name = t.0;
                backend_data = t.1;
            }

            let p = Project {
                backend_name: backend_name,
                backend_data: backend_data,
                layout_data: layout,
            };

            // TODO: Proper error handling
            p.save(filename).unwrap();
        }
    }

    /// Load the state of all the views from a previous run
    pub fn init(&mut self,
                layout_data: &str,
                view_plugins: &mut ViewPlugins,
                backend: Option<BackendHandle>,
                backend_plugins: &mut BackendPlugins) {
        // TODO: This only supports one window for now
        if self.windows.len() == 1 {
            // TODO: Proper error handling here (loading is ok to fail though)
            let _ = self.windows[0].init_layout(layout_data, view_plugins);

            if let Some(backend) = backend {
                if let Some(menu) =
                       backend_plugins.get_menu(backend, self.windows[0].menu_id_offset) {
                    self.windows[0].win.add_menu(&(*menu));
                    self.windows[0].menu_id_offset += 1000;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0
use anyhow::{format_err, Error, Result};
use serde::{de::Visitor, export::fmt::Debug, Deserialize, Deserializer, Serialize};
use std::{
    convert::TryFrom,
    fmt::{Display, Formatter},
    str::FromStr,
};

/// A registry of named chain IDs
/// Its main purpose is to improve human readability of reserved chain IDs in config files and CLI
/// When signing transactions for such chains, the numerical chain ID should still be used
/// (e.g. MAINNET has numeric chain ID 1, TESTNET has chain ID 2, etc)
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum NamedChain {
    /// Users might accidentally initialize the ChainId field to 0, hence reserving ChainId 0 for accidental
    /// initialization.
    /// MAINNET is the Libra mainnet production chain and is reserved for 1
    MAINNET = 1,
    // Even though these CHAIN IDs do not correspond to MAINNET, changing them should be avoided since they
    // can break test environments for various organisations.
    TESTNET = 2,
    DEVNET = 3,
    TESTING = 4,
}

impl NamedChain {
    fn str_to_chain_id(s: &str) -> Result<ChainId> {
        // TODO implement custom macro that derives FromStr impl for enum (similar to libra/common/num-variants)
        let reserved_chain = match s {
            "MAINNET" => NamedChain::MAINNET,
            "TESTNET" => NamedChain::TESTNET,
            "DEVNET" => NamedChain::DEVNET,
            "TESTING" => NamedChain::TESTING,
            _ => {
                return Err(format_err!("Not a reserved chain: {:?}", s));
            }
        };
        Ok(ChainId::new(reserved_chain.id()))
    }

    pub fn id(&self) -> u8 {
        *self as u8
    }

    fn from_chain_id(chain_id: &ChainId) -> Result<NamedChain, String> {
        match chain_id.id() {
            1 => Ok(NamedChain::MAINNET),
            2 => Ok(NamedChain::TESTNET),
            3 => Ok(NamedChain::DEVNET),
            4 => Ok(NamedChain::TESTING),
            _ => Err(String::from("Not a named chain")),
        }
    }
}

/// Note: u7 in a u8 is uleb-compatible, and any usage of this should be aware
/// that this field maybe updated to be uleb64 in the future
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ChainId(u8);

pub fn deserialize_config_chain_id<'de, D>(
    deserializer: D,
) -> std::result::Result<ChainId, D::Error>
where
    D: Deserializer<'de>,
{
    struct ChainIdVisitor;

    impl<'de> Visitor<'de> for ChainIdVisitor {
        type Value = ChainId;

        fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            formatter.write_str("ChainId as string or u8")
        }

        fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ChainId::from_str(value).map_err(serde::de::Error::custom)
        }

        fn visit_u64<E>(self, value: u64) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(ChainId::new(
                u8::try_from(value).map_err(serde::de::Error::custom)?,
            ))
        }
    }

    deserializer.deserialize_any(ChainIdVisitor)
}

impl Debug for ChainId {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(f, "{}", self)
    }
}

impl Display for ChainId {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "{}",
            NamedChain::from_chain_id(&self)
                .map_or_else(|_| self.0.to_string(), |chain| chain.to_string())
        )
    }
}

impl Display for NamedChain {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                NamedChain::DEVNET => "DEVNET",
                NamedChain::TESTNET => "TESTNET",
                NamedChain::MAINNET => "MAINNET",
                NamedChain::TESTING => "TESTING",
            }
        )
    }
}

impl Default for ChainId {
    fn default() -> Self {
        Self::test()
    }
}

impl FromStr for ChainId {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        assert!(!s.is_empty());
        NamedChain::str_to_chain_id(s).or_else(|_err| Ok(ChainId::new(s.parse::<u8>()?)))
    }
}

impl ChainId {
    pub fn new(id: u8) -> Self {
        assert!(id > 0, "cannot have chain ID with 0");
        Self(id)
    }

    pub fn id(&self) -> u8 {
        self.0
    }

    pub fn test() -> Self {
        ChainId::new(NamedChain::TESTING.id())
    }
}
<commit_msg>[chain id] rm panic in ChainId from_str<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0
use anyhow::{ensure, format_err, Error, Result};
use serde::{de::Visitor, export::fmt::Debug, Deserialize, Deserializer, Serialize};
use std::{
    convert::TryFrom,
    fmt::{Display, Formatter},
    str::FromStr,
};

/// A registry of named chain IDs
/// Its main purpose is to improve human readability of reserved chain IDs in config files and CLI
/// When signing transactions for such chains, the numerical chain ID should still be used
/// (e.g. MAINNET has numeric chain ID 1, TESTNET has chain ID 2, etc)
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum NamedChain {
    /// Users might accidentally initialize the ChainId field to 0, hence reserving ChainId 0 for accidental
    /// initialization.
    /// MAINNET is the Libra mainnet production chain and is reserved for 1
    MAINNET = 1,
    // Even though these CHAIN IDs do not correspond to MAINNET, changing them should be avoided since they
    // can break test environments for various organisations.
    TESTNET = 2,
    DEVNET = 3,
    TESTING = 4,
}

impl NamedChain {
    fn str_to_chain_id(s: &str) -> Result<ChainId> {
        // TODO implement custom macro that derives FromStr impl for enum (similar to libra/common/num-variants)
        let reserved_chain = match s {
            "MAINNET" => NamedChain::MAINNET,
            "TESTNET" => NamedChain::TESTNET,
            "DEVNET" => NamedChain::DEVNET,
            "TESTING" => NamedChain::TESTING,
            _ => {
                return Err(format_err!("Not a reserved chain: {:?}", s));
            }
        };
        Ok(ChainId::new(reserved_chain.id()))
    }

    pub fn id(&self) -> u8 {
        *self as u8
    }

    fn from_chain_id(chain_id: &ChainId) -> Result<NamedChain, String> {
        match chain_id.id() {
            1 => Ok(NamedChain::MAINNET),
            2 => Ok(NamedChain::TESTNET),
            3 => Ok(NamedChain::DEVNET),
            4 => Ok(NamedChain::TESTING),
            _ => Err(String::from("Not a named chain")),
        }
    }
}

/// Note: u7 in a u8 is uleb-compatible, and any usage of this should be aware
/// that this field maybe updated to be uleb64 in the future
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ChainId(u8);

pub fn deserialize_config_chain_id<'de, D>(
    deserializer: D,
) -> std::result::Result<ChainId, D::Error>
where
    D: Deserializer<'de>,
{
    struct ChainIdVisitor;

    impl<'de> Visitor<'de> for ChainIdVisitor {
        type Value = ChainId;

        fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            formatter.write_str("ChainId as string or u8")
        }

        fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ChainId::from_str(value).map_err(serde::de::Error::custom)
        }

        fn visit_u64<E>(self, value: u64) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(ChainId::new(
                u8::try_from(value).map_err(serde::de::Error::custom)?,
            ))
        }
    }

    deserializer.deserialize_any(ChainIdVisitor)
}

impl Debug for ChainId {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(f, "{}", self)
    }
}

impl Display for ChainId {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "{}",
            NamedChain::from_chain_id(&self)
                .map_or_else(|_| self.0.to_string(), |chain| chain.to_string())
        )
    }
}

impl Display for NamedChain {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                NamedChain::DEVNET => "DEVNET",
                NamedChain::TESTNET => "TESTNET",
                NamedChain::MAINNET => "MAINNET",
                NamedChain::TESTING => "TESTING",
            }
        )
    }
}

impl Default for ChainId {
    fn default() -> Self {
        Self::test()
    }
}

impl FromStr for ChainId {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        ensure!(!s.is_empty(), "Cannot create chain ID from empty string");
        NamedChain::str_to_chain_id(s).or_else(|_err| {
            let value = s.parse::<u8>()?;
            ensure!(value > 0, "cannot have chain ID with 0");
            Ok(ChainId::new(value))
        })
    }
}

impl ChainId {
    pub fn new(id: u8) -> Self {
        assert!(id > 0, "cannot have chain ID with 0");
        Self(id)
    }

    pub fn id(&self) -> u8 {
        self.0
    }

    pub fn test() -> Self {
        ChainId::new(NamedChain::TESTING.id())
    }
}

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

    #[test]
    fn test_chain_id_from_str() {
        assert!(ChainId::from_str("").is_err());
        assert!(ChainId::from_str("0").is_err());
        assert!(ChainId::from_str("256").is_err());
        assert!(ChainId::from_str("255255").is_err());
        assert_eq!(ChainId::from_str("TESTING").unwrap(), ChainId::test());
        assert_eq!(ChainId::from_str("255").unwrap(), ChainId::new(255));
    }
}
<|endoftext|>


<commit_before>use parking_lot::RwLock;
use std::rc::Rc;

use crate::core::view::ContentFilter;
use crate::core::view::FilterData;
use crate::core::view::FilterIo;
use crate::core::view::LayoutEnv;
use crate::core::Editor;

use crate::core::view::View;

use super::TextModeContext;
use crate::core::codec::text::u32_to_char;

use crate::core::codepointinfo::TextStyle;

pub struct WordWrapFilter {
    max_column: u64,
    column_count: u64,
    accum: Vec<FilterIo>,
    display_wrap: bool,
}

impl WordWrapFilter {
    pub fn new() -> Self {
        WordWrapFilter {
            max_column: 0,
            column_count: 0,
            accum: vec![],
            display_wrap: false,
        }
    }
}

fn set_io_color(io: &FilterIo, color: (u8, u8, u8)) -> FilterIo {
    // flush new line
    let mut new_io = FilterIo {
        // general info
        metadata: false,
        style: TextStyle::new(),
        offset: io.offset,
        size: io.size,
        data: io.data.clone(),
    };

    {
        new_io.style.is_blinking = true;
        new_io.style.is_selected = true;
        new_io.style.bg_color = color;
    }

    new_io
}

fn set_first_column_color(io: &FilterIo) -> FilterIo {
    set_io_color(io, (0, 0, 255))
}

fn build_wrap_point_io(blank_offset: Option<u64>) -> FilterIo {
    FilterIo {
        // general info
        metadata: true,
        style: TextStyle::new(), // TODO(ceg): customize
        offset: blank_offset,
        size: 0,
        data: FilterData::TextInfo {
            real_cp: '\n' as u32,
            displayed_cp: '\\' as u32,
        },
    }
}

impl ContentFilter<'_> for WordWrapFilter {
    fn name(&self) -> &'static str {
        &"WordWrapFilter"
    }

    fn setup(
        &mut self,
        _editor: &Editor,
        env: &mut LayoutEnv,
        view: &Rc<RwLock<View>>,
        _parent_view: Option<&View<'static>>,
    ) {
        self.max_column = env.screen.width() as u64;
        self.column_count = 0;
        self.accum = Vec::new();

        // the screen is the final output
        // TODO(ceg): ask env.screen.cp_width(cp) -> nb_cells
        // or embed cp_width in FilterIo meta ?

        let v = view.read();
        if v.check_mode_ctx::<TextModeContext>("text-mode") {
            let tm = v.mode_ctx::<TextModeContext>("text-mode");
            self.display_wrap = tm.display_word_wrap;
        }
    }

    /*
            TODO(ceg): filters dependencies: check in view's filter_array that
            dep.index < cur_filter.index or (and WARN)
            we can push multiple times new instance of a filter :-)

            prerequisite:
            - tab expansion before: ('\t' -> ' ' should be done before)

        display offset in status

            NB: accum.len() != column count

    BEFORE:
            |  0    1    2    3    4    5    6    7    8 |  9  |        max_col = 10
            | xx |    |   ww    | xx | xx | xx | xx | xx | xx  |
                   ^      ^                                       ^
                   |      |_ wide char (2 cols)                   |
                   |                                              |
             blank_col_idx                                    colum_count = 10

            |  0    1    2    3    4    5    6    7    8 |  9  | max_col = 10
            | xx |    |   ww    | xx | xx | xx | xx | xx | xx  | <ADD>
                   ^      ^
                   |      |_ wide char (2 cols)                   ^
                   |                                              |
             blank_col_idx                                    colum_count

            column_count + width(<ADD>) >= max_col  : compute wrap

        */
    fn run(
        &mut self,
        _view: &View,
        env: &mut LayoutEnv,
        filter_in: &Vec<FilterIo>,
        filter_out: &mut Vec<FilterIo>,
    ) {
        if self.max_column <= 2
        /* TODO(ceg) screen.max_char_width() */
        {
            *filter_out = filter_in.clone();
            return;
        }

        let mut blank_column_idx = 0;
        let mut blank_accum_idx = 0;
        let mut blank_offset: Option<u64> = None;

        let debug = false;

        for io in filter_in.iter() {
            if let FilterIo {
                data: FilterData::TextInfo { real_cp, .. },
                ..
            } = &*io
            {
                let c = u32_to_char(*real_cp);
                let width = env.screen.char_width(c) as u64;

                if debug {
                    dbg_println!("WRAP: -------------");
                    dbg_println!("WRAP: BEFORE : char '{}', width {}, column_count {} max_column {} blank_accum_idx {} blank_offset {:?} blank_column_idx {}",
                    c, width, self.column_count , self.max_column, blank_accum_idx , blank_offset , blank_column_idx);
                    dbg_println!(
                        "WRAP: self.column_count + width {}",
                        self.column_count + width
                    );
                    dbg_println!("WRAP: self.accum.len() {}", self.accum.len());

                    dbg_println!("WRAP:    >>>>>");
                }

                // width overflow  ?
                if self.column_count + width > self.max_column {
                    // not blank and accum > max column
                    if debug {
                        dbg_println!("WRAP: OVERFLOW self.column_count + width >= self.max_column");
                    }

                    // have previous blank ? => split accum after blank, insert '\' wrap point
                    if blank_offset.is_some()
                        && c != ' '
                        && c != '\n' // user option ?
                        && blank_column_idx > 0
                        && blank_column_idx + 1 != self.max_column
                    {
                        if debug {
                            dbg_println!("WRAP: line contains blank");

                            dbg_println!("WRAP: add WRAP POINT");
                        }
                        let mut fnl = build_wrap_point_io(blank_offset);

                        // TODO(ceg): add use option
                        if true || self.display_wrap {
                            fnl.style.color = (255, 255, 0); // yellow '\'
                        }

                        let mut new = self.accum.split_off(blank_accum_idx + 1);
                        if debug {
                            dbg_println!(
                                "WRAP: add WRAP POINT  SPLIT LEFT  , accum.len() {}",
                                self.accum.len()
                            );
                            dbg_println!(
                                "WRAP: add WRAP POINT  SPLIT RIGHT , new.len()   {}",
                                new.len()
                            );
                        }

                        if self.display_wrap {
                            // replace front/back
                            if !new.is_empty() {
                                let nio = new.remove(0);
                                new.insert(0, set_io_color(&nio, (255, 0, 0)));
                            }
                        }

                        filter_out.append(&mut self.accum);
                        self.accum = new;

                        filter_out.push(fnl);
                        if debug {
                            dbg_println!("WRAP: *** FLUSH *** accum.len() {}", self.accum.len());
                        }

                        // "current word" size
                        self.column_count = self.max_column - blank_column_idx - 1;

                        blank_accum_idx = 0;
                        blank_offset = None;
                        blank_column_idx = 0;
                    } else {
                        if debug {
                            dbg_println!("WRAP: line contains NO leading blank");
                        }

                        if self.display_wrap {
                            // replace  last char
                            if !self.accum.is_empty() {
                                let nio = self.accum.pop().unwrap();
                                self.accum.push(set_io_color(&nio, (0, 255, 0)));
                            }
                        }

                        // FLUSH
                        if debug {
                            dbg_println!("WRAP: FLUSH accum");
                        }
                        filter_out.append(&mut self.accum);
                        self.column_count = 0;
                    }
                    /* FALLTHROUGH  */
                }

                // APPEND
                if self.display_wrap && self.column_count == 0 {
                    self.accum.push(set_first_column_color(&io));
                } else {
                    self.accum.push(io.clone());
                }

                // self.column_count + width < self.max_column
                self.column_count += width; // char fits

                // check
                // new line before max column
                if c == '\n' {
                    if debug {
                        dbg_println!("WRAP: *** LF found: restart @ offset {:?} ***", io.offset);
                    }

                    if self.display_wrap {
                        self.accum.pop();
                        self.accum.push(set_io_color(&io, (128, 255, 255)));
                    }
                    // restart
                    filter_out.append(&mut self.accum);
                    self.column_count = 0;
                    blank_accum_idx = 0;
                    blank_offset = None;
                    blank_column_idx = 0;
                }

                if c == ' ' {
                    // remember blank idx/offset to build wrap point
                    blank_column_idx = self.column_count - width;
                    blank_accum_idx = self.accum.len() - 1;
                    blank_offset = io.offset;

                    if debug {
                        dbg_println!(
                            "WRAP: ***found BLANK: @ offset {:?} col_idx {} ***",
                            io.offset,
                            blank_column_idx
                        );
                    }

                    if self.display_wrap && blank_column_idx > 0 {
                        self.accum.pop();
                        self.accum.push(set_io_color(&io, (255, 255, 0)));
                    }
                }
            } else {
                /*  unhandled input type */
                self.accum.push(io.clone());
                filter_out.append(&mut self.accum);
            }
        }
    }

    fn finish(&mut self, _view: &View, _env: &mut LayoutEnv) {
        dbg_println!("WRAP: FINISH");
        // TODO fnish count ...
        // self.finish_count += 1;
    }
}
<commit_msg>fix word wrap : preserve/do-not-reset counters across multiple passes<commit_after>use parking_lot::RwLock;
use std::rc::Rc;

use crate::core::view::ContentFilter;
use crate::core::view::FilterData;
use crate::core::view::FilterIo;
use crate::core::view::LayoutEnv;
use crate::core::Editor;

use crate::core::view::View;

use super::TextModeContext;
use crate::core::codec::text::u32_to_char;

use crate::core::codepointinfo::TextStyle;

pub struct WordWrapFilter {
    max_column: u64,
    column_count: u64,
    accum: Vec<FilterIo>,
    display_wrap: bool,

    blank_column_idx: u64,
    blank_accum_idx: u64,
    blank_offset: Option<u64>,
}

impl WordWrapFilter {
    pub fn new() -> Self {
        WordWrapFilter {
            max_column: 0,
            column_count: 0,
            accum: vec![],
            display_wrap: false,
            blank_column_idx: 0,
            blank_accum_idx: 0,
            blank_offset: None,
        }
    }
}

fn set_io_color(io: &FilterIo, color: (u8, u8, u8)) -> FilterIo {
    // flush new line
    let mut new_io = FilterIo {
        // general info
        metadata: false,
        style: TextStyle::new(),
        offset: io.offset,
        size: io.size,
        data: io.data.clone(),
    };

    {
        new_io.style.is_blinking = true;
        new_io.style.is_selected = true;
        new_io.style.bg_color = color;
    }

    new_io
}

fn set_first_column_color(io: &FilterIo) -> FilterIo {
    set_io_color(io, (0, 0, 255))
}

fn build_wrap_point_io(blank_offset: Option<u64>) -> FilterIo {
    FilterIo {
        // general info
        metadata: true,
        style: TextStyle::new(), // TODO(ceg): customize
        offset: blank_offset,
        size: 0,
        data: FilterData::TextInfo {
            real_cp: '\n' as u32,
            displayed_cp: '\\' as u32,
        },
    }
}

impl ContentFilter<'_> for WordWrapFilter {
    fn name(&self) -> &'static str {
        &"WordWrapFilter"
    }

    fn setup(
        &mut self,
        _editor: &Editor,
        env: &mut LayoutEnv,
        view: &Rc<RwLock<View>>,
        _parent_view: Option<&View<'static>>,
    ) {
        self.max_column = env.screen.width() as u64;
        self.column_count = 0;
        self.accum = Vec::new();

        // the screen is the final output
        // TODO(ceg): ask env.screen.cp_width(cp) -> nb_cells
        // or embed cp_width in FilterIo meta ?

        let v = view.read();
        if v.check_mode_ctx::<TextModeContext>("text-mode") {
            let tm = v.mode_ctx::<TextModeContext>("text-mode");
            self.display_wrap = tm.display_word_wrap;
        }
    }

    /*
            TODO(ceg): filters dependencies: check in view's filter_array that
            dep.index < cur_filter.index or (and WARN)
            we can push multiple times new instance of a filter :-)

            prerequisite:
            - tab expansion before: ('\t' -> ' ' should be done before)

        display offset in status

            NB: accum.len() != column count

    BEFORE:
            |  0    1    2    3    4    5    6    7    8 |  9  |        max_col = 10
            | xx |    |   ww    | xx | xx | xx | xx | xx | xx  |
                   ^      ^                                       ^
                   |      |_ wide char (2 cols)                   |
                   |                                              |
             blank_col_idx                                    colum_count = 10

            |  0    1    2    3    4    5    6    7    8 |  9  | max_col = 10
            | xx |    |   ww    | xx | xx | xx | xx | xx | xx  | <ADD>
                   ^      ^
                   |      |_ wide char (2 cols)                   ^
                   |                                              |
             blank_col_idx                                    colum_count

            column_count + width(<ADD>) >= max_col  : compute wrap

        */

    fn run(
        &mut self,
        _view: &View,
        env: &mut LayoutEnv,
        filter_in: &Vec<FilterIo>,
        filter_out: &mut Vec<FilterIo>,
    ) {
        if self.max_column <= 2
        /* TODO(ceg) screen.max_char_width() */
        {
            *filter_out = filter_in.clone();
            return;
        }

        let debug = false;

        for io in filter_in.iter() {
            if let FilterIo {
                data: FilterData::TextInfo { real_cp, .. },
                ..
            } = &*io
            {
                let c = u32_to_char(*real_cp);
                let width = env.screen.char_width(c) as u64;

                if debug {
                    dbg_println!("WRAP: -------------");
                    dbg_println!("WRAP: BEFORE : char '{}', width {}, column_count {} max_column {} blank_accum_idx {} blank_offset {:?} blank_column_idx {}",
                    c, width, self.column_count , self.max_column, self.blank_accum_idx , self.blank_offset , self.blank_column_idx);
                    dbg_println!(
                        "WRAP: self.column_count + width {}",
                        self.column_count + width
                    );
                    dbg_println!("WRAP: self.accum.len() {}", self.accum.len());

                    dbg_println!("WRAP:    >>>>>");
                }

                // width overflow  ?
                if self.column_count + width > self.max_column {
                    // not blank and accum > max column
                    if debug {
                        dbg_println!("WRAP: OVERFLOW self.column_count + width >= self.max_column");
                    }

                    // have previous blank ? => split accum after blank, insert '\' wrap point
                    if self.blank_offset.is_some()
                        && c != ' '
                        && c != '\n' // user option ?
                        && self.blank_column_idx > 0
                        && self.blank_column_idx + 1 != self.max_column
                    {
                        if debug {
                            dbg_println!("WRAP: line contains blank");

                            dbg_println!("WRAP: add WRAP POINT");
                        }
                        let mut fnl = build_wrap_point_io(self.blank_offset);

                        // TODO(ceg): add use option
                        if true || self.display_wrap {
                            fnl.style.color = (255, 255, 0); // yellow '\'
                        }

                        let mut new = self.accum.split_off(self.blank_accum_idx as usize + 1);
                        if debug {
                            dbg_println!(
                                "WRAP: add WRAP POINT  SPLIT LEFT  , accum.len() {}",
                                self.accum.len()
                            );
                            dbg_println!(
                                "WRAP: add WRAP POINT  SPLIT RIGHT , new.len()   {}",
                                new.len()
                            );
                        }

                        if self.display_wrap {
                            // replace front/back
                            if !new.is_empty() {
                                let nio = new.remove(0);
                                new.insert(0, set_io_color(&nio, (255, 0, 0)));
                            }
                        }

                        filter_out.append(&mut self.accum);
                        self.accum = new;

                        filter_out.push(fnl);
                        if debug {
                            dbg_println!("WRAP: *** FLUSH *** accum.len() {}", self.accum.len());
                        }

                        // "current word" size
                        self.column_count = self.max_column - self.blank_column_idx - 1;

                        self.blank_accum_idx = 0;
                        self.blank_offset = None;
                        self.blank_column_idx = 0;
                    } else {
                        if debug {
                            dbg_println!("WRAP: line contains NO leading blank");
                        }

                        if self.display_wrap {
                            // replace  last char
                            if !self.accum.is_empty() {
                                let nio = self.accum.pop().unwrap();
                                self.accum.push(set_io_color(&nio, (0, 255, 0)));
                            }
                        }

                        // FLUSH
                        if debug {
                            dbg_println!("WRAP: FLUSH accum");
                        }
                        filter_out.append(&mut self.accum);
                        self.column_count = 0;
                    }
                    /* FALLTHROUGH  */
                }

                // APPEND
                if self.display_wrap && self.column_count == 0 {
                    self.accum.push(set_first_column_color(&io));
                } else {
                    self.accum.push(io.clone());
                }

                // self.column_count + width < self.max_column
                self.column_count += width; // char fits

                // check
                // new line before max column
                if c == '\n' {
                    if debug {
                        dbg_println!("WRAP: *** LF found: restart @ offset {:?} ***", io.offset);
                    }

                    if self.display_wrap {
                        self.accum.pop();
                        self.accum.push(set_io_color(&io, (128, 255, 255)));
                    }
                    // restart
                    filter_out.append(&mut self.accum);
                    self.column_count = 0;
                    self.blank_accum_idx = 0;
                    self.blank_offset = None;
                    self.blank_column_idx = 0;
                }

                if c == ' ' {
                    // remember blank idx/offset to build wrap point
                    self.blank_column_idx = self.column_count - width;
                    self.blank_accum_idx = self.accum.len() as u64 - 1;
                    self.blank_offset = io.offset;

                    if debug {
                        dbg_println!(
                            "WRAP: ***found BLANK: @ offset {:?} col_idx {} ***",
                            io.offset,
                            self.blank_column_idx
                        );
                    }

                    if self.display_wrap && self.blank_column_idx > 0 {
                        self.accum.pop();
                        self.accum.push(set_io_color(&io, (255, 255, 0)));
                    }
                }
            } else {
                /*  unhandled input type */
                self.accum.push(io.clone());
                filter_out.append(&mut self.accum);
            }
        }
    }

    fn finish(&mut self, _view: &View, _env: &mut LayoutEnv) {
        dbg_println!("WRAP: FINISH");
        // TODO finish count ...
        // self.finish_count += 1;
    }
}
<|endoftext|>


<commit_before>use rustc_errors::DiagnosticBuilder;
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_infer::infer::region_constraints::Constraint;
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
use rustc_infer::traits::{Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};

use std::fmt;
use std::rc::Rc;

use crate::borrow_check::region_infer::values::RegionElement;
use crate::borrow_check::MirBorrowckCtxt;

#[derive(Clone)]
crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);

/// What operation a universe was created for.
#[derive(Clone)]
enum UniverseInfoInner<'tcx> {
    /// Relating two types which have binders.
    RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
    /// Created from performing a `TypeOp`.
    TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
    /// Any other reason.
    Other,
}

impl UniverseInfo<'tcx> {
    crate fn other() -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::Other)
    }

    crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
    }

    crate fn report_error(
        &self,
        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
        placeholder: ty::PlaceholderRegion,
        error_element: RegionElement,
        span: Span,
    ) {
        match self.0 {
            UniverseInfoInner::RelateTys { expected, found } => {
                let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
                let err = mbcx.infcx.report_mismatched_types(
                    &ObligationCause::misc(span, body_id),
                    expected,
                    found,
                    TypeError::RegionsPlaceholderMismatch,
                );
                err.buffer(&mut mbcx.errors_buffer);
            }
            UniverseInfoInner::TypeOp(ref type_op_info) => {
                type_op_info.report_error(mbcx, placeholder, error_element, span);
            }
            UniverseInfoInner::Other => {
                // FIXME: This error message isn't great, but it doesn't show
                // up in the existing UI tests. Consider investigating this
                // some more.
                mbcx.infcx
                    .tcx
                    .sess
                    .struct_span_err(span, "higher-ranked subtype error")
                    .buffer(&mut mbcx.errors_buffer);
            }
        }
    }
}

crate trait ToUniverseInfo<'tcx> {
    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
}

impl<'tcx> ToUniverseInfo<'tcx>
    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
{
    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
            canonical_query: self,
            base_universe,
        })))
    }
}

impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
{
    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
            canonical_query: self,
            base_universe,
        })))
    }
}

impl<'tcx> ToUniverseInfo<'tcx>
    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
{
    fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        // Ascribe user type isn't usually called on types that have different
        // bound regions.
        UniverseInfo::other()
    }
}

impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
    fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        // We can't rerun custom type ops.
        UniverseInfo::other()
    }
}

#[allow(unused_lifetimes)]
trait TypeOpInfo<'tcx> {
    /// Returns an rrror to be reported if rerunning the type op fails to
    /// recover the error's cause.
    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;

    fn base_universe(&self) -> ty::UniverseIndex;

    fn nice_error(
        &self,
        tcx: TyCtxt<'tcx>,
        span: Span,
        placeholder_region: ty::Region<'tcx>,
        error_region: Option<ty::Region<'tcx>>,
    ) -> Option<DiagnosticBuilder<'tcx>>;

    fn report_error(
        &self,
        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
        placeholder: ty::PlaceholderRegion,
        error_element: RegionElement,
        span: Span,
    ) {
        let tcx = mbcx.infcx.tcx;
        let base_universe = self.base_universe();

        let adjusted_universe = if let Some(adjusted) =
            placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
        {
            adjusted
        } else {
            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
            return;
        };

        let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
            name: placeholder.name,
            universe: adjusted_universe.into(),
        }));

        let error_region =
            if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
                let adjusted_universe =
                    error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
                adjusted_universe.map(|adjusted| {
                    tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
                        name: error_placeholder.name,
                        universe: adjusted.into(),
                    }))
                })
            } else {
                None
            };

        debug!(?placeholder_region);

        let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);

        if let Some(nice_error) = nice_error {
            nice_error.buffer(&mut mbcx.errors_buffer);
        } else {
            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
        }
    }
}

struct PredicateQuery<'tcx> {
    canonical_query:
        Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
    base_universe: ty::UniverseIndex,
}

impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
        err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
        err
    }

    fn base_universe(&self) -> ty::UniverseIndex {
        self.base_universe
    }

    fn nice_error(
        &self,
        tcx: TyCtxt<'tcx>,
        span: Span,
        placeholder_region: ty::Region<'tcx>,
        error_region: Option<ty::Region<'tcx>>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);

            let (param_env, prove_predicate) = key.into_parts();
            fulfill_cx.register_predicate_obligation(
                infcx,
                Obligation::new(
                    ObligationCause::dummy_with_span(span),
                    param_env,
                    prove_predicate.predicate,
                ),
            );

            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
        })
    }
}

struct NormalizeQuery<'tcx, T> {
    canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
    base_universe: ty::UniverseIndex,
}

impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
where
    T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
{
    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
        err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
        err
    }

    fn base_universe(&self) -> ty::UniverseIndex {
        self.base_universe
    }

    fn nice_error(
        &self,
        tcx: TyCtxt<'tcx>,
        span: Span,
        placeholder_region: ty::Region<'tcx>,
        error_region: Option<ty::Region<'tcx>>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);

            let mut selcx = SelectionContext::new(infcx);
            let (param_env, value) = key.into_parts();

            let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
                &mut selcx,
                param_env,
                ObligationCause::dummy_with_span(span),
                value.value,
            );
            fulfill_cx.register_predicate_obligations(infcx, obligations);

            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
        })
    }
}

fn try_extract_error_from_fulfill_cx<'tcx>(
    mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
    infcx: &InferCtxt<'_, 'tcx>,
    placeholder_region: ty::Region<'tcx>,
    error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> {
    let tcx = infcx.tcx;

    // We generally shouldn't have here because the query was
    // already run, but there's no point using `delay_span_bug`
    // when we're going to emit an error here anyway.
    let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);

    let region_obligations = infcx.take_registered_region_obligations();
    debug!(?region_obligations);

    let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
        debug!(?region_constraints);
        region_constraints.constraints.iter().find_map(|(constraint, cause)| {
            match *constraint {
                Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
                    Some((sub, cause.clone()))
                }
                // FIXME: Should this check the universe of the var?
                Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
                    Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
                }
                _ => None,
            }
        })
    })?;

    debug!(?sub_region, ?cause);
    let nice_error = match (error_region, sub_region) {
        (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
            infcx,
            RegionResolutionError::SubSupConflict(
                vid,
                infcx.region_var_origin(vid),
                cause.clone(),
                error_region,
                cause.clone(),
                placeholder_region,
            ),
        ),
        (Some(error_region), _) => NiceRegionError::new(
            infcx,
            RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
        ),
        // Note universe here is wrong...
        (None, &ty::ReVar(vid)) => NiceRegionError::new(
            infcx,
            RegionResolutionError::UpperBoundUniverseConflict(
                vid,
                infcx.region_var_origin(vid),
                infcx.universe_of_region(sub_region),
                cause.clone(),
                placeholder_region,
            ),
        ),
        (None, _) => NiceRegionError::new(
            infcx,
            RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
        ),
    };
    nice_error.try_report_from_nll().or_else(|| {
        if let SubregionOrigin::Subtype(trace) = cause {
            Some(
                infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
            )
        } else {
            None
        }
    })
}
<commit_msg>Slight cleanup<commit_after>use rustc_errors::DiagnosticBuilder;
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_infer::infer::region_constraints::Constraint;
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
use rustc_infer::traits::{Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};

use std::fmt;
use std::rc::Rc;

use crate::borrow_check::region_infer::values::RegionElement;
use crate::borrow_check::MirBorrowckCtxt;

#[derive(Clone)]
crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);

/// What operation a universe was created for.
#[derive(Clone)]
enum UniverseInfoInner<'tcx> {
    /// Relating two types which have binders.
    RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
    /// Created from performing a `TypeOp`.
    TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
    /// Any other reason.
    Other,
}

impl UniverseInfo<'tcx> {
    crate fn other() -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::Other)
    }

    crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
    }

    crate fn report_error(
        &self,
        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
        placeholder: ty::PlaceholderRegion,
        error_element: RegionElement,
        span: Span,
    ) {
        match self.0 {
            UniverseInfoInner::RelateTys { expected, found } => {
                let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
                let err = mbcx.infcx.report_mismatched_types(
                    &ObligationCause::misc(span, body_id),
                    expected,
                    found,
                    TypeError::RegionsPlaceholderMismatch,
                );
                err.buffer(&mut mbcx.errors_buffer);
            }
            UniverseInfoInner::TypeOp(ref type_op_info) => {
                type_op_info.report_error(mbcx, placeholder, error_element, span);
            }
            UniverseInfoInner::Other => {
                // FIXME: This error message isn't great, but it doesn't show
                // up in the existing UI tests. Consider investigating this
                // some more.
                mbcx.infcx
                    .tcx
                    .sess
                    .struct_span_err(span, "higher-ranked subtype error")
                    .buffer(&mut mbcx.errors_buffer);
            }
        }
    }
}

crate trait ToUniverseInfo<'tcx> {
    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
}

impl<'tcx> ToUniverseInfo<'tcx>
    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
{
    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
            canonical_query: self,
            base_universe,
        })))
    }
}

impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
{
    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
            canonical_query: self,
            base_universe,
        })))
    }
}

impl<'tcx> ToUniverseInfo<'tcx>
    for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
{
    fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        // Ascribe user type isn't usually called on types that have different
        // bound regions.
        UniverseInfo::other()
    }
}

impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
    fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
        // We can't rerun custom type ops.
        UniverseInfo::other()
    }
}

#[allow(unused_lifetimes)]
trait TypeOpInfo<'tcx> {
    /// Returns an error to be reported if rerunning the type op fails to
    /// recover the error's cause.
    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;

    fn base_universe(&self) -> ty::UniverseIndex;

    fn nice_error(
        &self,
        tcx: TyCtxt<'tcx>,
        span: Span,
        placeholder_region: ty::Region<'tcx>,
        error_region: Option<ty::Region<'tcx>>,
    ) -> Option<DiagnosticBuilder<'tcx>>;

    fn report_error(
        &self,
        mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
        placeholder: ty::PlaceholderRegion,
        error_element: RegionElement,
        span: Span,
    ) {
        let tcx = mbcx.infcx.tcx;
        let base_universe = self.base_universe();

        let adjusted_universe = if let Some(adjusted) =
            placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
        {
            adjusted
        } else {
            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
            return;
        };

        let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
            name: placeholder.name,
            universe: adjusted_universe.into(),
        }));

        let error_region =
            if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
                let adjusted_universe =
                    error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
                adjusted_universe.map(|adjusted| {
                    tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
                        name: error_placeholder.name,
                        universe: adjusted.into(),
                    }))
                })
            } else {
                None
            };

        debug!(?placeholder_region);

        let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);

        if let Some(nice_error) = nice_error {
            nice_error.buffer(&mut mbcx.errors_buffer);
        } else {
            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
        }
    }
}

struct PredicateQuery<'tcx> {
    canonical_query:
        Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
    base_universe: ty::UniverseIndex,
}

impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
        err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
        err
    }

    fn base_universe(&self) -> ty::UniverseIndex {
        self.base_universe
    }

    fn nice_error(
        &self,
        tcx: TyCtxt<'tcx>,
        span: Span,
        placeholder_region: ty::Region<'tcx>,
        error_region: Option<ty::Region<'tcx>>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);

            let (param_env, prove_predicate) = key.into_parts();
            fulfill_cx.register_predicate_obligation(
                infcx,
                Obligation::new(
                    ObligationCause::dummy_with_span(span),
                    param_env,
                    prove_predicate.predicate,
                ),
            );

            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
        })
    }
}

struct NormalizeQuery<'tcx, T> {
    canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
    base_universe: ty::UniverseIndex,
}

impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
where
    T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
{
    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
        err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
        err
    }

    fn base_universe(&self) -> ty::UniverseIndex {
        self.base_universe
    }

    fn nice_error(
        &self,
        tcx: TyCtxt<'tcx>,
        span: Span,
        placeholder_region: ty::Region<'tcx>,
        error_region: Option<ty::Region<'tcx>>,
    ) -> Option<DiagnosticBuilder<'tcx>> {
        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);

            let mut selcx = SelectionContext::new(infcx);
            let (param_env, value) = key.into_parts();

            let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
                &mut selcx,
                param_env,
                ObligationCause::dummy_with_span(span),
                value.value,
            );
            fulfill_cx.register_predicate_obligations(infcx, obligations);

            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
        })
    }
}

fn try_extract_error_from_fulfill_cx<'tcx>(
    mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
    infcx: &InferCtxt<'_, 'tcx>,
    placeholder_region: ty::Region<'tcx>,
    error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> {
    let tcx = infcx.tcx;

    // We generally shouldn't have here because the query was
    // already run, but there's no point using `delay_span_bug`
    // when we're going to emit an error here anyway.
    let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);

    let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
        debug!(?region_constraints);
        region_constraints.constraints.iter().find_map(|(constraint, cause)| {
            match *constraint {
                Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
                    Some((sub, cause.clone()))
                }
                // FIXME: Should this check the universe of the var?
                Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
                    Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
                }
                _ => None,
            }
        })
    })?;

    debug!(?sub_region, ?cause);
    let nice_error = match (error_region, sub_region) {
        (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
            infcx,
            RegionResolutionError::SubSupConflict(
                vid,
                infcx.region_var_origin(vid),
                cause.clone(),
                error_region,
                cause.clone(),
                placeholder_region,
            ),
        ),
        (Some(error_region), _) => NiceRegionError::new(
            infcx,
            RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
        ),
        // Note universe here is wrong...
        (None, &ty::ReVar(vid)) => NiceRegionError::new(
            infcx,
            RegionResolutionError::UpperBoundUniverseConflict(
                vid,
                infcx.region_var_origin(vid),
                infcx.universe_of_region(sub_region),
                cause.clone(),
                placeholder_region,
            ),
        ),
        (None, _) => NiceRegionError::new(
            infcx,
            RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
        ),
    };
    nice_error.try_report_from_nll().or_else(|| {
        if let SubregionOrigin::Subtype(trace) = cause {
            Some(
                infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
            )
        } else {
            None
        }
    })
}
<|endoftext|>


<commit_before>use crate::io;
use crate::mem;
use crate::ptr;

use crate::sys::process::zircon::{Handle, zx_handle_t};
use crate::sys::process::process_common::*;

use libc::size_t;

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        let envp = self.capture_env();

        if self.saw_nul() {
            return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                      "nul byte found in provided data"));
        }

        let (ours, theirs) = self.setup_io(default, needs_stdin)?;

        let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };

        Ok((Process { handle: Handle::new(process_handle) }, ours))
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        if self.saw_nul() {
            return io::Error::new(io::ErrorKind::InvalidInput,
                                  "nul byte found in provided data")
        }

        match self.setup_io(default, true) {
            Ok((_, _)) => {
                // FIXME: This is tough because we don't support the exec syscalls
                unimplemented!();
            },
            Err(e) => e,
        }
    }

    unsafe fn do_exec(&mut self, stdio: ChildPipes, maybe_envp: Option<&CStringArray>)
                      -> io::Result<zx_handle_t> {
        use crate::sys::process::zircon::*;

        let envp = match maybe_envp {
            Some(envp) => envp.as_ptr(),
            None => ptr::null(),
        };

        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
            if let Some(local_fd) = local_io.fd() {
                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd,
                    target_fd,
                    ..Default::default()
                })
            } else {
                if let ChildStdio::Null = local_io {
                    // acts as no-op
                    return Ok(Default::default());
                }

                let mut handle = ZX_HANDLE_INVALID;
                let status = fdio_fd_clone(target_fd, &mut handle);
                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
                    // This descriptor is closed; skip it rather than generating an
                    // error.
                    return Ok(Default::default());
                }
                zx_cvt(status)?;

                let mut cloned_fd = 0;
                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;

                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd: cloned_fd as i32,
                    target_fd,
                    ..Default::default()
                })
            }
        };

        // Clone stdin, stdout, and stderr
        let action1 = make_action(&stdio.stdin, 0)?;
        let action2 = make_action(&stdio.stdout, 1)?;
        let action3 = make_action(&stdio.stderr, 2)?;
        let actions = [action1, action2, action3];

        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
        // always consumes transferred file descriptors.
        mem::forget(stdio);

        for callback in self.get_closures().iter_mut() {
            callback()?;
        }

        let mut process_handle: zx_handle_t = 0;
        zx_cvt(fdio_spawn_etc(
            ZX_HANDLE_INVALID,
            FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE,
            self.get_argv()[0], self.get_argv().as_ptr(), envp,
            actions.len() as size_t, actions.as_ptr(),
            &mut process_handle,
            ptr::null_mut(),
        ))?;
        // FIXME: See if we want to do something with that err_msg

        Ok(process_handle)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

pub struct Process {
    handle: Handle,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.handle.raw() as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        use crate::sys::process::zircon::*;

        unsafe { zx_cvt(zx_task_kill(self.handle.raw()))?; }

        Ok(())
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            zx_cvt(zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
                                      ZX_TIME_INFINITE, ptr::null_mut()))?;
            zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS,
                                      &mut proc_info as *mut _ as *mut libc::c_void,
                                      mem::size_of::<zx_info_process_t>(), &mut actual,
                                      &mut avail))?;
        }
        if actual != 1 {
            return Err(io::Error::new(io::ErrorKind::InvalidData,
                                      "Failed to get exit status of process"));
        }
        Ok(ExitStatus::new(proc_info.rec.return_code))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            let status = zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
                                            0, ptr::null_mut());
            match status {
                0 => { }, // Success
                x if x == ERR_TIMED_OUT => {
                    return Ok(None);
                },
                _ => { panic!("Failed to wait on process handle: {}", status); },
            }
            zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS,
                                      &mut proc_info as *mut _ as *mut libc::c_void,
                                      mem::size_of::<zx_info_process_t>(), &mut actual,
                                      &mut avail))?;
        }
        if actual != 1 {
            return Err(io::Error::new(io::ErrorKind::InvalidData,
                                      "Failed to get exit status of process"));
        }
        Ok(Some(ExitStatus::new(proc_info.rec.return_code)))
    }
}
<commit_msg>fuchsia: Fix default environment behavior when spawning<commit_after>use crate::io;
use crate::mem;
use crate::ptr;

use crate::sys::process::zircon::{Handle, zx_handle_t};
use crate::sys::process::process_common::*;

use libc::size_t;

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                 -> io::Result<(Process, StdioPipes)> {
        let envp = self.capture_env();

        if self.saw_nul() {
            return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                      "nul byte found in provided data"));
        }

        let (ours, theirs) = self.setup_io(default, needs_stdin)?;

        let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };

        Ok((Process { handle: Handle::new(process_handle) }, ours))
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        if self.saw_nul() {
            return io::Error::new(io::ErrorKind::InvalidInput,
                                  "nul byte found in provided data")
        }

        match self.setup_io(default, true) {
            Ok((_, _)) => {
                // FIXME: This is tough because we don't support the exec syscalls
                unimplemented!();
            },
            Err(e) => e,
        }
    }

    unsafe fn do_exec(&mut self, stdio: ChildPipes, maybe_envp: Option<&CStringArray>)
                      -> io::Result<zx_handle_t> {
        use crate::sys::process::zircon::*;

        let envp = match maybe_envp {
            // None means to clone the current environment, which is done in the
            // flags below.
            None => ptr::null(),
            Some(envp) => envp.as_ptr(),
        };

        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
            if let Some(local_fd) = local_io.fd() {
                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd,
                    target_fd,
                    ..Default::default()
                })
            } else {
                if let ChildStdio::Null = local_io {
                    // acts as no-op
                    return Ok(Default::default());
                }

                let mut handle = ZX_HANDLE_INVALID;
                let status = fdio_fd_clone(target_fd, &mut handle);
                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
                    // This descriptor is closed; skip it rather than generating an
                    // error.
                    return Ok(Default::default());
                }
                zx_cvt(status)?;

                let mut cloned_fd = 0;
                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;

                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd: cloned_fd as i32,
                    target_fd,
                    ..Default::default()
                })
            }
        };

        // Clone stdin, stdout, and stderr
        let action1 = make_action(&stdio.stdin, 0)?;
        let action2 = make_action(&stdio.stdout, 1)?;
        let action3 = make_action(&stdio.stderr, 2)?;
        let actions = [action1, action2, action3];

        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
        // always consumes transferred file descriptors.
        mem::forget(stdio);

        for callback in self.get_closures().iter_mut() {
            callback()?;
        }

        let mut process_handle: zx_handle_t = 0;
        zx_cvt(fdio_spawn_etc(
            ZX_HANDLE_INVALID,
            FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE
            | FDIO_SPAWN_CLONE_ENVIRON,  // this is ignored when envp is non-null
            self.get_argv()[0], self.get_argv().as_ptr(), envp,
            actions.len() as size_t, actions.as_ptr(),
            &mut process_handle,
            ptr::null_mut(),
        ))?;
        // FIXME: See if we want to do something with that err_msg

        Ok(process_handle)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

pub struct Process {
    handle: Handle,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.handle.raw() as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        use crate::sys::process::zircon::*;

        unsafe { zx_cvt(zx_task_kill(self.handle.raw()))?; }

        Ok(())
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            zx_cvt(zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
                                      ZX_TIME_INFINITE, ptr::null_mut()))?;
            zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS,
                                      &mut proc_info as *mut _ as *mut libc::c_void,
                                      mem::size_of::<zx_info_process_t>(), &mut actual,
                                      &mut avail))?;
        }
        if actual != 1 {
            return Err(io::Error::new(io::ErrorKind::InvalidData,
                                      "Failed to get exit status of process"));
        }
        Ok(ExitStatus::new(proc_info.rec.return_code))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            let status = zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
                                            0, ptr::null_mut());
            match status {
                0 => { }, // Success
                x if x == ERR_TIMED_OUT => {
                    return Ok(None);
                },
                _ => { panic!("Failed to wait on process handle: {}", status); },
            }
            zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS,
                                      &mut proc_info as *mut _ as *mut libc::c_void,
                                      mem::size_of::<zx_info_process_t>(), &mut actual,
                                      &mut avail))?;
        }
        if actual != 1 {
            return Err(io::Error::new(io::ErrorKind::InvalidData,
                                      "Failed to get exit status of process"));
        }
        Ok(Some(ExitStatus::new(proc_info.rec.return_code)))
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros to make our custom address types require a lot less repetitive code.

macro_rules! derive_addr {
    ($ty:ident, $size:ty) => {

        impl Addr for $ty {
            type Repr = $size;
        }

        impl $crate::core::convert::Into<$size> for $ty {
            #[inline] fn into(self) -> $size { self.0 }
        }

        impl $crate::core::convert::From<$size> for $ty {
            #[inline] fn from(n: $size) -> Self { $ty(n) }
        }

        impl<T> $crate::core::convert::From<*mut T> for $ty {
            #[inline] fn from(ptr: *mut T) -> Self { $ty(ptr as $size) }
        }

        impl<T> $crate::core::convert::From<*const T> for $ty {
            #[inline] fn from(ptr: *const T) -> Self { $ty(ptr as $size) }
        }

        impl $crate::core::ops::Deref for $ty {
            type Target = $size;
            #[inline] fn deref(&self) -> &Self::Target { &self.0 }
        }

        impl_ops! {
            impl Add, add, + for $ty, $size
            impl Sub, sub, - for $ty, $size
            impl Div, div, / for $ty, $size
            impl Mul, mul, * for $ty, $size
            impl Shl, shl, >> for $ty, $size
            impl Shr, shr, << for $ty, $size
            impl Rem, rem, % for $ty, $size
        }

        impl_fmt! {
            impl Binary for $ty
            impl Display for $ty
            impl Octal for $ty
            impl LowerHex for $ty
            impl UpperHex for $ty
        }

        impl $crate::core::ops::BitAnd<$size> for $ty {
            type Output = $size;

            fn bitand(self, rhs: $size) -> $size {
                self.0 & rhs
            }
        }
    }
}

macro_rules! forward_ref_binop {
    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
        impl<'a> $crate::core::ops::$imp<$u> for &'a $t {
            type Output = <$t as $crate::core::ops::$imp<$u>>::Output;
            #[inline]
            fn $method(self, other: $u)
                      -> <$t as $crate::core::ops::$imp<$u>>::Output {
                $crate::core::ops::$imp::$method(*self, other)
            }
        }

        impl<'a> $crate::core::ops::$imp<&'a $u> for $t {
            type Output = <$t as $crate::core::ops::$imp<$u>>::Output;
            #[inline]
            fn $method(self, other: &'a $u)
                      -> <$t as $crate::core::ops::$imp<$u>>::Output {
                $crate::core::ops::$imp::$method(self, *other)
            }
        }

        impl<'a, 'b> $crate::core::ops::$imp<&'a $u> for &'b $t {
            type Output = <$t as $crate::core::ops::$imp<$u>>::Output;

            #[inline]
            fn $method(self, other: &'a $u) -> <$t as $crate::core::ops::$imp<$u>>::Output {
                $crate::core::ops::$imp::$method(*self, *other)
            }
        }
    }
}
macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_ops {
    ($(impl $name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl $crate::core::ops::$name<$ty> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $ty) -> $ty {
                $ty(e!(self.0 $op rhs.0))
            }
        }
        impl $crate::core::ops::$name<$size> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $size) -> $ty {
                $ty(e!(self.0 $op rhs))
            }
        }

        forward_ref_binop! {
            impl $name, $fun for $ty, $ty
        }
        forward_ref_binop! {
            impl $name, $fun for $ty, $size
        }
    )*}
}

macro_rules! impl_fmt {
    ($(impl $name:ident for $ty:ty)*) => {$(
        impl $crate::core::fmt::$name for $ty {
            fn fmt(&self, f: &mut $crate::core::fmt::Formatter) -> $crate::core::fmt::Result {
                self.0.fmt(f)
            }
        }
    )*}
}
<commit_msg>[kernel] add const fns for making addrs into ptrs<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros to make our custom address types require a lot less repetitive code.

macro_rules! derive_addr {
    ($ty:ident, $size:ty) => {

        impl Addr for $ty {
            type Repr = $size;
        }

        impl $ty {
            pub const fn as_mut_ptr<T>(&self) -> *mut T { self.0 as *mut _ }
            pub const fn as_ptr<T>(&self) -> *const T { self.0 as *const _ }
        }

        impl $crate::core::convert::Into<$size> for $ty {
            #[inline] fn into(self) -> $size { self.0 }
        }

        impl $crate::core::convert::From<$size> for $ty {
            #[inline] fn from(n: $size) -> Self { $ty(n) }
        }

        impl<T> $crate::core::convert::From<*mut T> for $ty {
            #[inline] fn from(ptr: *mut T) -> Self { $ty(ptr as $size) }
        }

        impl<T> $crate::core::convert::From<*const T> for $ty {
            #[inline] fn from(ptr: *const T) -> Self { $ty(ptr as $size) }
        }

        impl $crate::core::ops::Deref for $ty {
            type Target = $size;
            #[inline] fn deref(&self) -> &Self::Target { &self.0 }
        }

        impl_ops! {
            impl Add, add, + for $ty, $size
            impl Sub, sub, - for $ty, $size
            impl Div, div, / for $ty, $size
            impl Mul, mul, * for $ty, $size
            impl Shl, shl, >> for $ty, $size
            impl Shr, shr, << for $ty, $size
            impl Rem, rem, % for $ty, $size
        }

        impl_fmt! {
            impl Binary for $ty
            impl Display for $ty
            impl Octal for $ty
            impl LowerHex for $ty
            impl UpperHex for $ty
        }

        impl $crate::core::ops::BitAnd<$size> for $ty {
            type Output = $size;

            fn bitand(self, rhs: $size) -> $size {
                self.0 & rhs
            }
        }
    }
}

macro_rules! forward_ref_binop {
    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
        impl<'a> $crate::core::ops::$imp<$u> for &'a $t {
            type Output = <$t as $crate::core::ops::$imp<$u>>::Output;
            #[inline]
            fn $method(self, other: $u)
                      -> <$t as $crate::core::ops::$imp<$u>>::Output {
                $crate::core::ops::$imp::$method(*self, other)
            }
        }

        impl<'a> $crate::core::ops::$imp<&'a $u> for $t {
            type Output = <$t as $crate::core::ops::$imp<$u>>::Output;
            #[inline]
            fn $method(self, other: &'a $u)
                      -> <$t as $crate::core::ops::$imp<$u>>::Output {
                $crate::core::ops::$imp::$method(self, *other)
            }
        }

        impl<'a, 'b> $crate::core::ops::$imp<&'a $u> for &'b $t {
            type Output = <$t as $crate::core::ops::$imp<$u>>::Output;

            #[inline]
            fn $method(self, other: &'a $u) -> <$t as $crate::core::ops::$imp<$u>>::Output {
                $crate::core::ops::$imp::$method(*self, *other)
            }
        }
    }
}
macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_ops {
    ($(impl $name:ident, $fun:ident, $op:tt for $ty:ident, $size:ty)*) => {$(
        impl $crate::core::ops::$name<$ty> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $ty) -> $ty {
                $ty(e!(self.0 $op rhs.0))
            }
        }
        impl $crate::core::ops::$name<$size> for $ty {
            type Output = $ty;

            #[inline] fn $fun(self, rhs: $size) -> $ty {
                $ty(e!(self.0 $op rhs))
            }
        }

        forward_ref_binop! {
            impl $name, $fun for $ty, $ty
        }
        forward_ref_binop! {
            impl $name, $fun for $ty, $size
        }
    )*}
}

macro_rules! impl_fmt {
    ($(impl $name:ident for $ty:ty)*) => {$(
        impl $crate::core::fmt::$name for $ty {
            fn fmt(&self, f: &mut $crate::core::fmt::Formatter) -> $crate::core::fmt::Result {
                self.0.fmt(f)
            }
        }
    )*}
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::error::Error;
use std::fmt;
use std::str;

use nom::IResult;

use super::ast;
use super::Message;

/// An error resulting from `parse_message`.
#[derive(Clone,Debug)]
pub enum ParseError {
    /// The message could not be parsed.
    NotImplemented,
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::NotImplemented => "Not implemented.",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

named!(format_body <&[u8], Box<ast::Format> >,
    map!(is_not!("}"), |name| Box::new(ast::SimpleFormat::new(str::from_utf8(name).unwrap()))));

named!(format <&[u8], Box<ast::Format> >,
    delimited!(
        char!('{'),
        format_body,
        char!('}')));

named!(plain_text <&[u8], Box<ast::Format> >,
    map!(is_not!("{"), |text| Box::new(ast::PlainText::new(str::from_utf8(text).unwrap()))));

named!(message_parts <&[u8], Vec<Box<ast::Format> > >,
    many0!(alt!(call!(format) | call!(plain_text))));

named!(message_parser <&[u8], Message>,
    chain!(
        parts: message_parts,
        || Message::new(parts)));

/// Parse some text and hopefully return a [`Message`].
///
/// [`Message`]: struct.Message.html
pub fn parse_message(message: &str) -> Result<Message, ParseError> {
    match message_parser(message.as_bytes()) {
        IResult::Error(_) => Err(ParseError::NotImplemented),
        IResult::Incomplete(_) => Err(ParseError::NotImplemented),
        IResult::Done(_, m) => Ok(m),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::{arg, Args};

    #[test]
    fn it_works() {
        match parse_message("{name} is from {city}.") {
            Ok(m) => {
                assert_eq!(m.format_message(&arg("name", &"Hendrik").arg("city", &"Berlin")),
                           "Hendrik is from Berlin.");
            }
            Err(e) => panic!("Parse failed: {}", e),
        }
    }
}
<commit_msg>parse_message: Fix clippy warning.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::error::Error;
use std::fmt;
use std::str;

use nom::IResult;

use super::ast;
use super::Message;

/// An error resulting from `parse_message`.
#[derive(Clone,Debug)]
pub enum ParseError {
    /// The message could not be parsed.
    NotImplemented,
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::NotImplemented => "Not implemented.",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

named!(format_body <&[u8], Box<ast::Format> >,
    map!(is_not!("}"), |name| Box::new(ast::SimpleFormat::new(str::from_utf8(name).unwrap()))));

named!(format <&[u8], Box<ast::Format> >,
    delimited!(
        char!('{'),
        format_body,
        char!('}')));

named!(plain_text <&[u8], Box<ast::Format> >,
    map!(is_not!("{"), |text| Box::new(ast::PlainText::new(str::from_utf8(text).unwrap()))));

named!(message_parts <&[u8], Vec<Box<ast::Format> > >,
    many0!(alt!(call!(format) | call!(plain_text))));

named!(message_parser <&[u8], Message>,
    chain!(
        parts: message_parts,
        || Message::new(parts)));

/// Parse some text and hopefully return a [`Message`].
///
/// [`Message`]: struct.Message.html
pub fn parse_message(message: &str) -> Result<Message, ParseError> {
    match message_parser(message.as_bytes()) {
        IResult::Error(_) |
        IResult::Incomplete(_) => Err(ParseError::NotImplemented),
        IResult::Done(_, m) => Ok(m),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::{arg, Args};

    #[test]
    fn it_works() {
        match parse_message("{name} is from {city}.") {
            Ok(m) => {
                assert_eq!(m.format_message(&arg("name", &"Hendrik").arg("city", &"Berlin")),
                           "Hendrik is from Berlin.");
            }
            Err(e) => panic!("Parse failed: {}", e),
        }
    }
}
<|endoftext|>