<commit_before>use std::boxed::FnBox;
use std::collections::{HashMap, HashSet};
use std::sync::{RwLock, Mutex, Arc};
use std::sync::atomic::{AtomicU64, Ordering};
use threadpool::ThreadPool;
use num_cpus;
use bifrost_hasher::{hash_str, hash_bytes};
use raft::RaftService;
use rpc;
use serde;
use super::super::{StateMachineCtl, OpType};
use super::super::super::RaftMsg;
use super::*;

lazy_static! {
    pub static ref SUBSCRIPTIONS: RwLock<HashMap<u64, Subscriptions>> = RwLock::new(HashMap::new());
    pub static ref THREAD_POOL: Mutex<ThreadPool> = Mutex::new(ThreadPool::new(
                        num_cpus::get()
                    ));
}

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<SyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address.clone());
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let session_match = self.subscribers.get(&suber_id).unwrap().session_id == session_id;
            if !session_match {
                println!("SESSION ID NOT MATCH!!!");
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(&address) {
                        SyncServiceClient::new(sub_service_id, client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        SMCallback {
            raft_service: raft_service,
            sm_id: state_machine_id,
        }
    }
    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R)
    where R: serde::Serialize + Clone + Send + Sync {
        println!("===============");
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let subscriptions_map = SUBSCRIPTIONS.read().unwrap();
                if let Some(svr_subs) = subscriptions_map.get(&raft_sid) {
                    if let Some(sub_ids) = svr_subs.subscriptions.get(&key) {
                        let data = serialize!(&data);
                        for sub_id in sub_ids {
                            if let Some(subscriber_id) = svr_subs.sub_suber.get(&sub_id) {
                                if let Some(subscriber) = svr_subs.subscribers.get(&subscriber_id) {
                                    let data = data.clone();
                                    let client = subscriber.client.clone();
                                    println!("--------");
                                    THREAD_POOL.lock().unwrap().execute(move || {
                                        client.notify(key, data);
                                    });
                                }
                            } else {println!("||||||||||||||||");}
                        }
                    } else {
                        let keys: Vec<SubKey> = svr_subs.subscriptions.keys().cloned().collect();
                        println!(">>>>>>>>>>>>>> {:?} -> {:?}", keys, key);
                    }
                } else {println!("<<<<<<<<<<<<<<<");}
            },
            _ => {}

        }
    }
}
<commit_msg>a heisenbug seems fixed with no reason<commit_after>use std::boxed::FnBox;
use std::collections::{HashMap, HashSet};
use std::sync::{RwLock, Mutex, Arc};
use std::sync::atomic::{AtomicU64, Ordering};
use threadpool::ThreadPool;
use num_cpus;
use bifrost_hasher::{hash_str, hash_bytes};
use raft::RaftService;
use rpc;
use serde;
use super::super::{StateMachineCtl, OpType};
use super::super::super::RaftMsg;
use super::*;

lazy_static! {
    pub static ref SUBSCRIPTIONS: RwLock<HashMap<u64, Subscriptions>> = RwLock::new(HashMap::new());
    pub static ref THREAD_POOL: Mutex<ThreadPool> = Mutex::new(ThreadPool::new(
                        num_cpus::get()
                    ));
}

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<SyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address.clone());
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let session_match = self.subscribers.get(&suber_id).unwrap().session_id == session_id;
            if !session_match {
                println!("SESSION ID NOT MATCH!!!");
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(&address) {
                        SyncServiceClient::new(sub_service_id, client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        SMCallback {
            raft_service: raft_service,
            sm_id: state_machine_id,
        }
    }
    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R)
    where R: serde::Serialize + Clone + Send + Sync {
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let subscriptions_map = SUBSCRIPTIONS.read().unwrap();
                if let Some(svr_subs) = subscriptions_map.get(&raft_sid) {
                    if let Some(sub_ids) = svr_subs.subscriptions.get(&key) {
                        let data = serialize!(&data);
                        for sub_id in sub_ids {
                            if let Some(subscriber_id) = svr_subs.sub_suber.get(&sub_id) {
                                if let Some(subscriber) = svr_subs.subscribers.get(&subscriber_id) {
                                    let data = data.clone();
                                    let client = subscriber.client.clone();
                                    THREAD_POOL.lock().unwrap().execute(move || {
                                        client.notify(key, data);
                                    });
                                }
                            }
                        }
                    }
                }
            },
            _ => {}

        }
    }
}
<|endoftext|>


<commit_before>use serde::de::{Deserialize, Deserializer, Error};

use types::*;

/// This object represents a Telegram user or bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct User {
    /// Unique identifier for this user or bot.
    pub id: UserId,
    /// User‘s or bot’s first name.
    pub first_name: String,
    /// User‘s or bot’s last name.
    pub last_name: Option<String>,
    /// User‘s or bot’s username.
    pub username: Option<String>,
}

/// This object represents a group.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct Group {
    /// Unique identifier for this chat.
    pub id: GroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: bool,
}

/// This object represents a supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct Supergroup {
    /// Unique identifier for this chat.
    pub id: SupergroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for supergroup.
    pub username: Option<String>,
}

/// This object represents a channel.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct Channel {
    /// Unique identifier for this chat.
    pub id: ChannelId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for channel.
    pub username: Option<String>,
}

/// This object represents a private, group or supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum MessageChat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl MessageChat {
    pub fn id(&self) -> ChatId {
        match *self {
            MessageChat::Private(ref x) => x.id.into(),
            MessageChat::Group(ref x) => x.id.into(),
            MessageChat::Supergroup(ref x) => x.id.into(),
            MessageChat::Unknown(ref x) => x.id.into(),
        }
    }
}

/// This object represents a chat.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Chat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    Channel(Channel),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl Chat {
    pub fn id(&self) -> ChatId {
        match *self {
            Chat::Private(ref x) => x.id.into(),
            Chat::Group(ref x) => x.id.into(),
            Chat::Supergroup(ref x) => x.id.into(),
            Chat::Channel(ref x) => x.id.into(),
            Chat::Unknown(ref x) => x.id.into(),
        }
    }
}

impl<'de> Deserialize<'de> for Chat {
    fn deserialize<D>(deserializer: D) -> Result<Chat, D::Error>
        where D: Deserializer<'de>
    {
        let raw: RawChat = Deserialize::deserialize(deserializer)?;

        macro_rules! required_field {
            ($name:ident) => {{
                match raw.$name {
                    Some(val) => val,
                    None => return Err(D::Error::missing_field(stringify!($name)))
                }
            }}
        }

        Ok(match raw.type_.as_ref() {
            "private" => {
                Chat::Private(User {
                    id: raw.id.into(),
                    username: raw.username,
                    first_name: required_field!(first_name),
                    last_name: raw.last_name,
                })
            }
            "group" => {
                Chat::Group(Group {
                    id: raw.id.into(),
                    title: required_field!(title),
                    all_members_are_administrators: required_field!(all_members_are_administrators),
                })
            }
            "supergroup" => {
                Chat::Supergroup(Supergroup {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            "channel" => {
                Chat::Channel(Channel {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            _ => Chat::Unknown(raw),
        })
    }
}

/// This object represents a chat, directly mapped.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct RawChat {
    /// Unique identifier for this chat.
    pub id: Integer,
    /// Type of chat, can be either “private”, “group”, “supergroup” or “channel”
    #[serde(rename="type")]
    pub type_: String,
    /// Title, for supergroups, channels and group chats
    pub title: Option<String>,
    /// Username, for private chats, supergroups and channels if available
    pub username: Option<String>,
    /// First name of the other party in a private chat
    pub first_name: Option<String>,
    /// Last name of the other party in a private chat
    pub last_name: Option<String>,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: Option<bool>,
}
<commit_msg>Added "is_bot" field on User structure<commit_after>use serde::de::{Deserialize, Deserializer, Error};

use types::*;

/// This object represents a Telegram user or bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct User {
    /// Unique identifier for this user or bot.
    pub id: UserId,
    /// User‘s or bot’s first name.
    pub first_name: String,
    /// User‘s or bot’s last name.
    pub last_name: Option<String>,
    /// User‘s or bot’s username.
    pub username: Option<String>,
    /// True, if this user is a bot.
    pub is_bot: bool,
}

/// This object represents a group.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct Group {
    /// Unique identifier for this chat.
    pub id: GroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: bool,
}

/// This object represents a supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct Supergroup {
    /// Unique identifier for this chat.
    pub id: SupergroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for supergroup.
    pub username: Option<String>,
}

/// This object represents a channel.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct Channel {
    /// Unique identifier for this chat.
    pub id: ChannelId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for channel.
    pub username: Option<String>,
}

/// This object represents a private, group or supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum MessageChat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl MessageChat {
    pub fn id(&self) -> ChatId {
        match *self {
            MessageChat::Private(ref x) => x.id.into(),
            MessageChat::Group(ref x) => x.id.into(),
            MessageChat::Supergroup(ref x) => x.id.into(),
            MessageChat::Unknown(ref x) => x.id.into(),
        }
    }
}

