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

/// Supervise a service.
///
/// The supervisor is responsible for running any services we are asked to start. It handles
/// spawning the new process, watching for failure, and ensuring the service is either up or down.
/// If the process dies, the supervisor will restart it.

use std;
use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::Child;
use std::result;
use std::thread;

use hcore::os::process::{HabChild, ExitStatusExt};
use hcore::util::perm::set_owner;
use hcore::service::ServiceGroup;
use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct;
use time::{self, Timespec};

use super::exec;
use error::{Result, Error};
use manager::service::Pkg;

static LOGKEY: &'static str = "SV";

#[derive(Debug, PartialEq, Deserialize, Serialize)]
pub enum ProcessState {
    Down,
    Up,
    Start,
    Restart,
}

impl fmt::Display for ProcessState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let state = match self {
            &ProcessState::Down => "down",
            &ProcessState::Up => "up",
            &ProcessState::Start => "start",
            &ProcessState::Restart => "restart",
        };
        write!(f, "{}", state)
    }
}

#[derive(Debug)]
pub struct Supervisor {
    pub child: Option<HabChild>,
    pub preamble: String,
    pub state: ProcessState,
    pub state_entered: Timespec,
    pub has_started: bool,
    pid: Option<PathBuf>,
}

impl Supervisor {
    pub fn new(service_group: &ServiceGroup) -> Supervisor {
        Supervisor {
            child: None,
            preamble: format!("{}", service_group),
            state: ProcessState::Down,
            state_entered: time::get_time(),
            has_started: false,
            pid: None,
        }
    }

    fn enter_state(&mut self, state: ProcessState) {
        self.state = state;
        self.state_entered = time::get_time();
    }

    pub fn status(&self) -> (bool, String) {
        let status = format!("{}: {} for {}",
                             self.preamble,
                             self.state,
                             time::get_time() - self.state_entered);
        let healthy = match self.state {
            ProcessState::Up | ProcessState::Start | ProcessState::Restart => true,
            ProcessState::Down => false,
        };
        (healthy, status)
    }

    pub fn start(&mut self, pkg: &Pkg) -> Result<()> {
        if self.child.is_some() {
            outputln!(preamble & self.preamble, "Already started");
            return Ok(());
        }
        debug!("Setting PATH for {} to PATH='{}'",
               &self.preamble,
               pkg.env
                   .get("PATH")
                   .map(|v| &**v)
                   .unwrap_or("<unknown>"));
        outputln!(preamble self.preamble,
                  "Starting process as user={}, group={}",
                  &pkg.svc_user,
                  &pkg.svc_group);
        self.enter_state(ProcessState::Start);
        let mut child = exec::run_cmd(&pkg.svc_run, &pkg)?.spawn()?;
        self.child = Some(HabChild::from(&mut child)?);
        self.create_pidfile(pkg)?;
        let package_name = self.preamble.clone();
        thread::Builder::new()
            .name(String::from("sup-service-read"))
            .spawn(move || -> Result<()> { child_reader(&mut child, package_name) })?;
        self.enter_state(ProcessState::Up);
        self.has_started = true;
        Ok(())
    }

    /// Send a SIGTERM to a process, wait 8 seconds, then send SIGKILL
    pub fn stop(&mut self) -> Result<()> {
        match self.child {
            Some(ref mut child) => {
                outputln!(preamble & self.preamble, "Stopping...");
                let shutdown = try!(child.kill());
                outputln!("{} - Shutdown method: {}", self.preamble, shutdown);
            }
            None => {}
        };
        self.check_process();
        Ok(())
    }

    pub fn down(&mut self) -> Result<()> {
        self.enter_state(ProcessState::Down);
        try!(self.stop());
        self.cleanup_pidfile();
        Ok(())
    }

    pub fn restart(&mut self, pkg: &Pkg) -> Result<()> {
        self.enter_state(ProcessState::Restart);
        try!(self.stop());
        try!(self.start(pkg));
        Ok(())
    }

    /// if the child process exists, check it's status via waitpid().
    pub fn check_process(&mut self) {
        let changed = match self.child {
            None => false,
            Some(ref mut child) => {
                match child.status() {
                    Ok(ref status) if status.no_status() => false,
                    Ok(ref status) => {
                        if status.code().is_some() {
                            outputln!("{} - process {} died with exit code {}",
                                      self.preamble,
                                      child.id(),
                                      status.code().unwrap());
                        } else if status.signal().is_some() {
                            outputln!("{} - process {} died with signal {}",
                                      self.preamble,
                                      child.id(),
                                      status.signal().unwrap());
                        }
                        true
                    }
                    Err(e) => {
                        debug!("Error checking process status: {}, continuing", e);
                        false
                    }
                }
            }
        };
        if changed {
            match self.state {
                ProcessState::Up | ProcessState::Start | ProcessState::Restart => {
                    outputln!("{} - Service exited", self.preamble);
                    self.child = None;
                }
                ProcessState::Down => {
                    self.enter_state(ProcessState::Down);
                    self.child = None;
                }
            }
        }
    }

    /// Create a pid file for a package
    /// The existence of this file does not guarantee that a
    /// process exists at the PID contained within.
    pub fn create_pidfile(&mut self, pkg: &Pkg) -> Result<()> {
        match self.child {
            Some(ref child) => {
                let ref pid = child.id();
                debug!("Creating PID file for child {} -> {:?}",
                       pkg.svc_pid_file.display(),
                       pid);
                let mut f = try!(File::create(&pkg.svc_pid_file));
                set_owner(&pkg.svc_pid_file, &pkg.svc_user, &pkg.svc_group)?;
                write!(f, "{}", pid)?;
                self.pid = Some(pkg.svc_pid_file.clone());
                Ok(())
            }
            None => Ok(()),
        }
    }

    /// Remove a pidfile for this package if it exists.
    /// Do NOT fail if there is an error removing the PIDFILE
    pub fn cleanup_pidfile(&mut self) {
        if let Some(ref pid_file) = self.pid {
            debug!("Attempting to clean up pid file {}", &pid_file.display());
            match std::fs::remove_file(pid_file) {
                Ok(_) => debug!("Removed pid file"),
                Err(e) => debug!("Error removing pidfile: {}, continuing", e),
            }
        }
        self.pid = None;
    }
}

impl Serialize for Supervisor {
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
        where S: Serializer
    {
        let pid = match self.child {
            Some(ref child) => Some(child.id()),
            None => None,
        };
        let mut strukt = try!(serializer.serialize_struct("supervisor", 5));
        try!(strukt.serialize_field("pid", &pid));
        try!(strukt.serialize_field("preamble", &self.preamble));
        try!(strukt.serialize_field("state", &self.state));
        try!(strukt.serialize_field("state_entered", &self.state_entered.sec));
        try!(strukt.serialize_field("started", &self.has_started));
        strukt.end()
    }
}

impl Drop for Supervisor {
    fn drop(&mut self) {
        let _ = self.cleanup_pidfile();
    }
}

/// Consume output from a child process until EOF, then finish
fn child_reader(child: &mut Child, package_name: String) -> Result<()> {
    let c_stdout = match child.stdout {
        Some(ref mut s) => s,
        None => return Err(sup_error!(Error::UnpackFailed)),
    };

    let mut reader = BufReader::new(c_stdout);
    let mut buffer = String::new();

    while reader.read_line(&mut buffer).unwrap() > 0 {
        let mut line = output_format!(preamble &package_name, logkey "O");
        line.push_str(&buffer);
        print!("{}", line);
        buffer.clear();
    }
    debug!("child_reader exiting");
    Ok(())
}
<commit_msg>captures standard error of supervisor child process and reads it to the output<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Supervise a service.
///
/// The supervisor is responsible for running any services we are asked to start. It handles
/// spawning the new process, watching for failure, and ensuring the service is either up or down.
/// If the process dies, the supervisor will restart it.

use std;
use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{ChildStderr, ChildStdout};
use std::result;
use std::thread;

use ansi_term::Colour;
use hcore::os::process::{HabChild, ExitStatusExt};
use hcore::util::perm::set_owner;
use hcore::service::ServiceGroup;
use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct;
use time::{self, Timespec};

use super::exec;
use error::{Result, Error};
use manager::service::Pkg;

static LOGKEY: &'static str = "SV";

#[derive(Debug, PartialEq, Deserialize, Serialize)]
pub enum ProcessState {
    Down,
    Up,
    Start,
    Restart,
}

impl fmt::Display for ProcessState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let state = match self {
            &ProcessState::Down => "down",
            &ProcessState::Up => "up",
            &ProcessState::Start => "start",
            &ProcessState::Restart => "restart",
        };
        write!(f, "{}", state)
    }
}

#[derive(Debug)]
pub struct Supervisor {
    pub child: Option<HabChild>,
    pub preamble: String,
    pub state: ProcessState,
    pub state_entered: Timespec,
    pub has_started: bool,
    pid: Option<PathBuf>,
}

impl Supervisor {
    pub fn new(service_group: &ServiceGroup) -> Supervisor {
        Supervisor {
            child: None,
            preamble: format!("{}", service_group),
            state: ProcessState::Down,
            state_entered: time::get_time(),
            has_started: false,
            pid: None,
        }
    }

    fn enter_state(&mut self, state: ProcessState) {
        self.state = state;
        self.state_entered = time::get_time();
    }

    pub fn status(&self) -> (bool, String) {
        let status = format!("{}: {} for {}",
                             self.preamble,
                             self.state,
                             time::get_time() - self.state_entered);
        let healthy = match self.state {
            ProcessState::Up | ProcessState::Start | ProcessState::Restart => true,
            ProcessState::Down => false,
        };
        (healthy, status)
    }

