<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// The crate store - a central repo for information collected about external
// crates and libraries

use schema;

use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex};
use rustc::hir::map::definitions::DefPathTable;
use rustc::hir::svh::Svh;
use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
use rustc::session::{Session, CrateDisambiguator};
use rustc_target::spec::PanicStrategy;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::util::nodemap::{FxHashMap, NodeMap};

use rustc_data_structures::sync::{Lrc, RwLock, Lock};
use syntax::{ast, attr};
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax_pos;

pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference};
pub use rustc::middle::cstore::NativeLibraryKind::*;
pub use rustc::middle::cstore::{CrateSource, LibSource, ForeignModule};

pub use cstore_impl::{provide, provide_extern};

// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
// own crate numbers.
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;

pub use rustc_data_structures::sync::MetadataRef;

pub struct MetadataBlob(pub MetadataRef);

/// Holds information about a syntax_pos::FileMap imported from another crate.
/// See `imported_filemaps()` for more information.
pub struct ImportedFileMap {
    /// This FileMap's byte-offset within the codemap of its original crate
    pub original_start_pos: syntax_pos::BytePos,
    /// The end of this FileMap within the codemap of its original crate
    pub original_end_pos: syntax_pos::BytePos,
    /// The imported FileMap's representation within the local codemap
    pub translated_filemap: Lrc<syntax_pos::FileMap>,
}

pub struct CrateMetadata {
    pub name: Symbol,

    /// Information about the extern crate that caused this crate to
    /// be loaded. If this is `None`, then the crate was injected
    /// (e.g., by the allocator)
    pub extern_crate: Lock<Option<ExternCrate>>,

    pub blob: MetadataBlob,
    pub cnum_map: Lock<CrateNumMap>,
    pub cnum: CrateNum,
    pub codemap_import_info: RwLock<Vec<ImportedFileMap>>,
    pub attribute_cache: Lock<[Vec<Option<Lrc<[ast::Attribute]>>>; 2]>,

    pub root: schema::CrateRoot,

    /// For each public item in this crate, we encode a key.  When the
    /// crate is loaded, we read all the keys and put them in this
    /// hashmap, which gives the reverse mapping.  This allows us to
    /// quickly retrace a `DefPath`, which is needed for incremental
    /// compilation support.
    pub def_path_table: Lrc<DefPathTable>,

    pub trait_impls: FxHashMap<(u32, DefIndex), schema::LazySeq<DefIndex>>,

    pub dep_kind: Lock<DepKind>,
    pub source: CrateSource,

    pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
}

pub struct CStore {
    metas: RwLock<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
    /// Map from NodeId's of local extern crate statements to crate numbers
    extern_mod_crate_map: Lock<NodeMap<CrateNum>>,
    pub metadata_loader: Box<MetadataLoader + Sync>,
}

impl CStore {
    pub fn new(metadata_loader: Box<MetadataLoader + Sync>) -> CStore {
        CStore {
            metas: RwLock::new(IndexVec::from_elem_n(None, 1)),
            extern_mod_crate_map: Lock::new(FxHashMap()),
            metadata_loader,
        }
    }

    pub(super) fn alloc_new_crate_num(&self) -> CrateNum {
        let mut metas = self.metas.borrow_mut();
        let cnum = CrateNum::new(metas.len());
        metas.push(None);
        cnum
    }

    pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
        self.metas.borrow()[cnum].clone().unwrap()
    }

    pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
        let mut metas = self.metas.borrow_mut();
        assert!(metas[cnum].is_none(), "Overwriting crate metadata entry");
        metas[cnum] = Some(data);
    }

    pub(super) fn iter_crate_data<I>(&self, mut i: I)
        where I: FnMut(CrateNum, &Lrc<CrateMetadata>)
    {
        for (k, v) in self.metas.borrow().iter_enumerated() {
            if let &Some(ref v) = v {
                i(k, v);
            }
        }
    }

    pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
        let mut ordering = Vec::new();
        self.push_dependencies_in_postorder(&mut ordering, krate);
        ordering.reverse();
        ordering
    }

    pub(super) fn push_dependencies_in_postorder(&self,
                                                 ordering: &mut Vec<CrateNum>,
                                                 krate: CrateNum) {
        if ordering.contains(&krate) {
            return;
        }

        let data = self.get_crate_data(krate);
        for &dep in data.cnum_map.borrow().iter() {
            if dep != krate {
                self.push_dependencies_in_postorder(ordering, dep);
            }
        }

        ordering.push(krate);
    }

    pub(super) fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
        let mut ordering = Vec::new();
        for (num, v) in self.metas.borrow().iter_enumerated() {
            if let &Some(_) = v {
                self.push_dependencies_in_postorder(&mut ordering, num);
            }
        }
        return ordering
    }

    pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
        self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
    }

    pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
        self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
    }
}

impl CrateMetadata {
    pub fn name(&self) -> Symbol {
        self.root.name
    }
    pub fn hash(&self) -> Svh {
        self.root.hash
    }
    pub fn disambiguator(&self) -> CrateDisambiguator {
        self.root.disambiguator
    }

    pub fn needs_allocator(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "needs_allocator")
    }

    pub fn has_global_allocator(&self) -> bool {
        self.root.has_global_allocator.clone()
    }

    pub fn has_default_lib_allocator(&self) -> bool {
        self.root.has_default_lib_allocator.clone()
    }

    pub fn is_panic_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "panic_runtime")
    }

    pub fn needs_panic_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "needs_panic_runtime")
    }

    pub fn is_compiler_builtins(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "compiler_builtins")
    }

    pub fn is_sanitizer_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "sanitizer_runtime")
    }

    pub fn is_profiler_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "profiler_runtime")
    }

    pub fn is_no_builtins(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "no_builtins")
    }

    pub fn panic_strategy(&self) -> PanicStrategy {
        self.root.panic_strategy.clone()
    }
}
<commit_msg>Add comment about first element in CStore::metas.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// The crate store - a central repo for information collected about external
// crates and libraries

use schema;

use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex};
use rustc::hir::map::definitions::DefPathTable;
use rustc::hir::svh::Svh;
use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
use rustc::session::{Session, CrateDisambiguator};
use rustc_target::spec::PanicStrategy;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::util::nodemap::{FxHashMap, NodeMap};

use rustc_data_structures::sync::{Lrc, RwLock, Lock};
use syntax::{ast, attr};
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax_pos;

pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference};
pub use rustc::middle::cstore::NativeLibraryKind::*;
pub use rustc::middle::cstore::{CrateSource, LibSource, ForeignModule};

pub use cstore_impl::{provide, provide_extern};

// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
// own crate numbers.
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;

pub use rustc_data_structures::sync::MetadataRef;

pub struct MetadataBlob(pub MetadataRef);

/// Holds information about a syntax_pos::FileMap imported from another crate.
/// See `imported_filemaps()` for more information.
pub struct ImportedFileMap {
    /// This FileMap's byte-offset within the codemap of its original crate
    pub original_start_pos: syntax_pos::BytePos,
    /// The end of this FileMap within the codemap of its original crate
    pub original_end_pos: syntax_pos::BytePos,
    /// The imported FileMap's representation within the local codemap
    pub translated_filemap: Lrc<syntax_pos::FileMap>,
}

pub struct CrateMetadata {
    pub name: Symbol,

    /// Information about the extern crate that caused this crate to
    /// be loaded. If this is `None`, then the crate was injected
    /// (e.g., by the allocator)
    pub extern_crate: Lock<Option<ExternCrate>>,

    pub blob: MetadataBlob,
    pub cnum_map: Lock<CrateNumMap>,
    pub cnum: CrateNum,
    pub codemap_import_info: RwLock<Vec<ImportedFileMap>>,
    pub attribute_cache: Lock<[Vec<Option<Lrc<[ast::Attribute]>>>; 2]>,

    pub root: schema::CrateRoot,

    /// For each public item in this crate, we encode a key.  When the
    /// crate is loaded, we read all the keys and put them in this
    /// hashmap, which gives the reverse mapping.  This allows us to
    /// quickly retrace a `DefPath`, which is needed for incremental
    /// compilation support.
    pub def_path_table: Lrc<DefPathTable>,

    pub trait_impls: FxHashMap<(u32, DefIndex), schema::LazySeq<DefIndex>>,

    pub dep_kind: Lock<DepKind>,
    pub source: CrateSource,

    pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
}

