<commit_before>// Copyright 2016 Martin Grabmueller. See the LICENSE file at the
// top-level directory of this distribution for license information.
//

extern crate peerington;
extern crate env_logger;
extern crate uuid;
extern crate term;

use peerington::config::get_config;
use peerington::config::print_usage;
use peerington::error::ConfigError;
use peerington::config::Config;
use peerington::node::NodeState;
use peerington::node::PeerState;
use peerington::node::Availability;
use peerington::node::Leadership;
use peerington::node::ElectionState;
use peerington::node::start_networking;
use peerington::node::get_election_state;
use peerington::node::current_leader;
use peerington::message::Message;
use peerington::message::Version;

use std::collections::HashSet;
use std::sync::Arc;
use std::env;
use std::io;
use std::io::Write;
use std::fmt;
use std::fs::{DirBuilder,remove_dir};
use std::path::Path;

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

    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    match get_config(args) {
        Err(ConfigError::HelpRequested(opts)) => {
            print_usage(&program, opts);
        }

        Err(e) => {
            println!("Error: {}", e);
        }

        Ok(config) =>
            run(config)
    }
}

fn handler(msg: Message) {
    match msg {
        _ => {
            println!("error: unknown message: {:?}", msg)
        }
    }
}

fn run(config: Config) {
    let conf = Arc::new(config);
    match NodeState::new(conf.clone()) {
        Ok(node_state) => {
            let lock_dir_path = Path::new(&conf.workspace_dir).join("lock");
            match DirBuilder::new().create(&lock_dir_path) {
                Ok(()) => {
                    let ns = Arc::new(node_state);
                    start_networking(ns.clone(), handler);
                    repl(conf, ns);
                    match remove_dir(&lock_dir_path) {
                        Ok(()) => {},
                        Err(e) => {
                            println!("could not remove lock directory `{:?}': {}", lock_dir_path, e);
                        }
                    }
                },
                Err(e) => {
                    println!("Could not create lock directory: {}", e);
                    println!("Maybe an instance is already running?");
                    println!("If not, remove `{:?}' and try again.", lock_dir_path);
                }
            }
        },
        Err(e) =>
            println!("cannot create node state: {}", e)
    }
}

/// Peerington tool command.
enum Command {
    /// Quit the read-eval-print loop.
    Quit,
    /// Give some help on the REPL.
    Help,
    /// Print node state
    State,
    /// Show configuration.
    Config,
    /// Show information on all known peers.
    Peers,
}

impl fmt::Display for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Command::Quit =>
                write!(f, "quit"),
            Command::Help =>
                write!(f, "help"),
            Command::State =>
                write!(f, "state"),
            Command::Config =>
                write!(f, "config"),
            Command::Peers =>
                write!(f, "peers"),
        }
    }
}

impl Command {
    fn parse(input: &str) -> Result<Command, CommandParseError> {
        let tokens: Vec<_> = input.split(' ').collect();
        if tokens.len() > 0 {
            match tokens[0] {
                "q" | "quit" =>
                    Ok(Command::Quit),
                "h" | "help" =>
                    Ok(Command::Help),
                "s" | "state" =>
                    Ok(Command::State),
                "c" | "config" =>
                    Ok(Command::Config),
                "p" | "peers" =>
                    Ok(Command::Peers),
                _ =>  {
                    Err(CommandParseError::UnknownCommand(tokens[0]))
                },
            }
        } else {
            Err(CommandParseError::Syntax("no command"))
        }
    }
}

/// Error produced when parsing a command fails.
enum CommandParseError<'a>  {
    UnknownCommand(&'a str),
    Syntax(&'a str),
}

impl <'a> fmt::Display for CommandParseError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandParseError::UnknownCommand(s) =>
                write!(f, "unknown command: {}", s),
            CommandParseError::Syntax(s) =>
                write!(f, "invalid syntax: {}", s),
        }
    }
}

/// Read-eval-print loop of the peerington command.
fn repl(config: Arc<Config>, node_state: Arc<NodeState>) {
    let prompt = config.uuid.hyphenated().to_string();
    let mut input = String::new();

    loop {
        input.clear();
        if let Err(e) = io::stdout().write(&prompt.as_bytes()[..8]) {
            println!("cannot write prompt: {}", e);
            return;
        }
        if let Err(e) = io::stdout().write(b"> ") {
            println!("cannot write prompt: {}", e);
            return;
        }
        if let Err(e) = io::stdout().flush() {
            println!("cannot write prompt: {}", e);
            return;
        }
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                match input.trim() {
                    "" =>
                        continue,
                    trimmed =>
                        match Command::parse(trimmed) {
                            Err(e) =>
                                println!("Error: {}", e),
                            Ok(Command::Quit) => {
                                println!("[exiting]");
                                return;
                            }
                            Ok(cmd) =>
                                execute(cmd, node_state.clone())
                        }
                }
            }
            Err(error) =>
                println!("cannot read stdin: {}", error),
        }
    }
}

/// Execute a peerington command.
fn execute(cmd: Command, node_state: Arc<NodeState>) {
    match cmd {
        Command::Help => {
            println!("  help              display this help message");
            println!("  quit              terminate this node");
            println!("  send UUID MSG     send the text MSG to node UUID");
            println!("  peers             display the node ring");
            println!("  config            display the node configuration");
            println!("  state             display the state of this node");
            println!("  network on|off    enable/disable networking on this node");
        },
        Command::Config => {
            let config = &node_state.config;
            println!("uuid: {}", config.uuid.hyphenated());
            println!("listening on:");
            for ref a in &config.listen_addresses {
                println!("  {}", a);
            }
            println!("configured seeds:");
            for ref a in &config.seed_addresses {
                println!("  {}", a);
            }
            println!("workspace: {}", config.workspace_dir);
            },
        Command::Peers => {
            match node_state.peers.lock() {
                Ok(peers) => {
                    println!(" # SLio uuid                                     ce rver  sver state           listen");
                    let mut self_addrs = HashSet::new();
                    for a in &node_state.config.listen_addresses {
                        self_addrs.insert(a.clone());
                    }
                    let self_peer_state =
                        { PeerState{uuid: node_state.config.uuid,
                                    proto_version_send: None,
                                    proto_version_recv: None,
                                    send_conn_count: 0,
                                    recv_conn_count: 0,
                                    connect_errors: 0,
                                    send_channel: None,
                                    availability: Some(Availability::Up),
                                    availability_info: Some(Availability::Up),
                                    addresses: self_addrs,
                                    }
                        };
                    let mut ps = Vec::new();
                    for (name, peer_state) in &*peers {
                        ps.push((name, peer_state));
                    }

                    ps.push((&node_state.config.uuid,
                             &self_peer_state));
                    ps.sort_by(|&(a, _), &(b, _)| a.cmp(&b));

                    let mut t = term::stdout().unwrap();

                    for (idx, &(name, peer_state)) in ps.iter().enumerate() {
                        let is_self = *name == self_peer_state.uuid;
                        let is_leader = Some(*name) == current_leader(node_state.clone());

                        match peer_state.availability {
                            None => {
                                t.fg(term::color::BRIGHT_BLACK).unwrap();
                                if is_leader {
                                    t.attr(term::Attr::Standout(true)).unwrap();
                                }
                            },
                            Some(Availability::Up) => {
                                t.fg(term::color::GREEN).unwrap();
                                if is_self {
                                    t.attr(term::Attr::Underline(true)).unwrap();
                                }
                                if is_leader {
                                    t.attr(term::Attr::Standout(true)).unwrap();
                                }
                            },
                            Some(Availability::Down) =>
                                t.fg(term::color::RED).unwrap()
                        };
                        println!("{:2} {}{}{}{} {} {:5} {:5} {:5} {:7} {:7} {:?}",
                                 idx,
                                 if is_self { "*" } else { " " },
                                 if is_leader { "L" } else { " " },
                                 if peer_state.recv_conn_count > 0 { "i" } else {" "},
                                 if peer_state.send_conn_count > 0 { "o" } else {" "},
                                 name,
                                 peer_state.connect_errors,
                                 peer_state.proto_version_recv.unwrap_or(Version(0)).number(),
                                 peer_state.proto_version_send.unwrap_or(Version(0)).number(),
                                 match peer_state.availability {
                                     None => "unknown",
                                     Some(Availability::Up) => "up",
                                     Some(Availability::Down) => "down",
                                 },
                                 match peer_state.availability_info {
                                     None => "unknown",
                                     Some(Availability::Up) => "up",
                                     Some(Availability::Down) => "down",
                                 },
                                 peer_state.addresses
                        );
                        t.reset().unwrap();
                    }
                    ()
                }
                Err(_) => {
                    println!("cannot lock node map");
                }
            }
        },
        Command::State => {
            let (leadership, election_state) = get_election_state(node_state.clone());
            println!("uuid:       {}", node_state.config.uuid);
            println!("leader:     {} {}",
                     match leadership {
                         Leadership::SelfLeader => format!("{}", node_state.config.uuid),
                         Leadership::LeaderKnown(u) => format!("{}", u),
                         Leadership::LeaderUnknown => "unknown".to_string(),
                     },
                     match election_state {
                         ElectionState::Participant => "(election in progress)",
                         ElectionState::NonParticipant => "",
                     });
        },
        Command::Quit => {
            // Should be handled in caller.
            unreachable!();
        }
    };
}
<commit_msg>Make 'p' command output nicer.<commit_after>// Copyright 2016 Martin Grabmueller. See the LICENSE file at the
// top-level directory of this distribution for license information.
//