/// This object represents a chat.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Chat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    Channel(Channel),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl Chat {
    pub fn id(&self) -> ChatId {
        match *self {
            Chat::Private(ref x) => x.id.into(),
            Chat::Group(ref x) => x.id.into(),
            Chat::Supergroup(ref x) => x.id.into(),
            Chat::Channel(ref x) => x.id.into(),
            Chat::Unknown(ref x) => x.id.into(),
        }
    }
}

impl<'de> Deserialize<'de> for Chat {
    fn deserialize<D>(deserializer: D) -> Result<Chat, D::Error>
        where D: Deserializer<'de>
    {
        let raw: RawChat = Deserialize::deserialize(deserializer)?;

        macro_rules! required_field {
            ($name:ident) => {{
                match raw.$name {
                    Some(val) => val,
                    None => return Err(D::Error::missing_field(stringify!($name)))
                }
            }}
        }

        Ok(match raw.type_.as_ref() {
            "private" => {
                Chat::Private(User {
                    id: raw.id.into(),
                    username: raw.username,
                    first_name: required_field!(first_name),
                    last_name: raw.last_name,
                })
            }
            "group" => {
                Chat::Group(Group {
                    id: raw.id.into(),
                    title: required_field!(title),
                    all_members_are_administrators: required_field!(all_members_are_administrators),
                })
            }
            "supergroup" => {
                Chat::Supergroup(Supergroup {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            "channel" => {
                Chat::Channel(Channel {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            _ => Chat::Unknown(raw),
        })
    }
}

/// This object represents a chat, directly mapped.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Deserialize)]
pub struct RawChat {
    /// Unique identifier for this chat.
    pub id: Integer,
    /// Type of chat, can be either “private”, “group”, “supergroup” or “channel”
    #[serde(rename="type")]
    pub type_: String,
    /// Title, for supergroups, channels and group chats
    pub title: Option<String>,
    /// Username, for private chats, supergroups and channels if available
    pub username: Option<String>,
    /// First name of the other party in a private chat
    pub first_name: Option<String>,
    /// Last name of the other party in a private chat
    pub last_name: Option<String>,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: Option<bool>,
}
<|endoftext|>


<commit_before>// Test proc-macro crate can be built without addtional RUSTFLAGS
// on musl target

// build-pass
// only-musl
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Foo)]
pub fn derive_foo(input: TokenStream) -> TokenStream {
    input
}
<commit_msg>override flags from compiletest<commit_after>// Test proc-macro crate can be built without addtional RUSTFLAGS
// on musl target
// override -Ctarget-feature=-crt-static from compiletest
// compile-flags: -Ctarget-feature=
// build-pass
// only-musl
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Foo)]
pub fn derive_foo(input: TokenStream) -> TokenStream {
    input
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::path::Path;

use error::Error;

use util::Process;

use task::traits::Detected;

/// Input and output detection strategy.
#[derive(
    Serialize,
    Deserialize,
    Copy,
    Clone,
    Ord,
    Eq,
    PartialOrd,
    PartialEq,
    Hash,
    Debug,
)]
pub enum Detect {
    /// Detect inputs and outputs for MSVC Cl.exe. This works by adding
    /// `/showIncludes` to the command line and parsing the output.
    Cl,

    /// Don't do any input/output detection. Just run the process as is. This
    /// assumes that all inputs and outputs have been explicitly specified up
    /// front.
    None,
}

impl Default for Detect {
    fn default() -> Self {
        Detect::None
    }
}

impl Detect {
    /// Based on the program name, figure out the best detection method. If not
    /// known, returns `None`.
    #[cfg(windows)]
    pub fn from_program(program: &Path) -> Detect {
        // Only use the file stem on Windows (no file extension).
        if let Some(stem) = program.file_stem() {
            match stem.to_str() {
                Some("cl") => Detect::Cl,
                // Some("gcc") => Detect::GCC,
                // Some("clang") => Detect::Clang,
                _ => Detect::default(),
            }
        } else {
            Detect::None
        }
    }

    /// Based on the program name, figure out the best detection method. If not
    /// known, returns `None`.
    #[cfg(unix)]
    pub fn from_program(program: &Path) -> Detect {
        // Use the whole file name on Unix platforms.
        if let Some(name) = program.file_name() {
            match name.to_str() {
                Some("cl") => Detect::Cl,
                // Some("gcc") => Detect::GCC,
                // Some("clang") => Detect::Clang,
                _ => Detect::None,
            }
        } else {
            Detect::None
        }
    }

    /// Run the given process, returning its inputs and outputs.
    pub fn run(
        self,
        root: &Path,
        process: &Process,
        log: &mut io::Write,
    ) -> Result<Detected, Error> {
        match self {
            Detect::Cl => cl::run(root, process, log),
            Detect::None => base::run(root, process, log),
        }
    }
}

mod base {
    use std::borrow::Cow;
    use std::io::{self, Read};
    use std::path::Path;

    use error::{Error, ResultExt};
    use util::Process;

    use task::traits::Detected;

    pub fn run(
        root: &Path,
        process: &Process,
        log: &mut io::Write,
    ) -> Result<Detected, Error> {
        let mut process = Cow::Borrowed(process);

        // Generate a response file if necessary.
        let response_file = if process.args.too_large() {
            Some(process.to_mut().response_file()
                 .context("Failed generating response file")?)
        } else {
            None
        };

        let (mut reader, child) = process.spawn(root)?;

        let detected = Detected::new();

        // Read the combined stdout/stderr.
        let mut buf = [0u8; 4096];
        loop {
            let n = reader.read(&mut buf)?;
            if n == 0 {
                break;
            }

            log.write_all(&buf[0..n])?;
        }

        child.wait()?;

        if let Some(response_file) = response_file {
            response_file.close().context("Failed deleting response file")?;
        }

        Ok(detected)
    }
}

mod cl {
    use std::io::{self, BufRead};
    use std::path::Path;

    use error::{Error, ResultExt};
    use util::Process;

    use task::traits::Detected;

    static INCLUDE_PREFIX: &str = "Note: including file: ";

    pub fn run(
        root: &Path,
        process: &Process,
        log: &mut io::Write,
    ) -> Result<Detected, Error> {
        let mut process = process.clone();

        // Use `/showIncludes` to capture header files that are used by the
        // build.
        //
        // TODO: Use the `VS_UNICODE_OUTPUT` environment variable to get Unicode
        // output from cl.exe.
        //
        // TODO: Echo "Note: including file: " line if "/showIncludes" is
        // already present in the command line arguments. This should
        // handle the various formats of "/showIncludes" as well (e.g.,
        // starting with '-' instead of '/', case differences).
        process.args.push("/showIncludes".into());

        // Generate a response file if necessary.
        let response_file = if process.args.too_large() {
            Some(process.response_file()
                 .context("Failed generating response file")?)
        } else {
            None
        };

        let (reader, child) = process.spawn(root)?;

        // Canonicalize the root path such that `strip_prefix` works below.
        let root = root.canonicalize()?;

        // Buffer the read such that we can read one line at a time.
        let mut reader = io::BufReader::new(reader);

        let mut detected = Detected::new();

        let mut line = String::new();

        while reader.read_line(&mut line)? != 0 {
            if line.starts_with(INCLUDE_PREFIX) {
                let include = &line[INCLUDE_PREFIX.len()..].trim();

                // Canonicalize the path such that the root path and this path
                // agree on the case of the file path. Otherwise, `strip_prefix`
                // won't work.
                let path = Path::new(include).canonicalize()?;

                // Only include paths that are contained within the project
                // root. Everything else is treated as a system dependency.
                if let Ok(path) = path.strip_prefix(&root) {
                    detected.add_input(path.to_path_buf());
                }
            } else {
                log.write_all(line.as_ref())?;
            }

            line.clear();
        }

        child.wait()?;

        if let Some(response_file) = response_file {
            response_file.close()
                .context("Failed deleting response file")?;
        }

        Ok(detected)
    }
}
<commit_msg>Minor cleanup<commit_after>// Copyright (c) 2018 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::path::Path;

use error::Error;

use util::Process;

use task::traits::Detected;

/// Input and output detection strategy.
#[derive(
    Serialize,
    Deserialize,
    Copy,
    Clone,
    Ord,
    Eq,
    PartialOrd,
    PartialEq,
    Hash,
    Debug,
)]
pub enum Detect {
    /// Detect inputs and outputs for MSVC Cl.exe. This works by adding
    /// `/showIncludes` to the command line and parsing the output.
    Cl,