    pub fn start(&mut self, pkg: &Pkg) -> Result<()> {
        if self.child.is_some() {
            outputln!(preamble & self.preamble, "Already started");
            return Ok(());
        }
        debug!("Setting PATH for {} to PATH='{}'",
               &self.preamble,
               pkg.env
                   .get("PATH")
                   .map(|v| &**v)
                   .unwrap_or("<unknown>"));
        outputln!(preamble self.preamble,
                  "Starting process as user={}, group={}",
                  &pkg.svc_user,
                  &pkg.svc_group);
        self.enter_state(ProcessState::Start);
        let mut child = exec::run_cmd(&pkg.svc_run, &pkg)?.spawn()?;
        self.child = Some(HabChild::from(&mut child)?);
        let c_stdout = child.stdout;
        let c_stderr = child.stderr;
        self.create_pidfile(pkg)?;
        let out_package_name = self.preamble.clone();
        let err_package_name = self.preamble.clone();
        thread::Builder::new()
            .name(String::from("sup-service-read-out"))
            .spawn(move || -> Result<()> { child_out_reader(c_stdout, out_package_name) })?;
        thread::Builder::new()
            .name(String::from("sup-service-read-err"))
            .spawn(move || -> Result<()> { child_err_reader(c_stderr, err_package_name) })?;
        self.enter_state(ProcessState::Up);
        self.has_started = true;
        Ok(())
    }

    /// Send a SIGTERM to a process, wait 8 seconds, then send SIGKILL
    pub fn stop(&mut self) -> Result<()> {
        match self.child {
            Some(ref mut child) => {
                outputln!(preamble & self.preamble, "Stopping...");
                let shutdown = try!(child.kill());
                outputln!("{} - Shutdown method: {}", self.preamble, shutdown);
            }
            None => {}
        };
        self.check_process();
        Ok(())
    }

    pub fn down(&mut self) -> Result<()> {
        self.enter_state(ProcessState::Down);
        try!(self.stop());
        self.cleanup_pidfile();
        Ok(())
    }

    pub fn restart(&mut self, pkg: &Pkg) -> Result<()> {
        self.enter_state(ProcessState::Restart);
        try!(self.stop());
        try!(self.start(pkg));
        Ok(())
    }

    /// if the child process exists, check it's status via waitpid().
    pub fn check_process(&mut self) {
        let changed = match self.child {
            None => false,
            Some(ref mut child) => {
                match child.status() {
                    Ok(ref status) if status.no_status() => false,
                    Ok(ref status) => {
                        if status.code().is_some() {
                            outputln!("{} - process {} died with exit code {}",
                                      self.preamble,
                                      child.id(),
                                      status.code().unwrap());
                        } else if status.signal().is_some() {
                            outputln!("{} - process {} died with signal {}",
                                      self.preamble,
                                      child.id(),
                                      status.signal().unwrap());
                        }
                        true
                    }
                    Err(e) => {
                        debug!("Error checking process status: {}, continuing", e);
                        false
                    }
                }
            }
        };
        if changed {
            match self.state {
                ProcessState::Up | ProcessState::Start | ProcessState::Restart => {
                    outputln!("{} - Service exited", self.preamble);
                    self.child = None;
                }
                ProcessState::Down => {
                    self.enter_state(ProcessState::Down);
                    self.child = None;
                }
            }
        }
    }

    /// Create a pid file for a package
    /// The existence of this file does not guarantee that a
    /// process exists at the PID contained within.
    pub fn create_pidfile(&mut self, pkg: &Pkg) -> Result<()> {
        match self.child {
            Some(ref child) => {
                let ref pid = child.id();
                debug!("Creating PID file for child {} -> {:?}",
                       pkg.svc_pid_file.display(),
                       pid);
                let mut f = try!(File::create(&pkg.svc_pid_file));
                set_owner(&pkg.svc_pid_file, &pkg.svc_user, &pkg.svc_group)?;
                write!(f, "{}", pid)?;
                self.pid = Some(pkg.svc_pid_file.clone());
                Ok(())
            }
            None => Ok(()),
        }
    }

    /// Remove a pidfile for this package if it exists.
    /// Do NOT fail if there is an error removing the PIDFILE
    pub fn cleanup_pidfile(&mut self) {
        if let Some(ref pid_file) = self.pid {
            debug!("Attempting to clean up pid file {}", &pid_file.display());
            match std::fs::remove_file(pid_file) {
                Ok(_) => debug!("Removed pid file"),
                Err(e) => debug!("Error removing pidfile: {}, continuing", e),
            }
        }
        self.pid = None;
    }
}

impl Serialize for Supervisor {
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
        where S: Serializer
    {
        let pid = match self.child {
            Some(ref child) => Some(child.id()),
            None => None,
        };
        let mut strukt = try!(serializer.serialize_struct("supervisor", 5));
        try!(strukt.serialize_field("pid", &pid));
        try!(strukt.serialize_field("preamble", &self.preamble));
        try!(strukt.serialize_field("state", &self.state));
        try!(strukt.serialize_field("state_entered", &self.state_entered.sec));
        try!(strukt.serialize_field("started", &self.has_started));
        strukt.end()
    }
}

impl Drop for Supervisor {
    fn drop(&mut self) {
        let _ = self.cleanup_pidfile();
    }
}

/// Consume output from a child process until EOF, then finish
fn child_out_reader(c_stdout: Option<ChildStdout>, package_name: String) -> Result<()> {
    let out = match c_stdout {
        Some(s) => s,
        None => return Err(sup_error!(Error::UnpackFailed)),
    };
    let mut reader = BufReader::new(out);
    let mut buffer = String::new();

    while reader.read_line(&mut buffer).unwrap() > 0 {
        let mut line = output_format!(preamble &package_name, logkey "O");
        line.push_str(&buffer);
        print!("{}", line);
        buffer.clear();
    }
    debug!("child_out_reader exiting");
    Ok(())
}

/// Consume standard error from a child process until EOF, then finish
fn child_err_reader(c_stderr: Option<ChildStderr>, package_name: String) -> Result<()> {
    let err = match c_stderr {
        Some(s) => s,
        None => return Err(sup_error!(Error::UnpackFailed)),
    };
    let mut reader = BufReader::new(err);
    let mut buffer = String::new();

    while reader.read_line(&mut buffer).unwrap() > 0 {
        let mut line = output_format!(preamble &package_name, logkey "E");
        let c = format!("{}", Colour::Red.bold().paint(buffer.clone()));
        line.push_str(c.as_str());
        let _ = write!(&mut std::io::stderr(), "{}", line);
        buffer.clear();
    }
    debug!("child_err_reader exiting");
    Ok(())
}
<|endoftext|>


<commit_before>use std::{
    sync::{
        Arc,
        atomic::{AtomicBool, Ordering::SeqCst},
    },
    fmt,
    collections::{HashSet, VecDeque},
};

use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit};
use libsyntax2::{
    TextUnit, TextRange, SmolStr, File, AstNode,
    SyntaxKind::*,
    ast::{self, NameOwner},
};

use {
    FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
    JobToken, CrateGraph, CrateId,
    module_map::{ModuleMap, Problem},
    roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
};

#[derive(Debug)]
pub(crate) struct AnalysisHostImpl {
    data: Arc<WorldData>
}

impl AnalysisHostImpl {
    pub fn new() -> AnalysisHostImpl {
        AnalysisHostImpl {
            data: Arc::new(WorldData::default()),
        }
    }
    pub fn analysis(
        &self,
        file_resolver: Arc<dyn FileResolver>,
    ) -> AnalysisImpl {
        AnalysisImpl {
            needs_reindex: AtomicBool::new(false),
            file_resolver,
            data: self.data.clone(),
        }
    }
    pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
        let data = self.data_mut();
        for (file_id, text) in changes {
            data.root.update(file_id, text);
        }
    }
    pub fn set_crate_graph(&mut self, graph: CrateGraph) {
        let mut visited = HashSet::new();
        for &file_id in graph.crate_roots.values() {
            if !visited.insert(file_id) {
                panic!("duplicate crate root: {:?}", file_id);
            }
        }
        self.data_mut().crate_graph = graph;
    }
    pub fn add_library(&mut self, root: ReadonlySourceRoot) {
        self.data_mut().libs.push(Arc::new(root));
    }
    fn data_mut(&mut self) -> &mut WorldData {
        Arc::make_mut(&mut self.data)
    }
}

pub(crate) struct AnalysisImpl {
    needs_reindex: AtomicBool,
    file_resolver: Arc<dyn FileResolver>,
    data: Arc<WorldData>,
}

impl fmt::Debug for AnalysisImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (&*self.data).fmt(f)
    }
}

impl Clone for AnalysisImpl {
    fn clone(&self) -> AnalysisImpl {
        AnalysisImpl {
            needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)),
            file_resolver: Arc::clone(&self.file_resolver),
            data: Arc::clone(&self.data),
        }
    }
}

