<commit_before>//! FIXME: write short doc here

use std::{
    path::{Path, PathBuf},
    sync::Arc,
};

use crossbeam_channel::{unbounded, Receiver};
use lsp_server::ErrorCode;
use lsp_types::Url;
use parking_lot::RwLock;
use ra_ide::{
    Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData,
    SourceRootId,
};
use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
use relative_path::RelativePathBuf;
use std::path::{Component, Prefix};

use crate::{
    main_loop::pending_requests::{CompletedRequest, LatestRequests},
    LspError, Result,
};
use std::str::FromStr;

#[derive(Debug, Clone)]
pub struct Options {
    pub publish_decorations: bool,
    pub supports_location_link: bool,
    pub line_folding_only: bool,
    pub max_inlay_hint_length: Option<usize>,
}

/// `WorldState` is the primary mutable state of the language server
///
/// The most interesting components are `vfs`, which stores a consistent
/// snapshot of the file systems, and `analysis_host`, which stores our
/// incremental salsa database.
#[derive(Debug)]
pub struct WorldState {
    pub options: Options,
    //FIXME: this belongs to `LoopState` rather than to `WorldState`
    pub roots_to_scan: usize,
    pub roots: Vec<PathBuf>,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis_host: AnalysisHost,
    pub vfs: Arc<RwLock<Vfs>>,
    pub task_receiver: Receiver<VfsTask>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

/// An immutable snapshot of the world's state at a point in time.
pub struct WorldSnapshot {
    pub options: Options,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis: Analysis,
    pub vfs: Arc<RwLock<Vfs>>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

impl WorldState {
    pub fn new(
        folder_roots: Vec<PathBuf>,
        workspaces: Vec<ProjectWorkspace>,
        lru_capacity: Option<usize>,
        exclude_globs: &[Glob],
        watch: Watch,
        options: Options,
        feature_flags: FeatureFlags,
    ) -> WorldState {
        let mut change = AnalysisChange::new();

        let mut roots = Vec::new();
        roots.extend(folder_roots.iter().map(|path| {
            let mut filter = RustPackageFilterBuilder::default().set_member(true);
            for glob in exclude_globs.iter() {
                filter = filter.exclude(glob.clone());
            }
            RootEntry::new(path.clone(), filter.into_vfs_filter())
        }));
        for ws in workspaces.iter() {
            roots.extend(ws.to_roots().into_iter().map(|pkg_root| {
                let mut filter =
                    RustPackageFilterBuilder::default().set_member(pkg_root.is_member());
                for glob in exclude_globs.iter() {
                    filter = filter.exclude(glob.clone());
                }
                RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter())
            }));
        }
        let (task_sender, task_receiver) = unbounded();
        let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
        let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
        let roots_to_scan = vfs_roots.len();
        for r in vfs_roots {
            let vfs_root_path = vfs.root2path(r);
            let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it));
            change.add_root(SourceRootId(r.0), is_local);
            change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string());
        }

        // FIXME: Read default cfgs from config
        let default_cfg_options = {
            let mut opts = get_rustc_cfg_options();
            opts.insert_atom("test".into());
            opts.insert_atom("debug_assertion".into());
            opts
        };

        // Create crate graph from all the workspaces
        let mut crate_graph = CrateGraph::default();
        let mut load = |path: &std::path::Path| {
            let vfs_file = vfs.load(path);
            vfs_file.map(|f| FileId(f.0))
        };
        for ws in workspaces.iter() {
            let (graph, crate_names) = ws.to_crate_graph(&default_cfg_options, &mut load);
            let shift = crate_graph.extend(graph);
            for (crate_id, name) in crate_names {
                change.set_debug_crate_name(crate_id.shift(shift), name)
            }
        }
        change.set_crate_graph(crate_graph);

        let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags);
        analysis_host.apply_change(change);
        WorldState {
            options,
            roots_to_scan,
            roots: folder_roots,
            workspaces: Arc::new(workspaces),
            analysis_host,
            vfs: Arc::new(RwLock::new(vfs)),
            task_receiver,
            latest_requests: Default::default(),
        }
    }

    /// Returns a vec of libraries
    /// FIXME: better API here
    pub fn process_changes(
        &mut self,
    ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)> {
        let changes = self.vfs.write().commit_changes();
        if changes.is_empty() {
            return Vec::new();
        }
        let mut libs = Vec::new();
        let mut change = AnalysisChange::new();
        for c in changes {
            match c {
                VfsChange::AddRoot { root, files } => {
                    let root_path = self.vfs.read().root2path(root);
                    let is_local = self.roots.iter().any(|r| root_path.starts_with(r));
                    if is_local {
                        self.roots_to_scan -= 1;
                        for (file, path, text) in files {
                            change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                        }
                    } else {
                        let files = files
                            .into_iter()
                            .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text))
                            .collect();
                        libs.push((SourceRootId(root.0), files));
                    }
                }
                VfsChange::AddFile { root, file, path, text } => {
                    change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                }
                VfsChange::RemoveFile { root, file, path } => {
                    change.remove_file(SourceRootId(root.0), FileId(file.0), path)
                }
                VfsChange::ChangeFile { file, text } => {
                    change.change_file(FileId(file.0), text);
                }
            }
        }
        self.analysis_host.apply_change(change);
        libs
    }

    pub fn add_lib(&mut self, data: LibraryData) {
        self.roots_to_scan -= 1;
        let mut change = AnalysisChange::new();
        change.add_library(data);
        self.analysis_host.apply_change(change);
    }

    pub fn snapshot(&self) -> WorldSnapshot {
        WorldSnapshot {
            options: self.options.clone(),
            workspaces: Arc::clone(&self.workspaces),
            analysis: self.analysis_host.analysis(),
            vfs: Arc::clone(&self.vfs),
            latest_requests: Arc::clone(&self.latest_requests),
        }
    }

    pub fn maybe_collect_garbage(&mut self) {
        self.analysis_host.maybe_collect_garbage()
    }

    pub fn collect_garbage(&mut self) {
        self.analysis_host.collect_garbage()
    }

    pub fn complete_request(&mut self, request: CompletedRequest) {
        self.latest_requests.write().record(request)
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis_host.feature_flags()
    }
}

impl WorldSnapshot {
    pub fn analysis(&self) -> &Analysis {
        &self.analysis
    }

    pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
        let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
        let file = self.vfs.read().path2file(&path).ok_or_else(|| {
            // Show warning as this file is outside current workspace
            LspError {
                code: ErrorCode::InvalidRequest as i32,
                message: "Rust file outside current workspace is not supported yet.".to_string(),
            }
        })?;
        Ok(FileId(file.0))
    }

    pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
        let path = self.vfs.read().file2path(VfsFile(id.0));
        let url = url_from_path_with_drive_lowercasing(path)?;

        Ok(url)
    }

    pub fn file_line_endings(&self, id: FileId) -> LineEndings {
        self.vfs.read().file_line_endings(VfsFile(id.0))
    }

    pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
        let base = self.vfs.read().root2path(VfsRoot(root.0));
        let path = path.to_path(base);
        let url = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.display()))?;
        Ok(url)
    }

    pub fn status(&self) -> String {
        let mut res = String::new();
        if self.workspaces.is_empty() {
            res.push_str("no workspaces\n")
        } else {
            res.push_str("workspaces:\n");
            for w in self.workspaces.iter() {
                res += &format!("{} packages loaded\n", w.n_packages());
            }
        }
        res.push_str("\nanalysis:\n");
        res.push_str(
            &self
                .analysis
                .status()
                .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
        );
        res
    }

    pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> {
        let path = self.vfs.read().file2path(VfsFile(file_id.0));
        self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path))
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis.feature_flags()
    }
}

/// Returns a `Url` object from a given path, will lowercase drive letters if present.
/// This will only happen when processing windows paths.
///
/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
    let component_has_windows_drive = path
        .as_ref()
        .components()
        .find(|comp| {
            if let Component::Prefix(c) = comp {
                match c.kind() {
                    Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
                    _ => return false,
                }
            }
            false
        })
        .is_some();

    // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
    if component_has_windows_drive {
        let url_original = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;

        let drive_partition: Vec<&str> =
            url_original.as_str().rsplitn(2, ':').collect::<Vec<&str>>();

        // There is a drive partition, but we never found a colon.
        // This should not happen, but in this case we just pass it through.
        if drive_partition.len() == 1 {
            return Ok(url_original);
        }

        let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
        let url = Url::from_str(&joined).expect("This came from a valid `Url`");

        Ok(url)
    } else {
        Ok(Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
    }
}

