<commit_before>use {Client, Result};
use Error::{self, ArgumentError, OperationError};

use bson::{self, Bson, oid};
use chrono::{DateTime, UTC};

use coll::options::FindOptions;
use command_type::CommandType;
use connstring::{self, Host};
use cursor::Cursor;
use pool::ConnectionPool;
use wire_protocol::flags::OpQueryFlags;

use std::collections::BTreeMap;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread;

use super::server::{ServerDescription, ServerType};
use super::{DEFAULT_HEARTBEAT_FREQUENCY_MS, TopologyDescription};

const DEFAULT_MAX_BSON_OBJECT_SIZE: i64 = 16 * 1024 * 1024;
const DEFAULT_MAX_MESSAGE_SIZE_BYTES: i64 = 48000000;

/// The result of an isMaster operation.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IsMasterResult {
    pub ok: bool,
    pub is_master: bool,
    pub max_bson_object_size: i64,
    pub max_message_size_bytes: i64,
    pub local_time: Option<DateTime<UTC>>,
    pub min_wire_version: i64,
    pub max_wire_version: i64,

    /// Shard-specific. mongos instances will add this field to the
    /// isMaster reply, and it will contain the value "isdbgrid".
    pub msg: String,

    // Replica Set specific
    pub is_replica_set: bool,
    pub is_secondary: bool,
    pub me: Option<Host>,
    pub hosts: Vec<Host>,
    pub passives: Vec<Host>,
    pub arbiters: Vec<Host>,
    pub arbiter_only: bool,
    pub tags: BTreeMap<String, String>,
    pub set_name: String,
    pub election_id: Option<oid::ObjectId>,
    pub primary: Option<Host>,
    pub hidden: bool,
}

/// Monitors and updates server and topology information.
pub struct Monitor {
    // Host being monitored.
    host: Host,
    // Connection pool for the host.
    server_pool: Arc<ConnectionPool>,
    // Topology description to update.
    top_description: Arc<RwLock<TopologyDescription>>,
    // Server description to update.
    server_description: Arc<RwLock<ServerDescription>>,
    // Client reference.
    client: Client,
    // Owned, single-threaded pool.
    personal_pool: Arc<ConnectionPool>,
    heartbeat_frequency_ms: AtomicUsize,
    /// While true, the monitor will check server connection health
    /// at the topology's heartbeat frequency rate.
    pub running: Arc<AtomicBool>,
}

impl IsMasterResult {
    /// Parses an isMaster response document from the server.
    pub fn new(doc: bson::Document) -> Result<IsMasterResult> {
        let ok = match doc.get("ok") {
            Some(&Bson::I64(v)) => if v == 0 { false } else { true },
            _ => return Err(ArgumentError("result does not contain `ok`.".to_owned())),
        };

        let mut result = IsMasterResult {
            ok: ok,
            is_master: false,
            max_bson_object_size: DEFAULT_MAX_BSON_OBJECT_SIZE,
            max_message_size_bytes: DEFAULT_MAX_MESSAGE_SIZE_BYTES,
            local_time: None,
            min_wire_version: -1,
            max_wire_version: -1,
            msg: String::new(),
            is_secondary: false,
            is_replica_set: false,
            me: None,
            hosts: Vec::new(),
            passives: Vec::new(),
            arbiters: Vec::new(),
            arbiter_only: false,
            tags: BTreeMap::new(),
            set_name: String::new(),
            election_id: None,
            primary: None,
            hidden: false,
        };

        if let Some(&Bson::Boolean(b)) = doc.get("ismaster") {
            result.is_master = b;
        }

        if let Some(&Bson::UtcDatetime(ref datetime)) = doc.get("localTime") {
            result.local_time = Some(datetime.clone());
        }

        if let Some(&Bson::I64(v)) = doc.get("minWireVersion") {
            result.min_wire_version = v;
        }

        if let Some(&Bson::I64(v)) = doc.get("maxWireVersion") {
            result.max_wire_version = v;
        }

        if let Some(&Bson::String(ref s)) = doc.get("msg") {
            result.msg = s.to_owned();
        }

        if let Some(&Bson::Boolean(ref b)) = doc.get("secondary") {
            result.is_secondary = *b;
        }

        if let Some(&Bson::Boolean(ref b)) = doc.get("isreplicaset") {
            result.is_replica_set = *b;
        }

        if let Some(&Bson::String(ref s)) = doc.get("setName") {
            result.set_name = s.to_owned();
        }

        if let Some(&Bson::String(ref s)) = doc.get("me") {
            result.me = Some(try!(connstring::parse_host(s)));
        }

        if let Some(&Bson::Array(ref arr)) = doc.get("hosts") {
            result.hosts = arr.iter().filter_map(|bson| match bson {
                &Bson::String(ref s) => connstring::parse_host(s).ok(),
                _ => None,
            }).collect();
        }

        if let Some(&Bson::Array(ref arr)) = doc.get("passives") {
            result.passives = arr.iter().filter_map(|bson| match bson {
                &Bson::String(ref s) => connstring::parse_host(s).ok(),
                _ => None,
            }).collect();
        }

        if let Some(&Bson::Array(ref arr)) = doc.get("arbiters") {
            result.arbiters = arr.iter().filter_map(|bson| match bson {
                &Bson::String(ref s) => connstring::parse_host(s).ok(),
                _ => None,
            }).collect();
        }

        if let Some(&Bson::String(ref s)) = doc.get("primary") {
            result.primary = Some(try!(connstring::parse_host(s)));
        }

        if let Some(&Bson::Boolean(ref b)) = doc.get("arbiterOnly") {
            result.arbiter_only = *b;
        }

        if let Some(&Bson::Boolean(ref h)) = doc.get("hidden") {
            result.hidden = *h;
        }

        if let Some(&Bson::Document(ref doc)) = doc.get("tags") {
            for (k, v) in doc.into_iter() {
                if let &Bson::String(ref tag) = v {
                    result.tags.insert(k.to_owned(), tag.to_owned());
                }
            }
        }

        match doc.get("electionId") {
            Some(&Bson::ObjectId(ref id)) => result.election_id = Some(id.clone()),
            Some(&Bson::Document(ref doc)) => if let Some(&Bson::String(ref s)) = doc.get("$oid") {
                result.election_id = Some(try!(oid::ObjectId::with_string(s)));
            },
            _ => (),
        }

        Ok(result)
    }
}

impl Monitor {
    /// Returns a new monitor connected to the server.
    pub fn new(client: Client, host: Host, pool: Arc<ConnectionPool>,
               top_description: Arc<RwLock<TopologyDescription>>,
               server_description: Arc<RwLock<ServerDescription>>) -> Monitor {

        Monitor {
            client: client,
            host: host.clone(),
            server_pool: pool,
            personal_pool: Arc::new(ConnectionPool::with_size(host, 1)),
            top_description: top_description,
            server_description: server_description,
            heartbeat_frequency_ms: AtomicUsize::new(DEFAULT_HEARTBEAT_FREQUENCY_MS as usize),
            running: Arc::new(AtomicBool::new(false)),
        }
    }

    // Set server description error field.
    fn set_err(&self, err: Error) {
        let mut server_description = self.server_description.write().unwrap();
        server_description.set_err(err);
        self.update_top_description(server_description.clone());
    }

    /// Returns an isMaster server response using an owned monitor socket.
    pub fn is_master(&self) -> Result<Cursor> {
        let options = FindOptions::new().with_limit(1);
        let flags = OpQueryFlags::with_find_options(&options);
        let mut filter = bson::Document::new();
        filter.insert("isMaster".to_owned(), Bson::I32(1));

        let stream = try!(self.personal_pool.acquire_stream());

        Cursor::query_with_stream(
            stream, self.client.clone(), "local.$cmd".to_owned(), 1,
            flags, options.skip as i32, 1, filter.clone(), options.projection.clone(),
            CommandType::IsMaster, false, None)
    }

    // Updates the server description associated with this monitor using an isMaster server response.
    fn update_server_description(&self, doc: bson::Document) -> Result<ServerDescription> {
        let ismaster_result = IsMasterResult::new(doc);
        let mut server_description = self.server_description.write().unwrap();
        match ismaster_result {
            Ok(ismaster) => server_description.update(ismaster),
            Err(err) => {
                server_description.set_err(err);
                return Err(OperationError("Failed to parse ismaster result.".to_owned()))
            },
        }

        Ok(server_description.clone())
    }