pub struct CStore {
    metas: RwLock<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
    /// Map from NodeId's of local extern crate statements to crate numbers
    extern_mod_crate_map: Lock<NodeMap<CrateNum>>,
    pub metadata_loader: Box<MetadataLoader + Sync>,
}

impl CStore {
    pub fn new(metadata_loader: Box<MetadataLoader + Sync>) -> CStore {
        CStore {
            // We add an empty entry for LOCAL_CRATE (which maps to zero) in
            // order to make array indices in `metas` match with the
            // corresponding `CrateNum`. This first entry will always remain
            // `None`.
            metas: RwLock::new(IndexVec::from_elem_n(None, 1)),
            extern_mod_crate_map: Lock::new(FxHashMap()),
            metadata_loader,
        }
    }

    pub(super) fn alloc_new_crate_num(&self) -> CrateNum {
        let mut metas = self.metas.borrow_mut();
        let cnum = CrateNum::new(metas.len());
        metas.push(None);
        cnum
    }

    pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
        self.metas.borrow()[cnum].clone().unwrap()
    }

    pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
        let mut metas = self.metas.borrow_mut();
        assert!(metas[cnum].is_none(), "Overwriting crate metadata entry");
        metas[cnum] = Some(data);
    }

    pub(super) fn iter_crate_data<I>(&self, mut i: I)
        where I: FnMut(CrateNum, &Lrc<CrateMetadata>)
    {
        for (k, v) in self.metas.borrow().iter_enumerated() {
            if let &Some(ref v) = v {
                i(k, v);
            }
        }
    }

    pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
        let mut ordering = Vec::new();
        self.push_dependencies_in_postorder(&mut ordering, krate);
        ordering.reverse();
        ordering
    }

    pub(super) fn push_dependencies_in_postorder(&self,
                                                 ordering: &mut Vec<CrateNum>,
                                                 krate: CrateNum) {
        if ordering.contains(&krate) {
            return;
        }

        let data = self.get_crate_data(krate);
        for &dep in data.cnum_map.borrow().iter() {
            if dep != krate {
                self.push_dependencies_in_postorder(ordering, dep);
            }
        }

        ordering.push(krate);
    }

    pub(super) fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
        let mut ordering = Vec::new();
        for (num, v) in self.metas.borrow().iter_enumerated() {
            if let &Some(_) = v {
                self.push_dependencies_in_postorder(&mut ordering, num);
            }
        }
        return ordering
    }

    pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
        self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
    }

    pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
        self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
    }
}

impl CrateMetadata {
    pub fn name(&self) -> Symbol {
        self.root.name
    }
    pub fn hash(&self) -> Svh {
        self.root.hash
    }
    pub fn disambiguator(&self) -> CrateDisambiguator {
        self.root.disambiguator
    }

    pub fn needs_allocator(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "needs_allocator")
    }

    pub fn has_global_allocator(&self) -> bool {
        self.root.has_global_allocator.clone()
    }

    pub fn has_default_lib_allocator(&self) -> bool {
        self.root.has_default_lib_allocator.clone()
    }

    pub fn is_panic_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "panic_runtime")
    }

    pub fn needs_panic_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "needs_panic_runtime")
    }

    pub fn is_compiler_builtins(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "compiler_builtins")
    }

    pub fn is_sanitizer_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "sanitizer_runtime")
    }

    pub fn is_profiler_runtime(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "profiler_runtime")
    }

    pub fn is_no_builtins(&self, sess: &Session) -> bool {
        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
        attr::contains_name(&attrs, "no_builtins")
    }

    pub fn panic_strategy(&self) -> PanicStrategy {
        self.root.panic_strategy.clone()
    }
}
<|endoftext|>


<commit_before>use std::path::Path;

use daemonize::Daemonize;
use log::error;