    /// Don't do any input/output detection. Just run the process as is. This
    /// assumes that all inputs and outputs have been explicitly specified up
    /// front.
    None,
}

impl Default for Detect {
    fn default() -> Self {
        Detect::None
    }
}

impl Detect {
    /// Based on the program name, figure out the best detection method. If not
    /// known, returns `None`.
    #[cfg(windows)]
    pub fn from_program(program: &Path) -> Detect {
        // Only use the file stem on Windows (no file extension).
        if let Some(stem) = program.file_stem() {
            match stem.to_str() {
                Some("cl") => Detect::Cl,
                // Some("gcc") => Detect::GCC,
                // Some("clang") => Detect::Clang,
                _ => Detect::default(),
            }
        } else {
            Detect::None
        }
    }

    /// Based on the program name, figure out the best detection method. If not
    /// known, returns `None`.
    #[cfg(unix)]
    pub fn from_program(program: &Path) -> Detect {
        // Use the whole file name on Unix platforms.
        if let Some(name) = program.file_name() {
            match name.to_str() {
                Some("cl") => Detect::Cl,
                // Some("gcc") => Detect::GCC,
                // Some("clang") => Detect::Clang,
                _ => Detect::None,
            }
        } else {
            Detect::None
        }
    }

    /// Run the given process, returning its inputs and outputs.
    pub fn run(
        self,
        root: &Path,
        process: &Process,
        log: &mut io::Write,
    ) -> Result<Detected, Error> {
        match self {
            Detect::Cl => cl::run(root, process, log),
            Detect::None => base::run(root, process, log),
        }
    }
}

mod base {
    use std::borrow::Cow;
    use std::io::{self, Read};
    use std::path::Path;

    use error::{Error, ResultExt};
    use util::Process;

    use task::traits::Detected;

    pub fn run(
        root: &Path,
        process: &Process,
        log: &mut io::Write,
    ) -> Result<Detected, Error> {
        let mut process = Cow::Borrowed(process);

        // Generate a response file if necessary.
        let response_file = if process.args.too_large() {
            Some(process.to_mut().response_file()
                 .context("Failed generating response file")?)
        } else {
            None
        };

        let (mut reader, child) = process.spawn(root)?;

        // Read the combined stdout/stderr.
        let mut buf = [0u8; 4096];
        loop {
            let n = reader.read(&mut buf)?;
            if n == 0 {
                break;
            }

            log.write_all(&buf[0..n])?;
        }

        child.wait()?;

        if let Some(response_file) = response_file {
            response_file.close().context("Failed deleting response file")?;
        }

        Ok(Detected::new())
    }
}

mod cl {
    use std::io::{self, BufRead};
    use std::path::Path;

    use error::{Error, ResultExt};
    use util::Process;

    use task::traits::Detected;

    static INCLUDE_PREFIX: &str = "Note: including file: ";

    pub fn run(
        root: &Path,
        process: &Process,
        log: &mut io::Write,
    ) -> Result<Detected, Error> {
        let mut process = process.clone();

        // Use `/showIncludes` to capture header files that are used by the
        // build.
        //
        // TODO: Use the `VS_UNICODE_OUTPUT` environment variable to get Unicode
        // output from cl.exe.
        //
        // TODO: Echo "Note: including file: " line if "/showIncludes" is
        // already present in the command line arguments. This should
        // handle the various formats of "/showIncludes" as well (e.g.,
        // starting with '-' instead of '/', case differences).
        process.args.push("/showIncludes".into());

        // Generate a response file if necessary.
        let response_file = if process.args.too_large() {
            Some(process.response_file()
                 .context("Failed generating response file")?)
        } else {
            None
        };

        let (reader, child) = process.spawn(root)?;

        // Canonicalize the root path such that `strip_prefix` works below.
        let root = root.canonicalize()?;

        // Buffer the read such that we can read one line at a time.
        let mut reader = io::BufReader::new(reader);

        let mut detected = Detected::new();

        let mut line = String::new();

        while reader.read_line(&mut line)? != 0 {
            if line.starts_with(INCLUDE_PREFIX) {
                let include = &line[INCLUDE_PREFIX.len()..].trim();

                // Canonicalize the path such that the root path and this path
                // agree on the case of the file path. Otherwise, `strip_prefix`
                // won't work.
                let path = Path::new(include).canonicalize()?;

                // Only include paths that are contained within the project
                // root. Everything else is treated as a system dependency.
                if let Ok(path) = path.strip_prefix(&root) {
                    detected.add_input(path.to_path_buf());
                }
            } else {
                log.write_all(line.as_ref())?;
            }

            line.clear();
        }

        child.wait()?;

        if let Some(response_file) = response_file {
            response_file.close()
                .context("Failed deleting response file")?;
        }

        Ok(detected)
    }
}
<|endoftext|>


<commit_before>use std::io;
use termcolor::{Color, ColorSpec};

use crate::diagnostic::Severity;

/// Configures how a diagnostic is rendered.
#[derive(Clone, Debug)]
pub struct Config {
    /// The display style to use when rendering diagnostics.
    /// Defaults to: `DisplayStyle::Rich`.
    pub display_style: DisplayStyle,
    /// Column width of tabs.
    /// Defaults to: `4`.
    pub tab_width: usize,
    /// Styles to use when rendering the diagnostic.
    pub styles: Styles,
    /// Characters to use when rendering the diagnostic.
    pub chars: Chars,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            display_style: DisplayStyle::Rich,
            tab_width: 4,
            styles: Styles::default(),
            chars: Chars::default(),
        }
    }
}

impl Config {
    /// Measure the width of a string, taking into account the tab width.
    pub fn width(&self, s: &str) -> usize {
        use unicode_width::UnicodeWidthChar;

        s.chars()
            .map(|ch| match ch {
                '\t' => self.tab_width,
                _ => ch.width().unwrap_or(0),
            })
            .sum()
    }

    /// Construct a source writer using the current config.
    pub fn source<'a, W: ?Sized>(&self, writer: &'a mut W) -> SourceWriter<&'a mut W> {
        SourceWriter {
            writer,
            tab_width: self.tab_width,
        }
    }
}

/// Writer that replaces tab characters with the configured number of spaces.
pub struct SourceWriter<W> {
    writer: W,
    tab_width: usize,
}

impl<W: io::Write> io::Write for SourceWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut last_term = 0usize;
        for (i, ch) in buf.iter().enumerate() {
            match ch {
                b'\t' => {
                    self.writer.write(&buf[last_term..i])?;
                    last_term = i + 1;
                    write!(
                        self.writer,
                        "{space: >width$}",
                        space = "",
                        width = self.tab_width,
                    )?
                },
                _ => {},
            }
        }
        self.writer.write(&buf[last_term..])?;
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

/// The display style to use when rendering diagnostics.
#[derive(Clone, Debug)]
pub enum DisplayStyle {
    /// Output a richly formatted diagnostic, with source code previews.
    ///
    /// ```text
    /// error[E0001]: unexpected type in `+` application
    ///
    ///    ┌── test:2:9 ───
    ///    │
    ///  2 │ (+ test "")
    ///    │         ^^ expected `Int` but found `String`
    ///    │
    ///    = expected type `Int`
    ///         found type `String`
    ///
    /// error[E0002]: Bad config found
    ///
    /// ```
    Rich,
    /// Output a short diagnostic, with a line number, severity, and message.
    ///
    /// ```text
    /// test:2:9: error[E0001]: unexpected type in `+` application
    /// error[E0002]: Bad config found
    /// ```
    Short,
}