impl AnalysisImpl {
    fn root(&self, file_id: FileId) -> &SourceRoot {
        if self.data.root.contains(file_id) {
            return &self.data.root;
        }
        &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
    }
    pub fn file_syntax(&self, file_id: FileId) -> &File {
        self.root(file_id).syntax(file_id)
    }
    pub fn file_line_index(&self, file_id: FileId) -> &LineIndex {
        self.root(file_id).lines(file_id)
    }
    pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        self.reindex();
        let mut buf = Vec::new();
        if query.libs {
            self.data.libs.iter()
                .for_each(|it| it.symbols(&mut buf));
        } else {
            self.data.root.symbols(&mut buf);
        }
        query.search(&buf, token)

    }
    pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
        let module_map = self.root(file_id).module_map();
        let id = module_map.file2module(file_id);
        module_map
            .parent_modules(
                id,
                &*self.file_resolver,
                &|file_id| self.file_syntax(file_id),
            )
            .into_iter()
            .map(|(id, name, node)| {
                let id = module_map.module2file(id);
                let sym = FileSymbol {
                    name,
                    node_range: node.range(),
                    kind: MODULE,
                };
                (id, sym)
            })
            .collect()
    }

    pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
        let module_map = self.root(file_id).module_map();
        let crate_graph = &self.data.crate_graph;
        let mut res = Vec::new();
        let mut work = VecDeque::new();
        work.push_back(file_id);
        let mut visited = HashSet::new();
        while let Some(id) = work.pop_front() {
            if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) {
                res.push(crate_id);
                continue;
            }
            let mid = module_map.file2module(id);
            let parents = module_map
                .parent_module_ids(
                    mid,
                    &*self.file_resolver,
                    &|file_id| self.file_syntax(file_id),
                )
                .into_iter()
                .map(|id| module_map.module2file(id))
                .filter(|&id| visited.insert(id));
            work.extend(parents);
        }
        res
    }
    pub fn crate_root(&self, crate_id: CrateId) -> FileId {
        self.data.crate_graph.crate_roots[&crate_id]
    }
    pub fn approximately_resolve_symbol(
        &self,
        file_id: FileId,
        offset: TextUnit,
        token: &JobToken,
    ) -> Vec<(FileId, FileSymbol)> {
        let root = self.root(file_id);
        let module_map = root.module_map();
        let file = root.syntax(file_id);
        let syntax = file.syntax();
        if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
            return self.index_resolve(name_ref, token);
        }
        if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) {
            if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
                if module.has_semi() {
                    let file_ids = self.resolve_module(module_map, file_id, module);

                    let res = file_ids.into_iter().map(|id| {
                        let name = module.name()
                            .map(|n| n.text())
                            .unwrap_or_else(|| SmolStr::new(""));
                        let symbol = FileSymbol {
                            name,
                            node_range: TextRange::offset_len(0.into(), 0.into()),
                            kind: MODULE,
                        };
                        (id, symbol)
                    }).collect();

                    return res;
                }
            }
        }
        vec![]
    }

    pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
        let root = self.root(file_id);
        let module_map = root.module_map();
        let syntax = root.syntax(file_id);

        let mut res = libeditor::diagnostics(&syntax)
            .into_iter()
            .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None })
            .collect::<Vec<_>>();

        module_map.problems(
            file_id,
            &*self.file_resolver,
            &|file_id| self.file_syntax(file_id),
            |name_node, problem| {
                let diag = match problem {
                    Problem::UnresolvedModule { candidate } => {
                        let create_file = FileSystemEdit::CreateFile {
                            anchor: file_id,
                            path: candidate.clone(),
                        };
                        let fix = SourceChange {
                            label: "create module".to_string(),
                            source_file_edits: Vec::new(),
                            file_system_edits: vec![create_file],
                            cursor_position: None,
                        };
                        Diagnostic {
                            range: name_node.syntax().range(),
                            message: "unresolved module".to_string(),
                            fix: Some(fix),
                        }
                    }
                    Problem::NotDirOwner { move_to, candidate } => {
                        let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() };
                        let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) };
                        let fix = SourceChange {
                            label: "move file and create module".to_string(),
                            source_file_edits: Vec::new(),
                            file_system_edits: vec![move_file, create_file],
                            cursor_position: None,
                        };
                        Diagnostic {
                            range: name_node.syntax().range(),
                            message: "can't declare module at this location".to_string(),
                            fix: Some(fix),
                        }
                    }
                };
                res.push(diag)
            }
        );
        res
    }

    pub fn assists(&self, file_id: FileId, offset: TextUnit) -> Vec<SourceChange> {
        let file = self.file_syntax(file_id);
        let actions = vec![
            ("flip comma", libeditor::flip_comma(&file, offset).map(|f| f())),
            ("add `#[derive]`", libeditor::add_derive(&file, offset).map(|f| f())),
            ("add impl", libeditor::add_impl(&file, offset).map(|f| f())),
        ];
        actions.into_iter()
            .filter_map(|(name, local_edit)| {
                Some(SourceChange::from_local_edit(
                    file_id, name, local_edit?,
                ))
            })
            .collect()
    }

    fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        let name = name_ref.text();
        let mut query = Query::new(name.to_string());
        query.exact();
        query.limit(4);
        self.world_symbols(query, token)
    }

    fn resolve_module(&self, module_map: &ModuleMap, file_id: FileId, module: ast::Module) -> Vec<FileId> {
        let name = match module.name() {
            Some(name) => name.text(),
            None => return Vec::new(),
        };
        let id = module_map.file2module(file_id);
        module_map
            .child_module_by_name(
                id, name.as_str(),
                &*self.file_resolver,
                &|file_id| self.file_syntax(file_id),
            )
            .into_iter()
            .map(|id| module_map.module2file(id))
            .collect()
    }

    fn reindex(&self) {
        if self.needs_reindex.compare_and_swap(true, false, SeqCst) {
            self.data.root.reindex();
        }
    }
}

#[derive(Clone, Default, Debug)]
struct WorldData {
    crate_graph: CrateGraph,
    root: WritableSourceRoot,
    libs: Vec<Arc<ReadonlySourceRoot>>,
}

impl SourceChange {
    pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
        let file_edit = SourceFileEdit {
            file_id,
            edits: edit.edit.into_atoms(),
        };
        SourceChange {
            label: label.to_string(),
            source_file_edits: vec![file_edit],
            file_system_edits: vec![],
            cursor_position: edit.cursor_position
                .map(|offset| Position { offset, file_id })
        }
    }
}

impl CrateGraph {
    fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
        let (&crate_id, _) = self.crate_roots
            .iter()
            .find(|(_crate_id, &root_id)| root_id == file_id)?;
        Some(crate_id)
    }
}
<commit_msg>micro-optimize<commit_after>use std::{
    sync::{
        Arc,
        atomic::{AtomicBool, Ordering::SeqCst},
    },
    fmt,
    collections::{HashSet, VecDeque},
};

use libeditor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit};
use libsyntax2::{
    TextUnit, TextRange, SmolStr, File, AstNode,
    SyntaxKind::*,
    ast::{self, NameOwner},
};

use {
    FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
    JobToken, CrateGraph, CrateId,
    module_map::{ModuleMap, Problem},
    roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
};

#[derive(Debug)]
pub(crate) struct AnalysisHostImpl {
    data: Arc<WorldData>
}

impl AnalysisHostImpl {
    pub fn new() -> AnalysisHostImpl {
        AnalysisHostImpl {
            data: Arc::new(WorldData::default()),
        }
    }
    pub fn analysis(
        &self,
        file_resolver: Arc<dyn FileResolver>,
    ) -> AnalysisImpl {
        AnalysisImpl {
            needs_reindex: AtomicBool::new(false),
            file_resolver,
            data: self.data.clone(),
        }
    }
    pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
        let data = self.data_mut();
        for (file_id, text) in changes {
            data.root.update(file_id, text);
        }
    }
    pub fn set_crate_graph(&mut self, graph: CrateGraph) {
        let mut visited = HashSet::new();
        for &file_id in graph.crate_roots.values() {
            if !visited.insert(file_id) {
                panic!("duplicate crate root: {:?}", file_id);
            }
        }
        self.data_mut().crate_graph = graph;
    }
    pub fn add_library(&mut self, root: ReadonlySourceRoot) {
        self.data_mut().libs.push(Arc::new(root));
    }
    fn data_mut(&mut self) -> &mut WorldData {
        Arc::make_mut(&mut self.data)
    }
}

pub(crate) struct AnalysisImpl {
    needs_reindex: AtomicBool,
    file_resolver: Arc<dyn FileResolver>,
    data: Arc<WorldData>,
}

impl fmt::Debug for AnalysisImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (&*self.data).fmt(f)
    }
}

impl Clone for AnalysisImpl {
    fn clone(&self) -> AnalysisImpl {
        AnalysisImpl {
            needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)),
            file_resolver: Arc::clone(&self.file_resolver),
            data: Arc::clone(&self.data),
        }
    }
}