/// Daemonize a server process in a *nix standard way
///
/// This function will redirect `stdout`, `stderr` to `/dev/null`,
/// and follow the exact behavior in shadowsocks-libev
pub fn daemonize<F: AsRef<Path>>(pid_path: Option<F>) {
    let mut d = Daemonize::new().umask(0).chroot("/");
    if let Some(p) = pid_path {
        d = d.pid_file(p);
    }

    if let Err(err) = d.start() {
        error!("failed to daemonize, {:?} ({})", err, err);
    }
}
<commit_msg>remove chroot when daemonizing (#640)<commit_after>use std::path::Path;

use daemonize::Daemonize;
use log::error;

/// Daemonize a server process in a *nix standard way
///
/// This function will redirect `stdout`, `stderr` to `/dev/null`,
/// and follow the exact behavior in shadowsocks-libev
pub fn daemonize<F: AsRef<Path>>(pid_path: Option<F>) {
    let mut d = Daemonize::new().umask(0);
    if let Some(p) = pid_path {
        d = d.pid_file(p);
    }

    if let Err(err) = d.start() {
        error!("failed to daemonize, {:?} ({})", err, err);
    }
}
<|endoftext|>


<commit_before>pub use amq_protocol::protocol::BasicProperties;

use amq_protocol::protocol::AMQPClass;
use amq_protocol::frame::AMQPFrame;
use crossbeam_channel::{self, Receiver, Sender};
use log::error;
use parking_lot::RwLock;

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

use crate::api::{Answer, ChannelState};
use crate::consumer::ConsumerSubscriber;
use crate::error::{Error, ErrorKind};
use crate::message::BasicGetMessage;
use crate::queue::Queue;

#[derive(Clone, Debug)]
pub struct ChannelHandle {
  pub id:              u16,
      frame_sender:    Sender<AMQPFrame>,
      awaiting_sender: Sender<Answer>,
}

impl ChannelHandle {
  pub fn await_answer(&mut self, answer: Answer) {
    // We always hold a reference to the receiver so it's safe to unwrap
    self.awaiting_sender.send(answer).unwrap()
  }

  #[doc(hidden)]
  pub fn send_method_frame(&mut self, method: AMQPClass) {
    self.send_frame(AMQPFrame::Method(self.id, method));
  }

  #[doc(hidden)]
  pub fn send_frame(&mut self, frame: AMQPFrame) {
    // We always hold a reference to the receiver so it's safe to unwrap
    self.frame_sender.send(frame).unwrap();
  }
}

#[derive(Debug)]
pub struct Channel {
  pub id:              u16,
  pub send_flow:       bool,
  pub receive_flow:    bool,
  pub queues:          HashMap<String, Queue>,
  pub prefetch_size:   u32,
  pub prefetch_count:  u16,
  pub confirm:         bool,
  pub acked:           HashSet<u64>,
  pub nacked:          HashSet<u64>,
  pub unacked:         HashSet<u64>,
  pub awaiting:        Receiver<Answer>,
      state:           Arc<RwLock<ChannelState>>,
      delivery_tag:    u64,
      frame_sender:    Sender<AMQPFrame>,
      awaiting_sender: Sender<Answer>,
}

impl Channel {
  pub fn new(channel_id: u16, frame_sender: Sender<AMQPFrame>) -> Channel {
    let (awaiting_sender, awaiting_receiver) = crossbeam_channel::unbounded();

    Channel {
      id:             channel_id,
      send_flow:      true,
      receive_flow:   true,
      queues:         HashMap::new(),
      prefetch_size:  0,
      prefetch_count: 0,
      confirm:        false,
      acked:          HashSet::new(),
      nacked:         HashSet::new(),
      unacked:        HashSet::new(),
      awaiting:       awaiting_receiver,
      state:          Arc::new(RwLock::new(ChannelState::Initial)),
      delivery_tag:   1,
      frame_sender,
      awaiting_sender,
    }
  }

  pub fn handle(&self) -> ChannelHandle {
    ChannelHandle {
      id:              self.id,
      frame_sender:    self.frame_sender.clone(),
      awaiting_sender: self.awaiting_sender.clone(),
    }
  }

  pub fn await_answer(&mut self, answer: Answer) {
    // We always hold a reference to the receiver so it's safe to unwrap
    self.awaiting_sender.send(answer).unwrap()
  }

  pub fn next_answer(&mut self) -> Option<Answer> {
      // Error means no message
    self.awaiting.try_recv().ok()
  }

  pub fn state(&self) -> ChannelState {
    self.state.read().clone()
  }

  pub fn set_state(&mut self, state: ChannelState) {
    let mut current_state = self.state.write();
    *current_state = state;
  }

  /// verifies if the channel's state is the one passed as argument
  pub fn check_state(&self, state: ChannelState) -> result::Result<(), Error> {
    let current_state = self.state();
    if current_state == state {
      Ok(())
    } else {
      Err(ErrorKind::InvalidState {
        expected: state,
        actual:   current_state,
      }.into())
    }
  }

  /// gets the next message corresponding to a queue, in response to a basic.get
  ///
  /// If there is no message, the method will return None
  pub fn next_basic_get_message(&mut self, queue_name: &str) -> Option<BasicGetMessage> {
      self.queues.get_mut(queue_name).and_then(|queue| queue.next_basic_get_message())
  }

  #[doc(hidden)]
  pub fn handle_content_header_frame(&mut self, size: u64, properties: BasicProperties) {
    if let ChannelState::WillReceiveContent(queue_name, consumer_tag) = self.state() {
      if size > 0 {
        self.set_state(ChannelState::ReceivingContent(queue_name.clone(), consumer_tag.clone(), size as usize));
      } else {
        self.set_state(ChannelState::Connected);
      }
      if let Some(ref mut q) = self.queues.get_mut(&queue_name) {
        if let Some(ref consumer_tag) = consumer_tag {
          if let Some(ref mut cs) = q.consumers.get_mut(consumer_tag) {
            cs.set_delivery_properties(properties);
            if size == 0 {
              cs.new_delivery_complete();
            }
          }
        } else {
          q.set_delivery_properties(properties);
          if size == 0 {
            q.new_delivery_complete();
          }
        }
      }
    } else {
      self.set_state(ChannelState::Error);
    }
  }

  #[doc(hidden)]
  pub fn handle_body_frame(&mut self, payload: Vec<u8>) {
    let payload_size = payload.len();

    if let ChannelState::ReceivingContent(queue_name, opt_consumer_tag, remaining_size) = self.state() {
      if remaining_size >= payload_size {
        if let Some(ref mut q) = self.queues.get_mut(&queue_name) {
          if let Some(ref consumer_tag) = opt_consumer_tag {
            if let Some(ref mut cs) = q.consumers.get_mut(consumer_tag) {
              cs.receive_delivery_content(payload);
              if remaining_size == payload_size {
                cs.new_delivery_complete();
              }
            }
          } else {
            q.receive_delivery_content(payload);
            if remaining_size == payload_size {
              q.new_delivery_complete();
            }
          }
        }

        if remaining_size == payload_size {
          self.set_state(ChannelState::Connected);
        } else {
          self.set_state(ChannelState::ReceivingContent(queue_name, opt_consumer_tag, remaining_size - payload_size));
        }
      } else {
        error!("body frame too large");
        self.set_state(ChannelState::Error);
      }
    } else {
      self.set_state(ChannelState::Error);
    }
  }

  pub fn is_connected(&self) -> bool {
    let current_state = self.state.read();
    *current_state != ChannelState::Initial && *current_state != ChannelState::Closed && *current_state != ChannelState::Error
  }

  pub fn next_delivery_tag(&mut self) -> u64 {
    let tag = self.delivery_tag;
    self.delivery_tag += 1;
    if self.delivery_tag == 0 {
      self.delivery_tag = 1;
    }
    tag
  }

  pub fn ack(&mut self, delivery_tag: u64) -> Result<(), Error> {
    self.drop_unacked(delivery_tag)?;
    self.acked.insert(delivery_tag);
    Ok(())
  }

  pub fn nack(&mut self, delivery_tag: u64) -> Result<(), Error> {
    self.drop_unacked(delivery_tag)?;
    self.nacked.insert(delivery_tag);
    Ok(())
  }

  fn drop_unacked(&mut self, delivery_tag: u64) -> Result<(), Error> {
    if !self.unacked.remove(&delivery_tag) {
      return Err(ErrorKind::PreconditionFailed.into());
    }
    Ok(())
  }
}
<commit_msg>async: add is_connected to ChannelHandle<commit_after>pub use amq_protocol::protocol::BasicProperties;

use amq_protocol::protocol::AMQPClass;
use amq_protocol::frame::AMQPFrame;
use crossbeam_channel::{self, Receiver, Sender};
use log::error;
use parking_lot::RwLock;

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

use crate::api::{Answer, ChannelState};
use crate::consumer::ConsumerSubscriber;
use crate::error::{Error, ErrorKind};
use crate::message::BasicGetMessage;
use crate::queue::Queue;

#[derive(Clone, Debug)]
pub struct ChannelHandle {
  pub id:              u16,
      state:           Arc<RwLock<ChannelState>>,
      frame_sender:    Sender<AMQPFrame>,
      awaiting_sender: Sender<Answer>,
}

impl ChannelHandle {
  pub fn await_answer(&mut self, answer: Answer) {
    // We always hold a reference to the receiver so it's safe to unwrap
    self.awaiting_sender.send(answer).unwrap()
  }

  #[doc(hidden)]
  pub fn send_method_frame(&mut self, method: AMQPClass) {
    self.send_frame(AMQPFrame::Method(self.id, method));
  }

  #[doc(hidden)]
  pub fn send_frame(&mut self, frame: AMQPFrame) {
    // We always hold a reference to the receiver so it's safe to unwrap
    self.frame_sender.send(frame).unwrap();
  }

  pub fn is_connected(&self) -> bool {
    let current_state = self.state.read();
    *current_state != ChannelState::Initial && *current_state != ChannelState::Closed && *current_state != ChannelState::Error
  }
}

#[derive(Debug)]
pub struct Channel {
  pub id:              u16,
  pub send_flow:       bool,
  pub receive_flow:    bool,
  pub queues:          HashMap<String, Queue>,
  pub prefetch_size:   u32,
  pub prefetch_count:  u16,
  pub confirm:         bool,
  pub acked:           HashSet<u64>,
  pub nacked:          HashSet<u64>,
  pub unacked:         HashSet<u64>,
  pub awaiting:        Receiver<Answer>,
      state:           Arc<RwLock<ChannelState>>,
      delivery_tag:    u64,
      frame_sender:    Sender<AMQPFrame>,
      awaiting_sender: Sender<Answer>,
}

impl Channel {
  pub fn new(channel_id: u16, frame_sender: Sender<AMQPFrame>) -> Channel {
    let (awaiting_sender, awaiting_receiver) = crossbeam_channel::unbounded();

    Channel {
      id:             channel_id,
      send_flow:      true,
      receive_flow:   true,
      queues:         HashMap::new(),
      prefetch_size:  0,
      prefetch_count: 0,
      confirm:        false,
      acked:          HashSet::new(),
      nacked:         HashSet::new(),
      unacked:        HashSet::new(),
      awaiting:       awaiting_receiver,
      state:          Arc::new(RwLock::new(ChannelState::Initial)),
      delivery_tag:   1,
      frame_sender,
      awaiting_sender,
    }
  }

  pub fn handle(&self) -> ChannelHandle {
    ChannelHandle {
      id:              self.id,
      state:           self.state.clone(),
      frame_sender:    self.frame_sender.clone(),
      awaiting_sender: self.awaiting_sender.clone(),
    }
  }

  pub fn await_answer(&mut self, answer: Answer) {
    // We always hold a reference to the receiver so it's safe to unwrap
    self.awaiting_sender.send(answer).unwrap()
  }

  pub fn next_answer(&mut self) -> Option<Answer> {
      // Error means no message
    self.awaiting.try_recv().ok()
  }

  pub fn state(&self) -> ChannelState {
    self.state.read().clone()
  }

  pub fn set_state(&mut self, state: ChannelState) {
    let mut current_state = self.state.write();
    *current_state = state;
  }

  /// verifies if the channel's state is the one passed as argument
  pub fn check_state(&self, state: ChannelState) -> result::Result<(), Error> {
    let current_state = self.state();
    if current_state == state {
      Ok(())
    } else {
      Err(ErrorKind::InvalidState {
        expected: state,
        actual:   current_state,
      }.into())
    }
  }

  /// gets the next message corresponding to a queue, in response to a basic.get
  ///
  /// If there is no message, the method will return None
  pub fn next_basic_get_message(&mut self, queue_name: &str) -> Option<BasicGetMessage> {
      self.queues.get_mut(queue_name).and_then(|queue| queue.next_basic_get_message())
  }

  #[doc(hidden)]
  pub fn handle_content_header_frame(&mut self, size: u64, properties: BasicProperties) {
    if let ChannelState::WillReceiveContent(queue_name, consumer_tag) = self.state() {
      if size > 0 {
        self.set_state(ChannelState::ReceivingContent(queue_name.clone(), consumer_tag.clone(), size as usize));
      } else {
        self.set_state(ChannelState::Connected);
      }
      if let Some(ref mut q) = self.queues.get_mut(&queue_name) {
        if let Some(ref consumer_tag) = consumer_tag {
          if let Some(ref mut cs) = q.consumers.get_mut(consumer_tag) {
            cs.set_delivery_properties(properties);
            if size == 0 {
              cs.new_delivery_complete();
            }
          }
        } else {
          q.set_delivery_properties(properties);
          if size == 0 {
            q.new_delivery_complete();
          }
        }
      }
    } else {
      self.set_state(ChannelState::Error);
    }
  }

  #[doc(hidden)]
  pub fn handle_body_frame(&mut self, payload: Vec<u8>) {
    let payload_size = payload.len();

    if let ChannelState::ReceivingContent(queue_name, opt_consumer_tag, remaining_size) = self.state() {
      if remaining_size >= payload_size {
        if let Some(ref mut q) = self.queues.get_mut(&queue_name) {
          if let Some(ref consumer_tag) = opt_consumer_tag {
            if let Some(ref mut cs) = q.consumers.get_mut(consumer_tag) {
              cs.receive_delivery_content(payload);
              if remaining_size == payload_size {
                cs.new_delivery_complete();
              }
            }
          } else {
            q.receive_delivery_content(payload);
            if remaining_size == payload_size {
              q.new_delivery_complete();
            }
          }
        }

        if remaining_size == payload_size {
          self.set_state(ChannelState::Connected);
        } else {
          self.set_state(ChannelState::ReceivingContent(queue_name, opt_consumer_tag, remaining_size - payload_size));
        }
      } else {
        error!("body frame too large");
        self.set_state(ChannelState::Error);
      }
    } else {
      self.set_state(ChannelState::Error);
    }
  }

  pub fn is_connected(&self) -> bool {
    let current_state = self.state.read();
    *current_state != ChannelState::Initial && *current_state != ChannelState::Closed && *current_state != ChannelState::Error
  }

  pub fn next_delivery_tag(&mut self) -> u64 {
    let tag = self.delivery_tag;
    self.delivery_tag += 1;
    if self.delivery_tag == 0 {
      self.delivery_tag = 1;
    }
    tag
  }

  pub fn ack(&mut self, delivery_tag: u64) -> Result<(), Error> {
    self.drop_unacked(delivery_tag)?;
    self.acked.insert(delivery_tag);
    Ok(())
  }

  pub fn nack(&mut self, delivery_tag: u64) -> Result<(), Error> {
    self.drop_unacked(delivery_tag)?;
    self.nacked.insert(delivery_tag);
    Ok(())
  }

  fn drop_unacked(&mut self, delivery_tag: u64) -> Result<(), Error> {
    if !self.unacked.remove(&delivery_tag) {
      return Err(ErrorKind::PreconditionFailed.into());
    }
    Ok(())
  }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>adding comments<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);
            println!("You want to change cwd to {:s} that's cool", pstring);
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>cd is now working<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd and Justin Ingram jci5kb
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::os::getcwd;
use extra::getopts;
use std::Path;

struct Shell {
    cmd_prompt: ~str,
    cwd: Path,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cwd: getcwd(),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);

            println!("You want to change cwd to {:s}", pstring);
            // See if we have the current cwd
            //println!("The current cwd is {:s}" , self.cwd.as_str());

            let mut npath = Path::new(pstring);

            let mut cpath = self.cwd.clone();
            cpath.push(npath);

            if cpath.exists() {
		self.cwd = cpath;
            } else {
		println("Path does not exist!");
            }

        }
        match self.cwd.as_str() {
	    Some(path_str) => {println!("{:s}", path_str); }
	    None	=> {println("Path not representable as string!"); }
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>//! This module provides a way to construct a `File`.
//! It is intended to be completely decoupled from the
//! parser, so as to allow to evolve the tree representation
//! and the parser algorithm independently.
//!
//! The `Sink` trait is the bridge between the parser and the
//! tree builder: the parser produces a stream of events like
//! `start node`, `finish node`, and `FileBuilder` converts
//! this stream to a real tree.
use std::mem;
use {
    TextUnit, TextRange, SmolStr,
    lexer::Token,
    parser_impl::Sink,
    SyntaxKind::{self, TOMBSTONE},
};

/// `Parser` produces a flat list of `Event`s.
/// They are converted to a tree-structure in
/// a separate pass, via `TreeBuilder`.
#[derive(Debug)]
pub(crate) enum Event {
    /// This event signifies the start of the node.
    /// It should be either abandoned (in which case the
    /// `kind` is `TOMBSTONE`, and the event is ignored),
    /// or completed via a `Finish` event.
    ///
    /// All tokens between a `Start` and a `Finish` would
    /// become the children of the respective node.
    ///
    /// For left-recursive syntactic constructs, the parser produces
    /// a child node before it sees a parent. `forward_parent`
    /// exists to allow to tweak parent-child relationships.
    ///
    /// Consider this path
    ///
    /// foo::bar
    ///
    /// The events for it would look like this:
    ///
    ///
    /// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
    ///       |                          /\
    ///       |                          |
    ///       +------forward-parent------+
    ///
    /// And the tree would look like this
    ///
    ///    +--PATH---------+
    ///    |   |           |
    ///    |   |           |
    ///    |  '::'       'bar'
    ///    |
    ///   PATH
    ///    |
    ///   'foo'
    ///
    /// See also `CompletedMarker::precede`.
    Start {
        kind: SyntaxKind,
        forward_parent: Option<u32>,
    },

    /// Complete the previous `Start` event
    Finish,

    /// Produce a single leaf-element.
    /// `n_raw_tokens` is used to glue complex contextual tokens.
    /// For example, lexer tokenizes `>>` as `>`, `>`, and
    /// `n_raw_tokens = 2` is used to produced a single `>>`.
    Token {
        kind: SyntaxKind,
        n_raw_tokens: u8,
    },

    Error {
        msg: String,
    },
}

pub(super) struct EventProcessor<'a, S: Sink> {
    sink: S,
    text_pos: TextUnit,
    text: &'a str,
    token_pos: usize,
    tokens: &'a [Token],
    events: &'a mut [Event],
}