/// Styles to use when rendering the diagnostic.
#[derive(Clone, Debug)]
pub struct Styles {
    /// The style to use when rendering bug headers.
    /// Defaults to `fg:red bold intense`.
    pub header_bug: ColorSpec,
    /// The style to use when rendering error headers.
    /// Defaults to `fg:red bold intense`.
    pub header_error: ColorSpec,
    /// The style to use when rendering warning headers.
    /// Defaults to `fg:yellow bold intense`.
    pub header_warning: ColorSpec,
    /// The style to use when rendering note headers.
    /// Defaults to `fg:green bold intense`.
    pub header_note: ColorSpec,
    /// The style to use when rendering help headers.
    /// Defaults to `fg:cyan bold intense`.
    pub header_help: ColorSpec,
    /// The style to use when the main diagnostic message.
    /// Defaults to `bold intense`.
    pub header_message: ColorSpec,

    /// The style to use when rendering bug labels.
    /// Defaults to `fg:red`.
    pub primary_label_bug: ColorSpec,
    /// The style to use when rendering error labels.
    /// Defaults to `fg:red`.
    pub primary_label_error: ColorSpec,
    /// The style to use when rendering warning labels.
    /// Defaults to `fg:yellow`.
    pub primary_label_warning: ColorSpec,
    /// The style to use when rendering note labels.
    /// Defaults to `fg:green`.
    pub primary_label_note: ColorSpec,
    /// The style to use when rendering help labels.
    /// Defaults to `fg:cyan`.
    pub primary_label_help: ColorSpec,
    /// The style to use when rendering secondary labels.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub secondary_label: ColorSpec,

    /// The style to use when rendering the line numbers.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub line_number: ColorSpec,
    /// The style to use when rendering the source code borders.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub source_border: ColorSpec,
    /// The style to use when rendering the note bullets.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub note_bullet: ColorSpec,
}

impl Styles {
    /// The style used to mark a header at a given severity.
    pub fn header(&self, severity: Severity) -> &ColorSpec {
        match severity {
            Severity::Bug => &self.header_bug,
            Severity::Error => &self.header_error,
            Severity::Warning => &self.header_warning,
            Severity::Note => &self.header_note,
            Severity::Help => &self.header_help,
        }
    }

    /// The style used to mark a primary label at a given severity.
    pub fn primary_label(&self, severity: Severity) -> &ColorSpec {
        match severity {
            Severity::Bug => &self.primary_label_bug,
            Severity::Error => &self.primary_label_error,
            Severity::Warning => &self.primary_label_warning,
            Severity::Note => &self.primary_label_note,
            Severity::Help => &self.primary_label_help,
        }
    }

    #[doc(hidden)]
    pub fn with_blue(blue: Color) -> Styles {
        let header = ColorSpec::new().set_bold(true).set_intense(true).clone();

        Styles {
            header_bug: header.clone().set_fg(Some(Color::Red)).clone(),
            header_error: header.clone().set_fg(Some(Color::Red)).clone(),
            header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(),
            header_note: header.clone().set_fg(Some(Color::Green)).clone(),
            header_help: header.clone().set_fg(Some(Color::Cyan)).clone(),
            header_message: header.clone(),

            primary_label_bug: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_error: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_warning: ColorSpec::new().set_fg(Some(Color::Yellow)).clone(),
            primary_label_note: ColorSpec::new().set_fg(Some(Color::Green)).clone(),
            primary_label_help: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
            secondary_label: ColorSpec::new().set_fg(Some(blue)).clone(),

            line_number: ColorSpec::new().set_fg(Some(blue)).clone(),
            source_border: ColorSpec::new().set_fg(Some(blue)).clone(),
            note_bullet: ColorSpec::new().set_fg(Some(blue)).clone(),
        }
    }
}

impl Default for Styles {
    fn default() -> Styles {
        // Blue is really difficult to see on the standard windows command line
        #[cfg(windows)]
        const BLUE: Color = Color::Cyan;
        #[cfg(not(windows))]
        const BLUE: Color = Color::Blue;

        Self::with_blue(BLUE)
    }
}

/// Characters to use when rendering the diagnostic.
#[derive(Clone, Debug)]
pub struct Chars {
    /// The character to use for the top-left border of the source.
    /// Defaults to: `'┌'`.
    pub source_border_top_left: char,
    /// The character to use for the top border of the source.
    /// Defaults to: `'─'`.
    pub source_border_top: char,
    /// The character to use for the left border of the source.
    /// Defaults to: `'│'`.
    pub source_border_left: char,
    /// The character to use for the left border break of the source.
    /// Defaults to: `'·'`.
    pub source_border_left_break: char,

    /// The character to use for the note bullet.
    /// Defaults to: `'='`.
    pub note_bullet: char,

    /// The character to use for marking a primary label.
    /// Defaults to: `'^'`.
    pub primary_caret: char,
    /// The character to use for marking a secondary label.
    /// Defaults to: `'-'`.
    pub secondary_caret: char,

    /// The character to use for marking the ends of a multi-line primary label.
    /// Defaults to: `'^'`.
    pub multiline_primary_caret: char,
    /// The character to use for marking the ends of a multi-line secondary label.
    /// Defaults to: `'\''`.
    pub multiline_secondary_caret: char,
    /// The character to use for the top-left corner of a multi-line label.
    /// Defaults to: `'╭'`.
    pub multiline_top_left: char,
    /// The character to use for the top of a multi-line label.
    /// Defaults to: `'─'`.
    pub multiline_top: char,
    /// The character to use for the bottom-left corner of a multi-line label.
    /// Defaults to: `'╰'`.
    pub multiline_bottom_left: char,
    /// The character to use when marking the bottom of a multi-line label.
    /// Defaults to: `'─'`.
    pub multiline_bottom: char,
    /// The character to use for the left of a multi-line label.
    /// Defaults to: `'│'`.
    pub multiline_left: char,
}

impl Default for Chars {
    fn default() -> Chars {
        Chars {
            source_border_top_left: '┌',
            source_border_top: '─',
            source_border_left: '│',
            source_border_left_break: '·',

            note_bullet: '=',

            primary_caret: '^',
            secondary_caret: '-',

            multiline_primary_caret: '^',
            multiline_secondary_caret: '\'',
            multiline_top_left: '╭',
            multiline_top: '─',
            multiline_bottom_left: '╰',
            multiline_bottom: '─',
            multiline_left: '│',
        }
    }
}
<commit_msg>Fix some clippy lints<commit_after>use std::io;
use termcolor::{Color, ColorSpec};

use crate::diagnostic::Severity;

/// Configures how a diagnostic is rendered.
#[derive(Clone, Debug)]
pub struct Config {
    /// The display style to use when rendering diagnostics.
    /// Defaults to: `DisplayStyle::Rich`.
    pub display_style: DisplayStyle,
    /// Column width of tabs.
    /// Defaults to: `4`.
    pub tab_width: usize,
    /// Styles to use when rendering the diagnostic.
    pub styles: Styles,
    /// Characters to use when rendering the diagnostic.
    pub chars: Chars,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            display_style: DisplayStyle::Rich,
            tab_width: 4,
            styles: Styles::default(),
            chars: Chars::default(),
        }
    }
}

impl Config {
    /// Measure the width of a string, taking into account the tab width.
    pub fn width(&self, s: &str) -> usize {
        use unicode_width::UnicodeWidthChar;

        s.chars()
            .map(|ch| match ch {
                '\t' => self.tab_width,
                _ => ch.width().unwrap_or(0),
            })
            .sum()
    }

    /// Construct a source writer using the current config.
    pub fn source<'a, W: ?Sized>(&self, writer: &'a mut W) -> SourceWriter<&'a mut W> {
        SourceWriter {
            writer,
            tab_width: self.tab_width,
        }
    }
}

/// Writer that replaces tab characters with the configured number of spaces.
pub struct SourceWriter<W> {
    writer: W,
    tab_width: usize,
}

impl<W: io::Write> io::Write for SourceWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut last_term = 0usize;
        for (i, ch) in buf.iter().enumerate() {
            if *ch == b'\t' {
                self.writer.write_all(&buf[last_term..i])?;
                last_term = i + 1;
                write!(
                    self.writer,
                    "{space: >width$}",
                    space = "",
                    width = self.tab_width,
                )?;
            }
        }
        self.writer.write_all(&buf[last_term..])?;
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