impl AnalysisImpl {
    fn root(&self, file_id: FileId) -> &SourceRoot {
        if self.data.root.contains(file_id) {
            return &self.data.root;
        }
        &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
    }
    pub fn file_syntax(&self, file_id: FileId) -> &File {
        self.root(file_id).syntax(file_id)
    }
    pub fn file_line_index(&self, file_id: FileId) -> &LineIndex {
        self.root(file_id).lines(file_id)
    }
    pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        self.reindex();
        let mut buf = Vec::new();
        if query.libs {
            self.data.libs.iter()
                .for_each(|it| it.symbols(&mut buf));
        } else {
            self.data.root.symbols(&mut buf);
        }
        query.search(&buf, token)

    }
    pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
        let root = self.root(file_id);
        let module_map = root.module_map();
        let id = module_map.file2module(file_id);
        module_map
            .parent_modules(
                id,
                &*self.file_resolver,
                &|file_id| root.syntax(file_id),
            )
            .into_iter()
            .map(|(id, name, node)| {
                let id = module_map.module2file(id);
                let sym = FileSymbol {
                    name,
                    node_range: node.range(),
                    kind: MODULE,
                };
                (id, sym)
            })
            .collect()
    }

    pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
        let module_map = self.root(file_id).module_map();
        let crate_graph = &self.data.crate_graph;
        let mut res = Vec::new();
        let mut work = VecDeque::new();
        work.push_back(file_id);
        let mut visited = HashSet::new();
        while let Some(id) = work.pop_front() {
            if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) {
                res.push(crate_id);
                continue;
            }
            let mid = module_map.file2module(id);
            let parents = module_map
                .parent_module_ids(
                    mid,
                    &*self.file_resolver,
                    &|file_id| self.file_syntax(file_id),
                )
                .into_iter()
                .map(|id| module_map.module2file(id))
                .filter(|&id| visited.insert(id));
            work.extend(parents);
        }
        res
    }
    pub fn crate_root(&self, crate_id: CrateId) -> FileId {
        self.data.crate_graph.crate_roots[&crate_id]
    }
    pub fn approximately_resolve_symbol(
        &self,
        file_id: FileId,
        offset: TextUnit,
        token: &JobToken,
    ) -> Vec<(FileId, FileSymbol)> {
        let root = self.root(file_id);
        let module_map = root.module_map();
        let file = root.syntax(file_id);
        let syntax = file.syntax();
        if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
            return self.index_resolve(name_ref, token);
        }
        if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) {
            if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
                if module.has_semi() {
                    let file_ids = self.resolve_module(module_map, file_id, module);

                    let res = file_ids.into_iter().map(|id| {
                        let name = module.name()
                            .map(|n| n.text())
                            .unwrap_or_else(|| SmolStr::new(""));
                        let symbol = FileSymbol {
                            name,
                            node_range: TextRange::offset_len(0.into(), 0.into()),
                            kind: MODULE,
                        };
                        (id, symbol)
                    }).collect();

                    return res;
                }
            }
        }
        vec![]
    }

    pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
        let root = self.root(file_id);
        let module_map = root.module_map();
        let syntax = root.syntax(file_id);

        let mut res = libeditor::diagnostics(&syntax)
            .into_iter()
            .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None })
            .collect::<Vec<_>>();

        module_map.problems(
            file_id,
            &*self.file_resolver,
            &|file_id| self.file_syntax(file_id),
            |name_node, problem| {
                let diag = match problem {
                    Problem::UnresolvedModule { candidate } => {
                        let create_file = FileSystemEdit::CreateFile {
                            anchor: file_id,
                            path: candidate.clone(),
                        };
                        let fix = SourceChange {
                            label: "create module".to_string(),
                            source_file_edits: Vec::new(),
                            file_system_edits: vec![create_file],
                            cursor_position: None,
                        };
                        Diagnostic {
                            range: name_node.syntax().range(),
                            message: "unresolved module".to_string(),
                            fix: Some(fix),
                        }
                    }
                    Problem::NotDirOwner { move_to, candidate } => {
                        let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() };
                        let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) };
                        let fix = SourceChange {
                            label: "move file and create module".to_string(),
                            source_file_edits: Vec::new(),
                            file_system_edits: vec![move_file, create_file],
                            cursor_position: None,
                        };
                        Diagnostic {
                            range: name_node.syntax().range(),
                            message: "can't declare module at this location".to_string(),
                            fix: Some(fix),
                        }
                    }
                };
                res.push(diag)
            }
        );
        res
    }

    pub fn assists(&self, file_id: FileId, offset: TextUnit) -> Vec<SourceChange> {
        let file = self.file_syntax(file_id);
        let actions = vec![
            ("flip comma", libeditor::flip_comma(&file, offset).map(|f| f())),
            ("add `#[derive]`", libeditor::add_derive(&file, offset).map(|f| f())),
            ("add impl", libeditor::add_impl(&file, offset).map(|f| f())),
        ];
        actions.into_iter()
            .filter_map(|(name, local_edit)| {
                Some(SourceChange::from_local_edit(
                    file_id, name, local_edit?,
                ))
            })
            .collect()
    }

    fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        let name = name_ref.text();
        let mut query = Query::new(name.to_string());
        query.exact();
        query.limit(4);
        self.world_symbols(query, token)
    }

    fn resolve_module(&self, module_map: &ModuleMap, file_id: FileId, module: ast::Module) -> Vec<FileId> {
        let name = match module.name() {
            Some(name) => name.text(),
            None => return Vec::new(),
        };
        let id = module_map.file2module(file_id);
        module_map
            .child_module_by_name(
                id, name.as_str(),
                &*self.file_resolver,
                &|file_id| self.file_syntax(file_id),
            )
            .into_iter()
            .map(|id| module_map.module2file(id))
            .collect()
    }

    fn reindex(&self) {
        if self.needs_reindex.compare_and_swap(true, false, SeqCst) {
            self.data.root.reindex();
        }
    }
}

#[derive(Clone, Default, Debug)]
struct WorldData {
    crate_graph: CrateGraph,
    root: WritableSourceRoot,
    libs: Vec<Arc<ReadonlySourceRoot>>,
}

impl SourceChange {
    pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
        let file_edit = SourceFileEdit {
            file_id,
            edits: edit.edit.into_atoms(),
        };
        SourceChange {
            label: label.to_string(),
            source_file_edits: vec![file_edit],
            file_system_edits: vec![],
            cursor_position: edit.cursor_position
                .map(|offset| Position { offset, file_id })
        }
    }
}

impl CrateGraph {
    fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
        let (&crate_id, _) = self.crate_roots
            .iter()
            .find(|(_crate_id, &root_id)| root_id == file_id)?;
        Some(crate_id)
    }
}
<|endoftext|>


<commit_before>extern crate parking_lot;
#[macro_use]
extern crate log;
extern crate once_cell;
extern crate libsyntax2;
extern crate libeditor;
extern crate fst;
extern crate rayon;
extern crate relative_path;
#[macro_use]
extern crate crossbeam_channel;

mod symbol_index;
mod module_map;
mod imp;
mod job;
mod roots;

use std::{
    sync::Arc,
    collections::HashMap,
};

use relative_path::{RelativePath, RelativePathBuf};
use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
use imp::{AnalysisImpl, AnalysisHostImpl};

pub use libeditor::{
    StructureNode, LineIndex, FileSymbol,
    Runnable, RunnableKind, HighlightedRange, CompletionItem,
};
pub use job::{JobToken, JobHandle};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CrateId(pub u32);

#[derive(Debug, Clone, Default)]
pub struct CrateGraph {
    pub crate_roots: HashMap<CrateId, FileId>,
}

pub trait FileResolver: Send + Sync + 'static {
    fn file_stem(&self, id: FileId) -> String;
    fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>;
}

#[derive(Debug)]
pub struct AnalysisHost {
    imp: AnalysisHostImpl
}

impl AnalysisHost {
    pub fn new() -> AnalysisHost {
        AnalysisHost { imp: AnalysisHostImpl::new() }
    }
    pub fn analysis(&self, file_resolver: impl FileResolver) -> Analysis {
        Analysis { imp: self.imp.analysis(Arc::new(file_resolver)) }
    }
    pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
        self.change_files(::std::iter::once((file_id, text)));
    }
    pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) {
        self.imp.change_files(&mut changes)
    }
    pub fn set_crate_graph(&mut self, graph: CrateGraph) {
        self.imp.set_crate_graph(graph)
    }
    pub fn add_library(&mut self, data: LibraryData) {
        self.imp.add_library(data.root)
    }
}

#[derive(Debug)]
pub struct SourceChange {
    pub label: String,
    pub source_file_edits: Vec<SourceFileEdit>,
    pub file_system_edits: Vec<FileSystemEdit>,
    pub cursor_position: Option<Position>,
}

#[derive(Debug)]
pub struct Position {
    pub file_id: FileId,
    pub offset: TextUnit,
}

#[derive(Debug)]
pub struct SourceFileEdit {
    pub file_id: FileId,
    pub edits: Vec<AtomEdit>,
}

#[derive(Debug)]
pub enum FileSystemEdit {
    CreateFile {
        anchor: FileId,
        path: RelativePathBuf,
    },
    MoveFile {
        file: FileId,
        path: RelativePathBuf,
    }
}

#[derive(Debug)]
pub struct Diagnostic {
    pub message: String,
    pub range: TextRange,
    pub fix: Option<SourceChange>,
}

#[derive(Debug)]
pub struct Query {
    query: String,
    lowercased: String,
    only_types: bool,
    libs: bool,
    exact: bool,
    limit: usize,
}

impl Query {
    pub fn new(query: String) -> Query {
        let lowercased = query.to_lowercase();
        Query {
            query,
            lowercased,
            only_types: false,
            libs: false,
            exact: false,
            limit: usize::max_value()
        }
    }
    pub fn only_types(&mut self) {
        self.only_types = true;
    }
    pub fn libs(&mut self) {
        self.libs = true;
    }
    pub fn exact(&mut self) {
        self.exact = true;
    }
    pub fn limit(&mut self, limit: usize) {
        self.limit = limit
    }
}

#[derive(Clone, Debug)]
pub struct Analysis {
    imp: AnalysisImpl
}

impl Analysis {
    pub fn file_syntax(&self, file_id: FileId) -> File {
        self.imp.file_syntax(file_id).clone()
    }
    pub fn file_line_index(&self, file_id: FileId) -> LineIndex {
        self.imp.file_line_index(file_id).clone()
    }
    pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange {
        libeditor::extend_selection(file, range).unwrap_or(range)
    }
    pub fn matching_brace(&self, file: &File, offset: TextUnit) -> Option<TextUnit> {
        libeditor::matching_brace(file, offset)
    }
    pub fn syntax_tree(&self, file_id: FileId) -> String {
        let file = self.file_syntax(file_id);
        libeditor::syntax_tree(&file)
    }
    pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange {
        let file = self.file_syntax(file_id);
        SourceChange::from_local_edit(file_id, "join lines", libeditor::join_lines(&file, range))
    }
    pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> {
        let file = self.file_syntax(file_id);
        Some(SourceChange::from_local_edit(file_id, "add semicolon", libeditor::on_eq_typed(&file, offset)?))
    }
    pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
        let file = self.file_syntax(file_id);
        libeditor::file_structure(&file)
    }
    pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        self.imp.world_symbols(query, token)
    }
    pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        self.imp.approximately_resolve_symbol(file_id, offset, token)
    }
    pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
        self.imp.parent_module(file_id)
    }
    pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
        self.imp.crate_for(file_id)
    }
    pub fn crate_root(&self, crate_id: CrateId) -> FileId {
        self.imp.crate_root(crate_id)
    }
    pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> {
        let file = self.file_syntax(file_id);
        libeditor::runnables(&file)
    }
    pub fn highlight(&self, file_id: FileId) -> Vec<HighlightedRange> {
        let file = self.file_syntax(file_id);
        libeditor::highlight(&file)
    }
    pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Option<Vec<CompletionItem>> {
        let file = self.file_syntax(file_id);
        libeditor::scope_completion(&file, offset)
    }
    pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> {
        self.imp.assists(file_id, range)
    }
    pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
        self.imp.diagnostics(file_id)
    }
}

#[derive(Debug)]
pub struct LibraryData {
    root: roots::ReadonlySourceRoot
}

impl LibraryData {
    pub fn prepare(files: Vec<(FileId, String)>) -> LibraryData {
        let root = roots::ReadonlySourceRoot::new(files);
        LibraryData { root }
    }
}
<commit_msg>Separete API from IMPL<commit_after>extern crate parking_lot;
#[macro_use]
extern crate log;
extern crate once_cell;
extern crate libsyntax2;
extern crate libeditor;
extern crate fst;
extern crate rayon;
extern crate relative_path;
#[macro_use]
extern crate crossbeam_channel;