#[test]
fn test_lowercase_drive_letter_with_drive() {
    let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();

    assert_eq!(url.to_string(), "file:///c:/Test");
}

#[test]
fn test_drive_without_colon_passthrough() {
    let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();

    assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
}
<commit_msg>cfg gated tests that only work on windows.<commit_after>//! FIXME: write short doc here

use std::{
    path::{Path, PathBuf},
    sync::Arc,
};

use crossbeam_channel::{unbounded, Receiver};
use lsp_server::ErrorCode;
use lsp_types::Url;
use parking_lot::RwLock;
use ra_ide::{
    Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData,
    SourceRootId,
};
use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
use relative_path::RelativePathBuf;
use std::path::{Component, Prefix};

use crate::{
    main_loop::pending_requests::{CompletedRequest, LatestRequests},
    LspError, Result,
};
use std::str::FromStr;

#[derive(Debug, Clone)]
pub struct Options {
    pub publish_decorations: bool,
    pub supports_location_link: bool,
    pub line_folding_only: bool,
    pub max_inlay_hint_length: Option<usize>,
}

/// `WorldState` is the primary mutable state of the language server
///
/// The most interesting components are `vfs`, which stores a consistent
/// snapshot of the file systems, and `analysis_host`, which stores our
/// incremental salsa database.
#[derive(Debug)]
pub struct WorldState {
    pub options: Options,
    //FIXME: this belongs to `LoopState` rather than to `WorldState`
    pub roots_to_scan: usize,
    pub roots: Vec<PathBuf>,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis_host: AnalysisHost,
    pub vfs: Arc<RwLock<Vfs>>,
    pub task_receiver: Receiver<VfsTask>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

/// An immutable snapshot of the world's state at a point in time.
pub struct WorldSnapshot {
    pub options: Options,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis: Analysis,
    pub vfs: Arc<RwLock<Vfs>>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

impl WorldState {
    pub fn new(
        folder_roots: Vec<PathBuf>,
        workspaces: Vec<ProjectWorkspace>,
        lru_capacity: Option<usize>,
        exclude_globs: &[Glob],
        watch: Watch,
        options: Options,
        feature_flags: FeatureFlags,
    ) -> WorldState {
        let mut change = AnalysisChange::new();

        let mut roots = Vec::new();
        roots.extend(folder_roots.iter().map(|path| {
            let mut filter = RustPackageFilterBuilder::default().set_member(true);
            for glob in exclude_globs.iter() {
                filter = filter.exclude(glob.clone());
            }
            RootEntry::new(path.clone(), filter.into_vfs_filter())
        }));
        for ws in workspaces.iter() {
            roots.extend(ws.to_roots().into_iter().map(|pkg_root| {
                let mut filter =
                    RustPackageFilterBuilder::default().set_member(pkg_root.is_member());
                for glob in exclude_globs.iter() {
                    filter = filter.exclude(glob.clone());
                }
                RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter())
            }));
        }
        let (task_sender, task_receiver) = unbounded();
        let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
        let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
        let roots_to_scan = vfs_roots.len();
        for r in vfs_roots {
            let vfs_root_path = vfs.root2path(r);
            let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it));
            change.add_root(SourceRootId(r.0), is_local);
            change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string());
        }

        // FIXME: Read default cfgs from config
        let default_cfg_options = {
            let mut opts = get_rustc_cfg_options();
            opts.insert_atom("test".into());
            opts.insert_atom("debug_assertion".into());
            opts
        };

        // Create crate graph from all the workspaces
        let mut crate_graph = CrateGraph::default();
        let mut load = |path: &std::path::Path| {
            let vfs_file = vfs.load(path);
            vfs_file.map(|f| FileId(f.0))
        };
        for ws in workspaces.iter() {
            let (graph, crate_names) = ws.to_crate_graph(&default_cfg_options, &mut load);
            let shift = crate_graph.extend(graph);
            for (crate_id, name) in crate_names {
                change.set_debug_crate_name(crate_id.shift(shift), name)
            }
        }
        change.set_crate_graph(crate_graph);

        let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags);
        analysis_host.apply_change(change);
        WorldState {
            options,
            roots_to_scan,
            roots: folder_roots,
            workspaces: Arc::new(workspaces),
            analysis_host,
            vfs: Arc::new(RwLock::new(vfs)),
            task_receiver,
            latest_requests: Default::default(),
        }
    }

    /// Returns a vec of libraries
    /// FIXME: better API here
    pub fn process_changes(
        &mut self,
    ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)> {
        let changes = self.vfs.write().commit_changes();
        if changes.is_empty() {
            return Vec::new();
        }
        let mut libs = Vec::new();
        let mut change = AnalysisChange::new();
        for c in changes {
            match c {
                VfsChange::AddRoot { root, files } => {
                    let root_path = self.vfs.read().root2path(root);
                    let is_local = self.roots.iter().any(|r| root_path.starts_with(r));
                    if is_local {
                        self.roots_to_scan -= 1;
                        for (file, path, text) in files {
                            change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                        }
                    } else {
                        let files = files
                            .into_iter()
                            .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text))
                            .collect();
                        libs.push((SourceRootId(root.0), files));
                    }
                }
                VfsChange::AddFile { root, file, path, text } => {
                    change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                }
                VfsChange::RemoveFile { root, file, path } => {
                    change.remove_file(SourceRootId(root.0), FileId(file.0), path)
                }
                VfsChange::ChangeFile { file, text } => {
                    change.change_file(FileId(file.0), text);
                }
            }
        }
        self.analysis_host.apply_change(change);
        libs
    }

    pub fn add_lib(&mut self, data: LibraryData) {
        self.roots_to_scan -= 1;
        let mut change = AnalysisChange::new();
        change.add_library(data);
        self.analysis_host.apply_change(change);
    }

    pub fn snapshot(&self) -> WorldSnapshot {
        WorldSnapshot {
            options: self.options.clone(),
            workspaces: Arc::clone(&self.workspaces),
            analysis: self.analysis_host.analysis(),
            vfs: Arc::clone(&self.vfs),
            latest_requests: Arc::clone(&self.latest_requests),
        }
    }

    pub fn maybe_collect_garbage(&mut self) {
        self.analysis_host.maybe_collect_garbage()
    }

    pub fn collect_garbage(&mut self) {
        self.analysis_host.collect_garbage()
    }

    pub fn complete_request(&mut self, request: CompletedRequest) {
        self.latest_requests.write().record(request)
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis_host.feature_flags()
    }
}

impl WorldSnapshot {
    pub fn analysis(&self) -> &Analysis {
        &self.analysis
    }

    pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
        let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
        let file = self.vfs.read().path2file(&path).ok_or_else(|| {
            // Show warning as this file is outside current workspace
            LspError {
                code: ErrorCode::InvalidRequest as i32,
                message: "Rust file outside current workspace is not supported yet.".to_string(),
            }
        })?;
        Ok(FileId(file.0))
    }

    pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
        let path = self.vfs.read().file2path(VfsFile(id.0));
        let url = url_from_path_with_drive_lowercasing(path)?;

        Ok(url)
    }

    pub fn file_line_endings(&self, id: FileId) -> LineEndings {
        self.vfs.read().file_line_endings(VfsFile(id.0))
    }

    pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
        let base = self.vfs.read().root2path(VfsRoot(root.0));
        let path = path.to_path(base);
        let url = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.display()))?;
        Ok(url)
    }

    pub fn status(&self) -> String {
        let mut res = String::new();
        if self.workspaces.is_empty() {
            res.push_str("no workspaces\n")
        } else {
            res.push_str("workspaces:\n");
            for w in self.workspaces.iter() {
                res += &format!("{} packages loaded\n", w.n_packages());
            }
        }
        res.push_str("\nanalysis:\n");
        res.push_str(
            &self
                .analysis
                .status()
                .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
        );
        res
    }

    pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> {
        let path = self.vfs.read().file2path(VfsFile(file_id.0));
        self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path))
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis.feature_flags()
    }
}