/// The display style to use when rendering diagnostics.
#[derive(Clone, Debug)]
pub enum DisplayStyle {
    /// Output a richly formatted diagnostic, with source code previews.
    ///
    /// ```text
    /// error[E0001]: unexpected type in `+` application
    ///
    ///    ┌── test:2:9 ───
    ///    │
    ///  2 │ (+ test "")
    ///    │         ^^ expected `Int` but found `String`
    ///    │
    ///    = expected type `Int`
    ///         found type `String`
    ///
    /// error[E0002]: Bad config found
    ///
    /// ```
    Rich,
    /// Output a short diagnostic, with a line number, severity, and message.
    ///
    /// ```text
    /// test:2:9: error[E0001]: unexpected type in `+` application
    /// error[E0002]: Bad config found
    /// ```
    Short,
}

/// Styles to use when rendering the diagnostic.
#[derive(Clone, Debug)]
pub struct Styles {
    /// The style to use when rendering bug headers.
    /// Defaults to `fg:red bold intense`.
    pub header_bug: ColorSpec,
    /// The style to use when rendering error headers.
    /// Defaults to `fg:red bold intense`.
    pub header_error: ColorSpec,
    /// The style to use when rendering warning headers.
    /// Defaults to `fg:yellow bold intense`.
    pub header_warning: ColorSpec,
    /// The style to use when rendering note headers.
    /// Defaults to `fg:green bold intense`.
    pub header_note: ColorSpec,
    /// The style to use when rendering help headers.
    /// Defaults to `fg:cyan bold intense`.
    pub header_help: ColorSpec,
    /// The style to use when the main diagnostic message.
    /// Defaults to `bold intense`.
    pub header_message: ColorSpec,

    /// The style to use when rendering bug labels.
    /// Defaults to `fg:red`.
    pub primary_label_bug: ColorSpec,
    /// The style to use when rendering error labels.
    /// Defaults to `fg:red`.
    pub primary_label_error: ColorSpec,
    /// The style to use when rendering warning labels.
    /// Defaults to `fg:yellow`.
    pub primary_label_warning: ColorSpec,
    /// The style to use when rendering note labels.
    /// Defaults to `fg:green`.
    pub primary_label_note: ColorSpec,
    /// The style to use when rendering help labels.
    /// Defaults to `fg:cyan`.
    pub primary_label_help: ColorSpec,
    /// The style to use when rendering secondary labels.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub secondary_label: ColorSpec,

    /// The style to use when rendering the line numbers.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub line_number: ColorSpec,
    /// The style to use when rendering the source code borders.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub source_border: ColorSpec,
    /// The style to use when rendering the note bullets.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub note_bullet: ColorSpec,
}

impl Styles {
    /// The style used to mark a header at a given severity.
    pub fn header(&self, severity: Severity) -> &ColorSpec {
        match severity {
            Severity::Bug => &self.header_bug,
            Severity::Error => &self.header_error,
            Severity::Warning => &self.header_warning,
            Severity::Note => &self.header_note,
            Severity::Help => &self.header_help,
        }
    }

    /// The style used to mark a primary label at a given severity.
    pub fn primary_label(&self, severity: Severity) -> &ColorSpec {
        match severity {
            Severity::Bug => &self.primary_label_bug,
            Severity::Error => &self.primary_label_error,
            Severity::Warning => &self.primary_label_warning,
            Severity::Note => &self.primary_label_note,
            Severity::Help => &self.primary_label_help,
        }
    }

    #[doc(hidden)]
    pub fn with_blue(blue: Color) -> Styles {
        let header = ColorSpec::new().set_bold(true).set_intense(true).clone();

        Styles {
            header_bug: header.clone().set_fg(Some(Color::Red)).clone(),
            header_error: header.clone().set_fg(Some(Color::Red)).clone(),
            header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(),
            header_note: header.clone().set_fg(Some(Color::Green)).clone(),
            header_help: header.clone().set_fg(Some(Color::Cyan)).clone(),
            header_message: header,

            primary_label_bug: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_error: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_warning: ColorSpec::new().set_fg(Some(Color::Yellow)).clone(),
            primary_label_note: ColorSpec::new().set_fg(Some(Color::Green)).clone(),
            primary_label_help: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
            secondary_label: ColorSpec::new().set_fg(Some(blue)).clone(),

            line_number: ColorSpec::new().set_fg(Some(blue)).clone(),
            source_border: ColorSpec::new().set_fg(Some(blue)).clone(),
            note_bullet: ColorSpec::new().set_fg(Some(blue)).clone(),
        }
    }
}

impl Default for Styles {
    fn default() -> Styles {
        // Blue is really difficult to see on the standard windows command line
        #[cfg(windows)]
        const BLUE: Color = Color::Cyan;
        #[cfg(not(windows))]
        const BLUE: Color = Color::Blue;

        Self::with_blue(BLUE)
    }
}

/// Characters to use when rendering the diagnostic.
#[derive(Clone, Debug)]
pub struct Chars {
    /// The character to use for the top-left border of the source.
    /// Defaults to: `'┌'`.
    pub source_border_top_left: char,
    /// The character to use for the top border of the source.
    /// Defaults to: `'─'`.
    pub source_border_top: char,
    /// The character to use for the left border of the source.
    /// Defaults to: `'│'`.
    pub source_border_left: char,
    /// The character to use for the left border break of the source.
    /// Defaults to: `'·'`.
    pub source_border_left_break: char,

    /// The character to use for the note bullet.
    /// Defaults to: `'='`.
    pub note_bullet: char,

    /// The character to use for marking a primary label.
    /// Defaults to: `'^'`.
    pub primary_caret: char,
    /// The character to use for marking a secondary label.
    /// Defaults to: `'-'`.
    pub secondary_caret: char,

    /// The character to use for marking the ends of a multi-line primary label.
    /// Defaults to: `'^'`.
    pub multiline_primary_caret: char,
    /// The character to use for marking the ends of a multi-line secondary label.
    /// Defaults to: `'\''`.
    pub multiline_secondary_caret: char,
    /// The character to use for the top-left corner of a multi-line label.
    /// Defaults to: `'╭'`.
    pub multiline_top_left: char,
    /// The character to use for the top of a multi-line label.
    /// Defaults to: `'─'`.
    pub multiline_top: char,
    /// The character to use for the bottom-left corner of a multi-line label.
    /// Defaults to: `'╰'`.
    pub multiline_bottom_left: char,
    /// The character to use when marking the bottom of a multi-line label.
    /// Defaults to: `'─'`.
    pub multiline_bottom: char,
    /// The character to use for the left of a multi-line label.
    /// Defaults to: `'│'`.
    pub multiline_left: char,
}

impl Default for Chars {
    fn default() -> Chars {
        Chars {
            source_border_top_left: '┌',
            source_border_top: '─',
            source_border_left: '│',
            source_border_left_break: '·',

            note_bullet: '=',

            primary_caret: '^',
            secondary_caret: '-',

            multiline_primary_caret: '^',
            multiline_secondary_caret: '\'',
            multiline_top_left: '╭',
            multiline_top: '─',
            multiline_bottom_left: '╰',
            multiline_bottom: '─',
            multiline_left: '│',
        }
    }
}
<|endoftext|>


<commit_before>//! Generic serialization framework.

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

pub trait Serialize {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

pub trait Serializer {
    type Error;

    /// `visit_bool` serializes a `bool` value.
    fn visit_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// `visit_isize` serializes a `isize` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i8` serializes a `i8` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i16` serializes a `i16` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i32` serializes a `i32` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i64` serializes a `i64` value.
    #[inline]
    fn visit_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// `visit_usize` serializes a `usize` value. By default it casts the value to a `u64` and
    /// passes it to the `visit_u64` method.
    #[inline]
    fn visit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u8` serializes a `u8` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u64` serializes a `u64` value.
    #[inline]
    fn visit_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// `visit_f32` serializes a `f32` value. By default it casts the value to a `f64` and passes
    /// it to the `visit_f64` method.
    #[inline]
    fn visit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.visit_f64(v as f64)
    }