extern crate peerington;
extern crate env_logger;
extern crate uuid;
extern crate term;

use peerington::config::get_config;
use peerington::config::print_usage;
use peerington::error::ConfigError;
use peerington::config::Config;
use peerington::node::NodeState;
use peerington::node::PeerState;
use peerington::node::Availability;
use peerington::node::Leadership;
use peerington::node::ElectionState;
use peerington::node::start_networking;
use peerington::node::get_election_state;
use peerington::node::current_leader;
use peerington::message::Message;
use peerington::message::Version;

use std::collections::HashSet;
use std::sync::Arc;
use std::env;
use std::io;
use std::io::Write;
use std::fmt;
use std::fs::{DirBuilder,remove_dir};
use std::path::Path;

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

    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    match get_config(args) {
        Err(ConfigError::HelpRequested(opts)) => {
            print_usage(&program, opts);
        }

        Err(e) => {
            println!("Error: {}", e);
        }

        Ok(config) =>
            run(config)
    }
}

fn handler(msg: Message) {
    match msg {
        _ => {
            println!("error: unknown message: {:?}", msg)
        }
    }
}

fn run(config: Config) {
    let conf = Arc::new(config);
    match NodeState::new(conf.clone()) {
        Ok(node_state) => {
            let lock_dir_path = Path::new(&conf.workspace_dir).join("lock");
            match DirBuilder::new().create(&lock_dir_path) {
                Ok(()) => {
                    let ns = Arc::new(node_state);
                    start_networking(ns.clone(), handler);
                    repl(conf, ns);
                    match remove_dir(&lock_dir_path) {
                        Ok(()) => {},
                        Err(e) => {
                            println!("could not remove lock directory `{:?}': {}", lock_dir_path, e);
                        }
                    }
                },
                Err(e) => {
                    println!("Could not create lock directory: {}", e);
                    println!("Maybe an instance is already running?");
                    println!("If not, remove `{:?}' and try again.", lock_dir_path);
                }
            }
        },
        Err(e) =>
            println!("cannot create node state: {}", e)
    }
}

/// Peerington tool command.
enum Command {
    /// Quit the read-eval-print loop.
    Quit,
    /// Give some help on the REPL.
    Help,
    /// Print node state
    State,
    /// Show configuration.
    Config,
    /// Show information on all known peers.
    Peers,
}

impl fmt::Display for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Command::Quit =>
                write!(f, "quit"),
            Command::Help =>
                write!(f, "help"),
            Command::State =>
                write!(f, "state"),
            Command::Config =>
                write!(f, "config"),
            Command::Peers =>
                write!(f, "peers"),
        }
    }
}

impl Command {
    fn parse(input: &str) -> Result<Command, CommandParseError> {
        let tokens: Vec<_> = input.split(' ').collect();
        if tokens.len() > 0 {
            match tokens[0] {
                "q" | "quit" =>
                    Ok(Command::Quit),
                "h" | "help" =>
                    Ok(Command::Help),
                "s" | "state" =>
                    Ok(Command::State),
                "c" | "config" =>
                    Ok(Command::Config),
                "p" | "peers" =>
                    Ok(Command::Peers),
                _ =>  {
                    Err(CommandParseError::UnknownCommand(tokens[0]))
                },
            }
        } else {
            Err(CommandParseError::Syntax("no command"))
        }
    }
}

/// Error produced when parsing a command fails.
enum CommandParseError<'a>  {
    UnknownCommand(&'a str),
    Syntax(&'a str),
}

impl <'a> fmt::Display for CommandParseError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandParseError::UnknownCommand(s) =>
                write!(f, "unknown command: {}", s),
            CommandParseError::Syntax(s) =>
                write!(f, "invalid syntax: {}", s),
        }
    }
}

/// Read-eval-print loop of the peerington command.
fn repl(config: Arc<Config>, node_state: Arc<NodeState>) {
    let prompt = config.uuid.hyphenated().to_string();
    let mut input = String::new();

    loop {
        input.clear();
        if let Err(e) = io::stdout().write(&prompt.as_bytes()[..8]) {
            println!("cannot write prompt: {}", e);
            return;
        }
        if let Err(e) = io::stdout().write(b"> ") {
            println!("cannot write prompt: {}", e);
            return;
        }
        if let Err(e) = io::stdout().flush() {
            println!("cannot write prompt: {}", e);
            return;
        }
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                match input.trim() {
                    "" =>
                        continue,
                    trimmed =>
                        match Command::parse(trimmed) {
                            Err(e) =>
                                println!("Error: {}", e),
                            Ok(Command::Quit) => {
                                println!("[exiting]");
                                return;
                            }
                            Ok(cmd) =>
                                execute(cmd, node_state.clone())
                        }
                }
            }
            Err(error) =>
                println!("cannot read stdin: {}", error),
        }
    }
}