impl<'a, S: Sink> EventProcessor<'a, S> {
    pub(super) fn new(sink: S, text: &'a str, tokens: &'a[Token], events: &'a mut [Event]) -> EventProcessor<'a, S> {
        EventProcessor {
            sink,
            text_pos: 0.into(),
            text,
            token_pos: 0,
            tokens,
            events
        }
    }

    pub(super) fn process(mut self) -> S {
        fn tombstone() -> Event {
            Event::Start { kind: TOMBSTONE, forward_parent: None }
        }
        let mut depth = 0;
        let mut forward_parents = Vec::new();

        for i in 0..self.events.len() {
            match mem::replace(&mut self.events[i], tombstone()) {
                Event::Start {
                    kind: TOMBSTONE, ..
                } => (),

                Event::Start { kind, forward_parent } => {
                    forward_parents.push(kind);
                    let mut idx = i;
                    let mut fp = forward_parent;
                    while let Some(fwd) = fp {
                        idx += fwd as usize;
                        fp = match mem::replace(&mut self.events[idx], tombstone()) {
                            Event::Start {
                                kind,
                                forward_parent,
                            } => {
                                forward_parents.push(kind);
                                forward_parent
                            },
                            _ => unreachable!(),
                        };
                    }
                    for kind in forward_parents.drain(..).rev() {
                        if depth > 0 {
                            self.eat_ws();
                        }
                        depth += 1;
                        self.sink.start_internal(kind);
                    }
                }
                Event::Finish => {
                    depth -= 1;
                    if depth == 0 {
                        self.eat_ws();
                    }

                    self.sink.finish_internal();
                }
                Event::Token {
                    kind,
                    mut n_raw_tokens,
                } => {
                    self.eat_ws();
                    let mut len = 0.into();
                    for _ in 0..n_raw_tokens {
                        len += self.tokens[self.token_pos].len;
                    }
                    self.leaf(kind, len, n_raw_tokens as usize);
                }
                Event::Error { msg } => self.sink.error(msg, self.text_pos),
            }
        }
        self.sink
    }

    fn eat_ws(&mut self) {
        while let Some(&token) = self.tokens.get(self.token_pos) {
            if !token.kind.is_trivia() {
                break;
            }
            self.leaf(token.kind, token.len, 1);
        }
    }

    fn leaf(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) {
        let range = TextRange::offset_len(self.text_pos, len);
        let text: SmolStr = self.text[range].into();
        self.text_pos += len;
        self.token_pos += n_tokens;
        self.sink.leaf(kind, text);
    }
}
<commit_msg>replace loop with iterators<commit_after>//! This module provides a way to construct a `File`.
//! It is intended to be completely decoupled from the
//! parser, so as to allow to evolve the tree representation
//! and the parser algorithm independently.
//!
//! The `Sink` trait is the bridge between the parser and the
//! tree builder: the parser produces a stream of events like
//! `start node`, `finish node`, and `FileBuilder` converts
//! this stream to a real tree.
use std::mem;
use {
    TextUnit, TextRange, SmolStr,
    lexer::Token,
    parser_impl::Sink,
    SyntaxKind::{self, TOMBSTONE},
};

/// `Parser` produces a flat list of `Event`s.
/// They are converted to a tree-structure in
/// a separate pass, via `TreeBuilder`.
#[derive(Debug)]
pub(crate) enum Event {
    /// This event signifies the start of the node.
    /// It should be either abandoned (in which case the
    /// `kind` is `TOMBSTONE`, and the event is ignored),
    /// or completed via a `Finish` event.
    ///
    /// All tokens between a `Start` and a `Finish` would
    /// become the children of the respective node.
    ///
    /// For left-recursive syntactic constructs, the parser produces
    /// a child node before it sees a parent. `forward_parent`
    /// exists to allow to tweak parent-child relationships.
    ///
    /// Consider this path
    ///
    /// foo::bar
    ///
    /// The events for it would look like this:
    ///
    ///
    /// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
    ///       |                          /\
    ///       |                          |
    ///       +------forward-parent------+
    ///
    /// And the tree would look like this
    ///
    ///    +--PATH---------+
    ///    |   |           |
    ///    |   |           |
    ///    |  '::'       'bar'
    ///    |
    ///   PATH
    ///    |
    ///   'foo'
    ///
    /// See also `CompletedMarker::precede`.
    Start {
        kind: SyntaxKind,
        forward_parent: Option<u32>,
    },