    /// `visit_f64` serializes a `f64` value.
    fn visit_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// `visit_char` serializes a character. By default it serializes it as a `&str` containing a
    /// single character.
    #[inline]
    fn visit_char(&mut self, v: char) -> Result<(), Self::Error> {
        // FIXME: this allocation is required in order to be compatible with stable rust, which
        // doesn't support encoding a `char` into a stack buffer.
        self.visit_str(&v.to_string())
    }

    /// `visit_str` serializes a `&str`.
    fn visit_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// `visit_bytes` is a hook that enables those serialization formats that support serializing
    /// byte slices separately from generic arrays. By default it serializes as a regular array.
    #[inline]
    fn visit_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
        self.visit_seq(impls::SeqIteratorVisitor::new(value.iter(), Some(value.len())))
    }

    fn visit_unit(&mut self) -> Result<(), Self::Error>;

    #[inline]
    fn visit_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    #[inline]
    fn visit_enum_unit(&mut self,
                       _name: &'static str,
                       _variant_index: usize,
                       _variant: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    #[inline]
    fn visit_enum_simple<T>(&mut self,
                            _name: &str,
                            _variant: &str,
                            _value: T,
                            ) -> Result<(), Self::Error>
        where T: Serialize;

    fn visit_none(&mut self) -> Result<(), Self::Error>;

    fn visit_some<V>(&mut self, value: V) -> Result<(), Self::Error>
        where V: Serialize;

    fn visit_seq<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor;

    fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize;

    #[inline]
    fn visit_tuple<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_seq(visitor)
    }

    #[inline]
    fn visit_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_seq_elt(value)
    }

    #[inline]
    fn visit_tuple_struct<V>(&mut self,
                          _name: &'static str,
                          visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple(visitor)
    }

    #[inline]
    fn visit_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_elt(value)
    }

    #[inline]
    fn visit_enum_seq<V>(&mut self,
                         _name: &'static str,
                         _variant_index: usize,
                         variant: &'static str,
                         visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple_struct(variant, visitor)
    }

    #[inline]
    fn visit_enum_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_struct_elt(value)
    }

    fn visit_map<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor;

    fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize;

    #[inline]
    fn visit_struct<V>(&mut self,
                          _name: &'static str,
                          visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_map(visitor)
    }

    #[inline]
    fn visit_struct_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize,
    {
        self.visit_map_elt(key, value)
    }

    #[inline]
    fn visit_enum_map<V>(&mut self,
                         _name: &'static str,
                         _variant_index: usize,
                         variant: &'static str,
                         visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_struct(variant, visitor)
    }

    #[inline]
    fn visit_enum_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize,
    {
        self.visit_struct_elt(key, value)
    }

    /// Specify a format string for the serializer.
    ///
    /// The serializer format is used to determine which format
    /// specific field attributes should be used with the serializer.
    fn format() -> &'static str {
        ""
    }
}

pub trait SeqVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the sequence if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}

pub trait MapVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the map if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}
<commit_msg>Re-indent<commit_after>//! Generic serialization framework.

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

pub trait Serialize {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

pub trait Serializer {
    type Error;

    /// `visit_bool` serializes a `bool` value.
    fn visit_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// `visit_isize` serializes a `isize` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i8` serializes a `i8` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i16` serializes a `i16` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i32` serializes a `i32` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i64` serializes a `i64` value.
    #[inline]
    fn visit_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// `visit_usize` serializes a `usize` value. By default it casts the value to a `u64` and
    /// passes it to the `visit_u64` method.
    #[inline]
    fn visit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u8` serializes a `u8` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u64` serializes a `u64` value.
    #[inline]
    fn visit_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// `visit_f32` serializes a `f32` value. By default it casts the value to a `f64` and passes
    /// it to the `visit_f64` method.
    #[inline]
    fn visit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.visit_f64(v as f64)
    }

    /// `visit_f64` serializes a `f64` value.
    fn visit_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// `visit_char` serializes a character. By default it serializes it as a `&str` containing a
    /// single character.
    #[inline]
    fn visit_char(&mut self, v: char) -> Result<(), Self::Error> {
        // FIXME: this allocation is required in order to be compatible with stable rust, which
        // doesn't support encoding a `char` into a stack buffer.
        self.visit_str(&v.to_string())
    }

    /// `visit_str` serializes a `&str`.
    fn visit_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// `visit_bytes` is a hook that enables those serialization formats that support serializing
    /// byte slices separately from generic arrays. By default it serializes as a regular array.
    #[inline]
    fn visit_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
        self.visit_seq(impls::SeqIteratorVisitor::new(value.iter(), Some(value.len())))
    }

    fn visit_unit(&mut self) -> Result<(), Self::Error>;

    #[inline]
    fn visit_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    #[inline]
    fn visit_enum_unit(&mut self,
                       _name: &'static str,
                       _variant_index: usize,
                       _variant: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    #[inline]
    fn visit_enum_simple<T>(&mut self,
                            _name: &str,
                            _variant: &str,
                            _value: T,
                            ) -> Result<(), Self::Error>
        where T: Serialize;

    fn visit_none(&mut self) -> Result<(), Self::Error>;

    fn visit_some<V>(&mut self, value: V) -> Result<(), Self::Error>
        where V: Serialize;

    fn visit_seq<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor;

    fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize;

    #[inline]
    fn visit_tuple<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_seq(visitor)
    }

    #[inline]
    fn visit_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_seq_elt(value)
    }

    #[inline]
    fn visit_tuple_struct<V>(&mut self,
                             _name: &'static str,
                             visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple(visitor)
    }

    #[inline]
    fn visit_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_elt(value)
    }

    #[inline]
    fn visit_enum_seq<V>(&mut self,
                         _name: &'static str,
                         _variant_index: usize,
                         variant: &'static str,
                         visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple_struct(variant, visitor)
    }

    #[inline]
    fn visit_enum_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_struct_elt(value)
    }

    fn visit_map<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor;

    fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize;

    #[inline]
    fn visit_struct<V>(&mut self,
                       _name: &'static str,
                       visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_map(visitor)
    }

    #[inline]
    fn visit_struct_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize,
    {
        self.visit_map_elt(key, value)
    }

    #[inline]
    fn visit_enum_map<V>(&mut self,
                         _name: &'static str,
                         _variant_index: usize,
                         variant: &'static str,
                         visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_struct(variant, visitor)
    }

    #[inline]
    fn visit_enum_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize,
    {
        self.visit_struct_elt(key, value)
    }

    /// Specify a format string for the serializer.
    ///
    /// The serializer format is used to determine which format
    /// specific field attributes should be used with the serializer.
    fn format() -> &'static str {
        ""
    }
}

pub trait SeqVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the sequence if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}

pub trait MapVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the map if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}
<|endoftext|>


<commit_before>//! This example demonstrates how to roll your own event loop,
//! if for some reason you want to do that instead of using the `EventHandler`
//! trait to do that for you.
//!
//! This is exactly how `ggez::event::run()` works, it really is not
//! doing anything magical.  But, if you want a bit more power over
//! the control flow of your game, this is how you get it.
//!
//! It is functionally identical to the `super_simple.rs` example apart from that.

use ggez::event;
use ggez::event::winit_event::{Event, KeyboardInput, WindowEvent};
use ggez::graphics::{self, Color, DrawMode};
use ggez::GameResult;