/// Execute a peerington command.
fn execute(cmd: Command, node_state: Arc<NodeState>) {
    match cmd {
        Command::Help => {
            println!("  help              display this help message");
            println!("  quit              terminate this node");
            println!("  send UUID MSG     send the text MSG to node UUID");
            println!("  peers             display the node ring");
            println!("  config            display the node configuration");
            println!("  state             display the state of this node");
            println!("  network on|off    enable/disable networking on this node");
        },
        Command::Config => {
            let config = &node_state.config;
            println!("uuid: {}", config.uuid.hyphenated());
            println!("listening on:");
            for ref a in &config.listen_addresses {
                println!("  {}", a);
            }
            println!("configured seeds:");
            for ref a in &config.seed_addresses {
                println!("  {}", a);
            }
            println!("workspace: {}", config.workspace_dir);
            },
        Command::Peers => {
            match node_state.peers.lock() {
                Ok(peers) => {
                    println!(" # SLio uuid                                 ce rver sver state listen");
                    let mut self_addrs = HashSet::new();
                    for a in &node_state.config.listen_addresses {
                        self_addrs.insert(a.clone());
                    }
                    let self_peer_state =
                        { PeerState{uuid: node_state.config.uuid,
                                    proto_version_send: None,
                                    proto_version_recv: None,
                                    send_conn_count: 0,
                                    recv_conn_count: 0,
                                    connect_errors: 0,
                                    send_channel: None,
                                    availability: Some(Availability::Up),
                                    availability_info: Some(Availability::Up),
                                    addresses: self_addrs,
                                    }
                        };
                    let mut ps = Vec::new();
                    for (name, peer_state) in &*peers {
                        ps.push((name, peer_state));
                    }

                    ps.push((&node_state.config.uuid,
                             &self_peer_state));
                    ps.sort_by(|&(a, _), &(b, _)| a.cmp(&b));

                    let mut t = term::stdout().unwrap();

                    for (idx, &(name, peer_state)) in ps.iter().enumerate() {
                        let is_self = *name == self_peer_state.uuid;
                        let is_leader = Some(*name) == current_leader(node_state.clone());

                        match peer_state.availability_info {
                            None => {
                                t.fg(term::color::BRIGHT_BLACK).unwrap();
                                if is_leader {
                                    t.attr(term::Attr::Standout(true)).unwrap();
                                }
                            },
                            Some(Availability::Up) => {
                                t.fg(term::color::GREEN).unwrap();
                                if is_self {
                                    t.attr(term::Attr::Underline(true)).unwrap();
                                }
                                if is_leader {
                                    t.attr(term::Attr::Standout(true)).unwrap();
                                }
                            },
                            Some(Availability::Down) =>
                                t.fg(term::color::RED).unwrap()
                        };
                        println!("{:2} {}{}{}{} {} {:2} {:4} {:4} {:1} {:3} {:?}",
                                 idx,
                                 if is_self { "*" } else { " " },
                                 if is_leader { "L" } else { " " },
                                 if peer_state.recv_conn_count > 0 { "i" } else {" "},
                                 if peer_state.send_conn_count > 0 { "o" } else {" "},
                                 name,
                                 peer_state.connect_errors,
                                 peer_state.proto_version_recv.unwrap_or(Version(0)).number(),
                                 peer_state.proto_version_send.unwrap_or(Version(0)).number(),
                                 match peer_state.availability {
                                     None => "?",
                                     Some(Availability::Up) => "\u{2714}",
                                     Some(Availability::Down) => "\u{2718}",
                                 },
                                 match peer_state.availability_info {
                                     None => "?",
                                     Some(Availability::Up) => "\u{2714}",
                                     Some(Availability::Down) => "\u{2718}",
                                 },
                                 peer_state.addresses
                        );
                        t.reset().unwrap();
                    }
                    ()
                }
                Err(_) => {
                    println!("cannot lock node map");
                }
            }
        },
        Command::State => {
            let (leadership, election_state) = get_election_state(node_state.clone());
            println!("uuid:       {}", node_state.config.uuid);
            println!("leader:     {} {}",
                     match leadership {
                         Leadership::SelfLeader => format!("{}", node_state.config.uuid),
                         Leadership::LeaderKnown(u) => format!("{}", u),
                         Leadership::LeaderUnknown => "unknown".to_string(),
                     },
                     match election_state {
                         ElectionState::Participant => "(election in progress)",
                         ElectionState::NonParticipant => "",
                     });
        },
        Command::Quit => {
            // Should be handled in caller.
            unreachable!();
        }
    };
}
<|endoftext|>


<commit_before>//! VFS stands for Virtual File System.
//!
//! When doing analysis, we don't want to do any IO, we want to keep all source
//! code in memory. However, the actual source code is stored on disk, so you
//! need to get it into the memory in the first place somehow. VFS is the
//! component which does this.
//!
//! It is also responsible for watching the disk for changes, and for merging
//! editor state (modified, unsaved files) with disk state.
//!
//! TODO: Some LSP clients support watching the disk, so this crate should to
//! support custom watcher events (related to
//! <https://github.com/rust-analyzer/rust-analyzer/issues/131>)
//!
//! VFS is based on a concept of roots: a set of directories on the file system
//! which are watched for changes. Typically, there will be a root for each
//! Cargo package.
mod roots;
mod io;

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

use crossbeam_channel::Receiver;
use ra_arena::{impl_arena_id, Arena, RawId, map::ArenaMap};
use relative_path::{RelativePath, RelativePathBuf};
use rustc_hash::{FxHashMap, FxHashSet};

use crate::{
    io::{TaskResult, Worker},
    roots::Roots,
};

pub use crate::{
    io::TaskResult as VfsTask,
    roots::VfsRoot,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VfsFile(pub RawId);
impl_arena_id!(VfsFile);

struct VfsFileData {
    root: VfsRoot,
    path: RelativePathBuf,
    is_overlayed: bool,
    text: Arc<String>,
}

pub struct Vfs {
    roots: Arc<Roots>,
    files: Arena<VfsFile, VfsFileData>,
    root2files: ArenaMap<VfsRoot, FxHashSet<VfsFile>>,
    pending_changes: Vec<VfsChange>,
    worker: Worker,
}

impl fmt::Debug for Vfs {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Vfs")
            .field("n_roots", &self.roots.len())
            .field("n_files", &self.files.len())
            .field("n_pending_changes", &self.pending_changes.len())
            .finish()
    }
}

impl Vfs {
    pub fn new(roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
        let roots = Arc::new(Roots::new(roots));
        let worker = io::start(Arc::clone(&roots));
        let mut root2files = ArenaMap::default();

        for root in roots.iter() {
            root2files.insert(root, Default::default());
            worker.sender().send(io::Task::AddRoot { root }).unwrap();
        }
        let res =
            Vfs { roots, files: Arena::default(), root2files, worker, pending_changes: Vec::new() };
        let vfs_roots = res.roots.iter().collect();
        (res, vfs_roots)
    }

    pub fn root2path(&self, root: VfsRoot) -> PathBuf {
        self.roots.path(root).to_path_buf()
    }

    pub fn path2file(&self, path: &Path) -> Option<VfsFile> {
        if let Some((_root, _path, Some(file))) = self.find_root(path) {
            return Some(file);
        }
        None
    }

    pub fn file2path(&self, file: VfsFile) -> PathBuf {
        let rel_path = &self.files[file].path;
        let root_path = &self.roots.path(self.files[file].root);
        rel_path.to_path(root_path)
    }

    pub fn num_roots(&self) -> usize {
        self.roots.len()
    }

    pub fn load(&mut self, path: &Path) -> Option<VfsFile> {
        if let Some((root, rel_path, file)) = self.find_root(path) {
            return if let Some(file) = file {
                Some(file)
            } else {
                let text = fs::read_to_string(path).unwrap_or_default();
                let text = Arc::new(text);
                let file = self.add_file(root, rel_path.clone(), Arc::clone(&text), false);
                let change = VfsChange::AddFile { file, text, root, path: rel_path };
                self.pending_changes.push(change);
                Some(file)
            };
        }
        None
    }

    pub fn task_receiver(&self) -> &Receiver<io::TaskResult> {
        self.worker.receiver()
    }