    /// Complete the previous `Start` event
    Finish,

    /// Produce a single leaf-element.
    /// `n_raw_tokens` is used to glue complex contextual tokens.
    /// For example, lexer tokenizes `>>` as `>`, `>`, and
    /// `n_raw_tokens = 2` is used to produced a single `>>`.
    Token {
        kind: SyntaxKind,
        n_raw_tokens: u8,
    },

    Error {
        msg: String,
    },
}

pub(super) struct EventProcessor<'a, S: Sink> {
    sink: S,
    text_pos: TextUnit,
    text: &'a str,
    token_pos: usize,
    tokens: &'a [Token],
    events: &'a mut [Event],
}

impl<'a, S: Sink> EventProcessor<'a, S> {
    pub(super) fn new(sink: S, text: &'a str, tokens: &'a[Token], events: &'a mut [Event]) -> EventProcessor<'a, S> {
        EventProcessor {
            sink,
            text_pos: 0.into(),
            text,
            token_pos: 0,
            tokens,
            events
        }
    }

    pub(super) fn process(mut self) -> S {
        fn tombstone() -> Event {
            Event::Start { kind: TOMBSTONE, forward_parent: None }
        }
        let mut depth = 0;
        let mut forward_parents = Vec::new();

        for i in 0..self.events.len() {
            match mem::replace(&mut self.events[i], tombstone()) {
                Event::Start {
                    kind: TOMBSTONE, ..
                } => (),

                Event::Start { kind, forward_parent } => {
                    forward_parents.push(kind);
                    let mut idx = i;
                    let mut fp = forward_parent;
                    while let Some(fwd) = fp {
                        idx += fwd as usize;
                        fp = match mem::replace(&mut self.events[idx], tombstone()) {
                            Event::Start {
                                kind,
                                forward_parent,
                            } => {
                                forward_parents.push(kind);
                                forward_parent
                            },
                            _ => unreachable!(),
                        };
                    }
                    for kind in forward_parents.drain(..).rev() {
                        if depth > 0 {
                            self.eat_ws();
                        }
                        depth += 1;
                        self.sink.start_internal(kind);
                    }
                }
                Event::Finish => {
                    depth -= 1;
                    if depth == 0 {
                        self.eat_ws();
                    }

                    self.sink.finish_internal();
                }
                Event::Token {
                    kind,
                    n_raw_tokens,
                } => {
                    self.eat_ws();
                    let n_raw_tokens = n_raw_tokens as usize;
                    let len = self.tokens[self.token_pos..self.token_pos + n_raw_tokens]
                        .iter()
                        .map(|it| it.len)
                        .sum::<TextUnit>();
                    self.leaf(kind, len, n_raw_tokens);
                }
                Event::Error { msg } => self.sink.error(msg, self.text_pos),
            }
        }
        self.sink
    }

    fn eat_ws(&mut self) {
        while let Some(&token) = self.tokens.get(self.token_pos) {
            if !token.kind.is_trivia() {
                break;
            }
            self.leaf(token.kind, token.len, 1);
        }
    }

    fn leaf(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) {
        let range = TextRange::offset_len(self.text_pos, len);
        let text: SmolStr = self.text[range].into();
        self.text_pos += len;
        self.token_pos += n_tokens;
        self.sink.leaf(kind, text);
    }
}
<|endoftext|>


<commit_before>use cairo;

use crate::float_eq_cairo::ApproxEqCairo;

mod rect {
    use crate::float_eq_cairo::ApproxEqCairo;
    use core::ops::{Add, Range, Sub};
    use num_traits::Zero;

    // Use our own min() and max() that are acceptable for floating point

    fn min<T: PartialOrd>(x: T, y: T) -> T {
        if x <= y {
            x
        } else {
            y
        }
    }

    fn max<T: PartialOrd>(x: T, y: T) -> T {
        if x >= y {
            x
        } else {
            y
        }
    }

    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
    pub struct Rect<T> {
        pub x0: T,
        pub y0: T,
        pub x1: T,
        pub y1: T,
    }

    impl<T> Rect<T> {
        #[inline]
        pub fn new(x0: T, y0: T, x1: T, y1: T) -> Self {
            Self { x0, y0, x1, y1 }
        }
    }

    impl<T> Rect<T>
    where
        T: Copy + PartialOrd + PartialEq + Add<T, Output = T> + Sub<T, Output = T> + Zero,
    {
        #[inline]
        pub fn from_size(w: T, h: T) -> Self {
            Self {
                x0: Zero::zero(),
                y0: Zero::zero(),
                x1: w,
                y1: h,
            }
        }

        #[inline]
        pub fn width(&self) -> T {
            self.x1 - self.x0
        }

        #[inline]
        pub fn height(&self) -> T {
            self.y1 - self.y0
        }

        #[inline]
        pub fn size(&self) -> (T, T) {
            (self.width(), self.height())
        }

        #[inline]
        pub fn x_range(&self) -> Range<T> {
            self.x0..self.x1
        }

        #[inline]
        pub fn y_range(&self) -> Range<T> {
            self.y0..self.y1
        }

        #[inline]
        pub fn contains(self, x: T, y: T) -> bool {
            x >= self.x0 && x < self.x1 && y >= self.y0 && y < self.y1
        }

        #[inline]
        pub fn translate(&self, by: (T, T)) -> Self {
            Self {
                x0: self.x0 + by.0,
                y0: self.y0 + by.1,
                x1: self.x1 + by.0,
                y1: self.y1 + by.1,
            }
        }

        #[inline]
        pub fn intersection(&self, rect: &Self) -> Option<Self> {
            let (x0, y0, x1, y1) = (
                max(self.x0, rect.x0),
                max(self.y0, rect.y0),
                min(self.x1, rect.x1),
                min(self.y1, rect.y1),
            );

            if x1 > x0 && y1 > y0 {
                Some(Self { x0, y0, x1, y1 })
            } else {
                None
            }
        }

        #[inline]
        pub fn union(&self, rect: &Self) -> Self {
            Self {
                x0: min(self.x0, rect.x0),
                y0: min(self.y0, rect.y0),
                x1: max(self.x1, rect.x1),
                y1: max(self.y1, rect.y1),
            }
        }
    }