    // Updates the topology description associated with this monitor using a new server description.
    fn update_top_description(&self, description: ServerDescription) {
        let mut top_description = self.top_description.write().unwrap();
        top_description.update(self.host.clone(), description, self.client.clone(),
                               self.top_description.clone());
    }

    // Updates server and topology descriptions using a successful isMaster cursor result.
    fn update_with_is_master_cursor(&self, cursor: &mut Cursor) {
        match cursor.next() {
            Some(Ok(doc)) => {
                if let Ok(description) = self.update_server_description(doc) {
                    self.update_top_description(description);
                }
            },
            Some(Err(err)) => {
                self.set_err(err);
            },
            None => {
                self.set_err(OperationError("ismaster returned no response.".to_owned()));
            }
        }
    }

    /// Execute isMaster and update the server and topology.
    pub fn execute_update(&self) {
        match self.is_master() {
            Ok(mut cursor) => self.update_with_is_master_cursor(&mut cursor),
            Err(err) => {
                // Refresh all connections
                self.server_pool.clear();
                self.personal_pool.clear();

                let stype = self.server_description.read().unwrap().server_type;

                if stype == ServerType::Unknown {
                    self.set_err(err);
                } else {
                    // Retry once
                    match self.is_master() {
                        Ok(mut cursor) => self.update_with_is_master_cursor(&mut cursor),
                        Err(err) => self.set_err(err),
                    }
                }
            }
        }
    }

    /// Starts server monitoring.
    pub fn run(&self) {
        if self.running.load(Ordering::SeqCst) {
            return;
        }

        self.running.store(true, Ordering::SeqCst);

        loop {
            if !self.running.load(Ordering::SeqCst) {
                break;
            }

            self.execute_update();

            if let Ok(description) = self.top_description.read() {
                self.heartbeat_frequency_ms.store(description.heartbeat_frequency_ms as usize,
                                                  Ordering::SeqCst);
            }

            thread::sleep_ms(self.heartbeat_frequency_ms.load(Ordering::SeqCst) as u32);
        }
    }
}
<commit_msg>Allow monitor to be woken up with Condvar<commit_after>use {Client, Result};
use Error::{self, ArgumentError, OperationError};

use bson::{self, Bson, oid};
use chrono::{DateTime, UTC};

use coll::options::FindOptions;
use command_type::CommandType;
use connstring::{self, Host};
use cursor::Cursor;
use pool::ConnectionPool;
use wire_protocol::flags::OpQueryFlags;

use std::collections::BTreeMap;
use std::sync::{Arc, Condvar, Mutex, RwLock};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use super::server::{ServerDescription, ServerType};
use super::{DEFAULT_HEARTBEAT_FREQUENCY_MS, TopologyDescription};

const DEFAULT_MAX_BSON_OBJECT_SIZE: i64 = 16 * 1024 * 1024;
const DEFAULT_MAX_MESSAGE_SIZE_BYTES: i64 = 48000000;

/// The result of an isMaster operation.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IsMasterResult {
    pub ok: bool,
    pub is_master: bool,
    pub max_bson_object_size: i64,
    pub max_message_size_bytes: i64,
    pub local_time: Option<DateTime<UTC>>,
    pub min_wire_version: i64,
    pub max_wire_version: i64,

    /// Shard-specific. mongos instances will add this field to the
    /// isMaster reply, and it will contain the value "isdbgrid".
    pub msg: String,

    // Replica Set specific
    pub is_replica_set: bool,
    pub is_secondary: bool,
    pub me: Option<Host>,
    pub hosts: Vec<Host>,
    pub passives: Vec<Host>,
    pub arbiters: Vec<Host>,
    pub arbiter_only: bool,
    pub tags: BTreeMap<String, String>,
    pub set_name: String,
    pub election_id: Option<oid::ObjectId>,
    pub primary: Option<Host>,
    pub hidden: bool,
}

/// Monitors and updates server and topology information.
pub struct Monitor {
    // Host being monitored.
    host: Host,
    // Connection pool for the host.
    server_pool: Arc<ConnectionPool>,
    // Topology description to update.
    top_description: Arc<RwLock<TopologyDescription>>,
    // Server description to update.
    server_description: Arc<RwLock<ServerDescription>>,
    // Client reference.
    client: Client,
    // Owned, single-threaded pool.
    personal_pool: Arc<ConnectionPool>,
    heartbeat_frequency_ms: AtomicUsize,
    dummy_lock: Mutex<()>,
    condvar: Condvar,
    /// While true, the monitor will check server connection health
    /// at the topology's heartbeat frequency rate.
    pub running: Arc<AtomicBool>,
}

impl IsMasterResult {
    /// Parses an isMaster response document from the server.
    pub fn new(doc: bson::Document) -> Result<IsMasterResult> {
        let ok = match doc.get("ok") {
            Some(&Bson::I64(v)) => if v == 0 { false } else { true },
            _ => return Err(ArgumentError("result does not contain `ok`.".to_owned())),
        };

        let mut result = IsMasterResult {
            ok: ok,
            is_master: false,
            max_bson_object_size: DEFAULT_MAX_BSON_OBJECT_SIZE,
            max_message_size_bytes: DEFAULT_MAX_MESSAGE_SIZE_BYTES,
            local_time: None,
            min_wire_version: -1,
            max_wire_version: -1,
            msg: String::new(),
            is_secondary: false,
            is_replica_set: false,
            me: None,
            hosts: Vec::new(),
            passives: Vec::new(),
            arbiters: Vec::new(),
            arbiter_only: false,
            tags: BTreeMap::new(),
            set_name: String::new(),
            election_id: None,
            primary: None,
            hidden: false,
        };

        if let Some(&Bson::Boolean(b)) = doc.get("ismaster") {
            result.is_master = b;
        }

        if let Some(&Bson::UtcDatetime(ref datetime)) = doc.get("localTime") {
            result.local_time = Some(datetime.clone());
        }

        if let Some(&Bson::I64(v)) = doc.get("minWireVersion") {
            result.min_wire_version = v;
        }

        if let Some(&Bson::I64(v)) = doc.get("maxWireVersion") {
            result.max_wire_version = v;
        }

        if let Some(&Bson::String(ref s)) = doc.get("msg") {
            result.msg = s.to_owned();
        }

        if let Some(&Bson::Boolean(ref b)) = doc.get("secondary") {
            result.is_secondary = *b;
        }

        if let Some(&Bson::Boolean(ref b)) = doc.get("isreplicaset") {
            result.is_replica_set = *b;
        }

        if let Some(&Bson::String(ref s)) = doc.get("setName") {
            result.set_name = s.to_owned();
        }

        if let Some(&Bson::String(ref s)) = doc.get("me") {
            result.me = Some(try!(connstring::parse_host(s)));
        }

        if let Some(&Bson::Array(ref arr)) = doc.get("hosts") {
            result.hosts = arr.iter().filter_map(|bson| match bson {
                &Bson::String(ref s) => connstring::parse_host(s).ok(),
                _ => None,
            }).collect();
        }

        if let Some(&Bson::Array(ref arr)) = doc.get("passives") {
            result.passives = arr.iter().filter_map(|bson| match bson {
                &Bson::String(ref s) => connstring::parse_host(s).ok(),
                _ => None,
            }).collect();
        }

        if let Some(&Bson::Array(ref arr)) = doc.get("arbiters") {
            result.arbiters = arr.iter().filter_map(|bson| match bson {
                &Bson::String(ref s) => connstring::parse_host(s).ok(),
                _ => None,
            }).collect();
        }

        if let Some(&Bson::String(ref s)) = doc.get("primary") {
            result.primary = Some(try!(connstring::parse_host(s)));
        }

        if let Some(&Bson::Boolean(ref b)) = doc.get("arbiterOnly") {
            result.arbiter_only = *b;
        }

        if let Some(&Bson::Boolean(ref h)) = doc.get("hidden") {
            result.hidden = *h;
        }

        if let Some(&Bson::Document(ref doc)) = doc.get("tags") {
            for (k, v) in doc.into_iter() {
                if let &Bson::String(ref tag) = v {
                    result.tags.insert(k.to_owned(), tag.to_owned());
                }
            }
        }

        match doc.get("electionId") {
            Some(&Bson::ObjectId(ref id)) => result.election_id = Some(id.clone()),
            Some(&Bson::Document(ref doc)) => if let Some(&Bson::String(ref s)) = doc.get("$oid") {
                result.election_id = Some(try!(oid::ObjectId::with_string(s)));
            },
            _ => (),
        }

        Ok(result)
    }
}