    pub fn handle_task(&mut self, task: io::TaskResult) {
        match task {
            TaskResult::BulkLoadRoot { root, files } => {
                let mut cur_files = Vec::new();
                // While we were scanning the root in the background, a file might have
                // been open in the editor, so we need to account for that.
                let existing = self.root2files[root]
                    .iter()
                    .map(|&file| (self.files[file].path.clone(), file))
                    .collect::<FxHashMap<_, _>>();
                for (path, text) in files {
                    if let Some(&file) = existing.get(&path) {
                        let text = Arc::clone(&self.files[file].text);
                        cur_files.push((file, path, text));
                        continue;
                    }
                    let text = Arc::new(text);
                    let file = self.add_file(root, path.clone(), Arc::clone(&text), false);
                    cur_files.push((file, path, text));
                }

                let change = VfsChange::AddRoot { root, files: cur_files };
                self.pending_changes.push(change);
            }
            TaskResult::SingleFile { root, path, text } => {
                match (self.find_file(root, &path), text) {
                    (Some(file), None) => {
                        self.do_remove_file(root, path, file, false);
                    }
                    (None, Some(text)) => {
                        self.do_add_file(root, path, text, false);
                    }
                    (Some(file), Some(text)) => {
                        self.do_change_file(file, text, false);
                    }
                    (None, None) => (),
                }
            }
        }
    }

    fn do_add_file(
        &mut self,
        root: VfsRoot,
        path: RelativePathBuf,
        text: String,
        is_overlay: bool,
    ) -> Option<VfsFile> {
        let text = Arc::new(text);
        let file = self.add_file(root, path.clone(), text.clone(), is_overlay);
        self.pending_changes.push(VfsChange::AddFile { file, root, path, text });
        Some(file)
    }

    fn do_change_file(&mut self, file: VfsFile, text: String, is_overlay: bool) {
        if !is_overlay && self.files[file].is_overlayed {
            return;
        }
        let text = Arc::new(text);
        self.change_file(file, text.clone(), is_overlay);
        self.pending_changes.push(VfsChange::ChangeFile { file, text });
    }

    fn do_remove_file(
        &mut self,
        root: VfsRoot,
        path: RelativePathBuf,
        file: VfsFile,
        is_overlay: bool,
    ) {
        if !is_overlay && self.files[file].is_overlayed {
            return;
        }
        self.remove_file(file);
        self.pending_changes.push(VfsChange::RemoveFile { root, path, file });
    }

    pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> {
        if let Some((root, rel_path, file)) = self.find_root(path) {
            if let Some(file) = file {
                self.do_change_file(file, text, true);
                Some(file)
            } else {
                self.do_add_file(root, rel_path, text, true)
            }
        } else {
            None
        }
    }

    pub fn change_file_overlay(&mut self, path: &Path, new_text: String) {
        if let Some((_root, _path, file)) = self.find_root(path) {
            let file = file.expect("can't change a file which wasn't added");
            self.do_change_file(file, new_text, true);
        }
    }

    pub fn remove_file_overlay(&mut self, path: &Path) -> Option<VfsFile> {
        if let Some((root, path, file)) = self.find_root(path) {
            let file = file.expect("can't remove a file which wasn't added");
            let full_path = path.to_path(&self.roots.path(root));
            if let Ok(text) = fs::read_to_string(&full_path) {
                self.do_change_file(file, text, true);
            } else {
                self.do_remove_file(root, path, file, true);
            }
            Some(file)
        } else {
            None
        }
    }

    pub fn commit_changes(&mut self) -> Vec<VfsChange> {
        mem::replace(&mut self.pending_changes, Vec::new())
    }

    fn add_file(
        &mut self,
        root: VfsRoot,
        path: RelativePathBuf,
        text: Arc<String>,
        is_overlayed: bool,
    ) -> VfsFile {
        let data = VfsFileData { root, path, text, is_overlayed };
        let file = self.files.alloc(data);
        self.root2files.get_mut(root).unwrap().insert(file);
        file
    }

    fn change_file(&mut self, file: VfsFile, new_text: Arc<String>, is_overlayed: bool) {
        let mut file_data = &mut self.files[file];
        file_data.text = new_text;
        file_data.is_overlayed = is_overlayed;
    }

    fn remove_file(&mut self, file: VfsFile) {
        // FIXME: use arena with removal
        self.files[file].text = Default::default();
        self.files[file].path = Default::default();
        let root = self.files[file].root;
        let removed = self.root2files.get_mut(root).unwrap().remove(&file);
        assert!(removed);
    }

    fn find_root(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf, Option<VfsFile>)> {
        let (root, path) = self.roots.find(&path)?;
        let file = self.find_file(root, &path);
        Some((root, path, file))
    }

    fn find_file(&self, root: VfsRoot, path: &RelativePath) -> Option<VfsFile> {
        self.root2files[root].iter().map(|&it| it).find(|&file| self.files[file].path == path)
    }
}

#[derive(Debug, Clone)]
pub enum VfsChange {
    AddRoot { root: VfsRoot, files: Vec<(VfsFile, RelativePathBuf, Arc<String>)> },
    AddFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf, text: Arc<String> },
    RemoveFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf },
    ChangeFile { file: VfsFile, text: Arc<String> },
}
<commit_msg>rename method<commit_after>//! VFS stands for Virtual File System.
//!
//! When doing analysis, we don't want to do any IO, we want to keep all source
//! code in memory. However, the actual source code is stored on disk, so you
//! need to get it into the memory in the first place somehow. VFS is the
//! component which does this.
//!
//! It is also responsible for watching the disk for changes, and for merging
//! editor state (modified, unsaved files) with disk state.
//!
//! TODO: Some LSP clients support watching the disk, so this crate should to
//! support custom watcher events (related to
//! <https://github.com/rust-analyzer/rust-analyzer/issues/131>)
//!
//! VFS is based on a concept of roots: a set of directories on the file system
//! which are watched for changes. Typically, there will be a root for each
//! Cargo package.
mod roots;
mod io;

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

use crossbeam_channel::Receiver;
use ra_arena::{impl_arena_id, Arena, RawId, map::ArenaMap};
use relative_path::{RelativePath, RelativePathBuf};
use rustc_hash::{FxHashMap, FxHashSet};

use crate::{
    io::{TaskResult, Worker},
    roots::Roots,
};

pub use crate::{
    io::TaskResult as VfsTask,
    roots::VfsRoot,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VfsFile(pub RawId);
impl_arena_id!(VfsFile);

struct VfsFileData {
    root: VfsRoot,
    path: RelativePathBuf,
    is_overlayed: bool,
    text: Arc<String>,
}

pub struct Vfs {
    roots: Arc<Roots>,
    files: Arena<VfsFile, VfsFileData>,
    root2files: ArenaMap<VfsRoot, FxHashSet<VfsFile>>,
    pending_changes: Vec<VfsChange>,
    worker: Worker,
}

impl fmt::Debug for Vfs {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Vfs")
            .field("n_roots", &self.roots.len())
            .field("n_files", &self.files.len())
            .field("n_pending_changes", &self.pending_changes.len())
            .finish()
    }
}

impl Vfs {
    pub fn new(roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
        let roots = Arc::new(Roots::new(roots));
        let worker = io::start(Arc::clone(&roots));
        let mut root2files = ArenaMap::default();

        for root in roots.iter() {
            root2files.insert(root, Default::default());
            worker.sender().send(io::Task::AddRoot { root }).unwrap();
        }
        let res =
            Vfs { roots, files: Arena::default(), root2files, worker, pending_changes: Vec::new() };
        let vfs_roots = res.roots.iter().collect();
        (res, vfs_roots)
    }

    pub fn root2path(&self, root: VfsRoot) -> PathBuf {
        self.roots.path(root).to_path_buf()
    }

    pub fn path2file(&self, path: &Path) -> Option<VfsFile> {
        if let Some((_root, _path, Some(file))) = self.find_root(path) {
            return Some(file);
        }
        None
    }

    pub fn file2path(&self, file: VfsFile) -> PathBuf {
        let rel_path = &self.files[file].path;
        let root_path = &self.roots.path(self.files[file].root);
        rel_path.to_path(root_path)
    }

    pub fn n_roots(&self) -> usize {
        self.roots.len()
    }