    impl Rect<i32> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width() == Zero::zero() || self.height() == Zero::zero()
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: (f64::from(self.x0) * x).floor() as i32,
                y0: (f64::from(self.y0) * y).floor() as i32,
                x1: (f64::from(self.x1) * x).ceil() as i32,
                y1: (f64::from(self.y1) * y).ceil() as i32,
            }
        }
    }

    impl Rect<f64> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width().approx_eq_cairo(0.0) || self.height().approx_eq_cairo(0.0)
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: self.x0 * x,
                y0: self.y0 * y,
                x1: self.x1 * x,
                y1: self.y1 * y,
            }
        }
    }
}

pub type Rect = rect::Rect<f64>;

impl From<cairo::Rectangle> for Rect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x,
            y0: r.y,
            x1: r.x + r.width,
            y1: r.y + r.height,
        }
    }
}

impl From<Rect> for cairo::Rectangle {
    #[inline]
    fn from(r: Rect) -> Self {
        Self {
            x: r.x0,
            y: r.y0,
            width: r.x1 - r.x0,
            height: r.y1 - r.y0,
        }
    }
}

pub type IRect = rect::Rect<i32>;

impl From<cairo::Rectangle> for IRect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x.floor() as i32,
            y0: r.y.floor() as i32,
            x1: (r.x + r.width).ceil() as i32,
            y1: (r.y + r.height).ceil() as i32,
        }
    }
}

impl From<IRect> for cairo::Rectangle {
    #[inline]
    fn from(r: IRect) -> Self {
        Self {
            x: f64::from(r.x0),
            y: f64::from(r.y0),
            width: f64::from(r.x1 - r.x0),
            height: f64::from(r.y1 - r.y0),
        }
    }
}

pub trait RectangleExt {
    fn new(x: f64, y: f64, width: f64, height: f64) -> cairo::Rectangle;
    fn from_size(width: f64, height: f64) -> cairo::Rectangle;
    fn from_extents(x0: f64, y0: f64, x1: f64, y1: f64) -> cairo::Rectangle;
    fn is_empty(&self) -> bool;
    fn intersection(&self, rect: &cairo::Rectangle) -> Option<cairo::Rectangle>;
    fn union(&self, rect: &cairo::Rectangle) -> cairo::Rectangle;
    fn translate(&self, by: (f64, f64)) -> cairo::Rectangle;
}

impl RectangleExt for cairo::Rectangle {
    fn new(x: f64, y: f64, width: f64, height: f64) -> cairo::Rectangle {
        cairo::Rectangle {
            x,
            y,
            width,
            height,
        }
    }

    fn from_size(width: f64, height: f64) -> cairo::Rectangle {
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width,
            height,
        }
    }

    fn from_extents(x0: f64, y0: f64, x1: f64, y1: f64) -> cairo::Rectangle {
        cairo::Rectangle {
            x: x0,
            y: y0,
            width: x1 - x0,
            height: y1 - y0,
        }
    }

    fn is_empty(&self) -> bool {
        self.width.approx_eq_cairo(0.0) || self.height.approx_eq_cairo(0.0)
    }

    fn intersection(&self, rect: &cairo::Rectangle) -> Option<cairo::Rectangle> {
        let (x1, y1, x2, y2) = (
            self.x.max(rect.x),
            self.y.max(rect.y),
            (self.x + self.width).min(rect.x + rect.width),
            (self.y + self.height).min(rect.y + rect.height),
        );

        if x2 > x1 && y2 > y1 {
            Some(cairo::Rectangle {
                x: x1,
                y: y1,
                width: x2 - x1,
                height: y2 - y1,
            })
        } else {
            None
        }
    }

    fn union(&self, rect: &cairo::Rectangle) -> cairo::Rectangle {
        let (x1, y1, x2, y2) = (
            self.x.min(rect.x),
            self.y.min(rect.y),
            (self.x + self.width).max(rect.x + rect.width),
            (self.y + self.height).max(rect.y + rect.height),
        );

        cairo::Rectangle {
            x: x1,
            y: y1,
            width: x2 - x1,
            height: y2 - y1,
        }
    }

    fn translate(&self, by: (f64, f64)) -> cairo::Rectangle {
        cairo::Rectangle {
            x: self.x + by.0,
            y: self.y + by.1,
            width: self.width,
            height: self.height,
        }
    }
}

pub trait TransformRect {
    fn transform_rect(&self, rect: &cairo::Rectangle) -> cairo::Rectangle;
}

impl TransformRect for cairo::Matrix {
    fn transform_rect(&self, rect: &cairo::Rectangle) -> cairo::Rectangle {
        let points = vec![
            self.transform_point(rect.x, rect.y),
            self.transform_point(rect.x + rect.width, rect.y),
            self.transform_point(rect.x, rect.y + rect.height),
            self.transform_point(rect.x + rect.width, rect.y + rect.height),
        ];

        let (mut xmin, mut ymin, mut xmax, mut ymax) = {
            let (x, y) = points[0];

            (x, y, x, y)
        };

        for &(x, y) in points.iter().take(4).skip(1) {
            if x < xmin {
                xmin = x;
            }

            if x > xmax {
                xmax = x;
            }

            if y < ymin {
                ymin = y;
            }

            if y > ymax {
                ymax = y;
            }
        }

        cairo::Rectangle {
            x: xmin,
            y: ymin,
            width: xmax - xmin,
            height: ymax - ymin,
        }
    }
}

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

    #[test]
    fn empty_rect() {
        let empty = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 0.0,
            height: 0.0,
        };
        let not_empty = cairo::Rectangle {
            x: 0.22,
            y: 0.22,
            width: 3.14,
            height: 3.14,
        };

        assert!(empty.is_empty());
        assert!(!not_empty.is_empty());
    }

    #[test]
    fn intersect_rects() {
        let r1 = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 4.14,
            height: 4.14,
        };
        let r2 = cairo::Rectangle {
            x: 0.22,
            y: 0.22,
            width: 3.14,
            height: 3.14,
        };
        let r3 = cairo::Rectangle {
            x: 10.0,
            y: 10.0,
            width: 3.14,
            height: 3.14,
        };

        let r = r1.intersection(&r2).unwrap();
        assert_approx_eq_cairo!(0.42_f64, r.x);
        assert_approx_eq_cairo!(0.42_f64, r.y);
        assert_approx_eq_cairo!(2.94_f64, r.width);
        assert_approx_eq_cairo!(2.94_f64, r.height);

        let r = r1.intersection(&r3);
        assert!(r.is_none());
    }

    #[test]
    fn union_rects() {
        let r1 = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 4.14,
            height: 4.14,
        };
        let r2 = cairo::Rectangle {
            x: 0.22,
            y: 0.22,
            width: 3.14,
            height: 3.14,
        };

        let r = r1.union(&r2);
        assert_approx_eq_cairo!(0.22_f64, r.x);
        assert_approx_eq_cairo!(0.22_f64, r.y);
        assert_approx_eq_cairo!(4.34_f64, r.width);
        assert_approx_eq_cairo!(4.34_f64, r.height);
    }

    #[test]
    fn transform_rect() {
        let r = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 3.14,
            height: 3.14,
        };

        let m = cairo::Matrix::identity();
        let tr = m.transform_rect(&r);
        assert_eq!(tr, r);

        let m = cairo::Matrix::new(2.0, 0.0, 0.0, 2.0, 1.5, 1.5);
        let tr = m.transform_rect(&r);
        assert_approx_eq_cairo!(2.34_f64, tr.x);
        assert_approx_eq_cairo!(2.34_f64, tr.y);
        assert_approx_eq_cairo!(6.28_f64, tr.width);
        assert_approx_eq_cairo!(6.28_f64, tr.height);
    }
}
<commit_msg>rect: conversion trait<commit_after>use cairo;

use crate::float_eq_cairo::ApproxEqCairo;

mod rect {
    use crate::float_eq_cairo::ApproxEqCairo;
    use core::ops::{Add, Range, Sub};
    use num_traits::Zero;

    // Use our own min() and max() that are acceptable for floating point

    fn min<T: PartialOrd>(x: T, y: T) -> T {
        if x <= y {
            x
        } else {
            y
        }
    }

    fn max<T: PartialOrd>(x: T, y: T) -> T {
        if x >= y {
            x
        } else {
            y
        }
    }

    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
    pub struct Rect<T> {
        pub x0: T,
        pub y0: T,
        pub x1: T,
        pub y1: T,
    }