impl Monitor {
    /// Returns a new monitor connected to the server.
    pub fn new(client: Client, host: Host, pool: Arc<ConnectionPool>,
               top_description: Arc<RwLock<TopologyDescription>>,
               server_description: Arc<RwLock<ServerDescription>>) -> Monitor {

        Monitor {
            client: client,
            host: host.clone(),
            server_pool: pool,
            personal_pool: Arc::new(ConnectionPool::with_size(host, 1)),
            top_description: top_description,
            server_description: server_description,
            heartbeat_frequency_ms: AtomicUsize::new(DEFAULT_HEARTBEAT_FREQUENCY_MS as usize),
            dummy_lock: Mutex::new(()),
            condvar: Condvar::new(),
            running: Arc::new(AtomicBool::new(false)),
        }
    }

    // Set server description error field.
    fn set_err(&self, err: Error) {
        let mut server_description = self.server_description.write().unwrap();
        server_description.set_err(err);
        self.update_top_description(server_description.clone());
    }

    /// Returns an isMaster server response using an owned monitor socket.
    pub fn is_master(&self) -> Result<Cursor> {
        let options = FindOptions::new().with_limit(1);
        let flags = OpQueryFlags::with_find_options(&options);
        let mut filter = bson::Document::new();
        filter.insert("isMaster".to_owned(), Bson::I32(1));

        let stream = try!(self.personal_pool.acquire_stream());

        Cursor::query_with_stream(
            stream, self.client.clone(), "local.$cmd".to_owned(), 1,
            flags, options.skip as i32, 1, filter.clone(), options.projection.clone(),
            CommandType::IsMaster, false, None)
    }

    // Updates the server description associated with this monitor using an isMaster server response.
    fn update_server_description(&self, doc: bson::Document) -> Result<ServerDescription> {
        let ismaster_result = IsMasterResult::new(doc);
        let mut server_description = self.server_description.write().unwrap();
        match ismaster_result {
            Ok(ismaster) => server_description.update(ismaster),
            Err(err) => {
                server_description.set_err(err);
                return Err(OperationError("Failed to parse ismaster result.".to_owned()))
            },
        }

        Ok(server_description.clone())
    }

    // Updates the topology description associated with this monitor using a new server description.
    fn update_top_description(&self, description: ServerDescription) {
        let mut top_description = self.top_description.write().unwrap();
        top_description.update(self.host.clone(), description, self.client.clone(),
                               self.top_description.clone());
    }

    // Updates server and topology descriptions using a successful isMaster cursor result.
    fn update_with_is_master_cursor(&self, cursor: &mut Cursor) {
        match cursor.next() {
            Some(Ok(doc)) => {
                if let Ok(description) = self.update_server_description(doc) {
                    self.update_top_description(description);
                }
            },
            Some(Err(err)) => {
                self.set_err(err);
            },
            None => {
                self.set_err(OperationError("ismaster returned no response.".to_owned()));
            }
        }
    }

    /// Execute isMaster and update the server and topology.
    fn execute_update(&self) {
        match self.is_master() {
            Ok(mut cursor) => self.update_with_is_master_cursor(&mut cursor),
            Err(err) => {
                // Refresh all connections
                self.server_pool.clear();
                self.personal_pool.clear();

                let stype = self.server_description.read().unwrap().server_type;

                if stype == ServerType::Unknown {
                    self.set_err(err);
                } else {
                    // Retry once
                    match self.is_master() {
                        Ok(mut cursor) => self.update_with_is_master_cursor(&mut cursor),
                        Err(err) => self.set_err(err),
                    }
                }
            }
        }
    }

    /// Starts server monitoring.
    pub fn run(&self) {
        if self.running.load(Ordering::SeqCst) {
            return;
        }

        self.running.store(true, Ordering::SeqCst);

        let mut guard = self.dummy_lock.lock().unwrap();

        loop {
            if !self.running.load(Ordering::SeqCst) {
                break;
            }

            self.execute_update();

            if let Ok(description) = self.top_description.read() {
                self.heartbeat_frequency_ms.store(description.heartbeat_frequency_ms as usize,
                                                  Ordering::SeqCst);
            }

            let frequency = self.heartbeat_frequency_ms.load(Ordering::SeqCst) as u32;
            guard = self.condvar.wait_timeout_ms(guard, frequency).unwrap().0;
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pub use self::interface::{QuirksMode, Quirks, LimitedQuirks, NoQuirks};
pub use self::interface::TreeSink;

mod interface;
mod states;
<commit_msg>More preliminary tree builder work<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// FIXME
#![allow(unused_imports)]

pub use self::interface::{QuirksMode, Quirks, LimitedQuirks, NoQuirks};
pub use self::interface::TreeSink;

use tokenizer::{Doctype, Attribute, AttrName, TagKind, StartTag, EndTag, Tag};
use tokenizer::{Token, DoctypeToken, TagToken, CommentToken};
use tokenizer::{CharacterToken, MultiCharacterToken, EOFToken, ParseError};
use tokenizer::TokenSink;

use std::default::Default;

mod interface;
mod states;

/// Tree builder options, with an impl for Default.
#[deriving(Clone)]
pub struct TreeBuilderOpts {
   pub scripting_enabled: bool,
}

impl Default for TreeBuilderOpts {
    fn default() -> TreeBuilderOpts {
        TreeBuilderOpts {
            scripting_enabled: true,
        }
    }
}

pub struct TreeBuilder<'sink, Handle, Sink> {
    /// Options controlling the behavior of the tree builder.
    opts: TreeBuilderOpts,

    /// Consumer of tree modifications.
    sink: &'sink mut Sink,

    /// Insertion mode.
    mode: states::InsertionMode,

    /// Original insertion mode, used by Text and InTableText modes.
    orig_mode: states::InsertionMode,

    /// Stack of open elements, most recently added at end.
    open_elems: Vec<Handle>,

    /// Head element pointer.
    head_elem: Option<Handle>,
}

impl<'sink, Handle, Sink: TreeSink<Handle>> TreeBuilder<'sink, Handle, Sink> {
    pub fn new(sink: &'sink mut Sink, opts: TreeBuilderOpts) -> TreeBuilder<'sink, Handle, Sink> {
        TreeBuilder {
            opts: opts,
            sink: sink,
            mode: states::Initial,
            orig_mode: states::Initial,
            open_elems: vec!(),
            head_elem: None,
        }
    }
}

impl<'sink, Handle, Sink: TreeSink<Handle>> TokenSink for TreeBuilder<'sink, Handle, Sink> {
    fn process_token(&mut self, _token: Token) {
        fail!("not implemented!");
    }
}
<|endoftext|>


<commit_before>use combine::parser::byte::{byte, crlf, newline as lf};
use combine::parser::range::{recognize, take_while, take_while1};
use combine::stream::RangeStream;
use combine::*;

pub(crate) unsafe fn from_utf8_unchecked<'b>(
    bytes: &'b [u8],
    safety_justification: &'static str,
) -> &'b str {
    if cfg!(debug_assertions) {
        // Catch problems more quickly when testing
        std::str::from_utf8(bytes).expect(safety_justification)
    } else {
        std::str::from_utf8_unchecked(bytes)
    }
}

// wschar = ( %x20 /              ; Space
//            %x09 )              ; Horizontal tab
#[inline]
pub(crate) fn is_wschar(c: u8) -> bool {
    matches!(c, b' ' | b'\t')
}

// ws = *wschar
parse!(ws() -> &'a str, {
    take_while(is_wschar).map(|b| {
        unsafe { from_utf8_unchecked(b, "`is_wschar` filters out on-ASCII") }
    })
});