    pub fn load(&mut self, path: &Path) -> Option<VfsFile> {
        if let Some((root, rel_path, file)) = self.find_root(path) {
            return if let Some(file) = file {
                Some(file)
            } else {
                let text = fs::read_to_string(path).unwrap_or_default();
                let text = Arc::new(text);
                let file = self.add_file(root, rel_path.clone(), Arc::clone(&text), false);
                let change = VfsChange::AddFile { file, text, root, path: rel_path };
                self.pending_changes.push(change);
                Some(file)
            };
        }
        None
    }

    pub fn task_receiver(&self) -> &Receiver<io::TaskResult> {
        self.worker.receiver()
    }

    pub fn handle_task(&mut self, task: io::TaskResult) {
        match task {
            TaskResult::BulkLoadRoot { root, files } => {
                let mut cur_files = Vec::new();
                // While we were scanning the root in the background, a file might have
                // been open in the editor, so we need to account for that.
                let existing = self.root2files[root]
                    .iter()
                    .map(|&file| (self.files[file].path.clone(), file))
                    .collect::<FxHashMap<_, _>>();
                for (path, text) in files {
                    if let Some(&file) = existing.get(&path) {
                        let text = Arc::clone(&self.files[file].text);
                        cur_files.push((file, path, text));
                        continue;
                    }
                    let text = Arc::new(text);
                    let file = self.add_file(root, path.clone(), Arc::clone(&text), false);
                    cur_files.push((file, path, text));
                }

                let change = VfsChange::AddRoot { root, files: cur_files };
                self.pending_changes.push(change);
            }
            TaskResult::SingleFile { root, path, text } => {
                match (self.find_file(root, &path), text) {
                    (Some(file), None) => {
                        self.do_remove_file(root, path, file, false);
                    }
                    (None, Some(text)) => {
                        self.do_add_file(root, path, text, false);
                    }
                    (Some(file), Some(text)) => {
                        self.do_change_file(file, text, false);
                    }
                    (None, None) => (),
                }
            }
        }
    }

    fn do_add_file(
        &mut self,
        root: VfsRoot,
        path: RelativePathBuf,
        text: String,
        is_overlay: bool,
    ) -> Option<VfsFile> {
        let text = Arc::new(text);
        let file = self.add_file(root, path.clone(), text.clone(), is_overlay);
        self.pending_changes.push(VfsChange::AddFile { file, root, path, text });
        Some(file)
    }

    fn do_change_file(&mut self, file: VfsFile, text: String, is_overlay: bool) {
        if !is_overlay && self.files[file].is_overlayed {
            return;
        }
        let text = Arc::new(text);
        self.change_file(file, text.clone(), is_overlay);
        self.pending_changes.push(VfsChange::ChangeFile { file, text });
    }

    fn do_remove_file(
        &mut self,
        root: VfsRoot,
        path: RelativePathBuf,
        file: VfsFile,
        is_overlay: bool,
    ) {
        if !is_overlay && self.files[file].is_overlayed {
            return;
        }
        self.remove_file(file);
        self.pending_changes.push(VfsChange::RemoveFile { root, path, file });
    }

    pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> {
        if let Some((root, rel_path, file)) = self.find_root(path) {
            if let Some(file) = file {
                self.do_change_file(file, text, true);
                Some(file)
            } else {
                self.do_add_file(root, rel_path, text, true)
            }
        } else {
            None
        }
    }

    pub fn change_file_overlay(&mut self, path: &Path, new_text: String) {
        if let Some((_root, _path, file)) = self.find_root(path) {
            let file = file.expect("can't change a file which wasn't added");
            self.do_change_file(file, new_text, true);
        }
    }

    pub fn remove_file_overlay(&mut self, path: &Path) -> Option<VfsFile> {
        if let Some((root, path, file)) = self.find_root(path) {
            let file = file.expect("can't remove a file which wasn't added");
            let full_path = path.to_path(&self.roots.path(root));
            if let Ok(text) = fs::read_to_string(&full_path) {
                self.do_change_file(file, text, true);
            } else {
                self.do_remove_file(root, path, file, true);
            }
            Some(file)
        } else {
            None
        }
    }

    pub fn commit_changes(&mut self) -> Vec<VfsChange> {
        mem::replace(&mut self.pending_changes, Vec::new())
    }

    fn add_file(
        &mut self,
        root: VfsRoot,
        path: RelativePathBuf,
        text: Arc<String>,
        is_overlayed: bool,
    ) -> VfsFile {
        let data = VfsFileData { root, path, text, is_overlayed };
        let file = self.files.alloc(data);
        self.root2files.get_mut(root).unwrap().insert(file);
        file
    }

    fn change_file(&mut self, file: VfsFile, new_text: Arc<String>, is_overlayed: bool) {
        let mut file_data = &mut self.files[file];
        file_data.text = new_text;
        file_data.is_overlayed = is_overlayed;
    }

    fn remove_file(&mut self, file: VfsFile) {
        // FIXME: use arena with removal
        self.files[file].text = Default::default();
        self.files[file].path = Default::default();
        let root = self.files[file].root;
        let removed = self.root2files.get_mut(root).unwrap().remove(&file);
        assert!(removed);
    }

    fn find_root(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf, Option<VfsFile>)> {
        let (root, path) = self.roots.find(&path)?;
        let file = self.find_file(root, &path);
        Some((root, path, file))
    }

    fn find_file(&self, root: VfsRoot, path: &RelativePath) -> Option<VfsFile> {
        self.root2files[root].iter().map(|&it| it).find(|&file| self.files[file].path == path)
    }
}

#[derive(Debug, Clone)]
pub enum VfsChange {
    AddRoot { root: VfsRoot, files: Vec<(VfsFile, RelativePathBuf, Arc<String>)> },
    AddFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf, text: Arc<String> },
    RemoveFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf },
    ChangeFile { file: VfsFile, text: Arc<String> },
}
<|endoftext|>


<commit_before>pub use regex::Regex;
use regex::Error;

#[cfg(test)] pub mod test;

/// The struct used for building verbal expression objects
pub struct VerEx {
    string: String
}

impl VerEx {
    // constructors
    /// Standard Constructor
    pub fn new() -> VerEx {
        VerEx {
            string: String::new(),
        }
    }

    /// Create a `VerEx` object from a `String`
    pub fn from_string(string: String) -> VerEx {
        VerEx {
            string: string,
        }
    }

    /// Create a `VerEx` object from a `&str`
    pub fn from_str(string: &str) -> VerEx {
        VerEx::from_string(string.to_string())
    }

    // --------------------------------------------------
    // fundamental methods
    /// Add a string to the regex string in the `VerEx` and return self
    pub fn add(&mut self, value: &str) -> &mut VerEx{
        self.string.push_str(value);
        self
    }

    /// Compile the `VerEx` to a `Regex` and return the result
    pub fn compile(&mut self) -> Result<Regex, Error> {
        Regex::new(self.string.as_ref())
    }

    /// Return the raw regex string contained in the `VerEx`
    pub fn raw(& self) -> &str {
        self.source()
    }

    /// Compile the `VerEx` to a `Regex` and return the result
    pub fn regex(&mut self) -> Result<Regex, Error> {
        self.compile()
    }

    /// Return the raw regex string contained in the `VerEx`
    pub fn source(& self) -> &str {
        self.string.as_ref()
    }

    /// Return the raw regex string contained in the `VerEx`
    pub fn value(& self) -> &str {
        self.source()
    }

    // classes
    pub fn open_class(&mut self) -> &mut VerEx {
        self.add(r"[")
    }

    pub fn close_class(&mut self) -> &mut VerEx {
        self.add(r"]")
    }