/// Returns a `Url` object from a given path, will lowercase drive letters if present.
/// This will only happen when processing windows paths.
///
/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
    let component_has_windows_drive = path
        .as_ref()
        .components()
        .find(|comp| {
            if let Component::Prefix(c) = comp {
                match c.kind() {
                    Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
                    _ => return false,
                }
            }
            false
        })
        .is_some();

    // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
    if component_has_windows_drive {
        let url_original = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;

        let drive_partition: Vec<&str> =
            url_original.as_str().rsplitn(2, ':').collect::<Vec<&str>>();

        // There is a drive partition, but we never found a colon.
        // This should not happen, but in this case we just pass it through.
        if drive_partition.len() == 1 {
            return Ok(url_original);
        }

        let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
        let url = Url::from_str(&joined).expect("This came from a valid `Url`");

        Ok(url)
    } else {
        Ok(Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
    }
}

// `Url` is not able to parse windows paths on unix machines.
#[cfg(target_os = "windows")]
#[cfg(test)]
mod path_conversion_windows_tests {
    use super::url_from_path_with_drive_lowercasing;
    #[test]
    fn test_lowercase_drive_letter_with_drive() {
        let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();

        assert_eq!(url.to_string(), "file:///c:/Test");
    }

    #[test]
    fn test_drive_without_colon_passthrough() {
        let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();

        assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
    }
}
<|endoftext|>


<commit_before>//! Like [`std::time::Instant`], but for memory.
//!
//! Measures the total size of all currently allocated objects.
use std::fmt;

use cfg_if::cfg_if;

#[derive(Copy, Clone)]
pub struct MemoryUsage {
    pub allocated: Bytes,
}

impl fmt::Display for MemoryUsage {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.allocated)
    }
}

impl std::ops::Sub for MemoryUsage {
    type Output = MemoryUsage;
    fn sub(self, rhs: MemoryUsage) -> MemoryUsage {
        MemoryUsage { allocated: self.allocated - rhs.allocated }
    }
}

impl MemoryUsage {
    pub fn now() -> MemoryUsage {
        cfg_if! {
            if #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] {
                jemalloc_ctl::epoch::advance().unwrap();
                MemoryUsage {
                    allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
                }
            } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
                memusage_linux()
            } else if #[cfg(windows)] {
                // There doesn't seem to be an API for determining heap usage, so we try to
                // approximate that by using the Commit Charge value.

                use winapi::um::processthreadsapi::*;
                use winapi::um::psapi::*;
                use std::mem::{MaybeUninit, size_of};

                let proc = unsafe { GetCurrentProcess() };
                let mut mem_counters = MaybeUninit::uninit();
                let cb = size_of::<PROCESS_MEMORY_COUNTERS>();
                let ret = unsafe { GetProcessMemoryInfo(proc, mem_counters.as_mut_ptr(), cb as u32) };
                assert!(ret != 0);

                let usage = unsafe { mem_counters.assume_init().PagefileUsage };
                MemoryUsage { allocated: Bytes(usage as isize) }
            } else {
                MemoryUsage { allocated: Bytes(0) }
            }
        }
    }
}

#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn memusage_linux() -> MemoryUsage {
    // Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2.
    // mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB.
    // mallinfo2 is very recent, so its presence needs to be detected at runtime.
    // Both are abysmally slow.

    use std::ffi::CStr;
    use std::sync::atomic::{AtomicUsize, Ordering};

    static MALLINFO2: AtomicUsize = AtomicUsize::new(1);

    let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed);
    if mallinfo2 == 1 {
        let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap();
        mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize;
        // NB: races don't matter here, since they'll always store the same value
        MALLINFO2.store(mallinfo2, Ordering::Relaxed);
    }

    if mallinfo2 == 0 {
        // mallinfo2 does not exist, use mallinfo.
        let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
        MemoryUsage { allocated: Bytes(alloc) }
    } else {
        let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) };
        let alloc = mallinfo2().uordblks as isize;
        MemoryUsage { allocated: Bytes(alloc) }
    }
}

#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Bytes(isize);

impl Bytes {
    pub fn megabytes(self) -> isize {
        self.0 / 1024 / 1024
    }
}

impl fmt::Display for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bytes = self.0;
        let mut value = bytes;
        let mut suffix = "b";
        if value.abs() > 4096 {
            value /= 1024;
            suffix = "kb";
            if value.abs() > 4096 {
                value /= 1024;
                suffix = "mb";
            }
        }
        f.pad(&format!("{}{}", value, suffix))
    }
}

impl std::ops::AddAssign<usize> for Bytes {
    fn add_assign(&mut self, x: usize) {
        self.0 += x as isize;
    }
}

impl std::ops::Sub for Bytes {
    type Output = Bytes;
    fn sub(self, rhs: Bytes) -> Bytes {
        Bytes(self.0 - rhs.0)
    }
}
<commit_msg>minor: squelch "unused" warning<commit_after>//! Like [`std::time::Instant`], but for memory.
//!
//! Measures the total size of all currently allocated objects.
use std::fmt;

use cfg_if::cfg_if;

#[derive(Copy, Clone)]
pub struct MemoryUsage {
    pub allocated: Bytes,
}

impl fmt::Display for MemoryUsage {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.allocated)
    }
}

impl std::ops::Sub for MemoryUsage {
    type Output = MemoryUsage;
    fn sub(self, rhs: MemoryUsage) -> MemoryUsage {
        MemoryUsage { allocated: self.allocated - rhs.allocated }
    }
}

impl MemoryUsage {
    pub fn now() -> MemoryUsage {
        cfg_if! {
            if #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] {
                jemalloc_ctl::epoch::advance().unwrap();
                MemoryUsage {
                    allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
                }
            } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
                memusage_linux()
            } else if #[cfg(windows)] {
                // There doesn't seem to be an API for determining heap usage, so we try to
                // approximate that by using the Commit Charge value.

                use winapi::um::processthreadsapi::*;
                use winapi::um::psapi::*;
                use std::mem::{MaybeUninit, size_of};

                let proc = unsafe { GetCurrentProcess() };
                let mut mem_counters = MaybeUninit::uninit();
                let cb = size_of::<PROCESS_MEMORY_COUNTERS>();
                let ret = unsafe { GetProcessMemoryInfo(proc, mem_counters.as_mut_ptr(), cb as u32) };
                assert!(ret != 0);

                let usage = unsafe { mem_counters.assume_init().PagefileUsage };
                MemoryUsage { allocated: Bytes(usage as isize) }
            } else {
                MemoryUsage { allocated: Bytes(0) }
            }
        }
    }
}

#[cfg(all(target_os = "linux", target_env = "gnu", not(feature = "jemalloc")))]
fn memusage_linux() -> MemoryUsage {
    // Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2.
    // mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB.
    // mallinfo2 is very recent, so its presence needs to be detected at runtime.
    // Both are abysmally slow.

    use std::ffi::CStr;
    use std::sync::atomic::{AtomicUsize, Ordering};

    static MALLINFO2: AtomicUsize = AtomicUsize::new(1);

    let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed);
    if mallinfo2 == 1 {
        let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap();
        mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize;
        // NB: races don't matter here, since they'll always store the same value
        MALLINFO2.store(mallinfo2, Ordering::Relaxed);
    }

    if mallinfo2 == 0 {
        // mallinfo2 does not exist, use mallinfo.
        let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
        MemoryUsage { allocated: Bytes(alloc) }
    } else {
        let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) };
        let alloc = mallinfo2().uordblks as isize;
        MemoryUsage { allocated: Bytes(alloc) }
    }
}

#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Bytes(isize);

impl Bytes {
    pub fn megabytes(self) -> isize {
        self.0 / 1024 / 1024
    }
}

impl fmt::Display for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bytes = self.0;
        let mut value = bytes;
        let mut suffix = "b";
        if value.abs() > 4096 {
            value /= 1024;
            suffix = "kb";
            if value.abs() > 4096 {
                value /= 1024;
                suffix = "mb";
            }
        }
        f.pad(&format!("{}{}", value, suffix))
    }
}

impl std::ops::AddAssign<usize> for Bytes {
    fn add_assign(&mut self, x: usize) {
        self.0 += x as isize;
    }
}

impl std::ops::Sub for Bytes {
    type Output = Bytes;
    fn sub(self, rhs: Bytes) -> Bytes {
        Bytes(self.0 - rhs.0)
    }
}
<|endoftext|>


<commit_before>extern crate glutin;
extern crate libc;
use glutin::*;
use std::ptr;

mod gl {
    include!(concat!(env!("OUT_DIR"), "/test_gl_bindings.rs"));
}
use gl::types::*;