// non-ascii = %x80-D7FF / %xE000-10FFFF
#[inline]
pub(crate) fn is_non_ascii(c: u8) -> bool {
    // - ASCII is 0xxxxxxx
    // - First byte for UTF-8 is 11xxxxxx
    // - Subsequent UTF-8 bytes are 10xxxxxx
    matches!(c, 0x80..=0xff)
}

// non-eol = %x09 / %x20-7E / non-ascii
#[inline]
fn is_non_eol(c: u8) -> bool {
    matches!(c, 0x09 | 0x20..=0x7E) | is_non_ascii(c)
}

// comment-start-symbol = %x23 ; #
const COMMENT_START_SYMBOL: u8 = b'#';

// comment = comment-start-symbol *non-eol
parse!(comment() -> &'a [u8], {
    recognize((
        attempt(byte(COMMENT_START_SYMBOL)),
        take_while(is_non_eol),
    ))
});

// newline = ( %x0A /              ; LF
//             %x0D.0A )           ; CRLF
parse!(newline() -> char, {
    choice((lf(), crlf()))
        .map(|_| '\n')
        .expected("a newline")
});

// ws-newline       = *( wschar / newline )
parse!(ws_newline() -> &'a str, {
    recognize(
        skip_many(choice((
            newline().map(|_| &b"\n"[..]),
            take_while1(is_wschar),
        ))),
    ).map(|b| {
        unsafe { from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") }
    })
});

// ws-newlines      = newline *( wschar / newline )
parse!(ws_newlines() -> &'a str, {
    recognize((
        newline(),
        ws_newline(),
    )).map(|b| {
        unsafe { from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") }
    })
});

// note: this rule is not present in the original grammar
// ws-comment-newline = *( ws-newline-nonempty / comment )
parse!(ws_comment_newline() -> &'a [u8], {
    recognize(
        skip_many(
            choice((
                skip_many1(
                    choice((
                        take_while1(is_wschar),
                        newline().map(|_| &b"\n"[..]),
                    ))
                ),
                comment().map(|_| ()),
            ))
        )
    )
});

// note: this rule is not present in the original grammar
// line-ending = newline / eof
parse!(line_ending() -> &'a str, {
    choice((
        newline().map(|_| "\n"),
        eof().map(|_| "")
    ))
});

// note: this rule is not present in the original grammar
// line-trailing = ws [comment] skip-line-ending
parse!(line_trailing() -> &'a [u8], {
    recognize((
        ws(),
        optional(comment()),
    )).skip(line_ending())
});
<commit_msg>refactor(parser): Remove superfluous 'attempt' (#221)<commit_after>use combine::parser::byte::{byte, crlf, newline as lf};
use combine::parser::range::{recognize, take_while, take_while1};
use combine::stream::RangeStream;
use combine::*;

pub(crate) unsafe fn from_utf8_unchecked<'b>(
    bytes: &'b [u8],
    safety_justification: &'static str,
) -> &'b str {
    if cfg!(debug_assertions) {
        // Catch problems more quickly when testing
        std::str::from_utf8(bytes).expect(safety_justification)
    } else {
        std::str::from_utf8_unchecked(bytes)
    }
}

// wschar = ( %x20 /              ; Space
//            %x09 )              ; Horizontal tab
#[inline]
pub(crate) fn is_wschar(c: u8) -> bool {
    matches!(c, b' ' | b'\t')
}

// ws = *wschar
parse!(ws() -> &'a str, {
    take_while(is_wschar).map(|b| {
        unsafe { from_utf8_unchecked(b, "`is_wschar` filters out on-ASCII") }
    })
});

// non-ascii = %x80-D7FF / %xE000-10FFFF
#[inline]
pub(crate) fn is_non_ascii(c: u8) -> bool {
    // - ASCII is 0xxxxxxx
    // - First byte for UTF-8 is 11xxxxxx
    // - Subsequent UTF-8 bytes are 10xxxxxx
    matches!(c, 0x80..=0xff)
}

// non-eol = %x09 / %x20-7E / non-ascii
#[inline]
fn is_non_eol(c: u8) -> bool {
    matches!(c, 0x09 | 0x20..=0x7E) | is_non_ascii(c)
}

// comment-start-symbol = %x23 ; #
const COMMENT_START_SYMBOL: u8 = b'#';

// comment = comment-start-symbol *non-eol
parse!(comment() -> &'a [u8], {
    recognize((
        byte(COMMENT_START_SYMBOL),
        take_while(is_non_eol),
    ))
});

// newline = ( %x0A /              ; LF
//             %x0D.0A )           ; CRLF
parse!(newline() -> char, {
    choice((lf(), crlf()))
        .map(|_| '\n')
        .expected("a newline")
});

// ws-newline       = *( wschar / newline )
parse!(ws_newline() -> &'a str, {
    recognize(
        skip_many(choice((
            newline().map(|_| &b"\n"[..]),
            take_while1(is_wschar),
        ))),
    ).map(|b| {
        unsafe { from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") }
    })
});

// ws-newlines      = newline *( wschar / newline )
parse!(ws_newlines() -> &'a str, {
    recognize((
        newline(),
        ws_newline(),
    )).map(|b| {
        unsafe { from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") }
    })
});

// note: this rule is not present in the original grammar
// ws-comment-newline = *( ws-newline-nonempty / comment )
parse!(ws_comment_newline() -> &'a [u8], {
    recognize(
        skip_many(
            choice((
                skip_many1(
                    choice((
                        take_while1(is_wschar),
                        newline().map(|_| &b"\n"[..]),
                    ))
                ),
                comment().map(|_| ()),
            ))
        )
    )
});

// note: this rule is not present in the original grammar
// line-ending = newline / eof
parse!(line_ending() -> &'a str, {
    choice((
        newline().map(|_| "\n"),
        eof().map(|_| "")
    ))
});

// note: this rule is not present in the original grammar
// line-trailing = ws [comment] skip-line-ending
parse!(line_trailing() -> &'a [u8], {
    recognize((
        ws(),
        optional(comment()),
    )).skip(line_ending())
});
<|endoftext|>


<commit_before>/*
 * Rustyard - Simon Whitehead, 2016
 */

use std;

use lexer;
use rpn_calculator as calc;
use token;

/// The ShuntingYard struct transforms an expression
/// to a 64-bit floating point value
pub struct ShuntingYard<'a> {
    lexer: lexer::Lexer<'a>,
    output_queue: Vec<token::Token>,
    stack: Vec<token::Token>,
    pub errors: Vec<String>
}

impl<'a> ShuntingYard<'a> {
    pub fn new(raw_input: &str) -> ShuntingYard {
        let mut yard = ShuntingYard {
            lexer: lexer::Lexer::new(raw_input),
            output_queue: vec![],
            stack: vec![],
            errors: vec![]
        };

        // If there were Lexer errors, add them now.
        let lexer_errors = yard.lexer.errors.clone();
        yard.errors.extend(lexer_errors);

        // Transform the Lexer input via the Shunting Yard algorithm
        yard.transform();
        yard
    }

    /// calculate returns a 64-bit floating value after
    /// parsing the Reverse Polish Notation represented
    /// by the output_queue.
    pub fn calculate(&self) -> Option<f64> {
        calc::calculate(&self.output_queue)
    }