    // groups
    pub fn open_group(&mut self) -> &mut VerEx {
        self.add(r"(?:")
    }

    pub fn open_capturing_group(&mut self) -> &mut VerEx {
        self.add(r"(")
    }

    pub fn close_group(&mut self) -> &mut VerEx {
        self.add(r")")
    }

    // --------------------------------------------------

    /// Any of the given characters
    pub fn any(&mut self, chars: &str) -> &mut VerEx {
        self.open_class()
            .add(chars)
            .close_class()
    }

    pub fn any_of(&mut self, chars: &str) -> &mut VerEx {
        self.any(chars)
    }

    /// Any character zero or more times
    pub fn anything(&mut self) -> &mut VerEx {
        self.add(r"(.*)")
    }

    /// Any character zero or more times except the provided characters
    pub fn anything_but(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .open_class()
            .add(r"^")
            .add(value)
            .close_class()
            .add(r"*")
            .close_group()
    }

    /// A line break!
    pub fn br(&mut self) -> &mut VerEx {
        self.line_break()
    }

    /// Find a specific string and capture it
    pub fn capture(&mut self, value: &str) -> &mut VerEx {
        self.open_capturing_group()
            .add(value)
            .close_group()
    }

    pub fn end_of_line(&mut self) -> &mut VerEx {
        self.add(r"$")
    }

    /// Find a specific string
    pub fn find(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .add(value)
            .close_group()
    }

    /// A line break!
    pub fn line_break(&mut self) -> &mut VerEx {
        self.open_group()
            .add(r"\n")
            .or(r"\r\n")
            .close_group()
    }

    /// Any string either one or zero times
    pub fn maybe(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .add(value)
            .close_group()
            .add(r"?")
    }

    pub fn or(&mut self, value: &str) -> &mut VerEx {
        self.add(r"|");
        if value.is_empty() {
            return self;
        } else {
            return self.then(value);
        }
    }

    /// A range of characters e.g. [A-Z]
    /// Usage example: verex.range(vec![('a', 'z'),('A', 'Z')])
    pub fn range(&mut self, range: Vec<(char, char)>) -> &mut VerEx {
        let mut string = r"[".to_string();
        for tuple in range {
            let from = tuple.0;
            let to = tuple.1;
            string.push(from);
            string.push('-');
            string.push(to);
        }
        string.push(']');
        self.add(string.as_ref())
    }

    /// Replace a substring
    pub fn replace(&mut self, from: &str, to: &str) -> &mut VerEx {
        self.string = self.string.replace(from, to);
        self
    }

    /// Any character at least one time
    pub fn something(&mut self) -> &mut VerEx {
        self.add(r"(.+)")
    }

    /// Any character at least one time except for these characters
    pub fn something_but(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .open_class()
            .add(r"^")
            .add(value)
            .close_class()
            .add(r"+")
            .close_group()
    }

    pub fn start_of_line(&mut self) -> &mut VerEx {
        self.add(r"^")
    }

    // A tab
    pub fn tab(&mut self) -> &mut VerEx {
        self.add(r"\t")
    }

    /// To use find "in the sentence" and make the chaining flow better
    pub fn then(&mut self, value: &str) -> &mut VerEx {
        self.find(value)
    }

    /// Any alphanumeric characters
    pub fn word(&mut self) -> &mut VerEx {
        self.find(r"\w+")
    }
}
<commit_msg>implement traits<commit_after>pub use regex::Regex;
use regex::Error;

#[cfg(test)] pub mod test;

/// The struct used for building verbal expression objects
#[derive(Debug, Clone)]
pub struct VerEx {
    string: String
}

impl VerEx {
    // constructors
    /// Standard Constructor
    pub fn new() -> VerEx {
        VerEx {
            string: String::new(),
        }
    }

    /// Create a `VerEx` object from a `String`
    pub fn from_string(string: String) -> VerEx {
        VerEx {
            string: string,
        }
    }

    /// Create a `VerEx` object from a `&str`
    pub fn from_str(string: &str) -> VerEx {
        VerEx::from_string(string.to_string())
    }

    // --------------------------------------------------
    // fundamental methods
    /// Add a string to the regex string in the `VerEx` and return self
    pub fn add(&mut self, value: &str) -> &mut VerEx{
        self.string.push_str(value);
        self
    }

    /// Compile the `VerEx` to a `Regex` and return the result
    pub fn compile(&mut self) -> Result<Regex, Error> {
        Regex::new(self.string.as_ref())
    }

    /// Return the raw regex string contained in the `VerEx`
    pub fn raw(& self) -> &str {
        self.source()
    }

    /// Compile the `VerEx` to a `Regex` and return the result
    pub fn regex(&mut self) -> Result<Regex, Error> {
        self.compile()
    }

    /// Return the raw regex string contained in the `VerEx`
    pub fn source(& self) -> &str {
        self.string.as_ref()
    }

    /// Return the raw regex string contained in the `VerEx`
    pub fn value(& self) -> &str {
        self.source()
    }

    // classes
    pub fn open_class(&mut self) -> &mut VerEx {
        self.add(r"[")
    }

    pub fn close_class(&mut self) -> &mut VerEx {
        self.add(r"]")
    }

    // groups
    pub fn open_group(&mut self) -> &mut VerEx {
        self.add(r"(?:")
    }

    pub fn open_capturing_group(&mut self) -> &mut VerEx {
        self.add(r"(")
    }

    pub fn close_group(&mut self) -> &mut VerEx {
        self.add(r")")
    }

    // --------------------------------------------------

    /// Any of the given characters
    pub fn any(&mut self, chars: &str) -> &mut VerEx {
        self.open_class()
            .add(chars)
            .close_class()
    }

    pub fn any_of(&mut self, chars: &str) -> &mut VerEx {
        self.any(chars)
    }

    /// Any character zero or more times
    pub fn anything(&mut self) -> &mut VerEx {
        self.add(r"(.*)")
    }

    /// Any character zero or more times except the provided characters
    pub fn anything_but(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .open_class()
            .add(r"^")
            .add(value)
            .close_class()
            .add(r"*")
            .close_group()
    }

    /// A line break!
    pub fn br(&mut self) -> &mut VerEx {
        self.line_break()
    }

    /// Find a specific string and capture it
    pub fn capture(&mut self, value: &str) -> &mut VerEx {
        self.open_capturing_group()
            .add(value)
            .close_group()
    }

    pub fn end_of_line(&mut self) -> &mut VerEx {
        self.add(r"$")
    }

    /// Find a specific string
    pub fn find(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .add(value)
            .close_group()
    }

    /// A line break!
    pub fn line_break(&mut self) -> &mut VerEx {
        self.open_group()
            .add(r"\n")
            .or(r"\r\n")
            .close_group()
    }

    /// Any string either one or zero times
    pub fn maybe(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .add(value)
            .close_group()
            .add(r"?")
    }

    pub fn or(&mut self, value: &str) -> &mut VerEx {
        self.add(r"|");
        if value.is_empty() {
            return self;
        } else {
            return self.then(value);
        }
    }

    /// A range of characters e.g. [A-Z]
    /// Usage example: verex.range(vec![('a', 'z'),('A', 'Z')])
    pub fn range(&mut self, range: Vec<(char, char)>) -> &mut VerEx {
        let mut string = r"[".to_string();
        for tuple in range {
            let from = tuple.0;
            let to = tuple.1;
            string.push(from);
            string.push('-');
            string.push(to);
        }
        string.push(']');
        self.add(string.as_ref())
    }

    /// Replace a substring
    pub fn replace(&mut self, from: &str, to: &str) -> &mut VerEx {
        self.string = self.string.replace(from, to);
        self
    }

    /// Any character at least one time
    pub fn something(&mut self) -> &mut VerEx {
        self.add(r"(.+)")
    }