#[cfg(not(target_os = "linux"))]
#[test]
fn test_headless() {
    let width: i32 = 256;
    let height: i32 = 256;
    let window = glutin::HeadlessRendererBuilder::new(width as u32, height as u32).build().unwrap();

    unsafe { window.make_current() };

    let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

    unsafe {
        let mut framebuffer = 0;
        let mut texture = 0;
        gl.GenFramebuffers(1, &mut framebuffer);
        gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
        gl.GenTextures(1, &mut texture);
        gl.BindTexture(gl::TEXTURE_2D, texture);
        gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
        gl.TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, width, height,
                     0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null());
        gl.FramebufferTexture(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, texture, 0);
        let status = gl.CheckFramebufferStatus(gl::FRAMEBUFFER);
        if status != gl::FRAMEBUFFER_COMPLETE {
          panic!("Error while creating the framebuffer");
        }

        gl.ClearColor(0.0, 1.0, 0.0, 1.0);
        gl.Clear(gl::COLOR_BUFFER_BIT);
        gl.Enable(gl::SCISSOR_TEST);
        gl.Scissor(1, 0, 1, 1);
        gl.ClearColor(1.0, 0.0, 0.0, 1.0);
        gl.Clear(gl::COLOR_BUFFER_BIT);

        let mut values: Vec<u8> = vec![0;(width*height*4) as usize];
        gl.ReadPixels(0, 0, width, height, gl::RGBA, gl::UNSIGNED_BYTE, values.as_mut_ptr() as *mut GLvoid);

        println!("{:?}", values);

        assert_eq!(values[0], 0);
        assert_eq!(values[1], 255);
        assert_eq!(values[2], 0);
        assert_eq!(values[3], 255);

        assert_eq!(values[4], 255);
        assert_eq!(values[5], 0);
        assert_eq!(values[6], 0);
        assert_eq!(values[7], 255);
    }
}
<commit_msg>Trigger build<commit_after>extern crate glutin;
extern crate libc;
use glutin::*;
use std::ptr;

mod gl {
    include!(concat!(env!("OUT_DIR"), "/test_gl_bindings.rs"));
}
use gl::types::*;

#[cfg(not(target_os = "linux"))]
#[test]
fn test_headless() {
    let width: i32 = 256;
    let height: i32 = 256;
    let window = glutin::HeadlessRendererBuilder::new(width as u32, height as u32).build().unwrap();

    unsafe { window.make_current() };

    let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

    unsafe {
        let mut framebuffer = 0;
        let mut texture = 0;
        gl.GenFramebuffers(1, &mut framebuffer);
        gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
        gl.GenTextures(1, &mut texture);
        gl.BindTexture(gl::TEXTURE_2D, texture);
        gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
        gl.TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, width, height,
                     0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null());
        gl.FramebufferTexture(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, texture, 0);
        let status = gl.CheckFramebufferStatus(gl::FRAMEBUFFER);
        if status != gl::FRAMEBUFFER_COMPLETE {
          panic!("Error while creating the framebuffer");
        }

        gl.ClearColor(0.0, 1.0, 0.0, 1.0);
        gl.Clear(gl::COLOR_BUFFER_BIT);
        gl.Enable(gl::SCISSOR_TEST);
        gl.Scissor(1, 0, 1, 1);
        gl.ClearColor(1.0, 0.0, 0.0, 1.0);
        gl.Clear(gl::COLOR_BUFFER_BIT);

        let mut values: Vec<u8> = vec![0;(width*height*4) as usize];
        gl.ReadPixels(0, 0, width, height, gl::RGBA, gl::UNSIGNED_BYTE, values.as_mut_ptr() as *mut GLvoid);

        println!("{:?}", values);

        assert_eq!(values[0], 0);
        assert_eq!(values[1], 255);
        assert_eq!(values[2], 0);
        assert_eq!(values[3], 255);

        assert_eq!(values[4], 255);
        assert_eq!(values[5], 0);
        assert_eq!(values[6], 0);
        assert_eq!(values[7], 255);
    }
}
<|endoftext|>


<commit_before>extern crate translator;

extern crate piston;
extern crate piston_window;
#[macro_use] extern crate conrod;
extern crate find_folder;

use piston_window::{PistonWindow, WindowSettings, Glyphs};
use piston::event_loop::{EventLoop};
use conrod::{Theme, Ui, Canvas, Widget};
use conrod::color::Colorable;

fn main() {
    let window: PistonWindow = WindowSettings::new("Hello Conrod", [800, 600])
                                                  .exit_on_esc(true)
                                                  .vsync(true)
                                                  .build()
                                                  .unwrap();

    let mut ui = {
        let assets_path = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
        let font_path = assets_path.join("NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    for event in window.ups(60) {
        ui.set_widgets(|ui| {
            Canvas::new()
                .pad(30.)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);
        });
    }
}

widget_ids! {
    CANVAS,
    INPUT_TEXT,
    OUTPUT_TEXT,
}
<commit_msg>TextBox<commit_after>extern crate translator;

extern crate piston;
extern crate piston_window;
#[macro_use] extern crate conrod;
extern crate find_folder;

use piston_window::{PistonWindow, WindowSettings, Glyphs, UpdateEvent};
use piston::event_loop::{EventLoop};
use conrod::{Theme, Ui, Canvas, TextBox, Widget, Sizeable};
use conrod::color::{self, Colorable};