    // Transforms the input from the Lexer in to the output_queue
    // and stack based on the Shunting Yard algorithm
    fn transform(&mut self) {
        // Iterate over each token and move it based on the algorithm
        for t in self.lexer.ast.to_vec() {
            // If the token is a number, then add it to the output queue
            match t {
                token::Token::WholeNumber(_) => self.output_queue.push(t),
                token::Token::DecimalNumber(_) => self.output_queue.push(t),
                token::Token::Operator(o1, o1_associativity, o1_precedence) => {
                    loop {
                        match self.stack.last() {
                            Some(&token::Token::Operator(_, _, o2_precedence)) => {
                                if (o1_associativity == token::LEFT_ASSOCIATIVE &&
                                   o1_precedence <= o2_precedence) ||
                                   (o1_associativity == token::RIGHT_ASSOCIATIVE &&
                                   o1_precedence < o2_precedence) {
                                    self.output_queue.push(self.stack.pop().unwrap());
                                } else {
                                    self.stack.push(token::Token::Operator(o1, o1_associativity, o1_precedence));
                                    break
                                }
                            },
                            _ => { self.stack.push(token::Token::Operator(o1, o1_associativity, o1_precedence)); break; }
                        }
                    }
                },
                token::Token::LeftParenthesis => self.stack.push(token::Token::LeftParenthesis),
                token::Token::RightParenthesis => {
                    let mut found_left_paren = false;
                    loop {
                        match self.stack.last() {
                            Some(&token::Token::LeftParenthesis) => {
                                found_left_paren = true;
                                self.stack.pop().unwrap();
                            },
                            None => {
                                if !found_left_paren {
                                    self.errors.push("Unbalanced parenthesis".to_string());
                                }
                                break;
                            },
                            _ => self.output_queue.push(self.stack.pop().unwrap()),
                        }
                    }
                },
                _ => ()
            }
        }

        // Are there any operators left on the stack?
        while self.stack.len() > 0 {
            // Pop them off and push them to the output_queue
            let op = self.stack.pop();
            match op {
                Some(token::Token::Operator(o, oa, op)) => {
                    self.output_queue.push(token::Token::Operator(o, oa, op));
                },
                Some(token::Token::LeftParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                Some(token::Token::RightParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                _ => ()
            }
        }
    }

    /// to_string_ast returns the string representation of the
    /// Lexer tokens.
    pub fn to_string_ast(&self) -> String {
        let mut result = String::new(); // String to output the result to
        let ast = self.lexer.ast.to_vec();    // Copy the AST into its own vector so we can consume it

        // Loop over each item in the AST and print a String representation of it
        for t in ast {
            match t {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };
            result.push_str(" "); // Space separated
        }

        // Return the result
        result
    }
}

impl<'a> std::string::ToString for ShuntingYard<'a> {
    /// to_string returns the string representation of the Shunting Yard
    /// algorithm in Reverse Polish Notation.
    fn to_string(&self) -> String {
        let mut result = String::new(); // String to output the result
        let output_queue = self.output_queue.to_vec(); // Make a copy of the output queue

        // Iterate over the output queue and print each one to the result
        for t in output_queue {
            match t {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };

            result.push_str(" "); // Space separated
        }

        result
    }

}
<commit_msg>Renamed 't' to 'tok' in a few places to make it more recognisable<commit_after>/*
 * Rustyard - Simon Whitehead, 2016
 */

use std;

use lexer;
use rpn_calculator as calc;
use token;

/// The ShuntingYard struct transforms an expression
/// to a 64-bit floating point value
pub struct ShuntingYard<'a> {
    lexer: lexer::Lexer<'a>,
    output_queue: Vec<token::Token>,
    stack: Vec<token::Token>,
    pub errors: Vec<String>
}

impl<'a> ShuntingYard<'a> {
    pub fn new(raw_input: &str) -> ShuntingYard {
        let mut yard = ShuntingYard {
            lexer: lexer::Lexer::new(raw_input),
            output_queue: vec![],
            stack: vec![],
            errors: vec![]
        };

        // If there were Lexer errors, add them now.
        let lexer_errors = yard.lexer.errors.clone();
        yard.errors.extend(lexer_errors);

        // Transform the Lexer input via the Shunting Yard algorithm
        yard.transform();
        yard
    }

    /// calculate returns a 64-bit floating value after
    /// parsing the Reverse Polish Notation represented
    /// by the output_queue.
    pub fn calculate(&self) -> Option<f64> {
        calc::calculate(&self.output_queue)
    }

    // Transforms the input from the Lexer in to the output_queue
    // and stack based on the Shunting Yard algorithm
    fn transform(&mut self) {
        // Iterate over each token and move it based on the algorithm
        for tok in self.lexer.ast.to_vec() {
            // If the token is a number, then add it to the output queue
            match tok {
                token::Token::WholeNumber(_) => self.output_queue.push(tok),
                token::Token::DecimalNumber(_) => self.output_queue.push(tok),
                token::Token::Operator(o1, o1_associativity, o1_precedence) => {
                    loop {
                        match self.stack.last() {
                            Some(&token::Token::Operator(_, _, o2_precedence)) => {
                                if (o1_associativity == token::LEFT_ASSOCIATIVE &&
                                   o1_precedence <= o2_precedence) ||
                                   (o1_associativity == token::RIGHT_ASSOCIATIVE &&
                                   o1_precedence < o2_precedence) {
                                    self.output_queue.push(self.stack.pop().unwrap());
                                } else {
                                    self.stack.push(token::Token::Operator(o1, o1_associativity, o1_precedence));
                                    break
                                }
                            },
                            _ => { self.stack.push(token::Token::Operator(o1, o1_associativity, o1_precedence)); break; }
                        }
                    }
                },
                token::Token::LeftParenthesis => self.stack.push(token::Token::LeftParenthesis),
                token::Token::RightParenthesis => {
                    let mut found_left_paren = false;
                    loop {
                        match self.stack.last() {
                            Some(&token::Token::LeftParenthesis) => {
                                found_left_paren = true;
                                self.stack.pop().unwrap();
                            },
                            None => {
                                if !found_left_paren {
                                    self.errors.push("Unbalanced parenthesis".to_string());
                                }
                                break;
                            },
                            _ => self.output_queue.push(self.stack.pop().unwrap()),
                        }
                    }
                },
                _ => ()
            }
        }

        // Are there any operators left on the stack?
        while self.stack.len() > 0 {
            // Pop them off and push them to the output_queue
            let op = self.stack.pop();
            match op {
                Some(token::Token::Operator(o, oa, op)) => {
                    self.output_queue.push(token::Token::Operator(o, oa, op));
                },
                Some(token::Token::LeftParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                Some(token::Token::RightParenthesis) => {
                    self.errors.push("Unbalanced parenthesis".to_string());
                    break;
                },
                _ => ()
            }
        }
    }

    /// to_string_ast returns the string representation of the
    /// Lexer tokens.
    pub fn to_string_ast(&self) -> String {
        let mut result = String::new(); // String to output the result to
        let ast = self.lexer.ast.to_vec();    // Copy the AST into its own vector so we can consume it

        // Loop over each item in the AST and print a String representation of it
        for tok in ast {
            match tok {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };
            result.push_str(" "); // Space separated
        }

        // Return the result
        result
    }
}

impl<'a> std::string::ToString for ShuntingYard<'a> {
    /// to_string returns the string representation of the Shunting Yard
    /// algorithm in Reverse Polish Notation.
    fn to_string(&self) -> String {
        let mut result = String::new(); // String to output the result
        let output_queue = self.output_queue.to_vec(); // Make a copy of the output queue

        // Iterate over the output queue and print each one to the result
        for tok in output_queue {
            match tok {
                token::Token::Operator(c, _, _) => result.push(c),
                token::Token::DecimalNumber(n) => result.push_str(&n.to_string()[..]),
                token::Token::LeftParenthesis => result.push_str("("),
                token::Token::RightParenthesis => result.push_str(")"),
                _ => ()
            };

            result.push_str(" "); // Space separated
        }

        result
    }

}
<|endoftext|>


<commit_before>//! Renderer for macro invocations.

use hir::{Documentation, HasSource};
use syntax::display::macro_label;
use test_utils::mark;

use crate::{
    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
    render::RenderContext,
};

pub(crate) fn render_macro<'a>(
    ctx: RenderContext<'a>,
    import_to_add: Option<ImportEdit>,
    name: String,
    macro_: hir::MacroDef,
) -> Option<CompletionItem> {
    let _p = profile::span("render_macro");
    MacroRender::new(ctx, name, macro_).render(import_to_add)
}

#[derive(Debug)]
struct MacroRender<'a> {
    ctx: RenderContext<'a>,
    name: String,
    macro_: hir::MacroDef,
    docs: Option<Documentation>,
    bra: &'static str,
    ket: &'static str,
}

impl<'a> MacroRender<'a> {
    fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRender<'a> {
        let docs = ctx.docs(macro_);
        let docs_str = docs.as_ref().map_or("", |s| s.as_str());
        let (bra, ket) = guess_macro_braces(&name, docs_str);