mod symbol_index;
mod module_map;
mod imp;
mod job;
mod roots;

use std::{
    sync::Arc,
    collections::HashMap,
};

use relative_path::{RelativePath, RelativePathBuf};
use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
use imp::{AnalysisImpl, AnalysisHostImpl};

pub use libeditor::{
    StructureNode, LineIndex, FileSymbol,
    Runnable, RunnableKind, HighlightedRange, CompletionItem,
};
pub use job::{JobToken, JobHandle};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CrateId(pub u32);

#[derive(Debug, Clone, Default)]
pub struct CrateGraph {
    pub crate_roots: HashMap<CrateId, FileId>,
}

pub trait FileResolver: Send + Sync + 'static {
    fn file_stem(&self, id: FileId) -> String;
    fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>;
}

#[derive(Debug)]
pub struct AnalysisHost {
    imp: AnalysisHostImpl
}

impl AnalysisHost {
    pub fn new() -> AnalysisHost {
        AnalysisHost { imp: AnalysisHostImpl::new() }
    }
    pub fn analysis(&self, file_resolver: impl FileResolver) -> Analysis {
        Analysis { imp: self.imp.analysis(Arc::new(file_resolver)) }
    }
    pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
        self.change_files(::std::iter::once((file_id, text)));
    }
    pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) {
        self.imp.change_files(&mut changes)
    }
    pub fn set_crate_graph(&mut self, graph: CrateGraph) {
        self.imp.set_crate_graph(graph)
    }
    pub fn add_library(&mut self, data: LibraryData) {
        self.imp.add_library(data.root)
    }
}

#[derive(Debug)]
pub struct SourceChange {
    pub label: String,
    pub source_file_edits: Vec<SourceFileEdit>,
    pub file_system_edits: Vec<FileSystemEdit>,
    pub cursor_position: Option<Position>,
}

#[derive(Debug)]
pub struct Position {
    pub file_id: FileId,
    pub offset: TextUnit,
}

#[derive(Debug)]
pub struct SourceFileEdit {
    pub file_id: FileId,
    pub edits: Vec<AtomEdit>,
}

#[derive(Debug)]
pub enum FileSystemEdit {
    CreateFile {
        anchor: FileId,
        path: RelativePathBuf,
    },
    MoveFile {
        file: FileId,
        path: RelativePathBuf,
    }
}

#[derive(Debug)]
pub struct Diagnostic {
    pub message: String,
    pub range: TextRange,
    pub fix: Option<SourceChange>,
}

#[derive(Debug)]
pub struct Query {
    query: String,
    lowercased: String,
    only_types: bool,
    libs: bool,
    exact: bool,
    limit: usize,
}

impl Query {
    pub fn new(query: String) -> Query {
        let lowercased = query.to_lowercase();
        Query {
            query,
            lowercased,
            only_types: false,
            libs: false,
            exact: false,
            limit: usize::max_value()
        }
    }
    pub fn only_types(&mut self) {
        self.only_types = true;
    }
    pub fn libs(&mut self) {
        self.libs = true;
    }
    pub fn exact(&mut self) {
        self.exact = true;
    }
    pub fn limit(&mut self, limit: usize) {
        self.limit = limit
    }
}

#[derive(Clone, Debug)]
pub struct Analysis {
    imp: AnalysisImpl
}

impl Analysis {
    pub fn file_syntax(&self, file_id: FileId) -> File {
        self.imp.file_syntax(file_id).clone()
    }
    pub fn file_line_index(&self, file_id: FileId) -> LineIndex {
        self.imp.file_line_index(file_id).clone()
    }
    pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange {
        libeditor::extend_selection(file, range).unwrap_or(range)
    }
    pub fn matching_brace(&self, file: &File, offset: TextUnit) -> Option<TextUnit> {
        libeditor::matching_brace(file, offset)
    }
    pub fn syntax_tree(&self, file_id: FileId) -> String {
        let file = self.imp.file_syntax(file_id);
        libeditor::syntax_tree(file)
    }
    pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange {
        let file = self.imp.file_syntax(file_id);
        SourceChange::from_local_edit(file_id, "join lines", libeditor::join_lines(file, range))
    }
    pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> {
        let file = self.imp.file_syntax(file_id);
        Some(SourceChange::from_local_edit(file_id, "add semicolon", libeditor::on_eq_typed(file, offset)?))
    }
    pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
        let file = self.imp.file_syntax(file_id);
        libeditor::file_structure(file)
    }
    pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        self.imp.world_symbols(query, token)
    }
    pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
        self.imp.approximately_resolve_symbol(file_id, offset, token)
    }
    pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
        self.imp.parent_module(file_id)
    }
    pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
        self.imp.crate_for(file_id)
    }
    pub fn crate_root(&self, crate_id: CrateId) -> FileId {
        self.imp.crate_root(crate_id)
    }
    pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> {
        let file = self.imp.file_syntax(file_id);
        libeditor::runnables(file)
    }
    pub fn highlight(&self, file_id: FileId) -> Vec<HighlightedRange> {
        let file = self.imp.file_syntax(file_id);
        libeditor::highlight(file)
    }
    pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Option<Vec<CompletionItem>> {
        let file = self.imp.file_syntax(file_id);
        libeditor::scope_completion(file, offset)
    }
    pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> {
        self.imp.assists(file_id, range)
    }
    pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
        self.imp.diagnostics(file_id)
    }
}

#[derive(Debug)]
pub struct LibraryData {
    root: roots::ReadonlySourceRoot
}

impl LibraryData {
    pub fn prepare(files: Vec<(FileId, String)>) -> LibraryData {
        let root = roots::ReadonlySourceRoot::new(files);
        LibraryData { root }
    }
}
<|endoftext|>


<commit_before>//! This module implements manually tracked test coverage, which is useful for
//! quickly finding a test responsible for testing a particular bit of code.
//!
//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html>
//! for details, but the TL;DR is that you write your test as
//!
//! ```
//! #[test]
//! fn test_foo() {
//!     mark::check!(test_foo);
//! }
//! ```
//!
//! and in the code under test you write
//!
//! ```
//! # use test_utils::mark;
//! # fn some_condition() -> bool { true }
//! fn foo() {
//!     if some_condition() {
//!         mark::hit!(test_foo);
//!     }
//! }
//! ```
//!
//! This module then checks that executing the test indeed covers the specified
//! function. This is useful if you come back to the `foo` function ten years
//! later and wonder where the test are: now you can grep for `test_foo`.
use std::sync::atomic::{AtomicUsize, Ordering};

#[macro_export]
macro_rules! _hit {
    ($ident:ident) => {{
        #[cfg(test)]
        {
            extern "C" {
                #[no_mangle]
                static $ident: std::sync::atomic::AtomicUsize;
            }
            unsafe {
                $ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
            }
        }
    }};
}
pub use _hit as hit;

#[macro_export]
macro_rules! _check {
    ($ident:ident) => {
        #[no_mangle]
        static $ident: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
        let _checker = $crate::mark::MarkChecker::new(&$ident);
    };
}
pub use _check as check;

pub struct MarkChecker {
    mark: &'static AtomicUsize,
    value_on_entry: usize,
}

impl MarkChecker {
    pub fn new(mark: &'static AtomicUsize) -> MarkChecker {
        let value_on_entry = mark.load(Ordering::SeqCst);
        MarkChecker { mark, value_on_entry }
    }
}

impl Drop for MarkChecker {
    fn drop(&mut self) {
        if std::thread::panicking() {
            return;
        }
        let value_on_exit = self.mark.load(Ordering::SeqCst);
        assert!(value_on_exit > self.value_on_entry, "mark was not hit")
    }
}
<commit_msg>Use relaxed ordering for marks<commit_after>//! This module implements manually tracked test coverage, which is useful for
//! quickly finding a test responsible for testing a particular bit of code.
//!
//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html>
//! for details, but the TL;DR is that you write your test as
//!
//! ```
//! #[test]
//! fn test_foo() {
//!     mark::check!(test_foo);
//! }
//! ```
//!
//! and in the code under test you write
//!
//! ```
//! # use test_utils::mark;
//! # fn some_condition() -> bool { true }
//! fn foo() {
//!     if some_condition() {
//!         mark::hit!(test_foo);
//!     }
//! }
//! ```
//!
//! This module then checks that executing the test indeed covers the specified
//! function. This is useful if you come back to the `foo` function ten years
//! later and wonder where the test are: now you can grep for `test_foo`.
use std::sync::atomic::{AtomicUsize, Ordering};

#[macro_export]
macro_rules! _hit {
    ($ident:ident) => {{
        #[cfg(test)]
        {
            extern "C" {
                #[no_mangle]
                static $ident: std::sync::atomic::AtomicUsize;
            }
            unsafe {
                $ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
            }
        }
    }};
}
pub use _hit as hit;

#[macro_export]
macro_rules! _check {
    ($ident:ident) => {
        #[no_mangle]
        static $ident: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
        let _checker = $crate::mark::MarkChecker::new(&$ident);
    };
}
pub use _check as check;

pub struct MarkChecker {
    mark: &'static AtomicUsize,
    value_on_entry: usize,
}

impl MarkChecker {
    pub fn new(mark: &'static AtomicUsize) -> MarkChecker {
        let value_on_entry = mark.load(Ordering::Relaxed);
        MarkChecker { mark, value_on_entry }
    }
}