    impl<T> Rect<T> {
        #[inline]
        pub fn new(x0: T, y0: T, x1: T, y1: T) -> Self {
            Self { x0, y0, x1, y1 }
        }
    }

    impl<T> Rect<T>
    where
        T: Copy + PartialOrd + PartialEq + Add<T, Output = T> + Sub<T, Output = T> + Zero,
    {
        #[inline]
        pub fn from_size(w: T, h: T) -> Self {
            Self {
                x0: Zero::zero(),
                y0: Zero::zero(),
                x1: w,
                y1: h,
            }
        }

        #[inline]
        pub fn width(&self) -> T {
            self.x1 - self.x0
        }

        #[inline]
        pub fn height(&self) -> T {
            self.y1 - self.y0
        }

        #[inline]
        pub fn size(&self) -> (T, T) {
            (self.width(), self.height())
        }

        #[inline]
        pub fn x_range(&self) -> Range<T> {
            self.x0..self.x1
        }

        #[inline]
        pub fn y_range(&self) -> Range<T> {
            self.y0..self.y1
        }

        #[inline]
        pub fn contains(self, x: T, y: T) -> bool {
            x >= self.x0 && x < self.x1 && y >= self.y0 && y < self.y1
        }

        #[inline]
        pub fn translate(&self, by: (T, T)) -> Self {
            Self {
                x0: self.x0 + by.0,
                y0: self.y0 + by.1,
                x1: self.x1 + by.0,
                y1: self.y1 + by.1,
            }
        }

        #[inline]
        pub fn intersection(&self, rect: &Self) -> Option<Self> {
            let (x0, y0, x1, y1) = (
                max(self.x0, rect.x0),
                max(self.y0, rect.y0),
                min(self.x1, rect.x1),
                min(self.y1, rect.y1),
            );

            if x1 > x0 && y1 > y0 {
                Some(Self { x0, y0, x1, y1 })
            } else {
                None
            }
        }

        #[inline]
        pub fn union(&self, rect: &Self) -> Self {
            Self {
                x0: min(self.x0, rect.x0),
                y0: min(self.y0, rect.y0),
                x1: max(self.x1, rect.x1),
                y1: max(self.y1, rect.y1),
            }
        }
    }

    impl Rect<i32> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width() == Zero::zero() || self.height() == Zero::zero()
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: (f64::from(self.x0) * x).floor() as i32,
                y0: (f64::from(self.y0) * y).floor() as i32,
                x1: (f64::from(self.x1) * x).ceil() as i32,
                y1: (f64::from(self.y1) * y).ceil() as i32,
            }
        }
    }

    impl Rect<f64> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width().approx_eq_cairo(0.0) || self.height().approx_eq_cairo(0.0)
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: self.x0 * x,
                y0: self.y0 * y,
                x1: self.x1 * x,
                y1: self.y1 * y,
            }
        }
    }
}

pub type Rect = rect::Rect<f64>;

impl From<Rect> for IRect {
    #[inline]
    fn from(r: Rect) -> Self {
        Self {
            x0: r.x0.floor() as i32,
            y0: r.y0.floor() as i32,
            x1: r.x1.ceil() as i32,
            y1: r.y1.ceil() as i32,
        }
    }
}

impl From<cairo::Rectangle> for Rect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x,
            y0: r.y,
            x1: r.x + r.width,
            y1: r.y + r.height,
        }
    }
}

impl From<Rect> for cairo::Rectangle {
    #[inline]
    fn from(r: Rect) -> Self {
        Self {
            x: r.x0,
            y: r.y0,
            width: r.x1 - r.x0,
            height: r.y1 - r.y0,
        }
    }
}

pub type IRect = rect::Rect<i32>;

impl From<IRect> for Rect {
    #[inline]
    fn from(r: IRect) -> Self {
        Self {
            x0: f64::from(r.x0),
            y0: f64::from(r.y0),
            x1: f64::from(r.x1),
            y1: f64::from(r.y1),
        }
    }
}

impl From<cairo::Rectangle> for IRect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x.floor() as i32,
            y0: r.y.floor() as i32,
            x1: (r.x + r.width).ceil() as i32,
            y1: (r.y + r.height).ceil() as i32,
        }
    }
}

impl From<IRect> for cairo::Rectangle {
    #[inline]
    fn from(r: IRect) -> Self {
        Self {
            x: f64::from(r.x0),
            y: f64::from(r.y0),
            width: f64::from(r.x1 - r.x0),
            height: f64::from(r.y1 - r.y0),
        }
    }
}

pub trait RectangleExt {
    fn new(x: f64, y: f64, width: f64, height: f64) -> cairo::Rectangle;
    fn from_size(width: f64, height: f64) -> cairo::Rectangle;
    fn from_extents(x0: f64, y0: f64, x1: f64, y1: f64) -> cairo::Rectangle;
    fn is_empty(&self) -> bool;
    fn intersection(&self, rect: &cairo::Rectangle) -> Option<cairo::Rectangle>;
    fn union(&self, rect: &cairo::Rectangle) -> cairo::Rectangle;
    fn translate(&self, by: (f64, f64)) -> cairo::Rectangle;
}

impl RectangleExt for cairo::Rectangle {
    fn new(x: f64, y: f64, width: f64, height: f64) -> cairo::Rectangle {
        cairo::Rectangle {
            x,
            y,
            width,
            height,
        }
    }

    fn from_size(width: f64, height: f64) -> cairo::Rectangle {
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width,
            height,
        }
    }

    fn from_extents(x0: f64, y0: f64, x1: f64, y1: f64) -> cairo::Rectangle {
        cairo::Rectangle {
            x: x0,
            y: y0,
            width: x1 - x0,
            height: y1 - y0,
        }
    }

    fn is_empty(&self) -> bool {
        self.width.approx_eq_cairo(0.0) || self.height.approx_eq_cairo(0.0)
    }

    fn intersection(&self, rect: &cairo::Rectangle) -> Option<cairo::Rectangle> {
        let (x1, y1, x2, y2) = (
            self.x.max(rect.x),
            self.y.max(rect.y),
            (self.x + self.width).min(rect.x + rect.width),
            (self.y + self.height).min(rect.y + rect.height),
        );

        if x2 > x1 && y2 > y1 {
            Some(cairo::Rectangle {
                x: x1,
                y: y1,
                width: x2 - x1,
                height: y2 - y1,
            })
        } else {
            None
        }
    }

    fn union(&self, rect: &cairo::Rectangle) -> cairo::Rectangle {
        let (x1, y1, x2, y2) = (
            self.x.min(rect.x),
            self.y.min(rect.y),
            (self.x + self.width).max(rect.x + rect.width),
            (self.y + self.height).max(rect.y + rect.height),
        );

        cairo::Rectangle {
            x: x1,
            y: y1,
            width: x2 - x1,
            height: y2 - y1,
        }
    }

    fn translate(&self, by: (f64, f64)) -> cairo::Rectangle {
        cairo::Rectangle {
            x: self.x + by.0,
            y: self.y + by.1,
            width: self.width,
            height: self.height,
        }
    }
}

pub trait TransformRect {
    fn transform_rect(&self, rect: &cairo::Rectangle) -> cairo::Rectangle;
}