    /// Any character at least one time except for these characters
    pub fn something_but(&mut self, value: &str) -> &mut VerEx {
        self.open_group()
            .open_class()
            .add(r"^")
            .add(value)
            .close_class()
            .add(r"+")
            .close_group()
    }

    pub fn start_of_line(&mut self) -> &mut VerEx {
        self.add(r"^")
    }

    // A tab
    pub fn tab(&mut self) -> &mut VerEx {
        self.add(r"\t")
    }

    /// To use find "in the sentence" and make the chaining flow better
    pub fn then(&mut self, value: &str) -> &mut VerEx {
        self.find(value)
    }

    /// Any alphanumeric characters
    pub fn word(&mut self) -> &mut VerEx {
        self.find(r"\w+")
    }
}

use std::fmt;

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

impl Eq for VerEx {}

use std::str::FromStr;

impl FromStr for VerEx {
    type Err = Error;

    fn from_str(s: &str) -> Result<VerEx, Error> {
        Ok(VerEx::from_str(s))
    }
}

/// Equality comparison is based on the original string. It is possible that different verbal expressions have the same matching behavior, but are still compared unequal.
impl PartialEq for VerEx {
    fn eq(&self, other: &VerEx) -> bool {
        self.string == other.string
    }
}
<|endoftext|>


<commit_before>
use {Field, Borrowed, Value};
use vecmath::{rotate_radians, multiply, translate, scale, shear};
use {Transform2d, Matrix2d, Rectangle, Color};
use {Fill, BackEnd};
use triangulation::{rect_tri_list_xy_f32, rect_tri_list_rgba_f32};

/// A rectangle color context.
pub struct RectangleColorContext<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> Transform2d<'a> for RectangleColorContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> Fill<'a> for RectangleColorContext<'a> {
    fn fill<B: BackEnd>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_rgba_f32() {
            let rect = self.rect.get();
            let rect: [f32, ..4] = [rect[0] as f32, rect[1] as f32, rect[2] as f32, rect[3] as f32];
            let color = self.color.get();
            let color: [f32, ..4] = [color[0] as f32, color[1] as f32, color[2] as f32, color[3] as f32];
            back_end.tri_list_xy_rgba_f32(
                rect_tri_list_xy_f32(rect),
                rect_tri_list_rgba_f32(color)
            );
        }
    }
}

<commit_msg>Call `unimplemented!` when no feature supported<commit_after>
use {Field, Borrowed, Value};
use vecmath::{rotate_radians, multiply, translate, scale, shear};
use {Transform2d, Matrix2d, Rectangle, Color};
use {Fill, BackEnd};
use triangulation::{rect_tri_list_xy_f32, rect_tri_list_rgba_f32};

/// A rectangle color context.
pub struct RectangleColorContext<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> Transform2d<'a> for RectangleColorContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> Fill<'a> for RectangleColorContext<'a> {
    fn fill<B: BackEnd>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_rgba_f32() {
            let rect = self.rect.get();
            let rect: [f32, ..4] = [rect[0] as f32, rect[1] as f32, rect[2] as f32, rect[3] as f32];
            let color = self.color.get();
            let color: [f32, ..4] = [color[0] as f32, color[1] as f32, color[2] as f32, color[3] as f32];
            back_end.tri_list_xy_rgba_f32(
                rect_tri_list_xy_f32(rect),
                rect_tri_list_rgba_f32(color)
            );
            return;
        }

        unimplemented!();
    }
}

<|endoftext|>


<commit_before>use super::{super::heap::Pointer, Event, FiberId, FullTracer, InFiberEvent};
use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        cst::{Cst, CstDb, CstKind},
        hir::Id,
    },
    database::Database,
    language_server::utils::LspPositionConversion,
    module::Module,
};
use itertools::Itertools;
use std::collections::HashMap;

// Stack traces are a reduced view of the tracing state that represent the stack
// trace at a given moment in time.

#[derive(Clone)]
pub enum StackEntry {
    Call {
        id: Id,
        closure: Pointer,
        args: Vec<Pointer>,
    },
    Needs {
        id: Id,
        condition: Pointer,
        reason: Pointer,
    },
    Module {
        module: Module,
    },
}

impl FullTracer {
    pub fn stack_traces(&self) -> HashMap<FiberId, Vec<StackEntry>> {
        let mut stacks: HashMap<FiberId, Vec<StackEntry>> = HashMap::new();
        for timed_event in &self.events {
            if let Event::InFiber { fiber, event } = &timed_event.event {
                let stack = stacks.entry(*fiber).or_default();
                match event {
                    InFiberEvent::ModuleStarted { module } => {
                        stack.push(StackEntry::Module {
                            module: module.clone(),
                        });
                    }
                    InFiberEvent::ModuleEnded { .. } => {
                        assert!(matches!(stack.pop().unwrap(), StackEntry::Module { .. }));
                    }
                    InFiberEvent::CallStarted { id, closure, args } => {
                        stack.push(StackEntry::Call {
                            id: id.clone(),
                            closure: *closure,
                            args: args.clone(),
                        });
                    }
                    InFiberEvent::CallEnded { .. } => {
                        assert!(matches!(stack.pop().unwrap(), StackEntry::Call { .. }));
                    }
                    InFiberEvent::NeedsStarted {
                        id,
                        condition,
                        reason,
                    } => {
                        stack.push(StackEntry::Needs {
                            id: id.clone(),
                            condition: *condition,
                            reason: *reason,
                        });
                    }
                    InFiberEvent::NeedsEnded => {
                        assert!(matches!(stack.pop().unwrap(), StackEntry::Needs { .. }));
                    }
                    _ => {}
                }
            }
        }
        stacks
    }
    pub fn format_stack_trace(&self, db: &Database, stack: &[StackEntry]) -> String {
        let mut lines = vec![];

        for entry in stack.iter().rev() {
            let hir_id = match entry {
                StackEntry::Call { id, .. } => Some(id),
                StackEntry::Needs { id, .. } => Some(id),
                StackEntry::Module { .. } => None,
            };
            let (cst_id, span) = if let Some(hir_id) = hir_id {
                let module = hir_id.module.clone();
                let cst_id = db.hir_to_cst_id(hir_id.clone());
                let cst = cst_id.map(|id| db.find_cst(module.clone(), id));
                let span = cst.map(|cst| {
                    (
                        db.offset_to_lsp(module.clone(), cst.span.start),
                        db.offset_to_lsp(module.clone(), cst.span.end),
                    )
                });
                (cst_id, span)
            } else {
                (None, None)
            };
            let caller_location_string = format!(
                "{} {}",
                hir_id
                    .map(|id| format!("{id}"))
                    .unwrap_or_else(|| "<no hir>".to_string()),
                span.map(|((start_line, start_col), (end_line, end_col))| format!(
                    "{}:{} – {}:{}",
                    start_line, start_col, end_line, end_col
                ))
                .unwrap_or_else(|| "<no location>".to_string())
            );
            let call_string = match entry {
                StackEntry::Call { closure, args, .. } => format!(
                    "{} {}",
                    cst_id
                        .and_then(|id| {
                            let cst = db.find_cst(hir_id.unwrap().module.clone(), id);
                            match cst.kind {
                                CstKind::Call { receiver, .. } => receiver.extract_receiver_name(),
                                _ => None,
                            }
                        })
                        .unwrap_or_else(|| closure.format(&self.heap)),
                    args.iter().map(|arg| arg.format(&self.heap)).join(" ")
                ),
                StackEntry::Needs {
                    condition, reason, ..
                } => format!(
                    "needs {} {}",
                    condition.format(&self.heap),
                    reason.format(&self.heap),
                ),
                StackEntry::Module { module } => format!("module {module}"),
            };
            lines.push(format!("{caller_location_string:90} {call_string}"));
        }
        lines.join("\n")
    }
    /// When a VM panics, some child fiber might be responsible for that. This
    /// function returns a formatted stack trace spanning all fibers in the
    /// chain from the panicking root fiber until the concrete failing needs.
    pub fn format_panic_stack_trace_to_root_fiber(&self, db: &Database) -> String {
        let mut panicking_fiber_chain = vec![FiberId::root()];
        for timed_event in self.events.iter().rev() {
            if let Event::FiberPanicked {
                fiber,
                panicked_child,
            } = timed_event.event
            {
                if fiber == *panicking_fiber_chain.last().unwrap() {
                    match panicked_child {
                        Some(child) => panicking_fiber_chain.push(child),
                        None => break,
                    }
                }
            }
        }

        let stack_traces = self.stack_traces();
        panicking_fiber_chain
            .into_iter()
            .rev()
            .map(|fiber| self.format_stack_trace(db, &stack_traces[&fiber]))
            .join("\n(fiber boundary)\n")
    }
}