        MacroRender { ctx, name, macro_, docs, bra, ket }
    }

    fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
        let mut builder =
            CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
                .kind(CompletionItemKind::Macro)
                .set_documentation(self.docs.clone())
                .set_deprecated(self.ctx.is_deprecated(self.macro_))
                .add_import(import_to_add)
                .detail(self.detail()?);

        let needs_bang = self.needs_bang();
        builder = match self.ctx.snippet_cap() {
            Some(cap) if needs_bang => {
                let snippet = self.snippet();
                let lookup = self.lookup();
                builder.insert_snippet(cap, snippet).lookup_by(lookup)
            }
            None if needs_bang => builder.insert_text(self.banged_name()),
            _ => {
                mark::hit!(dont_insert_macro_call_parens_unncessary);
                builder.insert_text(&self.name)
            }
        };

        Some(builder.build())
    }

    fn needs_bang(&self) -> bool {
        self.ctx.completion.use_item_syntax.is_none() && !self.ctx.completion.is_macro_call
    }

    fn label(&self) -> String {
        if self.needs_bang() && self.ctx.snippet_cap().is_some() {
            format!("{}!{}…{}", self.name, self.bra, self.ket)
        } else {
            self.banged_name()
        }
    }

    fn snippet(&self) -> String {
        format!("{}!{}$0{}", self.name, self.bra, self.ket)
    }

    fn lookup(&self) -> String {
        self.banged_name()
    }

    fn banged_name(&self) -> String {
        format!("{}!", self.name)
    }

    fn detail(&self) -> Option<String> {
        let ast_node = self.macro_.source(self.ctx.db())?.value;
        Some(macro_label(&ast_node))
    }
}

fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
    let mut votes = [0, 0, 0];
    for (idx, s) in docs.match_indices(&macro_name) {
        let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
        // Ensure to match the full word
        if after.starts_with('!')
            && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
        {
            // It may have spaces before the braces like `foo! {}`
            match after[1..].chars().find(|&c| !c.is_whitespace()) {
                Some('{') => votes[0] += 1,
                Some('[') => votes[1] += 1,
                Some('(') => votes[2] += 1,
                _ => {}
            }
        }
    }

    // Insert a space before `{}`.
    // We prefer the last one when some votes equal.
    let (_vote, (bra, ket)) = votes
        .iter()
        .zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
        .max_by_key(|&(&vote, _)| vote)
        .unwrap();
    (*bra, *ket)
}

#[cfg(test)]
mod tests {
    use test_utils::mark;

    use crate::test_utils::check_edit;

    #[test]
    fn dont_insert_macro_call_parens_unncessary() {
        mark::check!(dont_insert_macro_call_parens_unncessary);
        check_edit(
            "frobnicate!",
            r#"
//- /main.rs crate:main deps:foo
use foo::<|>;
//- /foo/lib.rs crate:foo
#[macro_export]
macro_rules! frobnicate { () => () }
"#,
            r#"
use foo::frobnicate;
"#,
        );

        check_edit(
            "frobnicate!",
            r#"
macro_rules! frobnicate { () => () }
fn main() { frob<|>!(); }
"#,
            r#"
macro_rules! frobnicate { () => () }
fn main() { frobnicate!(); }
"#,
        );
    }

    #[test]
    fn guesses_macro_braces() {
        check_edit(
            "vec!",
            r#"
/// Creates a [`Vec`] containing the arguments.
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
macro_rules! vec { () => {} }

fn fn main() { v<|> }
"#,
            r#"
/// Creates a [`Vec`] containing the arguments.
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
macro_rules! vec { () => {} }

fn fn main() { vec![$0] }
"#,
        );

        check_edit(
            "foo!",
            r#"
/// Foo
///
/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
/// call as `let _=foo!  { hello world };`
macro_rules! foo { () => {} }
fn main() { <|> }
"#,
            r#"
/// Foo
///
/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
/// call as `let _=foo!  { hello world };`
macro_rules! foo { () => {} }
fn main() { foo! {$0} }
"#,
        )
    }
}
<commit_msg>Handle case where detail doesn't exist without giving up on completion<commit_after>//! Renderer for macro invocations.

use hir::{Documentation, HasSource};
use syntax::display::macro_label;
use test_utils::mark;

use crate::{
    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
    render::RenderContext,
};

pub(crate) fn render_macro<'a>(
    ctx: RenderContext<'a>,
    import_to_add: Option<ImportEdit>,
    name: String,
    macro_: hir::MacroDef,
) -> Option<CompletionItem> {
    let _p = profile::span("render_macro");
    MacroRender::new(ctx, name, macro_).render(import_to_add)
}

#[derive(Debug)]
struct MacroRender<'a> {
    ctx: RenderContext<'a>,
    name: String,
    macro_: hir::MacroDef,
    docs: Option<Documentation>,
    bra: &'static str,
    ket: &'static str,
}

impl<'a> MacroRender<'a> {
    fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRender<'a> {
        let docs = ctx.docs(macro_);
        let docs_str = docs.as_ref().map_or("", |s| s.as_str());
        let (bra, ket) = guess_macro_braces(&name, docs_str);

        MacroRender { ctx, name, macro_, docs, bra, ket }
    }

    fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
        let mut builder =
            CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
                .kind(CompletionItemKind::Macro)
                .set_documentation(self.docs.clone())
                .set_deprecated(self.ctx.is_deprecated(self.macro_))
                .add_import(import_to_add)
                .set_detail(self.detail());

        let needs_bang = self.needs_bang();
        builder = match self.ctx.snippet_cap() {
            Some(cap) if needs_bang => {
                let snippet = self.snippet();
                let lookup = self.lookup();
                builder.insert_snippet(cap, snippet).lookup_by(lookup)
            }
            None if needs_bang => builder.insert_text(self.banged_name()),
            _ => {
                mark::hit!(dont_insert_macro_call_parens_unncessary);
                builder.insert_text(&self.name)
            }
        };

        Some(builder.build())
    }

    fn needs_bang(&self) -> bool {
        self.ctx.completion.use_item_syntax.is_none() && !self.ctx.completion.is_macro_call
    }

    fn label(&self) -> String {
        if self.needs_bang() && self.ctx.snippet_cap().is_some() {
            format!("{}!{}…{}", self.name, self.bra, self.ket)
        } else {
            self.banged_name()
        }
    }

    fn snippet(&self) -> String {
        format!("{}!{}$0{}", self.name, self.bra, self.ket)
    }

    fn lookup(&self) -> String {
        self.banged_name()
    }

    fn banged_name(&self) -> String {
        format!("{}!", self.name)
    }

    fn detail(&self) -> Option<String> {
        let ast_node = self.macro_.source(self.ctx.db())?.value;
        Some(macro_label(&ast_node))
    }
}

fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
    let mut votes = [0, 0, 0];
    for (idx, s) in docs.match_indices(&macro_name) {
        let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
        // Ensure to match the full word
        if after.starts_with('!')
            && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
        {
            // It may have spaces before the braces like `foo! {}`
            match after[1..].chars().find(|&c| !c.is_whitespace()) {
                Some('{') => votes[0] += 1,
                Some('[') => votes[1] += 1,
                Some('(') => votes[2] += 1,
                _ => {}
            }
        }
    }

    // Insert a space before `{}`.
    // We prefer the last one when some votes equal.
    let (_vote, (bra, ket)) = votes
        .iter()
        .zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
        .max_by_key(|&(&vote, _)| vote)
        .unwrap();
    (*bra, *ket)
}

#[cfg(test)]
mod tests {
    use test_utils::mark;

    use crate::test_utils::check_edit;

    #[test]
    fn dont_insert_macro_call_parens_unncessary() {
        mark::check!(dont_insert_macro_call_parens_unncessary);
        check_edit(
            "frobnicate!",
            r#"
//- /main.rs crate:main deps:foo
use foo::<|>;
//- /foo/lib.rs crate:foo
#[macro_export]
macro_rules! frobnicate { () => () }
"#,
            r#"
use foo::frobnicate;
"#,
        );

        check_edit(
            "frobnicate!",
            r#"
macro_rules! frobnicate { () => () }
fn main() { frob<|>!(); }
"#,
            r#"
macro_rules! frobnicate { () => () }
fn main() { frobnicate!(); }
"#,
        );
    }