pub fn main() -> GameResult {
    let cb = ggez::ContextBuilder::new("eventloop", "ggez");
    let (ref mut ctx, mut events_loop) = cb.build()?;

    let mut position: f32 = 1.0;

    // This is also used in the loop inside `::run()` - it can be flipped off with `event::quit()`
    while ctx.continuing {
        // Tell the timer stuff a frame has happened.
        // Without this the FPS timer functions and such won't work.
        ctx.timer_context.tick();
        // Handle events. Refer to `winit` docs for more information.
        use winit::platform::run_return::EventLoopExtRunReturn;
        events_loop.run_return(|event, _window_target, control_flow| {
            // This tells `ggez` to update it's internal states, should the event require that.
            // These include cursor position, view updating on resize, etc.
            event::process_event(ctx, &event);
            match event {
                Event::WindowEvent { event, .. } => match event {
                    WindowEvent::CloseRequested => event::quit(ctx),
                    WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                virtual_keycode: Some(keycode),
                                ..
                            },
                        ..
                    } => {
                        if let event::KeyCode::Escape = keycode {
                            *control_flow = winit::event_loop::ControlFlow::Exit
                        }
                    }
                    // `CloseRequested` and `KeyboardInput` events won't appear here.
                    x => println!("Other window event fired: {:?}", x),
                },

                x => println!("Device event fired: {:?}", x),
            }
        });

        // Update
        position += 1.0;

        // Draw
        graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());
        let circle = graphics::Mesh::new_circle(
            ctx,
            DrawMode::fill(),
            glam::Vec2::new(0.0, 0.0),
            100.0,
            2.0,
            Color::WHITE,
        )?;
        graphics::draw(ctx, &circle, (glam::Vec2::new(position, 380.0),))?;
        graphics::present(ctx)?;
        ggez::timer::yield_now();
    }
    Ok(())
}
<commit_msg>fixed eventloop example by updating it to actually work like the current implementation of ggez::event::run()<commit_after>//! This example demonstrates how to roll your own event loop,
//! if for some reason you want to do that instead of using the `EventHandler`
//! trait to do that for you.
//!
//! This is exactly how `ggez::event::run()` works, it really is not
//! doing anything magical.  But, if you want a bit more power over
//! the control flow of your game, this is how you get it.
//!
//! It is functionally identical to the `super_simple.rs` example apart from that.

use ggez::event;
use ggez::event::winit_event::{Event, KeyboardInput, WindowEvent};
use ggez::graphics::{self, Color, DrawMode};
use ggez::GameResult;
use winit::event_loop::ControlFlow;

pub fn main() -> GameResult {
    let cb = ggez::ContextBuilder::new("eventloop", "ggez");
    let (mut ctx, events_loop) = cb.build()?;

    let mut position: f32 = 1.0;

    // Handle events. Refer to `winit` docs for more information.
    events_loop.run(move |event, _window_target, control_flow| {
        if !ctx.continuing {
            *control_flow = ControlFlow::Exit;
            return;
        }

        *control_flow = ControlFlow::Poll;

        let ctx = &mut ctx;

        // This tells `ggez` to update it's internal states, should the event require that.
        // These include cursor position, view updating on resize, etc.
        event::process_event(ctx, &event);
        match event {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::CloseRequested => event::quit(ctx),
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            virtual_keycode: Some(keycode),
                            ..
                        },
                    ..
                } => {
                    if let event::KeyCode::Escape = keycode {
                        *control_flow = winit::event_loop::ControlFlow::Exit
                    }
                }
                // `CloseRequested` and `KeyboardInput` events won't appear here.
                x => println!("Other window event fired: {:?}", x),
            },
            Event::MainEventsCleared => {
                // Tell the timer stuff a frame has happened.
                // Without this the FPS timer functions and such won't work.
                ctx.timer_context.tick();

                // Update
                position += 1.0;

                // Draw
                graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());
                let circle = graphics::Mesh::new_circle(
                    ctx,
                    DrawMode::fill(),
                    glam::Vec2::new(0.0, 0.0),
                    100.0,
                    2.0,
                    Color::WHITE,
                )
                .unwrap();
                graphics::draw(ctx, &circle, (glam::Vec2::new(position, 380.0),)).unwrap();
                graphics::present(ctx).unwrap();
                ggez::timer::yield_now();
            }

            x => println!("Device event fired: {:?}", x),
        }
    });
}
<|endoftext|>


<commit_before>extern crate polydraw;

use polydraw::os::x11::{Display};

fn main() {
   let display = Display::default().unwrap();

   println!("{:?}", display.ptr);

   let connection = display.xcb_connection().unwrap();

   println!("{:?}", connection.ptr);

   display.xcb_own_event_queue();
}
<commit_msg>Delete unused example code<commit_after><|endoftext|>


<commit_before>use crate::{
    compiler::{
        error::{CompilerError, CompilerErrorPayload},
        hir::HirError,
    },
    database::Database,
    module::{Module, ModuleDb, Package},
};
use itertools::Itertools;
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Url};
use std::{ops::Range, sync::Arc};

impl CompilerError {
    pub fn into_diagnostic(self, db: &Database, module: Module) -> Diagnostic {
        Diagnostic {
            range: lsp_types::Range {
                start: db
                    .offset_to_lsp(module.clone(), self.span.start)
                    .to_position(),
                end: db.offset_to_lsp(module, self.span.end).to_position(),
            },
            severity: Some(DiagnosticSeverity::ERROR),
            code: None,
            code_description: None,
            source: Some("🍭 Candy".to_owned()),
            message: match self.payload {
                CompilerErrorPayload::InvalidUtf8 => "Invalid UTF-8".to_string(),
                CompilerErrorPayload::Rcst(rcst) => format!("RCST: {rcst:?}"),
                CompilerErrorPayload::Ast(ast) => format!("AST: {ast:?}"),
                CompilerErrorPayload::Hir(hir) => hir.format_message(),
            },
            related_information: None,
            tags: None,
            data: None,
        }
    }
}

impl HirError {
    fn format_message(&self) -> String {
        match self {
            HirError::UnknownReference { name } => format!("Unknown reference “{name}”."),
            HirError::PublicAssignmentInNotTopLevel => {
                "Public assignments (:=) can only be used in top-level code.".to_string()
            }
            HirError::PublicAssignmentWithSameName { .. } => "A public assignment with the same name already exists.".to_string(),
            HirError::NeedsWithWrongNumberOfArguments { num_args } => format!("`needs` accepts one or two arguments, but was called with {num_args} arguments. Its parameters are the `condition` and an optional `message`."),
        }
    }
}

impl From<Module> for Url {
    fn from(module: Module) -> Url {
        match module.package {
            Package::User(_) | Package::External(_) => Url::from_file_path(
                module
                    .to_possible_paths()
                    .unwrap()
                    .into_iter()
                    .find(|path| path.exists())
                    .unwrap(),
            )
            .unwrap(),
            Package::Anonymous { .. } => Url::parse("untitled").unwrap(),
        }
    }
}

// UTF-8 Byte Offset ↔ LSP Position/Range

impl Database {
    pub fn range_to_lsp(&self, module: Module, range: Range<usize>) -> lsp_types::Range {
        lsp_types::Range {
            start: self
                .offset_to_lsp(module.clone(), range.start)
                .to_position(),
            end: self.offset_to_lsp(module, range.end).to_position(),
        }
    }
}

#[salsa::query_group(LspPositionConversionStorage)]
pub trait LspPositionConversion: ModuleDb {
    // `lsp_types::Range` and `::Position` don't implement `Hash`, so they can't
    // be used as query keys directly.
    //
    // As its unlikely that a conversion is called multiple times with the same
    // key, we shouldn't loose much performance by not caching the individual
    // results.
    #[salsa::transparent]
    fn offset_from_lsp(&self, module: Module, line: u32, character: u32) -> usize;
    #[salsa::transparent]
    fn offset_to_lsp(&self, module: Module, position: usize) -> (u32, u32);

    fn line_start_utf8_byte_offsets(&self, module: Module) -> Arc<Vec<usize>>;
}

fn offset_from_lsp(
    db: &dyn LspPositionConversion,
    module: Module,
    line: u32,
    character: u32,
) -> usize {
    let text = db.get_module_content_as_string(module.clone()).unwrap();
    let line_start_offsets = db.line_start_utf8_byte_offsets(module);
    offset_from_lsp_raw(
        text.as_ref(),
        line_start_offsets.as_ref(),
        Position { line, character },
    )
}
pub fn offset_from_lsp_raw(text: &str, line_start_offsets: &[usize], position: Position) -> usize {
    let line_offset = line_start_offsets[position.line as usize];
    let line_length = if position.line as usize == line_start_offsets.len() - 1 {
        text.len() - line_offset
    } else {
        line_start_offsets[(position.line + 1) as usize] - line_offset
    };

    let line = &text[line_offset..line_offset + line_length];

    let words = line.encode_utf16().collect::<Vec<_>>();
    let char_offset = if position.character as usize >= words.len() {
        line_length
    } else {
        String::from_utf16(&words[0..position.character as usize])
            .unwrap()
            .len()
    };

    line_offset + char_offset
}