impl Cst {
    fn extract_receiver_name(&self) -> Option<String> {
        match &self.kind {
            CstKind::TrailingWhitespace { child, .. } => child.extract_receiver_name(),
            CstKind::Identifier(identifier) => Some(identifier.to_string()),
            CstKind::Parenthesized { inner, .. } => inner.extract_receiver_name(),
            CstKind::StructAccess { struct_, key, .. } => {
                let struct_string = struct_.extract_receiver_name()?;
                let key = key.extract_receiver_name()?;
                Some(format!("{struct_string}.{key}"))
            }
            _ => None,
        }
    }
}
<commit_msg>Apply suggestions from code review<commit_after>use super::{super::heap::Pointer, Event, FiberId, FullTracer, InFiberEvent};
use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        cst::{Cst, CstDb, CstKind},
        hir::Id,
    },
    database::Database,
    language_server::utils::LspPositionConversion,
    module::Module,
};
use itertools::Itertools;
use std::collections::HashMap;

// Stack traces are a reduced view of the tracing state that represent the stack
// trace at a given moment in time.

#[derive(Clone)]
pub enum StackEntry {
    Call {
        id: Id,
        closure: Pointer,
        args: Vec<Pointer>,
    },
    Needs {
        id: Id,
        condition: Pointer,
        reason: Pointer,
    },
    Module {
        module: Module,
    },
}

impl FullTracer {
    pub fn stack_traces(&self) -> HashMap<FiberId, Vec<StackEntry>> {
        let mut stacks: HashMap<FiberId, Vec<StackEntry>> = HashMap::new();
        for timed_event in &self.events {
            let Event::InFiber { fiber, event } = &timed_event.event else { continue; };
                let stack = stacks.entry(*fiber).or_default();
                match event {
                    InFiberEvent::ModuleStarted { module } => {
                        stack.push(StackEntry::Module {
                            module: module.clone(),
                        });
                    }
                    InFiberEvent::ModuleEnded { .. } => {
                        assert!(matches!(stack.pop().unwrap(), StackEntry::Module { .. }));
                    }
                    InFiberEvent::CallStarted { id, closure, args } => {
                        stack.push(StackEntry::Call {
                            id: id.clone(),
                            closure: *closure,
                            args: args.clone(),
                        });
                    }
                    InFiberEvent::CallEnded { .. } => {
                        assert!(matches!(stack.pop().unwrap(), StackEntry::Call { .. }));
                    }
                    InFiberEvent::NeedsStarted {
                        id,
                        condition,
                        reason,
                    } => {
                        stack.push(StackEntry::Needs {
                            id: id.clone(),
                            condition: *condition,
                            reason: *reason,
                        });
                    }
                    InFiberEvent::NeedsEnded => {
                        assert!(matches!(stack.pop().unwrap(), StackEntry::Needs { .. }));
                    }
                    _ => {}
                }
            }
        }
        stacks
    }
    pub fn format_stack_trace(&self, db: &Database, stack: &[StackEntry]) -> String {
        let mut lines = vec![];

        for entry in stack.iter().rev() {
            let hir_id = match entry {
                StackEntry::Call { id, .. } => Some(id),
                StackEntry::Needs { id, .. } => Some(id),
                StackEntry::Module { .. } => None,
            };
            let (cst_id, span) = if let Some(hir_id) = hir_id {
                let module = hir_id.module.clone();
                let cst_id = db.hir_to_cst_id(hir_id.clone());
                let cst = cst_id.map(|id| db.find_cst(module.clone(), id));
                let span = cst.map(|cst| {
                    (
                        db.offset_to_lsp(module.clone(), cst.span.start),
                        db.offset_to_lsp(module.clone(), cst.span.end),
                    )
                });
                (cst_id, span)
            } else {
                (None, None)
            };
            let caller_location_string = format!(
                "{} {}",
                hir_id
                    .map(|id| format!("{id}"))
                    .unwrap_or_else(|| "<no hir>".to_string()),
                span.map(|((start_line, start_col), (end_line, end_col))| format!(
                    "{}:{} – {}:{}",
                    start_line, start_col, end_line, end_col
                ))
                .unwrap_or_else(|| "<no location>".to_string())
            );
            let call_string = match entry {
                StackEntry::Call { closure, args, .. } => format!(
                    "{} {}",
                    cst_id
                        .and_then(|id| {
                            let cst = db.find_cst(hir_id.unwrap().module.clone(), id);
                            match cst.kind {
                                CstKind::Call { receiver, .. } => receiver.extract_receiver_name(),
                                _ => None,
                            }
                        })
                        .unwrap_or_else(|| closure.format(&self.heap)),
                    args.iter().map(|arg| arg.format(&self.heap)).join(" ")
                ),
                StackEntry::Needs {
                    condition, reason, ..
                } => format!(
                    "needs {} {}",
                    condition.format(&self.heap),
                    reason.format(&self.heap),
                ),
                StackEntry::Module { module } => format!("module {module}"),
            };
            lines.push(format!("{caller_location_string:90} {call_string}"));
        }
        lines.join("\n")
    }
    /// When a VM panics, some child fiber might be responsible for that. This
    /// function returns a formatted stack trace spanning all fibers in the
    /// chain from the panicking root fiber until the concrete failing needs.
    pub fn format_panic_stack_trace_to_root_fiber(&self, db: &Database) -> String {
        let mut panicking_fiber_chain = vec![FiberId::root()];
        for timed_event in self.events.iter().rev() {
            if let Event::FiberPanicked {
                fiber,
                panicked_child,
            } = timed_event.event
            {
                if fiber == *panicking_fiber_chain.last().unwrap() {
                    match panicked_child {
                        Some(child) => panicking_fiber_chain.push(child),
                        None => break,
                    }
                }
            }
        }

        let stack_traces = self.stack_traces();
        panicking_fiber_chain
            .into_iter()
            .rev()
            .map(|fiber| self.format_stack_trace(db, &stack_traces[&fiber]))
            .join("\n(fiber boundary)\n")
    }
}

impl Cst {
    fn extract_receiver_name(&self) -> Option<String> {
        match &self.kind {
            CstKind::TrailingWhitespace { child, .. } => child.extract_receiver_name(),
            CstKind::Identifier(identifier) => Some(identifier.to_string()),
            CstKind::Parenthesized { inner, .. } => inner.extract_receiver_name(),
            CstKind::StructAccess { struct_, key, .. } => {
                let struct_string = struct_.extract_receiver_name()?;
                let key = key.extract_receiver_name()?;
                Some(format!("{struct_string}.{key}"))
            }
            _ => None,
        }
    }
}
<|endoftext|>