    #[test]
    fn guesses_macro_braces() {
        check_edit(
            "vec!",
            r#"
/// Creates a [`Vec`] containing the arguments.
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
macro_rules! vec { () => {} }

fn fn main() { v<|> }
"#,
            r#"
/// Creates a [`Vec`] containing the arguments.
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
macro_rules! vec { () => {} }

fn fn main() { vec![$0] }
"#,
        );

        check_edit(
            "foo!",
            r#"
/// Foo
///
/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
/// call as `let _=foo!  { hello world };`
macro_rules! foo { () => {} }
fn main() { <|> }
"#,
            r#"
/// Foo
///
/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
/// call as `let _=foo!  { hello world };`
macro_rules! foo { () => {} }
fn main() { foo! {$0} }
"#,
        )
    }
}
<|endoftext|>


<commit_before>use ide_db::base_db::Upcast;
use ide_db::helpers::pick_best_token;
use ide_db::RootDatabase;
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T};

use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};

// Feature: Go to Type Definition
//
// Navigates to the type of an identifier.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Go to Type Definition*
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[]
pub(crate) fn goto_type_definition(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    let sema = hir::Semantics::new(db);

    let file: ast::SourceFile = sema.parse(position.file_id);
    let token: SyntaxToken =
        pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
            IDENT | INT_NUMBER | T![self] => 2,
            kind if kind.is_trivia() => 0,
            _ => 1,
        })?;
    let token: SyntaxToken = sema.descend_into_macros(token);

    let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| {
        let ty = match_ast! {
            match node {
                ast::Expr(it) => sema.type_of_expr(&it)?,
                ast::Pat(it) => sema.type_of_pat(&it)?,
                ast::SelfParam(it) => sema.type_of_self(&it)?,
                ast::Type(it) => sema.resolve_type(&it)?,
                ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?,
                ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?,
                // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
                ast::NameRef(it) => {
                    if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) {
                        let (_, _, ty) = sema.resolve_record_field(&record_field)?;
                        ty
                    } else {
                        let record_field = ast::RecordPatField::for_field_name_ref(&it)?;
                        sema.resolve_record_pat_field(&record_field)?.ty(db)
                    }
                },
                _ => return None,
            }
        };

        Some((ty, node))
    })?;
    let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?;

    let nav = adt_def.try_to_nav(db)?;
    Some(RangeInfo::new(node.text_range(), vec![nav]))
}

#[cfg(test)]
mod tests {
    use ide_db::base_db::FileRange;

    use crate::fixture;

    fn check(ra_fixture: &str) {
        let (analysis, position, mut annotations) = fixture::annotations(ra_fixture);
        let (expected, data) = annotations.pop().unwrap();
        assert!(data.is_empty());

        let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info;
        assert_eq!(navs.len(), 1);
        let nav = navs.pop().unwrap();
        assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
    }

    #[test]
    fn goto_type_definition_works_simple() {
        check(
            r#"
struct Foo;
     //^^^
fn foo() {
    let f: Foo; f$0
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_record_expr_field() {
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    Foo { foo$0 }
}
"#,
        );
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    Foo { foo$0: Bar }
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_record_pat_field() {
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    let Foo { foo$0 };
}
"#,
        );
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    let Foo { foo$0: bar };
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_works_simple_ref() {
        check(
            r#"
struct Foo;
     //^^^
fn foo() {
    let f: &Foo; f$0
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_works_through_macro() {
        check(
            r#"
macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
struct Foo {}
     //^^^
id! {
    fn bar() { let f$0 = Foo {}; }
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_for_param() {
        check(
            r#"
struct Foo;
     //^^^
fn foo($0f: Foo) {}
"#,
        );
    }

    #[test]
    fn goto_type_definition_for_tuple_field() {
        check(
            r#"
struct Foo;
     //^^^
struct Bar(Foo);
fn foo() {
    let bar = Bar(Foo);
    bar.$00;
}
"#,
        );
    }

    #[test]
    fn goto_def_for_self_param() {
        check(
            r#"
struct Foo;
     //^^^
impl Foo {
    fn f(&self$0) {}
}
"#,
        )
    }

    #[test]
    fn goto_def_for_type_fallback() {
        check(
            r#"
struct Foo;
     //^^^
impl Foo$0 {}
"#,
        )
    }

    #[test]
    fn goto_def_for_struct_field() {
        check(
            r#"
struct Bar;
     //^^^

struct Foo {
    bar$0: Bar,
}
"#,
        );
    }

    #[test]
    fn goto_def_for_enum_struct_field() {
        check(
            r#"
struct Bar;
     //^^^

enum Foo {
    Bar {
        bar$0: Bar
    },
}
"#,
        );
    }
}
<commit_msg>Return type arguments in goto_type_definition result<commit_after>use ide_db::{base_db::Upcast, helpers::pick_best_token, RootDatabase};
use rustc_hash::FxHashSet;
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T};

use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};

// Feature: Go to Type Definition
//
// Navigates to the type of an identifier.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Go to Type Definition*
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[]
pub(crate) fn goto_type_definition(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    let sema = hir::Semantics::new(db);

    let file: ast::SourceFile = sema.parse(position.file_id);
    let token: SyntaxToken =
        pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
            IDENT | INT_NUMBER | T![self] => 2,
            kind if kind.is_trivia() => 0,
            _ => 1,
        })?;
    let token: SyntaxToken = sema.descend_into_macros(token);

    let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| {
        let ty = match_ast! {
            match node {
                ast::Expr(it) => sema.type_of_expr(&it)?,
                ast::Pat(it) => sema.type_of_pat(&it)?,
                ast::SelfParam(it) => sema.type_of_self(&it)?,
                ast::Type(it) => sema.resolve_type(&it)?,
                ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?,
                // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
                ast::NameRef(it) => {
                    if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) {
                        let (_, _, ty) = sema.resolve_record_field(&record_field)?;
                        ty
                    } else {
                        let record_field = ast::RecordPatField::for_field_name_ref(&it)?;
                        sema.resolve_record_pat_field(&record_field)?.ty(db)
                    }
                },
                _ => return None,
            }
        };

        Some((ty, node))
    })?;

    let mut res = FxHashSet::default();
    let mut workload = vec![ty.strip_references()];
    while let Some(ty) = workload.pop() {
        if let Some(adt) = ty.as_adt() {
            res.insert(adt);
        }
        workload.extend(ty.strip_references().type_arguments());
    }

    Some(RangeInfo::new(
        node.text_range(),
        res.into_iter().flat_map(|adt| adt.try_to_nav(db)).collect(),
    ))
}

#[cfg(test)]
mod tests {
    use ide_db::base_db::FileRange;
    use itertools::Itertools;

    use crate::fixture;

    fn check(ra_fixture: &str) {
        let (analysis, position, expected) = fixture::annotations(ra_fixture);
        let navs = analysis.goto_type_definition(position).unwrap().unwrap().info;
        assert_ne!(navs.len(), 0);

        let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
        let navs = navs
            .into_iter()
            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
            .sorted_by_key(cmp)
            .collect::<Vec<_>>();
        let expected = expected
            .into_iter()
            .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
            .sorted_by_key(cmp)
            .collect::<Vec<_>>();
        assert_eq!(expected, navs);
    }