impl Drop for MarkChecker {
    fn drop(&mut self) {
        if std::thread::panicking() {
            return;
        }
        let value_on_exit = self.mark.load(Ordering::Relaxed);
        assert!(value_on_exit > self.value_on_entry, "mark was not hit")
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate rustc_serialize;
extern crate rusqlite;
extern crate jmap;
extern crate time;

#[macro_use]
extern crate log;

mod logger;
mod db;
mod util;
mod record;

use std::default::Default;
use std::io::{Read, Write, ErrorKind};

use std::fs::File;

use hyper::server::{Request, Response};
use hyper::method::Method;
use hyper::method::Method::{Post, Get, Head};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use hyper::header;

use rustc_serialize::json::{Json,ToJson};

use jmap::parse::FromJson;
use jmap::method::{RequestBatch, ResponseBatch, ResponseMethod};
use jmap::method::RequestMethod::*;
use jmap::method::ResponseMethod::*;

use util::RequestContext;
use record::RecordHandler;
use db::Db;

struct StatusBody {
    code: StatusCode,
    body: Option<Vec<u8>>
}
impl StatusBody {
    fn new(code: StatusCode, body: Option<Vec<u8>>) -> StatusBody {
        StatusBody { code: code, body: body }
    }
}

macro_rules! make_crud_method_dispatcher {
    ($method: expr, $rmethods: expr, $r: expr,
     $($ty: ty { $get: ident => $rget: ident, $set: ident => $rset: ident, $getup: ident => $rgetup: ident }),*) => {
        $rmethods = match $method {
            $(
                $get(args, id)
                    => vec!($r.get_records(&args).map(|a| $rget(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $set(args, id)
                    => vec!($r.set_records(&args).map(|a| $rset(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $getup(args, id) => $r.get_record_updates(&args).map(|a| {
                    match a {
                        (a, Some(b)) => vec!($rgetup(a, id.clone()), $rget(b, id.clone())),
                        (a, _)       => vec!($rgetup(a, id.clone())),
                    }
                }).unwrap_or_else(|e| vec!(ResponseError(e, id.clone()))),
            )*
            RequestError(args, id) => vec!(ResponseError(args, id)),
        };
    }
}

fn jmap_handler(mut req: Request) -> StatusBody {

    match Json::from_reader(&mut req) {
        Ok(j) => match RequestBatch::from_json(&j) {
            Ok(b) => {
                let mut rbatch: ResponseBatch = ResponseBatch::default();

                let r = RequestContext {
                    userid: 1, // XXX get userid from auth
                    db: Db::open().unwrap(),
                };

                for method in b.0.into_iter() {
                    let rmethods: Vec<ResponseMethod>;
                    make_crud_method_dispatcher!(method, rmethods, r,
                        Calendar {
                            GetCalendars       => Calendars,
                            SetCalendars       => CalendarsSet,
                            GetCalendarUpdates => CalendarUpdates
                        },
                        CalendarEvent {
                            GetCalendarEvents       => CalendarEvents,
                            SetCalendarEvents       => CalendarEventsSet,
                            GetCalendarEventUpdates => CalendarEventUpdates
                        },
                        Contact {
                            GetContacts       => Contacts,
                            SetContacts       => ContactsSet,
                            GetContactUpdates => ContactUpdates
                        },
                        ContactGroup {
                            GetContactGroups       => ContactGroups,
                            SetContactGroups       => ContactGroupsSet,
                            GetContactGroupUpdates => ContactGroupUpdates
                        },
                        Mailbox {
                            GetMailboxes      => Mailboxes,
                            SetMailboxes      => MailboxesSet,
                            GetMailboxUpdates => MailboxUpdates
                        }
                    );

                    rbatch.0.extend(rmethods.into_iter());
                }

                StatusBody::new(StatusCode::Ok, Some(rbatch.to_json().to_string().into_bytes()))
            },
            Err(e) =>
                StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
        },
        Err(e) => StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
    }
}

fn file_handler(path: &String, include_body: bool) -> StatusBody {
    match File::open(String::from("client") + if path == "/" { "/index.html" } else { path }) {
        Err(ref e) => match e.kind() {
            ErrorKind::NotFound => StatusBody::new(StatusCode::NotFound, None),
            // XXX others
            _ => StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
        },
        Ok(ref mut f) => {
            match include_body {
                false => StatusBody::new(StatusCode::Ok, None),
                true  => {
                    let mut s = String::new();
                    match f.read_to_string(&mut s) {
                        Err(ref e) =>
                            StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
                        _ =>
                            StatusBody::new(StatusCode::Ok, Some(s.into_bytes())),
                    }
                },
            }
        },
    }
}

fn finish_response(method: Method, path: &String, mut res: Response, out: StatusBody) {
    *res.status_mut() = out.code;

    info!("HTTP: {} {} => {}", method, path, out.code);

    match res.start()
        .and_then(|mut res|
                  match out.body {
                      Some(ref b) => {
                          try!(res.write_all(b));
                          Ok(res)
                      }
                      None => {
                          Ok(res)
                      }
                  })
        .and_then(|res| res.end()) {
            Err(e) => error!("response error: {}", e),
            _      => (),
        };
}

fn http_handler(mut req: Request, mut res: Response) {
    res.headers_mut().set(header::Server("salada/0.0.5".to_string()));

    let method = req.method.clone();
    let uri = req.uri.clone();

    match (method, uri) {
        (Post, AbsolutePath(ref path)) if path == "/jmap/" =>
            finish_response(Post, path, res, jmap_handler(req)),

        (Get, AbsolutePath(ref path)) =>
            finish_response(Get, path, res, file_handler(path, true)),

        (Head, AbsolutePath(ref path)) =>
            finish_response(Head, path, res, file_handler(path, false)),

        (_, ref ap) => {
            let s = match ap {
                &AbsolutePath(ref u) => u,
                _ => panic!("RequestUri not AbsolutePath?"),
            };
            let mut drain: Vec<u8> = vec!();
            req.read_to_end(&mut drain).ok();
            finish_response(req.method, &s, res, StatusBody::new(StatusCode::MethodNotAllowed, None))
        },
    };
}

fn main() {
    logger::init().unwrap();

    info!("Listening on http://127.0.0.1:3000/jmap");
    hyper::Server::http("127.0.0.1:3000").unwrap().handle(http_handler).unwrap();
}
<commit_msg>Read files into a byte buffer to remove UTF-8 requirement<commit_after>extern crate hyper;
extern crate rustc_serialize;
extern crate rusqlite;
extern crate jmap;
extern crate time;

#[macro_use]
extern crate log;

mod logger;
mod db;
mod util;
mod record;

use std::default::Default;
use std::io::{Read, Write, ErrorKind};

use std::fs::File;

use hyper::server::{Request, Response};
use hyper::method::Method;
use hyper::method::Method::{Post, Get, Head};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use hyper::header;

use rustc_serialize::json::{Json,ToJson};

use jmap::parse::FromJson;
use jmap::method::{RequestBatch, ResponseBatch, ResponseMethod};
use jmap::method::RequestMethod::*;
use jmap::method::ResponseMethod::*;

use util::RequestContext;
use record::RecordHandler;
use db::Db;

struct StatusBody {
    code: StatusCode,
    body: Option<Vec<u8>>
}
impl StatusBody {
    fn new(code: StatusCode, body: Option<Vec<u8>>) -> StatusBody {
        StatusBody { code: code, body: body }
    }
}

macro_rules! make_crud_method_dispatcher {
    ($method: expr, $rmethods: expr, $r: expr,
     $($ty: ty { $get: ident => $rget: ident, $set: ident => $rset: ident, $getup: ident => $rgetup: ident }),*) => {
        $rmethods = match $method {
            $(
                $get(args, id)
                    => vec!($r.get_records(&args).map(|a| $rget(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $set(args, id)
                    => vec!($r.set_records(&args).map(|a| $rset(a, id.clone())).unwrap_or_else(|e| ResponseError(e, id.clone()))),
                $getup(args, id) => $r.get_record_updates(&args).map(|a| {
                    match a {
                        (a, Some(b)) => vec!($rgetup(a, id.clone()), $rget(b, id.clone())),
                        (a, _)       => vec!($rgetup(a, id.clone())),
                    }
                }).unwrap_or_else(|e| vec!(ResponseError(e, id.clone()))),
            )*
            RequestError(args, id) => vec!(ResponseError(args, id)),
        };
    }
}

fn jmap_handler(mut req: Request) -> StatusBody {

    match Json::from_reader(&mut req) {
        Ok(j) => match RequestBatch::from_json(&j) {
            Ok(b) => {
                let mut rbatch: ResponseBatch = ResponseBatch::default();

                let r = RequestContext {
                    userid: 1, // XXX get userid from auth
                    db: Db::open().unwrap(),
                };

                for method in b.0.into_iter() {
                    let rmethods: Vec<ResponseMethod>;
                    make_crud_method_dispatcher!(method, rmethods, r,
                        Calendar {
                            GetCalendars       => Calendars,
                            SetCalendars       => CalendarsSet,
                            GetCalendarUpdates => CalendarUpdates
                        },
                        CalendarEvent {
                            GetCalendarEvents       => CalendarEvents,
                            SetCalendarEvents       => CalendarEventsSet,
                            GetCalendarEventUpdates => CalendarEventUpdates
                        },
                        Contact {
                            GetContacts       => Contacts,
                            SetContacts       => ContactsSet,
                            GetContactUpdates => ContactUpdates
                        },
                        ContactGroup {
                            GetContactGroups       => ContactGroups,
                            SetContactGroups       => ContactGroupsSet,
                            GetContactGroupUpdates => ContactGroupUpdates
                        },
                        Mailbox {
                            GetMailboxes      => Mailboxes,
                            SetMailboxes      => MailboxesSet,
                            GetMailboxUpdates => MailboxUpdates
                        }
                    );

                    rbatch.0.extend(rmethods.into_iter());
                }

                StatusBody::new(StatusCode::Ok, Some(rbatch.to_json().to_string().into_bytes()))
            },
            Err(e) =>
                StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
        },
        Err(e) => StatusBody::new(StatusCode::BadRequest, Some(e.to_string().into_bytes())),
    }
}

fn file_handler(path: &String, include_body: bool) -> StatusBody {
    match File::open(String::from("client") + if path == "/" { "/index.html" } else { path }) {
        Err(ref e) => match e.kind() {
            ErrorKind::NotFound => StatusBody::new(StatusCode::NotFound, None),
            // XXX others
            _ => StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
        },
        Ok(ref mut f) => {
            match include_body {
                false => StatusBody::new(StatusCode::Ok, None),
                true  => {
                    let mut buf: Vec<u8> = vec!();
                    match f.read_to_end(&mut buf) {
                        Err(ref e) =>
                            StatusBody::new(StatusCode::InternalServerError, Some(format!("{}", e).into_bytes())),
                        _ =>
                            StatusBody::new(StatusCode::Ok, Some(buf)),
                    }
                },
            }
        },
    }
}

fn finish_response(method: Method, path: &String, mut res: Response, out: StatusBody) {
    *res.status_mut() = out.code;

    info!("HTTP: {} {} => {}", method, path, out.code);

    match res.start()
        .and_then(|mut res|
                  match out.body {
                      Some(ref b) => {
                          try!(res.write_all(b));
                          Ok(res)
                      }
                      None => {
                          Ok(res)
                      }
                  })
        .and_then(|res| res.end()) {
            Err(e) => error!("response error: {}", e),
            _      => (),
        };
}

fn http_handler(mut req: Request, mut res: Response) {
    res.headers_mut().set(header::Server("salada/0.0.5".to_string()));

    let method = req.method.clone();
    let uri = req.uri.clone();

    match (method, uri) {
        (Post, AbsolutePath(ref path)) if path == "/jmap/" =>
            finish_response(Post, path, res, jmap_handler(req)),

        (Get, AbsolutePath(ref path)) =>
            finish_response(Get, path, res, file_handler(path, true)),

        (Head, AbsolutePath(ref path)) =>
            finish_response(Head, path, res, file_handler(path, false)),

        (_, ref ap) => {
            let s = match ap {
                &AbsolutePath(ref u) => u,
                _ => panic!("RequestUri not AbsolutePath?"),
            };
            let mut drain: Vec<u8> = vec!();
            req.read_to_end(&mut drain).ok();
            finish_response(req.method, &s, res, StatusBody::new(StatusCode::MethodNotAllowed, None))
        },
    };
}

fn main() {
    logger::init().unwrap();

    info!("Listening on http://127.0.0.1:3000/jmap");
    hyper::Server::http("127.0.0.1:3000").unwrap().handle(http_handler).unwrap();
}
<|endoftext|>


<commit_before>//! Generate update information from dependency information.

use std::rc::Rc;
use std::collections::HashMap;

use semver::Version;

use dependencies;

/// Stores old and new version.
pub struct Bump {
    /// The old version.
    pub old: Version,
    /// The new version.
    pub new: Version,
}

/// Stores update info for dependency.
pub struct Dependency {
    /// The library name.
    pub name: Rc<String>,
    /// Bump info.
    pub bump: Bump,
}

/// Stores information about a package.
pub struct Package {
    /// The package name.
    pub name: Rc<String>,
    /// The order to update library.
    pub order: u32,
    /// Update information.
    pub bump: Bump,
    /// The dependencies.
    pub dependencies: Vec<Dependency>,
}

/// Generates update info.
pub fn generate_update_info_from(dependency_info: &str) -> Result<String, String> {
    use piston_meta::*;

    type PackageIndex = usize;
    type Depth = u32;

    fn depth_of(
        package_index: PackageIndex,
        depths: &mut HashMap<PackageIndex, Depth>,
        dependencies_data: &[dependencies::Package]
    ) -> Depth {
        let package = &dependencies_data[package_index];
        let d = depths.get(&package_index).map(|d| *d);
        match d {
            None => {
                // The depth of a package equals maximum depth of the dependencies + 1.
                let new_depth: Depth = package.dependencies.iter().map(|dep| {
                        let mut depth = 0;
                        for (i, p) in dependencies_data.iter().enumerate() {
                            if p.name == dep.name {
                                depth = depth_of(i, depths, dependencies_data);
                            }
                        }
                        depth
                    }).max().unwrap_or(0) + 1;
                depths.insert(package_index, new_depth);
                new_depth
            }
            Some(x) => x
        }
    }

    // Parse and convert to dependencies data.
    let dependencies_meta_syntax = include_str!("../assets/dependencies/syntax.txt");
    let dependencies_meta_rules = stderr_unwrap(dependencies_meta_syntax,
        syntax(dependencies_meta_syntax));
    let dependency_info = stderr_unwrap(dependency_info,
        parse(&dependencies_meta_rules, dependency_info));
    let mut ignored = vec![];
    let dependencies_data = try!(dependencies::convert(&dependency_info, &mut ignored)
        .map_err(|_| String::from("Could not convert dependency info")));

    // Store the depths of libraries.
    let mut depths: HashMap<PackageIndex, Depth> = HashMap::new();
    for i in 0 .. dependencies_data.len() {
        let _depth = depth_of(i, &mut depths, &dependencies_data);
    }

    let mut new_versions: HashMap<Rc<String>, Version> = HashMap::new();
    for package in &dependencies_data {
        // Get latest version used by any dependency.
        for dep in &package.dependencies {
            let version = try!(Version::parse(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &dep.version, &dep.name)));
            let v = new_versions.get(&dep.name).map(|v| v.clone());
            match v {
                None => {
                    new_versions.insert(dep.name.clone(), version);
                }
                Some(v) => {
                    if v < version {
                        new_versions.insert(dep.name.clone(), version);
                    }
                }
            }
        }
    }

    // Overwrite the versions used by packages.
    for package in &dependencies_data {
        let version = try!(Version::parse(&package.version)
            .map_err(|_| format!("Could not parse version `{}` for `{}`",
                &package.version, &package.name)));
        new_versions.insert(package.name.clone(), version);
    }

    Ok(String::from(""))
}
<commit_msg>Use `HashMap` to store package indices<commit_after>//! Generate update information from dependency information.

use std::rc::Rc;
use std::collections::HashMap;

use semver::Version;

use dependencies;

/// Stores old and new version.
pub struct Bump {
    /// The old version.
    pub old: Version,
    /// The new version.
    pub new: Version,
}

/// Stores update info for dependency.
pub struct Dependency {
    /// The library name.
    pub name: Rc<String>,
    /// Bump info.
    pub bump: Bump,
}

/// Stores information about a package.
pub struct Package {
    /// The package name.
    pub name: Rc<String>,
    /// The order to update library.
    pub order: u32,
    /// Update information.
    pub bump: Bump,
    /// The dependencies.
    pub dependencies: Vec<Dependency>,
}

/// Generates update info.
pub fn generate_update_info_from(dependency_info: &str) -> Result<String, String> {
    use piston_meta::*;
    use std::iter::FromIterator;

    type PackageIndex = usize;
    type Depth = u32;

    fn depth_of(
        package_index: PackageIndex,
        package_indices: &HashMap<Rc<String>, PackageIndex>,
        depths: &mut HashMap<PackageIndex, Depth>,
        dependencies_data: &[dependencies::Package]
    ) -> Depth {
        let package = &dependencies_data[package_index];
        let d = depths.get(&package_index).map(|d| *d);
        match d {
            None => {
                // The depth of a package equals maximum depth of the dependencies + 1.
                let new_depth: Depth = package.dependencies.iter().map(|dep| {
                        package_indices.get(&dep.name).map(|&p| {
                                depth_of(p, package_indices, depths, dependencies_data)
                            }).unwrap_or(0)
                    }).max().unwrap_or(0) + 1;
                depths.insert(package_index, new_depth);
                new_depth
            }
            Some(x) => x
        }
    }

    // Parse and convert to dependencies data.
    let dependencies_meta_syntax = include_str!("../assets/dependencies/syntax.txt");
    let dependencies_meta_rules = stderr_unwrap(dependencies_meta_syntax,
        syntax(dependencies_meta_syntax));
    let dependency_info = stderr_unwrap(dependency_info,
        parse(&dependencies_meta_rules, dependency_info));
    let mut ignored = vec![];
    let dependencies_data = try!(dependencies::convert(&dependency_info, &mut ignored)
        .map_err(|_| String::from("Could not convert dependency info")));

    // Stores the package indices using package name as key.
    let package_indices: HashMap<Rc<String>, PackageIndex> =
        HashMap::from_iter(dependencies_data.iter().enumerate().map(
            |(i, p)| {
                (p.name.clone(), i)
            }));

    // Store the depths of libraries.
    let mut depths: HashMap<PackageIndex, Depth> = HashMap::new();
    for i in 0 .. dependencies_data.len() {
        let _depth = depth_of(i, &package_indices, &mut depths, &dependencies_data);
    }

    let mut new_versions: HashMap<Rc<String>, Version> = HashMap::new();
    for package in &dependencies_data {
        // Get latest version used by any dependency.
        for dep in &package.dependencies {
            let version = try!(Version::parse(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &dep.version, &dep.name)));
            let v = new_versions.get(&dep.name).map(|v| v.clone());
            match v {
                None => {
                    new_versions.insert(dep.name.clone(), version);
                }
                Some(v) => {
                    if v < version {
                        new_versions.insert(dep.name.clone(), version);
                    }
                }
            }
        }
    }

    // Overwrite the versions used by packages.
    for package in &dependencies_data {
        let version = try!(Version::parse(&package.version)
            .map_err(|_| format!("Could not parse version `{}` for `{}`",
                &package.version, &package.name)));
        new_versions.insert(package.name.clone(), version);
    }

    Ok(String::from(""))
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use crate::shell::Key;

/// Contains the state information for the keyboard.
///
/// This currently tracks which keys are currently pressed.
///
/// The key state is stored in a lazy-loaded HashMap.
///
/// There are several convenience methods to check common modifiers
/// (ctrl, shift, alt, etc).  This is useful if you don't care which
/// shift key is down.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct KeyboardState {
    key_list: HashMap<Key, bool>,
}

impl KeyboardState {
    /// Sets whether or not the given key is currently pressed
    pub fn set_key_state(&mut self, key: Key, pressed: bool) {
        self.key_list.insert(key, pressed);
    }

    /// Returns whether or not the requested key is pressed
    pub fn is_key_down(&self, key: Key) -> bool {
        match self.key_list.get(&key) {
            // If we have the key on this list, return its state
            Some(item) => *item,
            // Otherwise, it hasn't been set as down
            None => false,
        }
    }
    /// Returns whether or not any shift key is down.
    pub fn is_shift_down(&self) -> bool {
        self.is_key_down(Key::ShiftL) || self.is_key_down(Key::ShiftR)
    }

    /// Returns whether or not any alt key is down.
    pub fn is_alt_down(&self) -> bool {
        self.is_key_down(Key::Alt)
    }

    /// Returns whether or not any control key is down.
    pub fn is_ctrl_down(&self) -> bool {
        self.is_key_down(Key::Control)
    }

    /// Returns whether or not any home key is down.
    pub fn is_home_down(&self) -> bool {
        self.is_key_down(Key::Home)
    }
}

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

    #[test]
    /// A quick test to ensure that the items are properly set.
    fn basic_test() {
        let mut state = KeyboardState::default();
        // Do a quick check beforehand
        assert!(!state.is_key_down(Key::ShiftL));
        // Set the state down and immediately check
        state.set_key_state(Key::ShiftL, true);
        assert!(state.is_key_down(Key::ShiftL));
        state.set_key_state(Key::ShiftL, false);
        assert!(!state.is_key_down(Key::ShiftL));
        // Set quit a few in a row
        state.set_key_state(Key::ShiftL, true);
        state.set_key_state(Key::ShiftR, true);
        state.set_key_state(Key::Space, true);
        state.set_key_state(Key::Control, true);
        state.set_key_state(Key::Alt, true);
        // Ensure each of these are still down
        assert!(state.is_key_down(Key::ShiftL));
        assert!(state.is_key_down(Key::ShiftR));
        assert!(state.is_key_down(Key::Space));
        assert!(state.is_key_down(Key::Control));
        assert!(state.is_key_down(Key::Alt));
    }

    #[test]
    /// Test for the convenience methods
    fn test_convenience() {
        let mut state = KeyboardState::default();
        // Check to ensure they are all false
        assert!(!state.is_alt_down());
        assert!(!state.is_ctrl_down());
        assert!(!state.is_shift_down());
        // Set ctrl and alt to true and check
        state.set_key_state(Key::Control, true);
        assert!(state.is_ctrl_down());

        state.set_key_state(Key::Alt, true);
        assert!(state.is_alt_down());

        assert!(!state.is_shift_down());
        // Set shift (via L)
        state.set_key_state(Key::ShiftL, true);
        assert!(state.is_shift_down());
        // Set shift (via R and L both set)
        state.set_key_state(Key::ShiftR, true);
        assert!(state.is_shift_down(), "{}", true);
        // Disable L Shift to ensure correct result with just R held
        state.set_key_state(Key::ShiftL, false);
        assert!(state.is_shift_down());
        // Disable both shift keys
        state.set_key_state(Key::ShiftR, false);
        assert!(!state.is_shift_down());
        // Disable alt and ctrl and check again
        state.set_key_state(Key::Control, false);
        assert!(!state.is_ctrl_down());

        state.set_key_state(Key::Alt, false);
        assert!(!state.is_alt_down());
    }
}
<commit_msg>orbtk_core: documentation update `keyboard_state`<commit_after>use std::collections::HashMap;

use crate::shell::Key;

/// Contains the state information for the keyboard.
///
/// The keyboard state tracks which keys are currently pressed. The
/// active state is stored in a lazy-loaded HashMap.
///
/// Beside common key activities, you may need to react on generic
/// modifier keys (`Alt`, `Ctrl`, `Hyper`, `Shift`). Helper functions
/// offer several convenience methods to handle such keyboard events.
/// A generic method comes in handy, if you don't care which
/// modifier key is down (`Shift-left` or `Shift-right` => `Shift`).
/// The example section will also tackle the case, where a combined
/// event (`Ctrl+S`) keyboard state is handled.
///
/// # Example
/// Handle a key press inside a given view.
///
/// ```
/// use orbtk {
///     widgets::behaviors::MouseBehavior,
///     prelude::*;
///     shell::event::{Key, KeyEvent};
/// };
///
/// // [KeyboardState]
///
/// #[derive(Clone)]
/// enum KeyboardAction {
///     Key(KeyEvent),
///     RequestFocus,
/// }
///
/// #[derive(AsAny, Default)]
/// struct KeyboardState {
///     action: Option<KeyboardAction>,
///     event_adapter: EventAdapter,
/// }
///
/// // Implementation of KeyboardActions for trait `State`
/// impl State for KeyboardState {
///     fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
///         if let Some(action) = self.action.clone() {
///             match action {
///                 KeyboardAction::Key(key_event) => {
///                     match key_event.key {
///                         Key::Control => {
///                             // Ctrl+'a'
///                             if key_event.Key::A(false) {
///                                 self.handle_control_a(ctx);
///                             }
///                         }
///                         Key::Down => {
///                             self.handle_down_key(ctx);
///                         }
///                         Key::Enter => {
///                             self.handle_enter_key(ctx);
///                         }
///                         Key::Left => {
///                             self.handle_left_key(ctx);
///                         }
///                         Key::Right => {
///                             self.handle_right_key(ctx);
///                         }
///                         Key::Up => {
///                             self.handle_up_key(ctx);
///                         }
///                         _ => {}
///                     }
///                 }
///                 KeyboardAction::RequestFocus => {
///                     self.request_focus(ctx);
///                 }
///             }
///             self.action = None;
///         }
///
/// // associated functions
/// impl KeyboardState {
///     fn action(&mut self, action: DirectoryListAction) {
///         self.action = Some(action);
/// }
///
/// fn handle_down_key(&mut self, ctx: &mut Context<'_>) {
///     /// here goes your rust code to act on `Key::Down`
///     println!("Handle: `Key::Down`")
///     }
/// }
///
/// fn handle_enter_key(&mut self, ctx: &mut Context<'_>) {
///     /// here goes your rust code to act on `Key::Enter`
///     println!("Handle: `Key::Enter`")
///     }
/// }
///
/// fn handle_left_key(&mut self, ctx: &mut Context<'_>) {
///     /// here goes your rust code to act on `Key::Left`
///     println!("Handle: `Key::Left`")
///     }
/// }
///
/// fn handle_right_key(&mut self, ctx: &mut Context<'_>) {
///     /// here goes your rust code to act on `Key::Right`
///     println!("Handle: `Key::Right`")
///     }
/// }
///
/// fn handle_up_key(&mut self, ctx: &mut Context<'_>) {
///     /// here goes your rust code to act on `Key::Up`
///     println!("Handle: `Key::Up`")
///     }
/// }
///
/// // [KeyboardView]
/// // ... your view code
///
/// ```
#[derive(Default, Clone, Debug, PartialEq)]
pub struct KeyboardState {
    key_list: HashMap<Key, bool>,
}

impl KeyboardState {
    /// Sets whether or not the given key is currently pressed
    pub fn set_key_state(&mut self, key: Key, pressed: bool) {
        self.key_list.insert(key, pressed);
    }

    /// Returns whether or not the requested key is pressed
    pub fn is_key_down(&self, key: Key) -> bool {
        match self.key_list.get(&key) {
            // If we have the key on this list, return its state
            Some(item) => *item,
            // Otherwise, it hasn't been set as down
            None => false,
        }
    }
    /// Returns whether or not any shift key is down.
    pub fn is_shift_down(&self) -> bool {
        self.is_key_down(Key::ShiftL) || self.is_key_down(Key::ShiftR)
    }

    /// Returns whether or not any alt key is down.
    pub fn is_alt_down(&self) -> bool {
        self.is_key_down(Key::Alt)
    }

    /// Returns whether or not any control key is down.
    pub fn is_ctrl_down(&self) -> bool {
        self.is_key_down(Key::Control)
    }

    /// Returns whether or not any home key is down.
    pub fn is_home_down(&self) -> bool {
        self.is_key_down(Key::Home)
    }
}

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

    #[test]
    /// A quick test to ensure that the items are properly set.
    fn basic_test() {
        let mut state = KeyboardState::default();
        // Do a quick check beforehand
        assert!(!state.is_key_down(Key::ShiftL));
        // Set the state down and immediately check
        state.set_key_state(Key::ShiftL, true);
        assert!(state.is_key_down(Key::ShiftL));
        state.set_key_state(Key::ShiftL, false);
        assert!(!state.is_key_down(Key::ShiftL));
        // Set quit a few in a row
        state.set_key_state(Key::ShiftL, true);
        state.set_key_state(Key::ShiftR, true);
        state.set_key_state(Key::Space, true);
        state.set_key_state(Key::Control, true);
        state.set_key_state(Key::Alt, true);
        // Ensure each of these are still down
        assert!(state.is_key_down(Key::ShiftL));
        assert!(state.is_key_down(Key::ShiftR));
        assert!(state.is_key_down(Key::Space));
        assert!(state.is_key_down(Key::Control));
        assert!(state.is_key_down(Key::Alt));
    }

    #[test]
    /// Test for the convenience methods
    fn test_convenience() {
        let mut state = KeyboardState::default();
        // Check to ensure they are all false
        assert!(!state.is_alt_down());
        assert!(!state.is_ctrl_down());
        assert!(!state.is_shift_down());
        // Set ctrl and alt to true and check
        state.set_key_state(Key::Control, true);
        assert!(state.is_ctrl_down());

        state.set_key_state(Key::Alt, true);
        assert!(state.is_alt_down());

        assert!(!state.is_shift_down());
        // Set shift (via L)
        state.set_key_state(Key::ShiftL, true);
        assert!(state.is_shift_down());
        // Set shift (via R and L both set)
        state.set_key_state(Key::ShiftR, true);
        assert!(state.is_shift_down(), "{}", true);
        // Disable L Shift to ensure correct result with just R held
        state.set_key_state(Key::ShiftL, false);
        assert!(state.is_shift_down());
        // Disable both shift keys
        state.set_key_state(Key::ShiftR, false);
        assert!(!state.is_shift_down());
        // Disable alt and ctrl and check again
        state.set_key_state(Key::Control, false);
        assert!(!state.is_ctrl_down());

        state.set_key_state(Key::Alt, false);
        assert!(!state.is_alt_down());
    }
}
<|endoftext|>