impl TransformRect for cairo::Matrix {
    fn transform_rect(&self, rect: &cairo::Rectangle) -> cairo::Rectangle {
        let points = vec![
            self.transform_point(rect.x, rect.y),
            self.transform_point(rect.x + rect.width, rect.y),
            self.transform_point(rect.x, rect.y + rect.height),
            self.transform_point(rect.x + rect.width, rect.y + rect.height),
        ];

        let (mut xmin, mut ymin, mut xmax, mut ymax) = {
            let (x, y) = points[0];

            (x, y, x, y)
        };

        for &(x, y) in points.iter().take(4).skip(1) {
            if x < xmin {
                xmin = x;
            }

            if x > xmax {
                xmax = x;
            }

            if y < ymin {
                ymin = y;
            }

            if y > ymax {
                ymax = y;
            }
        }

        cairo::Rectangle {
            x: xmin,
            y: ymin,
            width: xmax - xmin,
            height: ymax - ymin,
        }
    }
}

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

    #[test]
    fn empty_rect() {
        let empty = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 0.0,
            height: 0.0,
        };
        let not_empty = cairo::Rectangle {
            x: 0.22,
            y: 0.22,
            width: 3.14,
            height: 3.14,
        };

        assert!(empty.is_empty());
        assert!(!not_empty.is_empty());
    }

    #[test]
    fn intersect_rects() {
        let r1 = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 4.14,
            height: 4.14,
        };
        let r2 = cairo::Rectangle {
            x: 0.22,
            y: 0.22,
            width: 3.14,
            height: 3.14,
        };
        let r3 = cairo::Rectangle {
            x: 10.0,
            y: 10.0,
            width: 3.14,
            height: 3.14,
        };

        let r = r1.intersection(&r2).unwrap();
        assert_approx_eq_cairo!(0.42_f64, r.x);
        assert_approx_eq_cairo!(0.42_f64, r.y);
        assert_approx_eq_cairo!(2.94_f64, r.width);
        assert_approx_eq_cairo!(2.94_f64, r.height);

        let r = r1.intersection(&r3);
        assert!(r.is_none());
    }

    #[test]
    fn union_rects() {
        let r1 = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 4.14,
            height: 4.14,
        };
        let r2 = cairo::Rectangle {
            x: 0.22,
            y: 0.22,
            width: 3.14,
            height: 3.14,
        };

        let r = r1.union(&r2);
        assert_approx_eq_cairo!(0.22_f64, r.x);
        assert_approx_eq_cairo!(0.22_f64, r.y);
        assert_approx_eq_cairo!(4.34_f64, r.width);
        assert_approx_eq_cairo!(4.34_f64, r.height);
    }

    #[test]
    fn transform_rect() {
        let r = cairo::Rectangle {
            x: 0.42,
            y: 0.42,
            width: 3.14,
            height: 3.14,
        };

        let m = cairo::Matrix::identity();
        let tr = m.transform_rect(&r);
        assert_eq!(tr, r);

        let m = cairo::Matrix::new(2.0, 0.0, 0.0, 2.0, 1.5, 1.5);
        let tr = m.transform_rect(&r);
        assert_approx_eq_cairo!(2.34_f64, tr.x);
        assert_approx_eq_cairo!(2.34_f64, tr.y);
        assert_approx_eq_cairo!(6.28_f64, tr.width);
        assert_approx_eq_cairo!(6.28_f64, tr.height);
    }
}
<|endoftext|>


<commit_before>use rustc_errors::DiagnosticBuilder;
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
use rustc_span::def_id::DefId;

use crate::transform::{MirPass, MirSource};

pub struct CheckConstItemMutation;

impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let mut checker = ConstMutationChecker { body, tcx, target_local: None };
        checker.visit_body(&body);
    }
}

struct ConstMutationChecker<'a, 'tcx> {
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    target_local: Option<Local>,
}

impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
    fn is_const_item(&self, local: Local) -> Option<DefId> {
        if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info {
            Some(def_id)
        } else {
            None
        }
    }
    fn lint_const_item_usage(
        &self,
        const_item: DefId,
        location: Location,
        decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>,
    ) {
        let source_info = self.body.source_info(location);
        let lint_root = self.body.source_scopes[source_info.scope]
            .local_data
            .as_ref()
            .assert_crate_local()
            .lint_root;

        self.tcx.struct_span_lint_hir(CONST_ITEM_MUTATION, lint_root, source_info.span, |lint| {
            decorate(lint)
                .span_note(self.tcx.def_span(const_item), "`const` item defined here")
                .emit()
        });
    }
}

impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
    fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) {
        if let StatementKind::Assign(box (lhs, _)) = &stmt.kind {
            // Check for assignment to fields of a constant
            // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
            // so emitting a lint would be redundant.
            if !lhs.projection.is_empty() {
                if let Some(def_id) = self.is_const_item(lhs.local) {
                    // Don't lint on writes through a pointer
                    // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`)
                    if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) {
                        self.lint_const_item_usage(def_id, loc, |lint| {
                            let mut lint = lint.build("attempting to modify a `const` item");
                            lint.note("each usage of a `const` item creates a new temporary - the original `const` item will not be modified");
                            lint
                        })
                    }
                }
            }
            // We are looking for MIR of the form:
            //
            // ```
            // _1 = const FOO;
            // _2 = &mut _1;
            // method_call(_2, ..)
            // ```
            //
            // Record our current LHS, so that we can detect this
            // pattern in `visit_rvalue`
            self.target_local = lhs.as_local();
        }
        self.super_statement(stmt, loc);
        self.target_local = None;
    }
    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) {
        if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue {
            let local = place.local;
            if let Some(def_id) = self.is_const_item(local) {
                // If this Rvalue is being used as the right-hand side of a
                // `StatementKind::Assign`, see if it ends up getting used as
                // the `self` parameter of a method call (as the terminator of our current
                // BasicBlock). If so, we emit a more specific lint.
                let method_did = self.target_local.and_then(|target_local| {
                    crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block)
                });
                let lint_loc =
                    if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
                self.lint_const_item_usage(def_id, lint_loc, |lint| {
                    let mut lint = lint.build("taking a mutable reference to a `const` item");
                    lint
                        .note("each usage of a `const` item creates a new temporary")
                        .note("the mutable reference will refer to this temporary, not the original `const` item");

                    if let Some((method_did, _substs)) = method_did {
                        lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
                    }

                    lint
                });
            }
        }
        self.super_rvalue(rvalue, loc);
    }
}
<commit_msg>Bypass const_item_mutation if const's type has Drop impl<commit_after>use rustc_errors::DiagnosticBuilder;
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
use rustc_span::def_id::DefId;

use crate::transform::{MirPass, MirSource};

pub struct CheckConstItemMutation;

impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
        let mut checker = ConstMutationChecker { body, tcx, target_local: None };
        checker.visit_body(&body);
    }
}

struct ConstMutationChecker<'a, 'tcx> {
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    target_local: Option<Local>,
}

impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
    fn is_const_item(&self, local: Local) -> Option<DefId> {
        if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info {
            Some(def_id)
        } else {
            None
        }
    }

    fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
        let def_id = self.is_const_item(local)?;
        match self.tcx.adt_def(def_id).destructor(self.tcx) {
            Some(_) => None,
            None => Some(def_id),
        }
    }

    fn lint_const_item_usage(
        &self,
        const_item: DefId,
        location: Location,
        decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>,
    ) {
        let source_info = self.body.source_info(location);
        let lint_root = self.body.source_scopes[source_info.scope]
            .local_data
            .as_ref()
            .assert_crate_local()
            .lint_root;

        self.tcx.struct_span_lint_hir(CONST_ITEM_MUTATION, lint_root, source_info.span, |lint| {
            decorate(lint)
                .span_note(self.tcx.def_span(const_item), "`const` item defined here")
                .emit()
        });
    }
}

impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
    fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) {
        if let StatementKind::Assign(box (lhs, _)) = &stmt.kind {
            // Check for assignment to fields of a constant
            // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
            // so emitting a lint would be redundant.
            if !lhs.projection.is_empty() {
                if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
                    // Don't lint on writes through a pointer
                    // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`)
                    if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) {
                        self.lint_const_item_usage(def_id, loc, |lint| {
                            let mut lint = lint.build("attempting to modify a `const` item");
                            lint.note("each usage of a `const` item creates a new temporary - the original `const` item will not be modified");
                            lint
                        })
                    }
                }
            }
            // We are looking for MIR of the form:
            //
            // ```
            // _1 = const FOO;
            // _2 = &mut _1;
            // method_call(_2, ..)
            // ```
            //
            // Record our current LHS, so that we can detect this
            // pattern in `visit_rvalue`
            self.target_local = lhs.as_local();
        }
        self.super_statement(stmt, loc);
        self.target_local = None;
    }
    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) {
        if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue {
            let local = place.local;
            if let Some(def_id) = self.is_const_item_without_destructor(local) {
                // If this Rvalue is being used as the right-hand side of a
                // `StatementKind::Assign`, see if it ends up getting used as
                // the `self` parameter of a method call (as the terminator of our current
                // BasicBlock). If so, we emit a more specific lint.
                let method_did = self.target_local.and_then(|target_local| {
                    crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block)
                });
                let lint_loc =
                    if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
                self.lint_const_item_usage(def_id, lint_loc, |lint| {
                    let mut lint = lint.build("taking a mutable reference to a `const` item");
                    lint
                        .note("each usage of a `const` item creates a new temporary")
                        .note("the mutable reference will refer to this temporary, not the original `const` item");

                    if let Some((method_did, _substs)) = method_did {
                        lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
                    }

                    lint
                });
            }
        }
        self.super_rvalue(rvalue, loc);
    }
}
<|endoftext|>