fn main() {
    let window: PistonWindow = WindowSettings::new("Hello Conrod", [800, 600])
                                                  .exit_on_esc(true)
                                                  .vsync(true)
                                                  .build()
                                                  .unwrap();

    let mut ui = {
        let assets_path = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
        let font_path = assets_path.join("NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    for w in window.ups(60) {
        ui.handle_event(&w);

        w.update(|_| ui.set_widgets(|ui| {
            let background_color = color::rgb(0.2, 0.35, 0.45);
            let mut text = "".to_owned();

            Canvas::new()
                    .pad(30.)
                    .color(background_color)
                    .scroll_kids()
                    .set(CANVAS, ui);

                TextBox::new(&mut text)
                    .font_size(20)
                    .w_h(420.0, 40.0)
                    .color(background_color.invert())
                    .react(|_string: &mut String|{})
                    .set(INPUT_TEXT, ui);

            TextBox::new(&mut text)
                    .font_size(20)
                    .w_h(320.0, 40.0)
                    .color(background_color.invert())
                    .react(|_string: &mut String|{})
                .set(OUTPUT_TEXT, ui);
        }));

        w.draw_2d(|context, graphic| ui.draw_if_changed(context, graphic));
    }
}

widget_ids! {
    CANVAS,
    INPUT_TEXT,
    OUTPUT_TEXT,
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(macro_rules, plugin_registrar, slicing_syntax)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use std::ptr;
use syntax::ast::{
    DUMMY_NODE_ID, Block, CompilerGenerated, ExprBox, Inherited, LitInt, Plus, TtToken, TokenTree,
    UnsafeBlock, UnsuffixedIntLit,
};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacExpr, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{self, Comma, Semi};
use syntax::ptr::P;

#[macro_export]
/// Creates an owned matrix from its arguments
///
/// - Each argument is an element of the matrix
/// - Semicolons `;` are used to separate rows
/// - Trailing semicolons are allowed
/// - Commas `,` are used to separate columns
/// - Trailing commas are *not* allowed
/// - If the matrix contains a single row, the macro will return `Row<Box<[_]>>`
/// - If the matrix contains a single column, the macro will return `Col<Box<[_]>>`
/// - Otherwise, the macro will return `Mat`
///
/// # Expansion
///
/// There are three possible expansions:
///
/// - Row vector
///
/// ``` ignore
/// mat![0, 1, 2]
/// ```
///
/// expands into:
///
/// ``` ignore
/// Row::new(box [0, 1, 2])
/// ```
///
/// - Column vector
///
/// ``` ignore
/// // NB Newlines are *not* required
/// mat![
///     0;
///     1;
///     2;  // This semicolon can be removed if desired
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// Col::new(box [0, 1, 2])
/// ```
///
/// - Matrix
///
/// ``` ignore
/// mat![
///     0, 1, 2;
///     3, 4, 5;
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// unsafe { Mat::from_parts(box [0, 3, 1, 4, 3, 5], (2, 3)) }
/// ```
///
/// Note that the order of the arguments have changed because matrices are stored in column-major
/// order
macro_rules! mat {
    ($($($elem:expr),+);+;) => { /* syntax extension */ }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("mat"), NormalTT(box expand_mat, None));
}

fn expand_mat<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    fn at_semicolons(tt: &TokenTree) -> bool {
        if let TtToken(_, Semi) = *tt {
            true
        } else {
            false
        }
    }

    fn at_commas(tt: &TokenTree) -> bool {
        if let TtToken(_, Comma) = *tt {
            true
        } else {
            false
        }
    }

    let rows = {
        let mut rows = tts.split(at_semicolons).collect::<Vec<_>>();
        // look for trailing semicolon
        if rows.last().map(|tts| tts.is_empty()) == Some(true) {
            rows.pop();
        }
        rows
    };

    let nrows = rows.len();

    let matrix = {
        let mut matrix = Vec::with_capacity(nrows);
        for (r, row) in rows.into_iter().enumerate() {
            let elems = row.split(at_commas).collect::<Vec<_>>();
            // look for trailing commas
            if elems.last().map(|tts| tts.is_empty()) == Some(true) {
                let err_msg = format!("row {}: trailing comma not allowed", r);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
            matrix.push(elems);
        }
        matrix
    };

    let ncols = {
        let mut cols_per_row = matrix.iter().map(|row| row.len());

        let ncols = match cols_per_row.next() {
            Some(ncols) => ncols,
            None => {
                cx.span_err(sp, "Empty matrix");
                return DummyResult::expr(sp);
            },
        };

        for (i, cols_per_row) in cols_per_row.enumerate() {
            if cols_per_row != ncols {
                let err_msg = format!(
                    "row {}: expected {} columns, but found {}",
                    i + 1,
                    ncols,
                    cols_per_row);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
        }

        ncols
    };

    for (r, row) in matrix.iter().enumerate() {
        for (c, elem) in row.iter().enumerate() {
            if elem.is_empty() {
                cx.span_err(sp, format!("no element found at ({}, {})", r, c)[]);
                return DummyResult::expr(sp);
            }
        }
    }

    let nelems = nrows * ncols;
    let mut elems = Vec::with_capacity(nelems);
    unsafe { elems.set_len(nelems) }

    for (r, row) in matrix.into_iter().enumerate() {
        for (c, elem) in row.into_iter().enumerate() {
            let dst = &mut elems[c * nrows + r];

            unsafe { ptr::write(dst, cx.new_parser_from_tts(elem).parse_expr()) }
        }
    }

    let vec = {
        let uses = vec![{
            let segments = vec![
                cx.ident_of("std"),
                cx.ident_of("boxed"),
                cx.ident_of("HEAP"),
            ];

            cx.view_use_simple(sp, Inherited, cx.path_global(sp, segments))
        }];

        let stmts = vec![];

        let expr = {
            let heap = cx.expr_ident(sp, cx.ident_of("HEAP"));
            let array = cx.expr_vec(sp, elems);

            Some(cx.expr(sp, ExprBox(Some(heap), array)))
        };

        cx.expr_block(cx.block_all(sp, uses, stmts, expr))
    };

    if nrows == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("RowVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else if ncols == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("ColVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Mat"),
                cx.ident_of("from_parts"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let size = cx.expr_tuple(sp, vec![
            cx.expr_lit(sp, LitInt(nrows as u64, UnsuffixedIntLit(Plus))),
            cx.expr_lit(sp, LitInt(ncols as u64, UnsuffixedIntLit(Plus))),
        ]);
        let args = vec![vec, size];

        let unsafe_block = cx.expr_block(P(Block {
            view_items: vec![],
            stmts: vec![],
            expr: Some(cx.expr_call(sp, fn_name, args)),
            id: DUMMY_NODE_ID,
            rules: UnsafeBlock(CompilerGenerated),
            span: sp,
        }));

        MacExpr::new(unsafe_block)
    }
}
<commit_msg>docs(macros): update<commit_after>#![deny(warnings)]
#![feature(macro_rules, plugin_registrar, slicing_syntax)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use std::ptr;
use syntax::ast::{
    DUMMY_NODE_ID, Block, CompilerGenerated, ExprBox, Inherited, LitInt, Plus, TtToken, TokenTree,
    UnsafeBlock, UnsuffixedIntLit,
};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacExpr, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{self, Comma, Semi};
use syntax::ptr::P;

#[macro_export]
/// Creates an owned matrix from its arguments
///
/// - Each argument is an element of the matrix
/// - Semicolons `;` are used to separate rows
/// - Trailing semicolons are allowed
/// - Commas `,` are used to separate columns
/// - Trailing commas are *not* allowed
/// - If the matrix contains a single row, the macro will return `RowVec`
/// - If the matrix contains a single column, the macro will return `ColVec`
/// - Otherwise, the macro will return `Mat`
///
/// # Expansion
///
/// There are three possible expansions:
///
/// - Row vector
///
/// ``` ignore
/// mat![0, 1, 2]
/// ```
///
/// expands into:
///
/// ``` ignore
/// RowVec::new(box [0, 1, 2])
/// ```
///
/// - Column vector
///
/// ``` ignore
/// // NB Newlines are *not* required
/// mat![
///     0;
///     1;
///     2;  // This semicolon can be removed if desired
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// ColVec::new(box [0, 1, 2])
/// ```
///
/// - Matrix
///
/// ``` ignore
/// mat![
///     0, 1, 2;
///     3, 4, 5;
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// unsafe { Mat::from_parts(box [0, 3, 1, 4, 3, 5], (2, 3)) }
/// ```
///
/// Note that the order of the arguments have changed because matrices are stored in column-major
/// order
macro_rules! mat {
    ($($($elem:expr),+);+;) => { /* syntax extension */ }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("mat"), NormalTT(box expand_mat, None));
}

fn expand_mat<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    fn at_semicolons(tt: &TokenTree) -> bool {
        if let TtToken(_, Semi) = *tt {
            true
        } else {
            false
        }
    }

    fn at_commas(tt: &TokenTree) -> bool {
        if let TtToken(_, Comma) = *tt {
            true
        } else {
            false
        }
    }

    let rows = {
        let mut rows = tts.split(at_semicolons).collect::<Vec<_>>();
        // look for trailing semicolon
        if rows.last().map(|tts| tts.is_empty()) == Some(true) {
            rows.pop();
        }
        rows
    };

    let nrows = rows.len();

    let matrix = {
        let mut matrix = Vec::with_capacity(nrows);
        for (r, row) in rows.into_iter().enumerate() {
            let elems = row.split(at_commas).collect::<Vec<_>>();
            // look for trailing commas
            if elems.last().map(|tts| tts.is_empty()) == Some(true) {
                let err_msg = format!("row {}: trailing comma not allowed", r);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
            matrix.push(elems);
        }
        matrix
    };

    let ncols = {
        let mut cols_per_row = matrix.iter().map(|row| row.len());

        let ncols = match cols_per_row.next() {
            Some(ncols) => ncols,
            None => {
                cx.span_err(sp, "Empty matrix");
                return DummyResult::expr(sp);
            },
        };

        for (i, cols_per_row) in cols_per_row.enumerate() {
            if cols_per_row != ncols {
                let err_msg = format!(
                    "row {}: expected {} columns, but found {}",
                    i + 1,
                    ncols,
                    cols_per_row);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
        }

        ncols
    };

    for (r, row) in matrix.iter().enumerate() {
        for (c, elem) in row.iter().enumerate() {
            if elem.is_empty() {
                cx.span_err(sp, format!("no element found at ({}, {})", r, c)[]);
                return DummyResult::expr(sp);
            }
        }
    }

    let nelems = nrows * ncols;
    let mut elems = Vec::with_capacity(nelems);
    unsafe { elems.set_len(nelems) }

    for (r, row) in matrix.into_iter().enumerate() {
        for (c, elem) in row.into_iter().enumerate() {
            let dst = &mut elems[c * nrows + r];

            unsafe { ptr::write(dst, cx.new_parser_from_tts(elem).parse_expr()) }
        }
    }

    let vec = {
        let uses = vec![{
            let segments = vec![
                cx.ident_of("std"),
                cx.ident_of("boxed"),
                cx.ident_of("HEAP"),
            ];

            cx.view_use_simple(sp, Inherited, cx.path_global(sp, segments))
        }];

        let stmts = vec![];

        let expr = {
            let heap = cx.expr_ident(sp, cx.ident_of("HEAP"));
            let array = cx.expr_vec(sp, elems);

            Some(cx.expr(sp, ExprBox(Some(heap), array)))
        };

        cx.expr_block(cx.block_all(sp, uses, stmts, expr))
    };

    if nrows == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("RowVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else if ncols == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("ColVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Mat"),
                cx.ident_of("from_parts"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let size = cx.expr_tuple(sp, vec![
            cx.expr_lit(sp, LitInt(nrows as u64, UnsuffixedIntLit(Plus))),
            cx.expr_lit(sp, LitInt(ncols as u64, UnsuffixedIntLit(Plus))),
        ]);
        let args = vec![vec, size];

        let unsafe_block = cx.expr_block(P(Block {
            view_items: vec![],
            stmts: vec![],
            expr: Some(cx.expr_call(sp, fn_name, args)),
            id: DUMMY_NODE_ID,
            rules: UnsafeBlock(CompilerGenerated),
            span: sp,
        }));

        MacExpr::new(unsafe_block)
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(macro_rules, plugin_registrar, slicing_syntax)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use std::ptr;
use syntax::ast::{
    DUMMY_NODE_ID, Block, CompilerGenerated, ExprBox, Inherited, LitInt, Plus, TtToken, TokenTree,
    UnsafeBlock, UnsuffixedIntLit,
};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacExpr, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{mod, Comma, Semi};
use syntax::ptr::P;

#[macro_export]
/// Creates an owned matrix from its arguments
///
/// - Each argument is an element of the matrix
/// - Semicolons `;` are used to separate rows
/// - Trailing semicolons are allowed
/// - Commas `,` are used to separate columns
/// - Trailing commas are *not* allowed
/// - If the matrix contains a single row, the macro will return `Row<Box<[_]>>`
/// - If the matrix contains a single column, the macro will return `Col<Box<[_]>>`
/// - Otherwise, the macro will return `Mat`
///
/// # Expansion
///
/// There are three possible expansions:
///
/// - Row vector
///
/// ``` ignore
/// mat![0, 1, 2]
/// ```
///
/// expands into:
///
/// ``` ignore
/// Row::new(box [0, 1, 2])
/// ```
///
/// - Column vector
///
/// ``` ignore
/// // NB Newlines are *not* required
/// mat![
///     0;
///     1;
///     2;  // This semicolon can be removed if desired
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// Col::new(box [0, 1, 2])
/// ```
///
/// - Matrix
///
/// ``` ignore
/// mat![
///     0, 1, 2;
///     3, 4, 5;
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// unsafe { Mat::from_parts(box [0, 3, 1, 4, 3, 5], (2, 3)) }
/// ```
///
/// Note that the order of the arguments have changed because matrices are stored in column-major
/// order
macro_rules! mat {
    ($($($elem:expr),+);+;) => { /* syntax extension */ }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("mat"), NormalTT(box expand_mat, None));
}

fn expand_mat<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    fn at_semicolons(tt: &TokenTree) -> bool {
        if let TtToken(_, Semi) = *tt {
            true
        } else {
            false
        }
    }

    fn at_commas(tt: &TokenTree) -> bool {
        if let TtToken(_, Comma) = *tt {
            true
        } else {
            false
        }
    }

    let rows = {
        let mut rows = tts.split(at_semicolons).collect::<Vec<_>>();
        // look for trailing semicolon
        if rows.last().map(|tts| tts.is_empty()) == Some(true) {
            rows.pop();
        }
        rows
    };

    let nrows = rows.len();

    let matrix = {
        let mut matrix = Vec::with_capacity(nrows);
        for (r, row) in rows.into_iter().enumerate() {
            let elems = row.split(at_commas).collect::<Vec<_>>();
            // look for trailing commas
            if elems.last().map(|tts| tts.is_empty()) == Some(true) {
                let err_msg = format!("row {}: trailing comma not allowed", r);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
            matrix.push(elems);
        }
        matrix
    };

    let ncols = {
        let mut cols_per_row = matrix.iter().map(|row| row.len());

        let ncols = match cols_per_row.next() {
            Some(ncols) => ncols,
            None => {
                cx.span_err(sp, "Empty matrix");
                return DummyResult::expr(sp);
            },
        };

        for (i, cols_per_row) in cols_per_row.enumerate() {
            if cols_per_row != ncols {
                let err_msg = format!(
                    "row {}: expected {} columns, but found {}",
                    i + 1,
                    ncols,
                    cols_per_row);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
        }

        ncols
    };

    for (r, row) in matrix.iter().enumerate() {
        for (c, elem) in row.iter().enumerate() {
            if elem.is_empty() {
                cx.span_err(sp, format!("no element found at ({}, {})", r, c)[]);
                return DummyResult::expr(sp);
            }
        }
    }

    let nelems = nrows * ncols;
    let mut elems = Vec::with_capacity(nelems);
    unsafe { elems.set_len(nelems) }

    for (r, row) in matrix.into_iter().enumerate() {
        for (c, elem) in row.into_iter().enumerate() {
            let dst = &mut elems[c * nrows + r];

            unsafe { ptr::write(dst, cx.new_parser_from_tts(elem).parse_expr()) }
        }
    }

    let vec = {
        let uses = vec![{
            let segments = vec![
                cx.ident_of("std"),
                cx.ident_of("boxed"),
                cx.ident_of("HEAP"),
            ];

            cx.view_use_simple(sp, Inherited, cx.path_global(sp, segments))
        }];

        let stmts = vec![];

        let expr = {
            let heap = cx.expr_ident(sp, cx.ident_of("HEAP"));
            let array = cx.expr_vec(sp, elems);

            Some(cx.expr(sp, ExprBox(heap, array)))
        };

        cx.expr_block(cx.block_all(sp, uses, stmts, expr))
    };

    if nrows == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Row"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else if ncols == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Col"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Mat"),
                cx.ident_of("from_parts"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let size = cx.expr_tuple(sp, vec![
            cx.expr_lit(sp, LitInt(nrows as u64, UnsuffixedIntLit(Plus))),
            cx.expr_lit(sp, LitInt(ncols as u64, UnsuffixedIntLit(Plus))),
        ]);
        let args = vec![vec, size];

        let unsafe_block = cx.expr_block(P(Block {
            view_items: vec![],
            stmts: vec![],
            expr: Some(cx.expr_call(sp, fn_name, args)),
            id: DUMMY_NODE_ID,
            rules: UnsafeBlock(CompilerGenerated),
            span: sp,
        }));

        MacExpr::new(unsafe_block)
    }
}
<commit_msg>fix(mat!): adapt to changes in `ExprBox`<commit_after>#![deny(warnings)]
#![feature(macro_rules, plugin_registrar, slicing_syntax)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use std::ptr;
use syntax::ast::{
    DUMMY_NODE_ID, Block, CompilerGenerated, ExprBox, Inherited, LitInt, Plus, TtToken, TokenTree,
    UnsafeBlock, UnsuffixedIntLit,
};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacExpr, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{mod, Comma, Semi};
use syntax::ptr::P;

#[macro_export]
/// Creates an owned matrix from its arguments
///
/// - Each argument is an element of the matrix
/// - Semicolons `;` are used to separate rows
/// - Trailing semicolons are allowed
/// - Commas `,` are used to separate columns
/// - Trailing commas are *not* allowed
/// - If the matrix contains a single row, the macro will return `Row<Box<[_]>>`
/// - If the matrix contains a single column, the macro will return `Col<Box<[_]>>`
/// - Otherwise, the macro will return `Mat`
///
/// # Expansion
///
/// There are three possible expansions:
///
/// - Row vector
///
/// ``` ignore
/// mat![0, 1, 2]
/// ```
///
/// expands into:
///
/// ``` ignore
/// Row::new(box [0, 1, 2])
/// ```
///
/// - Column vector
///
/// ``` ignore
/// // NB Newlines are *not* required
/// mat![
///     0;
///     1;
///     2;  // This semicolon can be removed if desired
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// Col::new(box [0, 1, 2])
/// ```
///
/// - Matrix
///
/// ``` ignore
/// mat![
///     0, 1, 2;
///     3, 4, 5;
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// unsafe { Mat::from_parts(box [0, 3, 1, 4, 3, 5], (2, 3)) }
/// ```
///
/// Note that the order of the arguments have changed because matrices are stored in column-major
/// order
macro_rules! mat {
    ($($($elem:expr),+);+;) => { /* syntax extension */ }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("mat"), NormalTT(box expand_mat, None));
}

fn expand_mat<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    fn at_semicolons(tt: &TokenTree) -> bool {
        if let TtToken(_, Semi) = *tt {
            true
        } else {
            false
        }
    }

    fn at_commas(tt: &TokenTree) -> bool {
        if let TtToken(_, Comma) = *tt {
            true
        } else {
            false
        }
    }

    let rows = {
        let mut rows = tts.split(at_semicolons).collect::<Vec<_>>();
        // look for trailing semicolon
        if rows.last().map(|tts| tts.is_empty()) == Some(true) {
            rows.pop();
        }
        rows
    };

    let nrows = rows.len();

    let matrix = {
        let mut matrix = Vec::with_capacity(nrows);
        for (r, row) in rows.into_iter().enumerate() {
            let elems = row.split(at_commas).collect::<Vec<_>>();
            // look for trailing commas
            if elems.last().map(|tts| tts.is_empty()) == Some(true) {
                let err_msg = format!("row {}: trailing comma not allowed", r);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
            matrix.push(elems);
        }
        matrix
    };

    let ncols = {
        let mut cols_per_row = matrix.iter().map(|row| row.len());

        let ncols = match cols_per_row.next() {
            Some(ncols) => ncols,
            None => {
                cx.span_err(sp, "Empty matrix");
                return DummyResult::expr(sp);
            },
        };

        for (i, cols_per_row) in cols_per_row.enumerate() {
            if cols_per_row != ncols {
                let err_msg = format!(
                    "row {}: expected {} columns, but found {}",
                    i + 1,
                    ncols,
                    cols_per_row);
                cx.span_err(sp, err_msg[]);
                return DummyResult::expr(sp);
            }
        }

        ncols
    };

    for (r, row) in matrix.iter().enumerate() {
        for (c, elem) in row.iter().enumerate() {
            if elem.is_empty() {
                cx.span_err(sp, format!("no element found at ({}, {})", r, c)[]);
                return DummyResult::expr(sp);
            }
        }
    }

    let nelems = nrows * ncols;
    let mut elems = Vec::with_capacity(nelems);
    unsafe { elems.set_len(nelems) }

    for (r, row) in matrix.into_iter().enumerate() {
        for (c, elem) in row.into_iter().enumerate() {
            let dst = &mut elems[c * nrows + r];

            unsafe { ptr::write(dst, cx.new_parser_from_tts(elem).parse_expr()) }
        }
    }

    let vec = {
        let uses = vec![{
            let segments = vec![
                cx.ident_of("std"),
                cx.ident_of("boxed"),
                cx.ident_of("HEAP"),
            ];

            cx.view_use_simple(sp, Inherited, cx.path_global(sp, segments))
        }];

        let stmts = vec![];

        let expr = {
            let heap = cx.expr_ident(sp, cx.ident_of("HEAP"));
            let array = cx.expr_vec(sp, elems);

            Some(cx.expr(sp, ExprBox(Some(heap), array)))
        };

        cx.expr_block(cx.block_all(sp, uses, stmts, expr))
    };

    if nrows == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Row"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else if ncols == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Col"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Mat"),
                cx.ident_of("from_parts"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let size = cx.expr_tuple(sp, vec![
            cx.expr_lit(sp, LitInt(nrows as u64, UnsuffixedIntLit(Plus))),
            cx.expr_lit(sp, LitInt(ncols as u64, UnsuffixedIntLit(Plus))),
        ]);
        let args = vec![vec, size];

        let unsafe_block = cx.expr_block(P(Block {
            view_items: vec![],
            stmts: vec![],
            expr: Some(cx.expr_call(sp, fn_name, args)),
            id: DUMMY_NODE_ID,
            rules: UnsafeBlock(CompilerGenerated),
            span: sp,
        }));

        MacExpr::new(unsafe_block)
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        println!("IT WORKS");
    }
}<commit_msg>Wrote test<commit_after>extern crate pastebin_rust_api;

#[cfg(test)]
mod tests {
    use pastebin_rust_api::paster::Paster;
    use pastebin_rust_api::paster::access::Access;

    #[test]
    fn test_post() {
        let parser = Paster::new(Some("e27fc5e3a33b4a5e7b509e9d06723fcc".to_owned()));
        let response = parser.paste("<html></html>", &Access::UNLISTED, "TestHtml", "1M", "html", "");
        assert!(response.is_ok());
        println!("url: {}", response.ok().unwrap().url);
    }
}<|endoftext|>


<commit_before>//! Error Reporting for static impl Traits.

use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use rustc_errors::{struct_span_err, Applicability, ErrorReported};
use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
use rustc_middle::ty::RegionKind;

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
    /// Print the error message for lifetime errors when the return type is a static impl Trait.
    pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
        debug!("try_report_static_impl_trait(error={:?})", self.error);
        if let Some(ref error) = self.error {
            if let RegionResolutionError::SubSupConflict(
                _,
                var_origin,
                sub_origin,
                sub_r,
                sup_origin,
                sup_r,
            ) = error
            {
                debug!(
                    "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
                    var_origin, sub_origin, sub_r, sup_origin, sup_r
                );
                let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
                debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
                let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
                debug!("try_report_static_impl_trait: fn_return={:?}", fn_return);
                if **sub_r == RegionKind::ReStatic {
                    let sp = var_origin.span();
                    let return_sp = sub_origin.span();
                    let param_info = self.find_param_with_region(sup_r, sub_r)?;
                    let (lifetime_name, lifetime) = if sup_r.has_name() {
                        (sup_r.to_string(), format!("lifetime `{}`", sup_r))
                    } else {
                        ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
                    };
                    let mut err = struct_span_err!(
                        self.tcx().sess,
                        sp,
                        E0759,
                        "cannot infer an appropriate lifetime"
                    );
                    err.span_label(
                        param_info.param_ty_span,
                        &format!("this data with {}...", lifetime),
                    );
                    debug!("try_report_static_impl_trait: param_info={:?}", param_info);

                    // We try to make the output have fewer overlapping spans if possible.
                    if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
                        && sup_origin.span() != return_sp
                    {
                        // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`

                        // Customize the spans and labels depending on their relative order so
                        // that split sentences flow correctly.
                        if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
                            // Avoid the following:
                            //
                            // error: cannot infer an appropriate lifetime
                            //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
                            //    |
                            // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
                            //    |           ----                      ---------^-
                            //
                            // and instead show:
                            //
                            // error: cannot infer an appropriate lifetime
                            //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
                            //    |
                            // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
                            //    |           ----                               ^
                            err.span_label(
                                sup_origin.span(),
                                "...is captured here, requiring it to live as long as `'static`",
                            );
                        } else {
                            err.span_label(sup_origin.span(), "...is captured here...");
                            if return_sp < sup_origin.span() {
                                err.span_note(
                                    return_sp,
                                    "...and is required to live as long as `'static` here",
                                );
                            } else {
                                err.span_label(
                                    return_sp,
                                    "...and is required to live as long as `'static` here",
                                );
                            }
                        }
                    } else {
                        err.span_label(
                            return_sp,
                            "...is captured and required to live as long as `'static` here",
                        );
                    }

                    // only apply this suggestion onto functions with
                    // explicit non-desugar'able return.
                    if fn_return.span.desugaring_kind().is_none() {
                        // FIXME: account for the need of parens in `&(dyn Trait + '_)`

                        let consider = "consider changing the";
                        let declare = "to declare that the";
                        let arg = match param_info.param.pat.simple_ident() {
                            Some(simple_ident) => format!("argument `{}`", simple_ident),
                            None => "the argument".to_string(),
                        };
                        let explicit =
                            format!("you can add an explicit `{}` lifetime bound", lifetime_name);
                        let explicit_static =
                            format!("explicit `'static` bound to the lifetime of {}", arg);
                        let captures = format!("captures data from {}", arg);
                        let add_static_bound =
                            "alternatively, add an explicit `'static` bound to this reference";
                        let plus_lt = format!(" + {}", lifetime_name);
                        match fn_return.kind {
                            TyKind::Def(item_id, _) => {
                                let item = self.tcx().hir().item(item_id.id);
                                let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
                                    opaque
                                } else {
                                    err.emit();
                                    return Some(ErrorReported);
                                };

                                if let Some(span) = opaque
                                    .bounds
                                    .iter()
                                    .filter_map(|arg| match arg {
                                        GenericBound::Outlives(Lifetime {
                                            name: LifetimeName::Static,
                                            span,
                                            ..
                                        }) => Some(*span),
                                        _ => None,
                                    })
                                    .next()
                                {
                                    err.span_suggestion_verbose(
                                        span,
                                        &format!("{} `impl Trait`'s {}", consider, explicit_static),
                                        lifetime_name,
                                        Applicability::MaybeIncorrect,
                                    );
                                    err.span_suggestion_verbose(
                                        param_info.param_ty_span,
                                        add_static_bound,
                                        param_info.param_ty.to_string(),
                                        Applicability::MaybeIncorrect,
                                    );
                                } else {
                                    err.span_suggestion_verbose(
                                        fn_return.span.shrink_to_hi(),
                                        &format!(
                                            "{declare} `impl Trait` {captures}, {explicit}",
                                            declare = declare,
                                            captures = captures,
                                            explicit = explicit,
                                        ),
                                        plus_lt,
                                        Applicability::MaybeIncorrect,
                                    );
                                };
                            }
                            TyKind::TraitObject(_, lt) => match lt.name {
                                LifetimeName::ImplicitObjectLifetimeDefault => {
                                    err.span_suggestion_verbose(
                                        fn_return.span.shrink_to_hi(),
                                        &format!(
                                            "{declare} trait object {captures}, {explicit}",
                                            declare = declare,
                                            captures = captures,
                                            explicit = explicit,
                                        ),
                                        plus_lt,
                                        Applicability::MaybeIncorrect,
                                    );
                                }
                                _ => {
                                    err.span_suggestion_verbose(
                                        lt.span,
                                        &format!("{} trait object's {}", consider, explicit_static),
                                        lifetime_name,
                                        Applicability::MaybeIncorrect,
                                    );
                                    err.span_suggestion_verbose(
                                        param_info.param_ty_span,
                                        add_static_bound,
                                        param_info.param_ty.to_string(),
                                        Applicability::MaybeIncorrect,
                                    );
                                }
                            },
                            _ => {}
                        }
                    }
                    err.emit();
                    return Some(ErrorReported);
                }
            }
        }
        None
    }
}
<commit_msg>fix rebase<commit_after>//! Error Reporting for static impl Traits.

use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use rustc_errors::{struct_span_err, Applicability, ErrorReported};
use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
use rustc_middle::ty::RegionKind;

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
    /// Print the error message for lifetime errors when the return type is a static impl Trait.
    pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
        debug!("try_report_static_impl_trait(error={:?})", self.error);
        if let Some(ref error) = self.error {
            if let RegionResolutionError::SubSupConflict(
                _,
                var_origin,
                sub_origin,
                sub_r,
                sup_origin,
                sup_r,
            ) = error
            {
                debug!(
                    "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
                    var_origin, sub_origin, sub_r, sup_origin, sup_r
                );
                let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
                debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
                let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
                debug!("try_report_static_impl_trait: fn_return={:?}", fn_return);
                if **sub_r == RegionKind::ReStatic {
                    let sp = var_origin.span();
                    let return_sp = sub_origin.span();
                    let param_info = self.find_param_with_region(sup_r, sub_r)?;
                    let (lifetime_name, lifetime) = if sup_r.has_name() {
                        (sup_r.to_string(), format!("lifetime `{}`", sup_r))
                    } else {
                        ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
                    };
                    let mut err = struct_span_err!(
                        self.tcx().sess,
                        sp,
                        E0759,
                        "cannot infer an appropriate lifetime"
                    );
                    err.span_label(
                        param_info.param_ty_span,
                        &format!("this data with {}...", lifetime),
                    );
                    debug!("try_report_static_impl_trait: param_info={:?}", param_info);

                    // We try to make the output have fewer overlapping spans if possible.
                    if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
                        && sup_origin.span() != return_sp
                    {
                        // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`

                        // Customize the spans and labels depending on their relative order so
                        // that split sentences flow correctly.
                        if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
                            // Avoid the following:
                            //
                            // error: cannot infer an appropriate lifetime
                            //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
                            //    |
                            // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
                            //    |           ----                      ---------^-
                            //
                            // and instead show:
                            //
                            // error: cannot infer an appropriate lifetime
                            //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
                            //    |
                            // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
                            //    |           ----                               ^
                            err.span_label(
                                sup_origin.span(),
                                "...is captured here, requiring it to live as long as `'static`",
                            );
                        } else {
                            err.span_label(sup_origin.span(), "...is captured here...");
                            if return_sp < sup_origin.span() {
                                err.span_note(
                                    return_sp,
                                    "...and is required to live as long as `'static` here",
                                );
                            } else {
                                err.span_label(
                                    return_sp,
                                    "...and is required to live as long as `'static` here",
                                );
                            }
                        }
                    } else {
                        err.span_label(
                            return_sp,
                            "...is captured and required to live as long as `'static` here",
                        );
                    }

                    // only apply this suggestion onto functions with
                    // explicit non-desugar'able return.
                    if fn_return.span.desugaring_kind().is_none() {
                        // FIXME: account for the need of parens in `&(dyn Trait + '_)`

                        let consider = "consider changing the";
                        let declare = "to declare that the";
                        let arg = match param_info.param.pat.simple_ident() {
                            Some(simple_ident) => format!("argument `{}`", simple_ident),
                            None => "the argument".to_string(),
                        };
                        let explicit =
                            format!("you can add an explicit `{}` lifetime bound", lifetime_name);
                        let explicit_static =
                            format!("explicit `'static` bound to the lifetime of {}", arg);
                        let captures = format!("captures data from {}", arg);
                        let add_static_bound =
                            "alternatively, add an explicit `'static` bound to this reference";
                        let plus_lt = format!(" + {}", lifetime_name);
                        match fn_return.kind {
                            TyKind::OpaqueDef(item_id, _) => {
                                let item = self.tcx().hir().item(item_id.id);
                                let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
                                    opaque
                                } else {
                                    err.emit();
                                    return Some(ErrorReported);
                                };

                                if let Some(span) = opaque
                                    .bounds
                                    .iter()
                                    .filter_map(|arg| match arg {
                                        GenericBound::Outlives(Lifetime {
                                            name: LifetimeName::Static,
                                            span,
                                            ..
                                        }) => Some(*span),
                                        _ => None,
                                    })
                                    .next()
                                {
                                    err.span_suggestion_verbose(
                                        span,
                                        &format!("{} `impl Trait`'s {}", consider, explicit_static),
                                        lifetime_name,
                                        Applicability::MaybeIncorrect,
                                    );
                                    err.span_suggestion_verbose(
                                        param_info.param_ty_span,
                                        add_static_bound,
                                        param_info.param_ty.to_string(),
                                        Applicability::MaybeIncorrect,
                                    );
                                } else {
                                    err.span_suggestion_verbose(
                                        fn_return.span.shrink_to_hi(),
                                        &format!(
                                            "{declare} `impl Trait` {captures}, {explicit}",
                                            declare = declare,
                                            captures = captures,
                                            explicit = explicit,
                                        ),
                                        plus_lt,
                                        Applicability::MaybeIncorrect,
                                    );
                                };
                            }
                            TyKind::TraitObject(_, lt) => match lt.name {
                                LifetimeName::ImplicitObjectLifetimeDefault => {
                                    err.span_suggestion_verbose(
                                        fn_return.span.shrink_to_hi(),
                                        &format!(
                                            "{declare} trait object {captures}, {explicit}",
                                            declare = declare,
                                            captures = captures,
                                            explicit = explicit,
                                        ),
                                        plus_lt,
                                        Applicability::MaybeIncorrect,
                                    );
                                }
                                _ => {
                                    err.span_suggestion_verbose(
                                        lt.span,
                                        &format!("{} trait object's {}", consider, explicit_static),
                                        lifetime_name,
                                        Applicability::MaybeIncorrect,
                                    );
                                    err.span_suggestion_verbose(
                                        param_info.param_ty_span,
                                        add_static_bound,
                                        param_info.param_ty.to_string(),
                                        Applicability::MaybeIncorrect,
                                    );
                                }
                            },
                            _ => {}
                        }
                    }
                    err.emit();
                    return Some(ErrorReported);
                }
            }
        }
        None
    }
}
<|endoftext|>