fn offset_to_lsp(db: &dyn LspPositionConversion, module: Module, mut offset: usize) -> (u32, u32) {
    let text = db.get_module_content_as_string(module.clone()).unwrap();
    if offset > text.len() {
        offset = text.len();
    }
    let line_start_offsets = db.line_start_utf8_byte_offsets(module);

    let line = line_start_offsets
        .binary_search(&offset)
        .unwrap_or_else(|i| i - 1);

    let line_start = line_start_offsets[line];
    let character_utf16_offset = text[line_start..offset.to_owned()].encode_utf16().count();
    (line as u32, character_utf16_offset as u32)
}

pub trait TupleToPosition {
    fn to_position(&self) -> Position;
}
impl TupleToPosition for (u32, u32) {
    fn to_position(&self) -> Position {
        Position {
            line: self.0,
            character: self.1,
        }
    }
}

fn line_start_utf8_byte_offsets(db: &dyn LspPositionConversion, module: Module) -> Arc<Vec<usize>> {
    let text = db.get_module_content_as_string(module).unwrap();
    Arc::new(line_start_utf8_byte_offsets_raw(&text))
}
pub fn line_start_utf8_byte_offsets_raw(text: &str) -> Vec<usize> {
    let mut offsets = vec![0];
    offsets.append(
        &mut text
            .bytes()
            .enumerate()
            .filter(|(_, it)| it == &b'\n')
            .map(|(index, _)| index + 1)
            .collect(),
    );
    offsets
}

pub trait JoinWithCommasAndAnd {
    fn join_with_commas_and_and(self) -> String;
}
impl JoinWithCommasAndAnd for Vec<String> {
    fn join_with_commas_and_and(mut self) -> String {
        match &self[..] {
            [] => panic!("Joining no parts."),
            [part] => part.to_string(),
            [first, second] => format!("{first} and {second}"),
            _ => {
                let last = self.pop().unwrap();
                format!("{}, and {last}", self.into_iter().join(", "))
            }
        }
    }
}
<commit_msg>Fix Url creation of anonymous packages<commit_after>use crate::{
    compiler::{
        error::{CompilerError, CompilerErrorPayload},
        hir::HirError,
    },
    database::Database,
    module::{Module, ModuleDb, Package},
};
use itertools::Itertools;
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Url};
use std::{ops::Range, sync::Arc};

impl CompilerError {
    pub fn into_diagnostic(self, db: &Database, module: Module) -> Diagnostic {
        Diagnostic {
            range: lsp_types::Range {
                start: db
                    .offset_to_lsp(module.clone(), self.span.start)
                    .to_position(),
                end: db.offset_to_lsp(module, self.span.end).to_position(),
            },
            severity: Some(DiagnosticSeverity::ERROR),
            code: None,
            code_description: None,
            source: Some("🍭 Candy".to_owned()),
            message: match self.payload {
                CompilerErrorPayload::InvalidUtf8 => "Invalid UTF-8".to_string(),
                CompilerErrorPayload::Rcst(rcst) => format!("RCST: {rcst:?}"),
                CompilerErrorPayload::Ast(ast) => format!("AST: {ast:?}"),
                CompilerErrorPayload::Hir(hir) => hir.format_message(),
            },
            related_information: None,
            tags: None,
            data: None,
        }
    }
}

impl HirError {
    fn format_message(&self) -> String {
        match self {
            HirError::UnknownReference { name } => format!("Unknown reference “{name}”."),
            HirError::PublicAssignmentInNotTopLevel => {
                "Public assignments (:=) can only be used in top-level code.".to_string()
            }
            HirError::PublicAssignmentWithSameName { .. } => "A public assignment with the same name already exists.".to_string(),
            HirError::NeedsWithWrongNumberOfArguments { num_args } => format!("`needs` accepts one or two arguments, but was called with {num_args} arguments. Its parameters are the `condition` and an optional `message`."),
        }
    }
}

impl From<Module> for Url {
    fn from(module: Module) -> Url {
        match module.package {
            Package::User(_) | Package::External(_) => Url::from_file_path(
                module
                    .to_possible_paths()
                    .unwrap()
                    .into_iter()
                    .find(|path| path.exists())
                    .unwrap(),
            )
            .unwrap(),
            Package::Anonymous { root_content } => Url::parse(&format!(
                "untitled:{}",
                String::from_utf8((*root_content).clone()).unwrap()
            ))
            .unwrap(),
        }
    }
}

// UTF-8 Byte Offset ↔ LSP Position/Range

impl Database {
    pub fn range_to_lsp(&self, module: Module, range: Range<usize>) -> lsp_types::Range {
        lsp_types::Range {
            start: self
                .offset_to_lsp(module.clone(), range.start)
                .to_position(),
            end: self.offset_to_lsp(module, range.end).to_position(),
        }
    }
}

#[salsa::query_group(LspPositionConversionStorage)]
pub trait LspPositionConversion: ModuleDb {
    // `lsp_types::Range` and `::Position` don't implement `Hash`, so they can't
    // be used as query keys directly.
    //
    // As its unlikely that a conversion is called multiple times with the same
    // key, we shouldn't loose much performance by not caching the individual
    // results.
    #[salsa::transparent]
    fn offset_from_lsp(&self, module: Module, line: u32, character: u32) -> usize;
    #[salsa::transparent]
    fn offset_to_lsp(&self, module: Module, position: usize) -> (u32, u32);

    fn line_start_utf8_byte_offsets(&self, module: Module) -> Arc<Vec<usize>>;
}

fn offset_from_lsp(
    db: &dyn LspPositionConversion,
    module: Module,
    line: u32,
    character: u32,
) -> usize {
    let text = db.get_module_content_as_string(module.clone()).unwrap();
    let line_start_offsets = db.line_start_utf8_byte_offsets(module);
    offset_from_lsp_raw(
        text.as_ref(),
        line_start_offsets.as_ref(),
        Position { line, character },
    )
}
pub fn offset_from_lsp_raw(text: &str, line_start_offsets: &[usize], position: Position) -> usize {
    let line_offset = line_start_offsets[position.line as usize];
    let line_length = if position.line as usize == line_start_offsets.len() - 1 {
        text.len() - line_offset
    } else {
        line_start_offsets[(position.line + 1) as usize] - line_offset
    };

    let line = &text[line_offset..line_offset + line_length];

    let words = line.encode_utf16().collect::<Vec<_>>();
    let char_offset = if position.character as usize >= words.len() {
        line_length
    } else {
        String::from_utf16(&words[0..position.character as usize])
            .unwrap()
            .len()
    };

    line_offset + char_offset
}

fn offset_to_lsp(db: &dyn LspPositionConversion, module: Module, mut offset: usize) -> (u32, u32) {
    let text = db.get_module_content_as_string(module.clone()).unwrap();
    if offset > text.len() {
        offset = text.len();
    }
    let line_start_offsets = db.line_start_utf8_byte_offsets(module);

    let line = line_start_offsets
        .binary_search(&offset)
        .unwrap_or_else(|i| i - 1);

    let line_start = line_start_offsets[line];
    let character_utf16_offset = text[line_start..offset.to_owned()].encode_utf16().count();
    (line as u32, character_utf16_offset as u32)
}

pub trait TupleToPosition {
    fn to_position(&self) -> Position;
}
impl TupleToPosition for (u32, u32) {
    fn to_position(&self) -> Position {
        Position {
            line: self.0,
            character: self.1,
        }
    }
}

fn line_start_utf8_byte_offsets(db: &dyn LspPositionConversion, module: Module) -> Arc<Vec<usize>> {
    let text = db.get_module_content_as_string(module).unwrap();
    Arc::new(line_start_utf8_byte_offsets_raw(&text))
}
pub fn line_start_utf8_byte_offsets_raw(text: &str) -> Vec<usize> {
    let mut offsets = vec![0];
    offsets.append(
        &mut text
            .bytes()
            .enumerate()
            .filter(|(_, it)| it == &b'\n')
            .map(|(index, _)| index + 1)
            .collect(),
    );
    offsets
}

pub trait JoinWithCommasAndAnd {
    fn join_with_commas_and_and(self) -> String;
}
impl JoinWithCommasAndAnd for Vec<String> {
    fn join_with_commas_and_and(mut self) -> String {
        match &self[..] {
            [] => panic!("Joining no parts."),
            [part] => part.to_string(),
            [first, second] => format!("{first} and {second}"),
            _ => {
                let last = self.pop().unwrap();
                format!("{}, and {last}", self.into_iter().join(", "))
            }
        }
    }
}
<|endoftext|>