    #[test]
    fn goto_type_definition_works_simple() {
        check(
            r#"
struct Foo;
     //^^^
fn foo() {
    let f: Foo; f$0
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_record_expr_field() {
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    Foo { foo$0 }
}
"#,
        );
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    Foo { foo$0: Bar }
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_record_pat_field() {
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    let Foo { foo$0 };
}
"#,
        );
        check(
            r#"
struct Bar;
    // ^^^
struct Foo { foo: Bar }
fn foo() {
    let Foo { foo$0: bar };
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_works_simple_ref() {
        check(
            r#"
struct Foo;
     //^^^
fn foo() {
    let f: &Foo; f$0
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_works_through_macro() {
        check(
            r#"
macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
struct Foo {}
     //^^^
id! {
    fn bar() { let f$0 = Foo {}; }
}
"#,
        );
    }

    #[test]
    fn goto_type_definition_for_param() {
        check(
            r#"
struct Foo;
     //^^^
fn foo($0f: Foo) {}
"#,
        );
    }

    #[test]
    fn goto_type_definition_for_tuple_field() {
        check(
            r#"
struct Foo;
     //^^^
struct Bar(Foo);
fn foo() {
    let bar = Bar(Foo);
    bar.$00;
}
"#,
        );
    }

    #[test]
    fn goto_def_for_self_param() {
        check(
            r#"
struct Foo;
     //^^^
impl Foo {
    fn f(&self$0) {}
}
"#,
        )
    }

    #[test]
    fn goto_def_for_type_fallback() {
        check(
            r#"
struct Foo;
     //^^^
impl Foo$0 {}
"#,
        )
    }

    #[test]
    fn goto_def_for_struct_field() {
        check(
            r#"
struct Bar;
     //^^^

struct Foo {
    bar$0: Bar,
}
"#,
        );
    }

    #[test]
    fn goto_def_for_enum_struct_field() {
        check(
            r#"
struct Bar;
     //^^^

enum Foo {
    Bar {
        bar$0: Bar
    },
}
"#,
        );
    }

    #[test]
    fn goto_def_considers_generics() {
        check(
            r#"
struct Foo;
     //^^^
struct Bar<T, U>(T, U);
     //^^^
struct Baz<T>(T);
     //^^^

fn foo(x$0: Bar<Baz<Foo>, Baz<usize>) {}
"#,
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{proof::SparseMerkleRangeProof, state_store::state_key::StateKey};
use aptos_crypto::{
    hash::{CryptoHash, CryptoHasher, SPARSE_MERKLE_PLACEHOLDER_HASH},
    HashValue,
};
use aptos_crypto_derive::CryptoHasher;
use serde::{Deserialize, Serialize};

#[derive(
    Clone,
    Debug,
    Default,
    CryptoHasher,
    Eq,
    PartialEq,
    Serialize,
    Deserialize,
    Ord,
    PartialOrd,
    Hash,
)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))]
pub struct StateValue {
    pub maybe_bytes: Option<Vec<u8>>,
    hash: HashValue,
}

impl StateValue {
    fn new(maybe_bytes: Option<Vec<u8>>) -> Self {
        let mut hasher = StateValueHasher::default();
        let hash = if let Some(bytes) = &maybe_bytes {
            hasher.update(bytes);
            hasher.finish()
        } else {
            HashValue::zero()
        };
        Self { maybe_bytes, hash }
    }

    pub fn empty() -> Self {
        StateValue::new(None)
    }
}

impl From<Vec<u8>> for StateValue {
    fn from(bytes: Vec<u8>) -> Self {
        StateValue::new(Some(bytes))
    }
}

impl CryptoHash for StateValue {
    type Hasher = StateValueHasher;

    fn hash(&self) -> HashValue {
        self.hash
    }
}

/// TODO(joshlind): add a proof implementation (e.g., verify()) and unit tests
/// for these once we start supporting them.
///
/// A single chunk of all state values at a specific version.
/// Note: this is similar to `StateSnapshotChunk` but all data is included
/// in the struct itself and not behind pointers/handles to file locations.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))]
pub struct StateValueChunkWithProof {
    pub first_index: u64,     // The first hashed state index in chunk
    pub last_index: u64,      // The last hashed state index in chunk
    pub first_key: HashValue, // The first hashed state key in chunk
    pub last_key: HashValue,  // The last hashed state key in chunk
    pub raw_values: Vec<(StateKey, StateValue)>, // The hashed state key and and raw state value.
    pub proof: SparseMerkleRangeProof, // The proof to ensure the chunk is in the hashed states
    pub root_hash: HashValue, // The root hash of the sparse merkle tree for this chunk
}

impl StateValueChunkWithProof {
    /// Returns true iff this chunk is the last chunk (i.e., there are no
    /// more state values to write to storage after this chunk).
    pub fn is_last_chunk(&self) -> bool {
        let right_siblings = self.proof.right_siblings();
        right_siblings
            .iter()
            .all(|sibling| *sibling == *SPARSE_MERKLE_PLACEHOLDER_HASH)
    }
}

#[cfg(test)]
mod tests {
    use crate::state_store::state_value::StateValue;

    #[test]
    fn test_empty_state_value() {
        StateValue::new(None);
    }
}
<commit_msg>[storage] skip serde StateValue hash (#2056)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{proof::SparseMerkleRangeProof, state_store::state_key::StateKey};
use aptos_crypto::{
    hash::{CryptoHash, CryptoHasher, SPARSE_MERKLE_PLACEHOLDER_HASH},
    HashValue,
};
use aptos_crypto_derive::CryptoHasher;
#[cfg(any(test, feature = "fuzzing"))]
use proptest::{arbitrary::Arbitrary, prelude::*};
use serde::{Deserialize, Deserializer, Serialize};

#[derive(Clone, Debug, Default, CryptoHasher, Eq, PartialEq, Serialize, Ord, PartialOrd, Hash)]
pub struct StateValue {
    pub maybe_bytes: Option<Vec<u8>>,
    #[serde(skip)]
    hash: HashValue,
}

#[cfg(any(test, feature = "fuzzing"))]
impl Arbitrary for StateValue {
    type Parameters = ();
    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        any::<Vec<u8>>()
            .prop_map(|maybe_bytes| StateValue::new(Some(maybe_bytes)))
            .boxed()
    }

    type Strategy = BoxedStrategy<Self>;
}

impl<'de> Deserialize<'de> for StateValue {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Deserialize)]
        #[serde(rename = "StateValue")]
        struct MaybeBytes {
            maybe_bytes: Option<Vec<u8>>,
        }
        let bytes = MaybeBytes::deserialize(deserializer)?;

        Ok(Self::new(bytes.maybe_bytes))
    }
}

impl StateValue {
    fn new(maybe_bytes: Option<Vec<u8>>) -> Self {
        let mut hasher = StateValueHasher::default();
        let hash = if let Some(bytes) = &maybe_bytes {
            hasher.update(bytes);
            hasher.finish()
        } else {
            HashValue::zero()
        };
        Self { maybe_bytes, hash }
    }

    pub fn empty() -> Self {
        StateValue::new(None)
    }
}

impl From<Vec<u8>> for StateValue {
    fn from(bytes: Vec<u8>) -> Self {
        StateValue::new(Some(bytes))
    }
}

impl CryptoHash for StateValue {
    type Hasher = StateValueHasher;

    fn hash(&self) -> HashValue {
        self.hash
    }
}

/// TODO(joshlind): add a proof implementation (e.g., verify()) and unit tests
/// for these once we start supporting them.
///
/// A single chunk of all state values at a specific version.
/// Note: this is similar to `StateSnapshotChunk` but all data is included
/// in the struct itself and not behind pointers/handles to file locations.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))]
pub struct StateValueChunkWithProof {
    pub first_index: u64,     // The first hashed state index in chunk
    pub last_index: u64,      // The last hashed state index in chunk
    pub first_key: HashValue, // The first hashed state key in chunk
    pub last_key: HashValue,  // The last hashed state key in chunk
    pub raw_values: Vec<(StateKey, StateValue)>, // The hashed state key and and raw state value.
    pub proof: SparseMerkleRangeProof, // The proof to ensure the chunk is in the hashed states
    pub root_hash: HashValue, // The root hash of the sparse merkle tree for this chunk
}

impl StateValueChunkWithProof {
    /// Returns true iff this chunk is the last chunk (i.e., there are no
    /// more state values to write to storage after this chunk).
    pub fn is_last_chunk(&self) -> bool {
        let right_siblings = self.proof.right_siblings();
        right_siblings
            .iter()
            .all(|sibling| *sibling == *SPARSE_MERKLE_PLACEHOLDER_HASH)
    }
}

#[cfg(test)]
mod tests {
    use crate::state_store::state_value::StateValue;

    #[test]
    fn test_empty_state_value() {
        StateValue::new(None);
    }
}
<|endoftext|>