<commit_before>use std::collections::HashMap;
use std::io::ErrorKind;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

use crate::error::Error;

// Indicate an interest in read and/or write events.
struct Interest(bool, bool);

// Object returned when the EventLoop is run.  When this is dropped, the EventLoop is stopped.
pub struct EventLoopStopper {
    poller: Arc<polling::Poller>,
    quit: Arc<AtomicBool>,
}

impl EventLoopStopper {
    pub fn new(poller: Arc<polling::Poller>, quit: Arc<AtomicBool>) -> Self {
        Self { poller, quit }
    }
}

impl Drop for EventLoopStopper {
    fn drop(&mut self) {
        self.quit.store(true, Ordering::Relaxed);
        self.poller.notify().expect("Failed to notify poller");
    }
}

// The EventLoop sets up a polling::Poller and use it to wait for events on file descriptors as
// directed by the c-ares library.
pub struct EventLoop {
    poller: Arc<polling::Poller>,
    interests: Arc<Mutex<HashMap<c_ares::Socket, Interest>>>,
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: Arc<AtomicBool>,
}

impl EventLoop {
    // Create a new event loop.
    pub fn new(mut options: c_ares::Options) -> Result<Self, Error> {
        // Create a polling::Poller on which to wait for events, and a channel for sending messages
        // to the event loop.
        let poller = Arc::new(polling::Poller::new()?);
        let interests: HashMap<c_ares::Socket, Interest> = HashMap::new();
        let interests = Arc::new(Mutex::new(interests));

        // Whenever c-ares tells us what to do with a file descriptor, we'll update the poller
        // accordingly.
        {
            let poller = Arc::clone(&poller);
            let interests = Arc::clone(&interests);
            let sock_callback = move |socket: c_ares::Socket, readable: bool, writable: bool| {
                let mut interests = interests.lock().unwrap();
                if !readable && !writable {
                    if interests.remove(&socket).is_some() {
                        poller
                            .remove(socket)
                            .expect("Failed to remove socket from poller");
                    }
                } else {
                    let interest = Interest(readable, writable);
                    if interests.insert(socket, interest).is_none() {
                        poller
                            .insert(socket)
                            .expect("failed to add socket to poller");
                    }
                    let event = polling::Event {
                        key: socket as usize,
                        readable,
                        writable,
                    };
                    poller
                        .interest(socket, event)
                        .expect("failed to register interest");
                }
            };
            options.set_socket_state_callback(sock_callback);
        }

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::with_options(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            poller,
            interests,
            ares_channel: locked_channel,
            quit: Arc::new(AtomicBool::new(false)),
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopStopper {
        // Create a stopper.
        let poller = Arc::clone(&self.poller);
        let quit = Arc::clone(&self.quit);
        let stopper = EventLoopStopper::new(poller, quit);

        thread::spawn(|| self.event_loop_thread());
        stopper
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = vec![];
        let timeout = Duration::from_millis(500);
        loop {
            // Wait for something to happen.
            events.clear();
            let results = self.poller.wait(&mut events, Some(timeout));

            // If we're asked to quit, then quit.
            if self.quit.load(Ordering::Relaxed) {
                break;
            }

            // Interrupted is OK, we just retry.  Other errors are unexpected.
            if let Err(ref err) = results {
                if err.kind() == ErrorKind::Interrupted {
                    continue;
                }
            }
            let results = results.expect("Poll failed");

            // Process any events.
            match results {
                0 => {
                    // No events.  Have c-ares process any timeouts.
                    self.ares_channel
                        .lock()
                        .unwrap()
                        .process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
                }
                _ => {
                    // Process events.
                    for event in &events {
                        self.handle_event(&event);
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &polling::Event) {
        // `polling` always operates in oneshot mode, but c-ares expects us to maintain an interest
        // in sockets until told otherwise.
        //
        // So re-assert our interest in this socket.
        let socket = event.key as c_ares::Socket;
        {
            let interests = self.interests.lock().unwrap();
            if let Some(Interest(readable, writable)) = interests.get(&socket) {
                let new_event = polling::Event {
                    key: event.key,
                    readable: *readable,
                    writable: *writable,
                };
                self.poller
                    .interest(socket, new_event)
                    .expect("failed to register interest");
            }
        }

        // Tell c-ares that something happened.
        let rfd = if event.readable {
            socket
        } else {
            c_ares::SOCKET_BAD
        };
        let wfd = if event.writable {
            socket
        } else {
            c_ares::SOCKET_BAD
        };
        self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
    }
}
<commit_msg>fix outdated comment<commit_after>use std::collections::HashMap;
use std::io::ErrorKind;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

use crate::error::Error;

// Indicate an interest in read and/or write events.
struct Interest(bool, bool);

// Object returned when the EventLoop is run.  When this is dropped, the EventLoop is stopped.
pub struct EventLoopStopper {
    poller: Arc<polling::Poller>,
    quit: Arc<AtomicBool>,
}

impl EventLoopStopper {
    pub fn new(poller: Arc<polling::Poller>, quit: Arc<AtomicBool>) -> Self {
        Self { poller, quit }
    }
}

impl Drop for EventLoopStopper {
    fn drop(&mut self) {
        self.quit.store(true, Ordering::Relaxed);
        self.poller.notify().expect("Failed to notify poller");
    }
}

// The EventLoop sets up a polling::Poller and use it to wait for events on file descriptors as
// directed by the c-ares library.
pub struct EventLoop {
    poller: Arc<polling::Poller>,
    interests: Arc<Mutex<HashMap<c_ares::Socket, Interest>>>,
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: Arc<AtomicBool>,
}

impl EventLoop {
    // Create a new event loop.
    pub fn new(mut options: c_ares::Options) -> Result<Self, Error> {
        // Create a polling::Poller on which to wait for events, and a hashmap to record what
        // sockets are interested in.
        let poller = Arc::new(polling::Poller::new()?);
        let interests: HashMap<c_ares::Socket, Interest> = HashMap::new();
        let interests = Arc::new(Mutex::new(interests));

        // Whenever c-ares tells us what to do with a file descriptor, we'll update the poller
        // accordingly.
        {
            let poller = Arc::clone(&poller);
            let interests = Arc::clone(&interests);
            let sock_callback = move |socket: c_ares::Socket, readable: bool, writable: bool| {
                let mut interests = interests.lock().unwrap();
                if !readable && !writable {
                    if interests.remove(&socket).is_some() {
                        poller
                            .remove(socket)
                            .expect("Failed to remove socket from poller");
                    }
                } else {
                    let interest = Interest(readable, writable);
                    if interests.insert(socket, interest).is_none() {
                        poller
                            .insert(socket)
                            .expect("failed to add socket to poller");
                    }
                    let event = polling::Event {
                        key: socket as usize,
                        readable,
                        writable,
                    };
                    poller
                        .interest(socket, event)
                        .expect("failed to register interest");
                }
            };
            options.set_socket_state_callback(sock_callback);
        }

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::with_options(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            poller,
            interests,
            ares_channel: locked_channel,
            quit: Arc::new(AtomicBool::new(false)),
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopStopper {
        // Create a stopper.
        let poller = Arc::clone(&self.poller);
        let quit = Arc::clone(&self.quit);
        let stopper = EventLoopStopper::new(poller, quit);

        thread::spawn(|| self.event_loop_thread());
        stopper
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = vec![];
        let timeout = Duration::from_millis(500);
        loop {
            // Wait for something to happen.
            events.clear();
            let results = self.poller.wait(&mut events, Some(timeout));

            // If we're asked to quit, then quit.
            if self.quit.load(Ordering::Relaxed) {
                break;
            }

            // Interrupted is OK, we just retry.  Other errors are unexpected.
            if let Err(ref err) = results {
                if err.kind() == ErrorKind::Interrupted {
                    continue;
                }
            }
            let results = results.expect("Poll failed");

            // Process any events.
            match results {
                0 => {
                    // No events.  Have c-ares process any timeouts.
                    self.ares_channel
                        .lock()
                        .unwrap()
                        .process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
                }
                _ => {
                    // Process events.
                    for event in &events {
                        self.handle_event(&event);
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &polling::Event) {
        // `polling` always operates in oneshot mode, but c-ares expects us to maintain an interest
        // in sockets until told otherwise.
        //
        // So re-assert our interest in this socket.
        let socket = event.key as c_ares::Socket;
        {
            let interests = self.interests.lock().unwrap();
            if let Some(Interest(readable, writable)) = interests.get(&socket) {
                let new_event = polling::Event {
                    key: event.key,
                    readable: *readable,
                    writable: *writable,
                };
                self.poller
                    .interest(socket, new_event)
                    .expect("failed to register interest");
            }
        }

        // Tell c-ares that something happened.
        let rfd = if event.readable {
            socket
        } else {
            c_ares::SOCKET_BAD
        };
        let wfd = if event.writable {
            socket
        } else {
            c_ares::SOCKET_BAD
        };
        self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    smoke_test_environment::SmokeTestEnvironment,
    test_utils::diem_swarm_utils::load_backend_storage,
};
use diem_config::config::NodeConfig;
use diem_global_constants::CONSENSUS_KEY;
use diem_key_manager::{
    diem_interface::{DiemInterface, JsonRpcDiemInterface},
    KeyManager,
};
use diem_secure_storage::{CryptoStorage, Storage};
use diem_secure_time::RealTimeService;
use diem_smoke_test_attribute::smoke_test;
use diem_types::chain_id::ChainId;
use std::{convert::TryInto, thread, thread::sleep, time::Duration};

#[smoke_test]
fn test_key_manager_consensus_rotation() {
    // Create and launch a local validator swarm
    let mut env = SmokeTestEnvironment::new(1);
    env.validator_swarm.launch();

    // Fetch the first node config in the swarm
    let node_config_path = env.validator_swarm.config.config_files.get(0).unwrap();
    let node_config = NodeConfig::load(&node_config_path).unwrap();

    // Load validator's on disk storage
    let secure_backend = load_backend_storage(&env.validator_swarm, 0);
    let storage: Storage = (&secure_backend).try_into().unwrap();

    // Create a json-rpc connection to the blockchain and verify storage matches the on-chain state.
    let json_rpc_endpoint = format!(
        "http://127.0.0.1:{}",
        env.validator_swarm.get_client_port(0)
    );
    let diem_interface = JsonRpcDiemInterface::new(json_rpc_endpoint.clone());
    let account = node_config.validator_network.unwrap().peer_id();
    let current_consensus = storage.get_public_key(CONSENSUS_KEY).unwrap().public_key;
    let validator_info = diem_interface.retrieve_validator_info(account).unwrap();
    assert_eq!(&current_consensus, validator_info.consensus_public_key());

    // Create the key manager
    let key_manager_storage: Storage = (&secure_backend).try_into().unwrap();
    let mut key_manager = KeyManager::new(
        JsonRpcDiemInterface::new(json_rpc_endpoint),
        key_manager_storage,
        RealTimeService::new(),
        1,
        1000, // Large sleep period to force a single rotation
        1000,
        ChainId::test(),
    );

    // Spawn the key manager and execute a rotation
    let _key_manager_thread = thread::spawn(move || key_manager.execute());

    // Verify the consensus key has been rotated in secure storage and on-chain.
    for _ in 0..10 {
        sleep(Duration::from_secs(6));

        let rotated_consensus = storage.get_public_key(CONSENSUS_KEY).unwrap().public_key;
        let validator_info = diem_interface.retrieve_validator_info(account).unwrap();
        if current_consensus != rotated_consensus
            && validator_info.consensus_public_key() == &rotated_consensus
        {
            return; // The consensus key was successfully rotated
        }
    }

    panic!("The key manager failed to rotate the consensus key!");
}
<commit_msg>[Key Manager] Make the key manager smoke test less aggressive.<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    smoke_test_environment::SmokeTestEnvironment,
    test_utils::diem_swarm_utils::load_backend_storage,
};
use diem_config::config::NodeConfig;
use diem_global_constants::CONSENSUS_KEY;
use diem_key_manager::{
    diem_interface::{DiemInterface, JsonRpcDiemInterface},
    KeyManager,
};
use diem_secure_storage::{CryptoStorage, Storage};
use diem_secure_time::RealTimeService;
use diem_smoke_test_attribute::smoke_test;
use diem_types::chain_id::ChainId;
use std::{convert::TryInto, thread, thread::sleep, time::Duration};

#[smoke_test]
fn test_key_manager_consensus_rotation() {
    // Create and launch a local validator swarm
    let mut env = SmokeTestEnvironment::new(1);
    env.validator_swarm.launch();

    // Fetch the first node config in the swarm
    let node_config_path = env.validator_swarm.config.config_files.get(0).unwrap();
    let node_config = NodeConfig::load(&node_config_path).unwrap();

    // Load validator's on disk storage
    let secure_backend = load_backend_storage(&env.validator_swarm, 0);
    let storage: Storage = (&secure_backend).try_into().unwrap();

    // Create a json-rpc connection to the blockchain and verify storage matches the on-chain state.
    let json_rpc_endpoint = format!(
        "http://127.0.0.1:{}",
        env.validator_swarm.get_client_port(0)
    );
    let diem_interface = JsonRpcDiemInterface::new(json_rpc_endpoint.clone());
    let account = node_config.validator_network.unwrap().peer_id();
    let current_consensus = storage.get_public_key(CONSENSUS_KEY).unwrap().public_key;
    let validator_info = diem_interface.retrieve_validator_info(account).unwrap();
    assert_eq!(&current_consensus, validator_info.consensus_public_key());

    // Create the key manager
    let key_manager_storage: Storage = (&secure_backend).try_into().unwrap();
    let mut key_manager = KeyManager::new(
        JsonRpcDiemInterface::new(json_rpc_endpoint),
        key_manager_storage,
        RealTimeService::new(),
        1,
        1000, // Large sleep period to force a single rotation
        1000,
        ChainId::test(),
    );

    // Add some time padding to ensure the libra timestamp increases on-chain
    sleep(Duration::from_secs(10));

    // Spawn the key manager and execute a rotation
    let _key_manager_thread = thread::spawn(move || key_manager.execute());

    // Verify the consensus key has been rotated in secure storage and on-chain.
    for _ in 0..10 {
        sleep(Duration::from_secs(6));

        let rotated_consensus = storage.get_public_key(CONSENSUS_KEY).unwrap().public_key;
        let validator_info = diem_interface.retrieve_validator_info(account).unwrap();
        if current_consensus != rotated_consensus
            && validator_info.consensus_public_key() == &rotated_consensus
        {
            return; // The consensus key was successfully rotated
        }
    }

    panic!("The key manager failed to rotate the consensus key!");
}
<|endoftext|>


<commit_before>use std::fmt;
use std::hash;
use std::marker::{PhantomData, PhantomFn};
use std::mem;
use std::ops::{Deref, DerefMut};

use Message;
use runtime::Object;

#[link(name = "objc", kind = "dylib")]
extern {
    fn objc_retain(obj: *mut Object) -> *mut Object;
    fn objc_release(obj: *mut Object);
}

unsafe fn retain<T: Message>(ptr: *mut T) -> *mut T {
    objc_retain(ptr as *mut Object) as *mut T
}

unsafe fn release<T: Message>(ptr: *mut T) {
    objc_release(ptr as *mut Object);
}

/// A type used to mark that a struct owns the object(s) it contains,
/// so it has the sole references to them.
pub enum Owned { }
/// A type used to mark that the object(s) a struct contains are shared,
/// so there may be other references to them.
pub enum Shared { }

/// A type that marks what type of ownership a struct has over the object(s)
/// it contains; specifically, either `Owned` or `Shared`.
pub trait Ownership : 'static + PhantomFn<Self> { }
impl Ownership for Owned { }
impl Ownership for Shared { }

/// A pointer type for Objective-C's reference counted objects.
///
/// The object of an `Id` is retained and sent a `release` message when
/// the `Id` is dropped.
///
/// An `Id` may be either `Owned` or `Shared`, represented by the types `Id`
/// and `ShareId`, respectively. If owned, there are no other references to the
/// object and the `Id` can be mutably dereferenced. `ShareId`, however, can
/// only be immutably dereferenced because there may be other references to the
/// object, but a `ShareId` can be cloned to provide more references to the
/// object. An owned `Id` can be "downgraded" freely to a `ShareId`, but there
/// is no way to safely upgrade back.
pub struct Id<T, O = Owned> {
    ptr: *mut T,
    own: PhantomData<O>,
}

impl<T, O> Id<T, O> where T: Message, O: Ownership {
    unsafe fn from_ptr_unchecked(ptr: *mut T) -> Id<T, O> {
        Id { ptr: ptr, own: PhantomData }
    }

    /// Constructs an `Id` from a pointer to an unretained object and
    /// retains it. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        let ptr = retain(ptr);
        Id::from_ptr_unchecked(ptr)
    }

    /// Constructs an `Id` from a pointer to a retained object; this won't
    /// retain the pointer, so the caller must ensure the object has a +1
    /// retain count. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        Id::from_ptr_unchecked(ptr)
    }
}

impl<T> Id<T, Owned> where T: Message {
    /// "Downgrade" an owned `Id` to a `ShareId`, allowing it to be cloned.
    pub fn share(self) -> ShareId<T> {
        unsafe {
            let ptr = self.ptr;
            mem::forget(self);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

impl<T> Clone for Id<T, Shared> where T: Message {
    fn clone(&self) -> ShareId<T> {
        unsafe {
            let ptr = retain(self.ptr);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

#[unsafe_destructor]
impl<T, O> Drop for Id<T, O> where T: Message {
    fn drop(&mut self) {
        unsafe {
            release(self.ptr);
        }
    }
}

unsafe impl<T, O> Sync for Id<T, O> where T: Sync { }

unsafe impl<T> Send for Id<T, Owned> where T: Send { }

unsafe impl<T> Send for Id<T, Shared> where T: Sync { }

impl<T, O> Deref for Id<T, O> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for Id<T, Owned> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T, O> PartialEq for Id<T, O> where T: PartialEq {
    fn eq(&self, other: &Id<T, O>) -> bool {
        self.deref() == other.deref()
    }

    fn ne(&self, other: &Id<T, O>) -> bool {
        self.deref() != other.deref()
    }
}

impl<T, O> Eq for Id<T, O> where T: Eq { }

impl<T, O> hash::Hash for Id<T, O> where T: hash::Hash {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        self.deref().hash(state)
    }
}

impl<T, O> fmt::Debug for Id<T, O> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.deref().fmt(f)
    }
}

/// A convenient alias for a shared `Id`.
pub type ShareId<T> = Id<T, Shared>;

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

    fn retain_count(obj: &Object) -> usize {
        unsafe { msg_send![obj, retainCount] }
    }

    #[test]
    fn test_clone() {
        let obj = test_utils::sample_object();
        assert!(retain_count(&obj) == 1);

        let obj = obj.share();
        assert!(retain_count(&obj) == 1);

        let cloned = obj.clone();
        assert!(retain_count(&cloned) == 2);
        assert!(retain_count(&obj) == 2);

        drop(obj);
        assert!(retain_count(&cloned) == 1);
    }
}
<commit_msg>Added a StrongPtr struct to remove unsafe_destructor.<commit_after>use std::fmt;
use std::hash;
use std::marker::{PhantomData, PhantomFn};
use std::ops::{Deref, DerefMut};

use Message;
use runtime::Object;

#[link(name = "objc", kind = "dylib")]
extern {
    fn objc_retain(obj: *mut Object) -> *mut Object;
    fn objc_release(obj: *mut Object);
}

struct StrongPtr(*mut Object);

impl Drop for StrongPtr {
    fn drop(&mut self) {
        unsafe {
            objc_release(self.0);
        }
    }
}

/// A type used to mark that a struct owns the object(s) it contains,
/// so it has the sole references to them.
pub enum Owned { }
/// A type used to mark that the object(s) a struct contains are shared,
/// so there may be other references to them.
pub enum Shared { }

/// A type that marks what type of ownership a struct has over the object(s)
/// it contains; specifically, either `Owned` or `Shared`.
pub trait Ownership : 'static + PhantomFn<Self> { }
impl Ownership for Owned { }
impl Ownership for Shared { }

/// A pointer type for Objective-C's reference counted objects.
///
/// The object of an `Id` is retained and sent a `release` message when
/// the `Id` is dropped.
///
/// An `Id` may be either `Owned` or `Shared`, represented by the types `Id`
/// and `ShareId`, respectively. If owned, there are no other references to the
/// object and the `Id` can be mutably dereferenced. `ShareId`, however, can
/// only be immutably dereferenced because there may be other references to the
/// object, but a `ShareId` can be cloned to provide more references to the
/// object. An owned `Id` can be "downgraded" freely to a `ShareId`, but there
/// is no way to safely upgrade back.
pub struct Id<T, O = Owned> {
    ptr: StrongPtr,
    item: PhantomData<T>,
    own: PhantomData<O>,
}

impl<T, O> Id<T, O> where T: Message, O: Ownership {
    unsafe fn new(ptr: StrongPtr) -> Id<T, O> {
        Id { ptr: ptr, item: PhantomData, own: PhantomData }
    }

    /// Constructs an `Id` from a pointer to an unretained object and
    /// retains it. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        Id::new(StrongPtr(objc_retain(ptr as *mut Object)))
    }

    /// Constructs an `Id` from a pointer to a retained object; this won't
    /// retain the pointer, so the caller must ensure the object has a +1
    /// retain count. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        Id::new(StrongPtr(ptr as *mut Object))
    }
}

impl<T> Id<T, Owned> where T: Message {
    /// "Downgrade" an owned `Id` to a `ShareId`, allowing it to be cloned.
    pub fn share(self) -> ShareId<T> {
        let Id { ptr, .. } = self;
        unsafe { Id::new(ptr) }
    }
}

impl<T> Clone for Id<T, Shared> where T: Message {
    fn clone(&self) -> ShareId<T> {
        unsafe {
            Id::new(StrongPtr(objc_retain(self.ptr.0)))
        }
    }
}

unsafe impl<T, O> Sync for Id<T, O> where T: Sync { }

unsafe impl<T> Send for Id<T, Owned> where T: Send { }

unsafe impl<T> Send for Id<T, Shared> where T: Sync { }

impl<T, O> Deref for Id<T, O> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*(self.ptr.0 as *mut T) }
    }
}

impl<T> DerefMut for Id<T, Owned> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.ptr.0 as *mut T) }
    }
}

impl<T, O> PartialEq for Id<T, O> where T: PartialEq {
    fn eq(&self, other: &Id<T, O>) -> bool {
        self.deref() == other.deref()
    }

    fn ne(&self, other: &Id<T, O>) -> bool {
        self.deref() != other.deref()
    }
}

impl<T, O> Eq for Id<T, O> where T: Eq { }

impl<T, O> hash::Hash for Id<T, O> where T: hash::Hash {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        self.deref().hash(state)
    }
}

impl<T, O> fmt::Debug for Id<T, O> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.deref().fmt(f)
    }
}

/// A convenient alias for a shared `Id`.
pub type ShareId<T> = Id<T, Shared>;

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

    fn retain_count(obj: &Object) -> usize {
        unsafe { msg_send![obj, retainCount] }
    }

    #[test]
    fn test_clone() {
        let obj = test_utils::sample_object();
        assert!(retain_count(&obj) == 1);

        let obj = obj.share();
        assert!(retain_count(&obj) == 1);

        let cloned = obj.clone();
        assert!(retain_count(&cloned) == 2);
        assert!(retain_count(&obj) == 2);

        drop(obj);
        assert!(retain_count(&cloned) == 1);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;

use deadpool_postgres::Client;

use crate::data_types::AlleleShortMap;
use crate::db::Processed;
use crate::types::OrganismTaxonId;

pub struct Loader {
    conn: Client,
    taxonid: OrganismTaxonId,
    processed: Processed,
}

impl Loader {
    pub fn new(conn: Client, taxonid: OrganismTaxonId, processed: Processed) -> Loader {
        Loader {
            conn,
            taxonid,
            processed,
        }
    }

    pub async fn load_alleles(&mut self, alleles: &AlleleShortMap) -> Result<(), Box<dyn Error>>
    {
        let organism = self.processed.organism_by_taxonid(self.taxonid)
            .expect(&format!("load failed, organism not in database with taxon ID: {}", self.taxonid));

        let trans = self.conn.transaction().await?;

        let allele_insert_sql = "INSERT INTO feature(uniquename, name, type_id, organism_id)
VALUES ($1, $2,
        (SELECT cvterm_id FROM cvterm t join cv ON cv.cv_id = t.cv_id WHERE t.name = 'allele' AND cv.name = 'sequence' LIMIT 1),
        (SELECT organism_id FROM organism WHERE genus = $3 AND species = $4 LIMIT 1))";

        let allele_smt = trans.prepare(allele_insert_sql).await?;

        let rel_sql = "INSERT INTO feature_relationship(subject_id, object_id, type_id)
VALUES ((SELECT feature_id FROM feature f join cvterm t ON f.type_id = t.cvterm_id WHERE t.name = 'allele' AND f.uniquename = $1),
        (SELECT feature_id FROM feature f join cvterm t ON f.type_id = t.cvterm_id WHERE (t.name = 'gene' OR t.name = 'pseudogene') AND f.uniquename = $2),
        (SELECT cvterm_id FROM cvterm t join cv ON cv.cv_id = t.cv_id WHERE t.name = 'instance_of' AND cv.name = 'pombase_relations' LIMIT 1))";

        let rel_smt = trans.prepare(rel_sql).await?;

        let add_feat_prop_sql = "INSERT INTO featureprop(feature_id, type_id, value)
VALUES ((SELECT feature_id FROM feature f join cvterm t ON f.type_id = t.cvterm_id WHERE t.name = 'allele' AND f.uniquename = $1),
        (SELECT cvterm_id FROM cvterm t join cv ON cv.cv_id = t.cv_id WHERE t.name = $2 AND cv.name = 'PomBase feature property types' LIMIT 1),
        $3)";

        let add_feat_prop_smt = trans.prepare(add_feat_prop_sql).await?;

        let add_synonym_sql =
            "INSERT INTO synonym (name, type_id, synonym_sgml)
                                   VALUES ($1, (SELECT cvterm_id FROM cvterm t JOIN cv ON cv.cv_id = t.cv_id
                                                 WHERE t.name = 'exact' AND cv.name = 'synonym_type'), '')
                              ON CONFLICT DO NOTHING";

        let add_synonym_smt = trans.prepare(add_synonym_sql).await?;

        let add_pub_sql =
            "INSERT INTO pub (uniquename, type_id)
                         VALUES ($1, (SELECT cvterm_id FROM cvterm WHERE name = 'paper'))
                        ON CONFLICT DO NOTHING";

        let add_pub_smt = trans.prepare(add_pub_sql).await?;

        let add_feat_synonym_sql =
            "INSERT INTO feature_synonym (feature_id, synonym_id, pub_id)
                 SELECT (SELECT feature_id FROM feature f WHERE f.uniquename = $1),
                        (SELECT synonym_id FROM synonym
                              JOIN cvterm t ON t.cvterm_id = synonym.type_id
                              JOIN cv ON cv.cv_id = t.cv_id
                             WHERE synonym.name = $2 AND t.name = 'exact' AND cv.name = 'synonym_type'),
                        (SELECT pub_id FROM pub WHERE uniquename = $3)";

        let add_feat_synonym_smt = trans.prepare(add_feat_synonym_sql).await?;

        for allele in alleles.values() {
            if self.processed.allele_by_uniquename(&allele.uniquename).is_some() {
                panic!("allele loading failed: can't find {} in the database", allele.uniquename);
            }

            if self.processed.gene_by_uniquename(&allele.gene_uniquename).is_none() {
                panic!("allele loading failed: can't find {} in the database", allele.gene_uniquename);
            }

            let allele_uniquename = allele.uniquename.as_str();
            let allele_name = allele.name.as_ref().map(|s| s.as_str());
            let genus = organism.genus.as_str();
            let species = organism.species.as_str();
            let gene_uniquename = allele.gene_uniquename.as_str();

            trans.query(&allele_smt,
                        &[&allele_uniquename, &allele_name, &genus, &species]).await?;

            trans.query(&rel_smt, &[&allele_uniquename, &gene_uniquename]).await?;

            let allele_type = allele.allele_type.as_str();
            trans.query(&add_feat_prop_smt, &[&allele_uniquename, &"allele_type", &allele_type]).await?;

            let allele_description = allele.description.as_ref().map(|s| s.as_str());
            trans.query(&add_feat_prop_smt, &[&allele_uniquename, &"description", &allele_description]).await?;

            for synonym in &allele.synonyms {
              let synonym_name = synonym.name.as_str();

              trans.query(&add_synonym_smt, &[&synonym_name]).await?;

              let pub_uniquename =
                  if let Some(ref uniquename) = synonym.reference {
                    uniquename.as_str()
                  } else {
                    "null"
                  };

              trans.query(&add_pub_smt, &[&pub_uniquename]).await?;

              trans.query(&add_feat_synonym_smt, &[&allele_uniquename, &synonym_name, &pub_uniquename]).await?;
            }
        }

        trans.commit().await?;

        Ok(())
    }
}
<commit_msg>Warn, don't fail loading duplicate allele names<commit_after>use std::collections::HashSet;
use std::error::Error;

use deadpool_postgres::Client;

use crate::data_types::AlleleShortMap;
use crate::db::Processed;
use crate::types::OrganismTaxonId;

pub struct Loader {
    conn: Client,
    taxonid: OrganismTaxonId,
    processed: Processed,
}

impl Loader {
    pub fn new(conn: Client, taxonid: OrganismTaxonId, processed: Processed) -> Loader {
        Loader {
            conn,
            taxonid,
            processed,
        }
    }

    pub async fn load_alleles(&mut self, alleles: &AlleleShortMap) -> Result<(), Box<dyn Error>>
    {
        let organism = self.processed.organism_by_taxonid(self.taxonid)
            .expect(&format!("load failed, organism not in database with taxon ID: {}", self.taxonid));

        let trans = self.conn.transaction().await?;

        let allele_insert_sql = "INSERT INTO feature(uniquename, name, type_id, organism_id)
VALUES ($1, $2,
        (SELECT cvterm_id FROM cvterm t join cv ON cv.cv_id = t.cv_id WHERE t.name = 'allele' AND cv.name = 'sequence' LIMIT 1),
        (SELECT organism_id FROM organism WHERE genus = $3 AND species = $4 LIMIT 1))";

        let allele_smt = trans.prepare(allele_insert_sql).await?;

        let rel_sql = "INSERT INTO feature_relationship(subject_id, object_id, type_id)
VALUES ((SELECT feature_id FROM feature f join cvterm t ON f.type_id = t.cvterm_id WHERE t.name = 'allele' AND f.uniquename = $1),
        (SELECT feature_id FROM feature f join cvterm t ON f.type_id = t.cvterm_id WHERE (t.name = 'gene' OR t.name = 'pseudogene') AND f.uniquename = $2),
        (SELECT cvterm_id FROM cvterm t join cv ON cv.cv_id = t.cv_id WHERE t.name = 'instance_of' AND cv.name = 'pombase_relations' LIMIT 1))";

        let rel_smt = trans.prepare(rel_sql).await?;

        let add_feat_prop_sql = "INSERT INTO featureprop(feature_id, type_id, value)
VALUES ((SELECT feature_id FROM feature f join cvterm t ON f.type_id = t.cvterm_id WHERE t.name = 'allele' AND f.uniquename = $1),
        (SELECT cvterm_id FROM cvterm t join cv ON cv.cv_id = t.cv_id WHERE t.name = $2 AND cv.name = 'PomBase feature property types' LIMIT 1),
        $3)";

        let add_feat_prop_smt = trans.prepare(add_feat_prop_sql).await?;

        let add_synonym_sql =
            "INSERT INTO synonym (name, type_id, synonym_sgml)
                                   VALUES ($1, (SELECT cvterm_id FROM cvterm t JOIN cv ON cv.cv_id = t.cv_id
                                                 WHERE t.name = 'exact' AND cv.name = 'synonym_type'), '')
                              ON CONFLICT DO NOTHING";

        let add_synonym_smt = trans.prepare(add_synonym_sql).await?;

        let add_pub_sql =
            "INSERT INTO pub (uniquename, type_id)
                         VALUES ($1, (SELECT cvterm_id FROM cvterm WHERE name = 'paper'))
                        ON CONFLICT DO NOTHING";

        let add_pub_smt = trans.prepare(add_pub_sql).await?;

        let add_feat_synonym_sql =
            "INSERT INTO feature_synonym (feature_id, synonym_id, pub_id)
                 SELECT (SELECT feature_id FROM feature f WHERE f.uniquename = $1),
                        (SELECT synonym_id FROM synonym
                              JOIN cvterm t ON t.cvterm_id = synonym.type_id
                              JOIN cv ON cv.cv_id = t.cv_id
                             WHERE synonym.name = $2 AND t.name = 'exact' AND cv.name = 'synonym_type'),
                        (SELECT pub_id FROM pub WHERE uniquename = $3)";

        let add_feat_synonym_smt = trans.prepare(add_feat_synonym_sql).await?;

        let mut seen_allele_names = HashSet::new();

        for allele in alleles.values() {
            if let Some(ref allele_name) = allele.name {
                if seen_allele_names.contains(allele_name) {
                    eprintln!("skipping allele with name that has alread been loaded: {} {}",
                              allele_name.as_str(),
                              allele.allele_type);
                    continue;
                } else {
                    seen_allele_names.insert(allele_name.clone());
               }
            }

            if self.processed.allele_by_uniquename(&allele.uniquename).is_some() {
                panic!("allele loading failed: can't find {} in the database", allele.uniquename);
            }

            if self.processed.gene_by_uniquename(&allele.gene_uniquename).is_none() {
                panic!("allele loading failed: can't find {} in the database", allele.gene_uniquename);
            }

            let allele_uniquename = allele.uniquename.as_str();
            let allele_name = allele.name.as_ref().map(|s| s.as_str());
            let genus = organism.genus.as_str();
            let species = organism.species.as_str();
            let gene_uniquename = allele.gene_uniquename.as_str();

            trans.query(&allele_smt,
                        &[&allele_uniquename, &allele_name, &genus, &species]).await?;

            trans.query(&rel_smt, &[&allele_uniquename, &gene_uniquename]).await?;

            let allele_type = allele.allele_type.as_str();
            trans.query(&add_feat_prop_smt, &[&allele_uniquename, &"allele_type", &allele_type]).await?;

            let allele_description = allele.description.as_ref().map(|s| s.as_str());
            trans.query(&add_feat_prop_smt, &[&allele_uniquename, &"description", &allele_description]).await?;

            for synonym in &allele.synonyms {
              let synonym_name = synonym.name.as_str();

              trans.query(&add_synonym_smt, &[&synonym_name]).await?;

              let pub_uniquename =
                  if let Some(ref uniquename) = synonym.reference {
                    uniquename.as_str()
                  } else {
                    "null"
                  };

              trans.query(&add_pub_smt, &[&pub_uniquename]).await?;

              trans.query(&add_feat_synonym_smt, &[&allele_uniquename, &synonym_name, &pub_uniquename]).await?;
            }
        }

        trans.commit().await?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>use create::Regexp;

#[derive(Debug, PartialEq)]
pub enum Inst {
    Char(char),
    Match,
    Jump(usize),
    Split(usize, usize)
}

#[derive(Debug, PartialEq)]
pub struct Thread {
    pub saw_char: bool,
    pub pc: usize
}

pub fn thompson_vm(insts: &Vec<Inst>, input: &str) -> bool {
    fn addthread(list: &mut Vec<Thread>, thread: Thread) {
        let mut contains = false;
        for elem in list.iter() {
            if thread == *elem { contains = true; break; }
        }
        if !contains { list.push(thread); }
    }

    let mut cur_stack: Vec<Thread> = Vec::new();
    let mut new_stack: Vec<Thread> = Vec::new();

    addthread(&mut cur_stack, Thread { saw_char: false, pc: 0});

    for (cur_char_index, cur_char) in input.chars().enumerate() {
        let mut i = 0;

        loop {
            if i >= cur_stack.len() { break; }

            let thread_pc: usize = cur_stack[i].pc;
            let thread_saw_char: bool = cur_stack[i].saw_char;
            let inst = &insts[thread_pc];

            use Inst::*;
            match *inst {
                Char(c) => {
                    if thread_saw_char {
                        addthread(&mut new_stack, Thread { saw_char: false,
                                                      pc: thread_pc });
                    } else {
                        if c == cur_char {
                            addthread(&mut cur_stack, Thread { saw_char: true,
                                                          pc: thread_pc + 1});
                        }
                    }
                },
                Match => return true,
                Jump(jump_pc) => {
                    addthread(&mut cur_stack,
                              Thread { saw_char: thread_saw_char,
                                       pc: jump_pc });
                },
                Split(s1_pc, s2_pc) => {
                    addthread(&mut cur_stack,
                              Thread { saw_char: thread_saw_char,
                                       pc: s1_pc});
                    addthread(&mut cur_stack,
                              Thread { saw_char: thread_saw_char,
                                       pc: s2_pc});
                }
            }

            i += 1
        }
        cur_stack = new_stack;
        new_stack = Vec::new();
    }
    false
}

pub fn compile_regexp(regexp: &Regexp) -> Vec<Inst> {
    let mut insts = compile_regexp_offset(&regexp, 0);
    insts.push(Inst::Match);
    insts
}

fn compile_regexp_offset(regexp: &Regexp, offset: usize) -> Vec<Inst> {
    let mut insts = Vec::new();
    use create::Regexp::*;
    use self::Inst::{Jump,Split};
    match *regexp {
        Char(c) => {
            let char_inst = Inst::Char(c);
            insts.push(char_inst);
        },
        Concatenation(ref regexps) => {
            let mut num_insts = 0;
            for sub_regexp in regexps {
                let mut sub_insts = compile_regexp_offset(&sub_regexp,
                                                          offset + num_insts);
                num_insts += sub_insts.len();
                insts.append(&mut sub_insts);
            }
        },
        Alternation(ref regexps) => {
            let num_alternatives = regexps.len();
            let mut alternatives_insts: Vec<Vec<Inst>> = Vec::new();
            for sub_regexp in regexps {
                let sub_insts = compile_regexp_offset(&sub_regexp, offset);
                alternatives_insts.push(sub_insts);
            }
            let total_len = alternatives_insts.iter()
                .fold(0, |sum,x| sum + x.len())
                + alternatives_insts.len() - 1; // + alternates_insts.len() - 1
                                                // accounts for the Jumps we add
            for (i, sub_insts) in alternatives_insts.iter_mut().enumerate() {
                // Add a jump instruction to all but the last alternative
                if i < num_alternatives - 1 {
                    let jump_to_end = Jump(total_len + offset);
                    sub_insts.push(jump_to_end);
                }
                insts.append(sub_insts);
            }
        },
        Optional(ref inner_regexp) => {
            let mut inner_insts = compile_regexp_offset(&*inner_regexp,
                                                        offset + 1);
            let split_inst = Split(offset + 1, offset + inner_insts.len() + 1);
            insts.push(split_inst);
            insts.append(&mut inner_insts);
        },
        Repeated(ref inner_regexp) => {
            let mut inner_insts = compile_regexp_offset(&*inner_regexp,
                                                        offset);
            let split_inst = Split(offset, offset + inner_insts.len() + 1);
            insts.append(&mut inner_insts);
            insts.push(split_inst);
        },
        OptionalRepeated(ref inner_regexp) => {
            let mut inner_insts = compile_regexp_offset(&*inner_regexp,
                                                        offset + 1);
            let split_inst = Split(offset + 1, offset + inner_insts.len() + 2);
            let jump_inst = Jump(offset);
            insts.push(split_inst);
            insts.append(&mut inner_insts);
            insts.push(jump_inst);
        }
    }
    insts
}

// struct State {
//     c: Option<char>,
//     action: Action
// }

// enum Action {
//     AdvanceTo(Vec<Box<State>>),
//     Match
// }

// fn construct_state_tree<'a>(regexp: Regexp) -> Box<State> {
//     let match_state = Box::new(State {c: None, action: Action::Match });
//     construct_state_tree_next(regexp, match_state)
// }

// fn construct_state_tree_next<'a>(regexp: Regexp, next: Box<State>) -> Box<State> {
//     let match_state = Box::new(State {c: None, action: Action::Match });
//     use self::Action::*;
//     if let Regexp::Concatenation(regexps) = regexp {
//         let mut concated_states: Vec<Box<State>> = Vec::new();
//         for inner_regexp in regexps {
//             let sub_state = construct_state_tree(inner_regexp);
//             concated_states.push(sub_state);
//         }
//         let mut prev_last = next;
//         while concated_states.len() > 0 {
//             let mut last = concated_states.pop().unwrap();
//             match last.action {
//                 AdvanceTo(ref mut next_states) => {
//                     next_states.push(prev_last);
//                 },
//                 Match => panic!("Illegal State: Sub-state of concatenation cannot \
//                                  contain Match")
//             }
//             prev_last = last;
//         }
//         prev_last
//     } else if let Regexp::Alternation(regexps) = regexp {
//         let mut parts: Vec<Box<State>> = Vec::new();
//         for inner_regexp in regexps {
//             let sub_state =
//                 construct_state_tree_next(inner_regexp, next);
//             parts.push(sub_state);
//         }
//         let wrapping_state = State { c: None, action: AdvanceTo(parts) };
//         Box::new(wrapping_state)
//     } else {
//         panic!("Error");
//     }
//     match regexp {
//         Regexp::Concatenation(regexps) => {
//             let mut concated_states: Vec<Box<State>> = Vec::new();
//             for inner_regexp in regexps {
//                 let sub_state = construct_state_tree(inner_regexp);
//                 concated_states.push(sub_state);
//             }
//             let mut prev_last = next;
//             while concated_states.len() > 0 {
//                 let mut last = concated_states.pop().unwrap();
//                 match last.action {
//                     AdvanceTo(ref mut next_states) => {
//                         next_states.push(prev_last);
//                     },
//                     Match => panic!("Illegal State: Sub-state of concatenation cannot \
//                                      contain Match")
//                 }
//                 prev_last = last;
//             }
//             prev_last
//         },
//         Regexp::Alternation(regexps) => {
//             let mut parts: Vec<Box<State>> = Vec::new();
//             for inner_regexp in regexps {
//                 let sub_state =
//                     construct_state_tree_next(inner_regexp, next);
//                 parts.push(sub_state);
//             }
//             let wrapping_state = State { c: None, action: AdvanceTo(parts) };
//             Box::new(wrapping_state)
//         }
//         Regexp::Char(c) => Box::new(State {c: Some(c), action: AdvanceTo(vec![next])}),
//         Regexp::Optional(inner_regexp) => {
//             let inner_state = construct_state_tree_next(*inner_regexp, next);
//             let optional_state = Box::new(State { c: None,
//                                              action: AdvanceTo(vec![inner_state,
//                                                                     next])});
//             optional_state
//         },
//         Regexp::Repeated(inner_regexp) => {
//             let inner_state = construct_state_tree_next(*inner_regexp, next);
//             let mut repeated_state = Box::new(State { c: None,
//                                              action: AdvanceTo(vec![inner_state,
//                                                                     next])});
//             match repeated_state.action {
//                 AdvanceTo(ref mut next_states) => next_states.push(repeated_state),
//                 Match => unreachable!()
//             }
//             repeated_state
//         },
//         _ => panic!("Hello")

//     }
// }
<commit_msg>Silenced warning<commit_after>use create::Regexp;

#[derive(Debug, PartialEq)]
pub enum Inst {
    Char(char),
    Match,
    Jump(usize),
    Split(usize, usize)
}

#[derive(Debug, PartialEq)]
pub struct Thread {
    pub saw_char: bool,
    pub pc: usize
}

pub fn thompson_vm(insts: &Vec<Inst>, input: &str) -> bool {
    fn addthread(list: &mut Vec<Thread>, thread: Thread) {
        let mut contains = false;
        for elem in list.iter() {
            if thread == *elem { contains = true; break; }
        }
        if !contains { list.push(thread); }
    }

    let mut cur_stack: Vec<Thread> = Vec::new();
    let mut new_stack: Vec<Thread> = Vec::new();

    addthread(&mut cur_stack, Thread { saw_char: false, pc: 0});

    for (_, cur_char) in input.chars().enumerate() {
        let mut i = 0;

        loop {
            if i >= cur_stack.len() { break; }

            let thread_pc: usize = cur_stack[i].pc;
            let thread_saw_char: bool = cur_stack[i].saw_char;
            let inst = &insts[thread_pc];

            use Inst::*;
            match *inst {
                Char(c) => {
                    if thread_saw_char {
                        addthread(&mut new_stack, Thread { saw_char: false,
                                                      pc: thread_pc });
                    } else {
                        if c == cur_char {
                            addthread(&mut cur_stack, Thread { saw_char: true,
                                                          pc: thread_pc + 1});
                        }
                    }
                },
                Match => return true,
                Jump(jump_pc) => {
                    addthread(&mut cur_stack,
                              Thread { saw_char: thread_saw_char,
                                       pc: jump_pc });
                },
                Split(s1_pc, s2_pc) => {
                    addthread(&mut cur_stack,
                              Thread { saw_char: thread_saw_char,
                                       pc: s1_pc});
                    addthread(&mut cur_stack,
                              Thread { saw_char: thread_saw_char,
                                       pc: s2_pc});
                }
            }

            i += 1
        }
        cur_stack = new_stack;
        new_stack = Vec::new();
    }
    false
}

pub fn compile_regexp(regexp: &Regexp) -> Vec<Inst> {
    let mut insts = compile_regexp_offset(&regexp, 0);
    insts.push(Inst::Match);
    insts
}

fn compile_regexp_offset(regexp: &Regexp, offset: usize) -> Vec<Inst> {
    let mut insts = Vec::new();
    use create::Regexp::*;
    use self::Inst::{Jump,Split};
    match *regexp {
        Char(c) => {
            let char_inst = Inst::Char(c);
            insts.push(char_inst);
        },
        Concatenation(ref regexps) => {
            let mut num_insts = 0;
            for sub_regexp in regexps {
                let mut sub_insts = compile_regexp_offset(&sub_regexp,
                                                          offset + num_insts);
                num_insts += sub_insts.len();
                insts.append(&mut sub_insts);
            }
        },
        Alternation(ref regexps) => {
            let num_alternatives = regexps.len();
            let mut alternatives_insts: Vec<Vec<Inst>> = Vec::new();
            for sub_regexp in regexps {
                let sub_insts = compile_regexp_offset(&sub_regexp, offset);
                alternatives_insts.push(sub_insts);
            }
            let total_len = alternatives_insts.iter()
                .fold(0, |sum,x| sum + x.len())
                + alternatives_insts.len() - 1; // + alternates_insts.len() - 1
                                                // accounts for the Jumps we add
            for (i, sub_insts) in alternatives_insts.iter_mut().enumerate() {
                // Add a jump instruction to all but the last alternative
                if i < num_alternatives - 1 {
                    let jump_to_end = Jump(total_len + offset);
                    sub_insts.push(jump_to_end);
                }
                insts.append(sub_insts);
            }
        },
        Optional(ref inner_regexp) => {
            let mut inner_insts = compile_regexp_offset(&*inner_regexp,
                                                        offset + 1);
            let split_inst = Split(offset + 1, offset + inner_insts.len() + 1);
            insts.push(split_inst);
            insts.append(&mut inner_insts);
        },
        Repeated(ref inner_regexp) => {
            let mut inner_insts = compile_regexp_offset(&*inner_regexp,
                                                        offset);
            let split_inst = Split(offset, offset + inner_insts.len() + 1);
            insts.append(&mut inner_insts);
            insts.push(split_inst);
        },
        OptionalRepeated(ref inner_regexp) => {
            let mut inner_insts = compile_regexp_offset(&*inner_regexp,
                                                        offset + 1);
            let split_inst = Split(offset + 1, offset + inner_insts.len() + 2);
            let jump_inst = Jump(offset);
            insts.push(split_inst);
            insts.append(&mut inner_insts);
            insts.push(jump_inst);
        }
    }
    insts
}

// struct State {
//     c: Option<char>,
//     action: Action
// }

// enum Action {
//     AdvanceTo(Vec<Box<State>>),
//     Match
// }

// fn construct_state_tree<'a>(regexp: Regexp) -> Box<State> {
//     let match_state = Box::new(State {c: None, action: Action::Match });
//     construct_state_tree_next(regexp, match_state)
// }

// fn construct_state_tree_next<'a>(regexp: Regexp, next: Box<State>) -> Box<State> {
//     let match_state = Box::new(State {c: None, action: Action::Match });
//     use self::Action::*;
//     if let Regexp::Concatenation(regexps) = regexp {
//         let mut concated_states: Vec<Box<State>> = Vec::new();
//         for inner_regexp in regexps {
//             let sub_state = construct_state_tree(inner_regexp);
//             concated_states.push(sub_state);
//         }
//         let mut prev_last = next;
//         while concated_states.len() > 0 {
//             let mut last = concated_states.pop().unwrap();
//             match last.action {
//                 AdvanceTo(ref mut next_states) => {
//                     next_states.push(prev_last);
//                 },
//                 Match => panic!("Illegal State: Sub-state of concatenation cannot \
//                                  contain Match")
//             }
//             prev_last = last;
//         }
//         prev_last
//     } else if let Regexp::Alternation(regexps) = regexp {
//         let mut parts: Vec<Box<State>> = Vec::new();
//         for inner_regexp in regexps {
//             let sub_state =
//                 construct_state_tree_next(inner_regexp, next);
//             parts.push(sub_state);
//         }
//         let wrapping_state = State { c: None, action: AdvanceTo(parts) };
//         Box::new(wrapping_state)
//     } else {
//         panic!("Error");
//     }
//     match regexp {
//         Regexp::Concatenation(regexps) => {
//             let mut concated_states: Vec<Box<State>> = Vec::new();
//             for inner_regexp in regexps {
//                 let sub_state = construct_state_tree(inner_regexp);
//                 concated_states.push(sub_state);
//             }
//             let mut prev_last = next;
//             while concated_states.len() > 0 {
//                 let mut last = concated_states.pop().unwrap();
//                 match last.action {
//                     AdvanceTo(ref mut next_states) => {
//                         next_states.push(prev_last);
//                     },
//                     Match => panic!("Illegal State: Sub-state of concatenation cannot \
//                                      contain Match")
//                 }
//                 prev_last = last;
//             }
//             prev_last
//         },
//         Regexp::Alternation(regexps) => {
//             let mut parts: Vec<Box<State>> = Vec::new();
//             for inner_regexp in regexps {
//                 let sub_state =
//                     construct_state_tree_next(inner_regexp, next);
//                 parts.push(sub_state);
//             }
//             let wrapping_state = State { c: None, action: AdvanceTo(parts) };
//             Box::new(wrapping_state)
//         }
//         Regexp::Char(c) => Box::new(State {c: Some(c), action: AdvanceTo(vec![next])}),
//         Regexp::Optional(inner_regexp) => {
//             let inner_state = construct_state_tree_next(*inner_regexp, next);
//             let optional_state = Box::new(State { c: None,
//                                              action: AdvanceTo(vec![inner_state,
//                                                                     next])});
//             optional_state
//         },
//         Regexp::Repeated(inner_regexp) => {
//             let inner_state = construct_state_tree_next(*inner_regexp, next);
//             let mut repeated_state = Box::new(State { c: None,
//                                              action: AdvanceTo(vec![inner_state,
//                                                                     next])});
//             match repeated_state.action {
//                 AdvanceTo(ref mut next_states) => next_states.push(repeated_state),
//                 Match => unreachable!()
//             }
//             repeated_state
//         },
//         _ => panic!("Hello")

//     }
// }
<|endoftext|>


<commit_before>//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(in_band_lifetimes)]
#![feature(unboxed_closures)]
#![feature(generators)]
#![feature(generator_trait)]
#![feature(fn_traits)]
#![feature(unsize)]
#![feature(specialization)]
#![feature(optin_builtin_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
#![feature(stmt_expr_attributes)]
#![feature(core_intrinsics)]
#![feature(integer_atomics)]
#![feature(test)]
#![feature(associated_type_bounds)]
#![feature(thread_id_value)]
#![cfg_attr(unix, feature(libc))]
#![allow(rustc::default_hash_types)]

#[macro_use]
extern crate log;
#[cfg(unix)]
extern crate libc;
#[macro_use]
extern crate cfg_if;

pub use rustc_serialize::hex::ToHex;

#[inline(never)]
#[cold]
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
    f()
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::likely($e) }
        }
    };
}

#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::unlikely($e) }
        }
    };
}

pub mod base_n;
pub mod binary_search_util;
pub mod box_region;
pub mod captures;
pub mod const_cstr;
pub mod flock;
pub mod fx;
pub mod graph;
pub mod jobserver;
pub mod macros;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
pub use ena::snapshot_vec;
pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
pub mod sharded;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub use ena::unify;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
    /// Forgets the function which prevents it from running.
    /// Ensure that the function owns no memory, otherwise it will be leaked.
    #[inline]
    pub fn disable(self) {
        std::mem::forget(self);
    }
}

impl<F: Fn()> Drop for OnDrop<F> {
    #[inline]
    fn drop(&mut self) {
        (self.0)();
    }
}

// See comments in src/librustc/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<commit_msg>Remove unused feature gates from librustc_data_structures<commit_after>//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(in_band_lifetimes)]
#![feature(unboxed_closures)]
#![feature(generators)]
#![feature(generator_trait)]
#![feature(fn_traits)]
#![feature(specialization)]
#![feature(optin_builtin_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
#![feature(stmt_expr_attributes)]
#![feature(core_intrinsics)]
#![feature(test)]
#![feature(associated_type_bounds)]
#![feature(thread_id_value)]
#![allow(rustc::default_hash_types)]

#[macro_use]
extern crate log;
#[cfg(unix)]
extern crate libc;
#[macro_use]
extern crate cfg_if;

pub use rustc_serialize::hex::ToHex;

#[inline(never)]
#[cold]
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
    f()
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::likely($e) }
        }
    };
}

#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::unlikely($e) }
        }
    };
}

pub mod base_n;
pub mod binary_search_util;
pub mod box_region;
pub mod captures;
pub mod const_cstr;
pub mod flock;
pub mod fx;
pub mod graph;
pub mod jobserver;
pub mod macros;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
pub use ena::snapshot_vec;
pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
pub mod sharded;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub use ena::unify;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
    /// Forgets the function which prevents it from running.
    /// Ensure that the function owns no memory, otherwise it will be leaked.
    #[inline]
    pub fn disable(self) {
        std::mem::forget(self);
    }
}

impl<F: Fn()> Drop for OnDrop<F> {
    #[inline]
    fn drop(&mut self) {
        (self.0)();
    }
}

// See comments in src/librustc/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<|endoftext|>


<commit_before>
use tensor::{Tensor, TensorKind};

pub fn byte_tensor_kind<T>(arg: T) -> TensorKind {
    unimplemented!()
}
pub fn float_tensor_kind<T>(arg: T) -> TensorKind {
    unimplemented!()
}
pub fn long_tensor_kind<T>(arg: T) -> TensorKind {
    unimplemented!()
}
pub fn byte_tensor<T>(arg: T) -> Tensor<u8> {
    unimplemented!()
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32> {
    unimplemented!()
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64> {
    unimplemented!()
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64> {
    unimplemented!()
}
<commit_msg>add generic tensor constructor<commit_after>
use tensor::{Tensor, TensorKind};

pub fn byte_tensor_kind<T>(arg: T) -> TensorKind {
    unimplemented!()
}
pub fn float_tensor_kind<T>(arg: T) -> TensorKind {
    unimplemented!()
}
pub fn long_tensor_kind<T>(arg: T) -> TensorKind {
    unimplemented!()
}
pub fn byte_tensor<T>(arg: T) -> Tensor<u8> {
    unimplemented!()
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32> {
    unimplemented!()
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64> {
    unimplemented!()
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64> {
    unimplemented!()
}
pub fn tensor<S, D>(arg: S) -> Tensor<D> {
    unimplemented!()
}
<|endoftext|>


<commit_before>//! This module implements the root command of the CLI tool.

use std::env;
use std::process;

use clap::{App, AppSettings, Arg};
use failure::Error;

use config::{prepare_environment, Auth, Config};
use constants::VERSION;
use utils::system::{print_error, QuietExit};
use utils::update::run_sentrycli_update_nagger;

const ABOUT: &'static str = "
Command line utility for Sentry.

This tool helps you managing remote resources on a Sentry server like
sourcemaps, debug symbols or releases.  Use `--help` on the subcommands
to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dif);
        $mac!(upload_dsym);
        $mac!(upload_proguard);
        $mac!(releases);
        $mac!(issues);
        $mac!(repos);
        $mac!(projects);
        #[cfg(not(feature = "managed"))]
        $mac!(update);
        #[cfg(not(feature = "managed"))]
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        $mac!(react_native);
        $mac!(difutil);
        $mac!(bash_hook);

        // these here exist for legacy reasons only.  They were moved
        // to subcommands of the react-native command.  Note that
        // codepush was never available on that level.
        #[cfg(target_os = "macos")]
        $mac!(react_native_xcode);
        $mac!(react_native_gradle);
    };
}

// commands we want to run the update nagger on
const UPDATE_NAGGER_CMDS: &'static [&'static str] = &[
    "releases", "issues", "repos", "projects", "info", "login", "difutil",
];

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod bash_hook;
pub mod info;
pub mod issues;
pub mod login;
pub mod projects;
pub mod releases;
pub mod repos;
pub mod send_event;
pub mod uninstall;
pub mod update;
pub mod upload_dif;
pub mod upload_dsym;
pub mod upload_proguard;

pub mod react_native;
pub mod react_native_appcenter;
pub mod react_native_codepush;
pub mod react_native_gradle;
#[cfg(target_os = "macos")]
pub mod react_native_xcode;

pub mod difutil;
pub mod difutil_check;
pub mod difutil_find;
pub mod difutil_id;

fn preexecute_hooks() -> Result<bool, Error> {
    return sentry_react_native_xcode_wrap();

    #[cfg(target_os = "macos")]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
            env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
            if &val == "1" {
                react_native_xcode::wrap_call()?;
                return Ok(true);
            }
        }
        Ok(false)
    }

    #[cfg(not(target_os = "macos"))]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        Ok(false)
    }
}

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: Vec<String>) -> Result<(), Error> {
    let mut config = Config::from_cli_config()?;

    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    if preexecute_hooks()? {
        return Ok(());
    }

    let mut app =
        App::new("sentry-cli")
            .help_message("Print this help message.")
            .version(VERSION)
            .version_message("Print version information.")
            .about(ABOUT)
            .max_term_width(100)
            .setting(AppSettings::VersionlessSubcommands)
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .global_setting(AppSettings::UnifiedHelpMessage)
            .arg(Arg::with_name("url").value_name("URL").long("url").help(
                "Fully qualified URL to the Sentry server.{n}[defaults to https://sentry.io/]",
            ))
            .arg(
                Arg::with_name("auth_token")
                    .value_name("AUTH_TOKEN")
                    .long("auth-token")
                    .help("Use the given Sentry auth token."),
            )
            .arg(
                Arg::with_name("api_key")
                    .value_name("API_KEY")
                    .long("api-key")
                    .help("The the given Sentry API key."),
            )
            .arg(
                Arg::with_name("log_level")
                    .value_name("LOG_LEVEL")
                    .long("log-level")
                    .help(
                        "Set the log output verbosity.{n}\
                         [valid levels: TRACE, DEBUG, INFO, WARN, ERROR]",
                    ),
            );

    macro_rules! add_subcommand {
        ($name:ident) => {{
            let mut cmd = $name::make_app(App::new(stringify!($name).replace("_", "-").as_str()));

            // for legacy reasons
            if stringify!($name).starts_with("react_native_") {
                cmd = cmd.setting(AppSettings::Hidden);
            }

            app = app.subcommand(cmd);
        }};
    }
    each_subcommand!(add_subcommand);

    let matches = app.get_matches_from_safe(args)?;

    if let Some(url) = matches.value_of("url") {
        config.set_base_url(url);
    }
    if let Some(api_key) = matches.value_of("api_key") {
        config.set_auth(Auth::Key(api_key.to_owned()));
    }
    if let Some(auth_token) = matches.value_of("auth_token") {
        config.set_auth(Auth::Token(auth_token.to_owned()));
    }
    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.set_log_level(level);
            }
            Err(_) => {
                bail!("Unknown log level: {}", level_str);
            }
        }
    }

    // bind the config to the process and fetch an immutable reference to it
    config.bind_to_process();

    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(&cmd) {
                let rv = $name::execute(&sub_matches)?;
                if UPDATE_NAGGER_CMDS.iter().any(|x| x == &cmd) {
                    run_sentrycli_update_nagger();
                }
                return Ok(rv);
            }
        }};
    }
    each_subcommand!(execute_subcommand);
    unreachable!();
}

fn run() -> Result<(), Error> {
    prepare_environment();
    match execute(env::args().collect()) {
        Ok(()) => Ok(()),
        Err(err) => {
            // if the user hit an error, it might be time to run the update
            // nagger because maybe they tried to do something only newer
            // versions support.
            run_sentrycli_update_nagger();
            Err(err)
        }
    }
}

fn setup() {
    use log;
    use utils::logging::Logger;
    use utils::system::{init_backtrace, load_dotenv};

    init_backtrace();
    load_dotenv();

    // we use debug internally but our log handler then rejects to a lower limit.
    // This is okay for our uses but not as efficient.
    log::set_max_level(log::LevelFilter::Debug);

    // if we work with crash reporting we initialize the sentry system.  This
    // also configures the logger.
    #[cfg(feature = "with_crash_reporting")]
    {
        use utils::crashreporting::setup;
        setup(Box::new(Logger));
    }
    #[cfg(not(feature = "with_crash_reporting"))]
    {
        static LOGGER: Logger = Logger;
        log::set_logger(&Logger);
    }
}

/// Executes the command line application and exists the process.
pub fn main() {
    setup();
    match run() {
        Ok(()) => process::exit(0),
        Err(err) => {
            if let Some(&QuietExit(code)) = err.downcast_ref() {
                process::exit(code);
            } else {
                print_error(&err);
                #[cfg(feature = "with_crash_reporting")]
                {
                    use utils::crashreporting::try_report_to_sentry;
                    try_report_to_sentry(&err);
                }
                process::exit(1);
            }
        }
    }
}
<commit_msg>fix: Use correct grammar in help messages (#337)<commit_after>//! This module implements the root command of the CLI tool.

use std::env;
use std::process;

use clap::{App, AppSettings, Arg};
use failure::Error;

use config::{prepare_environment, Auth, Config};
use constants::VERSION;
use utils::system::{print_error, QuietExit};
use utils::update::run_sentrycli_update_nagger;

const ABOUT: &'static str = "
Command line utility for Sentry.

This tool helps you manage remote resources on a Sentry server like
sourcemaps, debug symbols or releases.  Use `--help` on the subcommands
to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dif);
        $mac!(upload_dsym);
        $mac!(upload_proguard);
        $mac!(releases);
        $mac!(issues);
        $mac!(repos);
        $mac!(projects);
        #[cfg(not(feature = "managed"))]
        $mac!(update);
        #[cfg(not(feature = "managed"))]
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        $mac!(react_native);
        $mac!(difutil);
        $mac!(bash_hook);

        // these here exist for legacy reasons only.  They were moved
        // to subcommands of the react-native command.  Note that
        // codepush was never available on that level.
        #[cfg(target_os = "macos")]
        $mac!(react_native_xcode);
        $mac!(react_native_gradle);
    };
}

// commands we want to run the update nagger on
const UPDATE_NAGGER_CMDS: &'static [&'static str] = &[
    "releases", "issues", "repos", "projects", "info", "login", "difutil",
];

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod bash_hook;
pub mod info;
pub mod issues;
pub mod login;
pub mod projects;
pub mod releases;
pub mod repos;
pub mod send_event;
pub mod uninstall;
pub mod update;
pub mod upload_dif;
pub mod upload_dsym;
pub mod upload_proguard;

pub mod react_native;
pub mod react_native_appcenter;
pub mod react_native_codepush;
pub mod react_native_gradle;
#[cfg(target_os = "macos")]
pub mod react_native_xcode;

pub mod difutil;
pub mod difutil_check;
pub mod difutil_find;
pub mod difutil_id;

fn preexecute_hooks() -> Result<bool, Error> {
    return sentry_react_native_xcode_wrap();

    #[cfg(target_os = "macos")]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
            env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
            if &val == "1" {
                react_native_xcode::wrap_call()?;
                return Ok(true);
            }
        }
        Ok(false)
    }

    #[cfg(not(target_os = "macos"))]
    fn sentry_react_native_xcode_wrap() -> Result<bool, Error> {
        Ok(false)
    }
}

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: Vec<String>) -> Result<(), Error> {
    let mut config = Config::from_cli_config()?;

    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    if preexecute_hooks()? {
        return Ok(());
    }

    let mut app =
        App::new("sentry-cli")
            .help_message("Print this help message.")
            .version(VERSION)
            .version_message("Print version information.")
            .about(ABOUT)
            .max_term_width(100)
            .setting(AppSettings::VersionlessSubcommands)
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .global_setting(AppSettings::UnifiedHelpMessage)
            .arg(Arg::with_name("url").value_name("URL").long("url").help(
                "Fully qualified URL to the Sentry server.{n}[defaults to https://sentry.io/]",
            ))
            .arg(
                Arg::with_name("auth_token")
                    .value_name("AUTH_TOKEN")
                    .long("auth-token")
                    .help("Use the given Sentry auth token."),
            )
            .arg(
                Arg::with_name("api_key")
                    .value_name("API_KEY")
                    .long("api-key")
                    .help("The given Sentry API key."),
            )
            .arg(
                Arg::with_name("log_level")
                    .value_name("LOG_LEVEL")
                    .long("log-level")
                    .help(
                        "Set the log output verbosity.{n}\
                         [valid levels: TRACE, DEBUG, INFO, WARN, ERROR]",
                    ),
            );

    macro_rules! add_subcommand {
        ($name:ident) => {{
            let mut cmd = $name::make_app(App::new(stringify!($name).replace("_", "-").as_str()));

            // for legacy reasons
            if stringify!($name).starts_with("react_native_") {
                cmd = cmd.setting(AppSettings::Hidden);
            }

            app = app.subcommand(cmd);
        }};
    }
    each_subcommand!(add_subcommand);

    let matches = app.get_matches_from_safe(args)?;

    if let Some(url) = matches.value_of("url") {
        config.set_base_url(url);
    }
    if let Some(api_key) = matches.value_of("api_key") {
        config.set_auth(Auth::Key(api_key.to_owned()));
    }
    if let Some(auth_token) = matches.value_of("auth_token") {
        config.set_auth(Auth::Token(auth_token.to_owned()));
    }
    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.set_log_level(level);
            }
            Err(_) => {
                bail!("Unknown log level: {}", level_str);
            }
        }
    }

    // bind the config to the process and fetch an immutable reference to it
    config.bind_to_process();

    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(&cmd) {
                let rv = $name::execute(&sub_matches)?;
                if UPDATE_NAGGER_CMDS.iter().any(|x| x == &cmd) {
                    run_sentrycli_update_nagger();
                }
                return Ok(rv);
            }
        }};
    }
    each_subcommand!(execute_subcommand);
    unreachable!();
}

fn run() -> Result<(), Error> {
    prepare_environment();
    match execute(env::args().collect()) {
        Ok(()) => Ok(()),
        Err(err) => {
            // if the user hit an error, it might be time to run the update
            // nagger because maybe they tried to do something only newer
            // versions support.
            run_sentrycli_update_nagger();
            Err(err)
        }
    }
}

fn setup() {
    use log;
    use utils::logging::Logger;
    use utils::system::{init_backtrace, load_dotenv};

    init_backtrace();
    load_dotenv();

    // we use debug internally but our log handler then rejects to a lower limit.
    // This is okay for our uses but not as efficient.
    log::set_max_level(log::LevelFilter::Debug);

    // if we work with crash reporting we initialize the sentry system.  This
    // also configures the logger.
    #[cfg(feature = "with_crash_reporting")]
    {
        use utils::crashreporting::setup;
        setup(Box::new(Logger));
    }
    #[cfg(not(feature = "with_crash_reporting"))]
    {
        static LOGGER: Logger = Logger;
        log::set_logger(&Logger);
    }
}

/// Executes the command line application and exists the process.
pub fn main() {
    setup();
    match run() {
        Ok(()) => process::exit(0),
        Err(err) => {
            if let Some(&QuietExit(code)) = err.downcast_ref() {
                process::exit(code);
            } else {
                print_error(&err);
                #[cfg(feature = "with_crash_reporting")]
                {
                    use utils::crashreporting::try_report_to_sentry;
                    try_report_to_sentry(&err);
                }
                process::exit(1);
            }
        }
    }
}
<|endoftext|>


<commit_before>#[link(name="cat", vers="1.0.0", author="Seldaek")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern mod extra;

use std::os;
use std::io::{stdin, stderr, stdout, Writer, Reader};
use extra::getopts::*;

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("A", "show-all", "equivalent to -vET"),
        groups::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        groups::optflag("e", "", "equivalent to -vE"),
        groups::optflag("E", "show-ends", "display $ at end of each line"),
        groups::optflag("n", "number", "number all output lines"),
        groups::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        groups::optflag("t", "", "equivalent to -vT"),
        groups::optflag("T", "show-tabs", "display TAB characters as ^I"),
        groups::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            stderr().write_line("Invalid options");
            stderr().write_line(fail_str(f));
            os::set_exit_status(1);
            return
        }
    };
    if opts_present(&matches, [~"h", ~"help"]) {
        println("cat 1.0.0");
        println("");
        println("Usage:");
        println(fmt!("  %s [OPTION]... [FILE]...", program));
        println("");
        print(groups::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println("");
        println("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if opts_present(&matches, [~"V", ~"version"]) {
        println("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if opts_present(&matches, [~"n", ~"number"]) {
        number_mode = NumberAll;
    }
    if opts_present(&matches, [~"b", ~"number-nonblank"]) {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = opts_present(&matches, [~"v", ~"show-nonprinting", ~"A", ~"show-all", ~"t", ~"e"]);
    let show_ends = opts_present(&matches, [~"E", ~"show-ends", ~"A", ~"show-all", ~"e"]);
    let show_tabs = opts_present(&matches, [~"T", ~"show-tabs",  ~"A", ~"show-all", ~"t"]);
    let squeeze_blank = opts_present(&matches, [~"s", ~"squeeze-blank"]);
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = '\t' as u8;
static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;

#[cfg(windows)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF || byte == CR
}

#[cfg(unix)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let writer = stdout();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        for path in files.iter() {
            let reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { loop }
            };

            let mut counter: uint = 1;
            let mut at_line_start = true;
            let is_numbering = number == NumberAll || number == NumberNonEmpty;

            loop {
                let buf = reader.read_bytes(2);
                for byte in buf.iter() {
                    if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                        writer.write_str(fmt!("%6u  ", counter));
                        counter += 1;
                        at_line_start = false;
                    }
                    if is_numbering && *byte == LF {
                        at_line_start = true;
                    }
                    if show_tabs && *byte == TAB {
                        writer.write(['^' as u8, 'I' as u8]);
                    } else if show_ends && *byte == LF {
                        writer.write(['$' as u8, LF]);
                    } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                        let mut byte = *byte;
                        if byte >= 128 {
                            writer.write(['M' as u8, '-' as u8]);
                            byte = byte - 128;
                        }
                        if byte < 32 {
                            writer.write(['^' as u8, byte + 64]);
                        } else if byte == 127 {
                            writer.write(['^' as u8, byte - 64]);
                        } else {
                            writer.write([byte]);
                        }
                    } else {
                        writer.write([*byte]);
                    }
                }

                if reader.eof() {
                    break;
                }
            }
        }

        return;
    }

    // passthru mode
    for path in files.iter() {
        let reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { loop }
        };

        loop {
            writer.write(reader.read_bytes(100000));
            if reader.eof() {
                break;
            }
        }
    }
}

fn open(path: ~str) -> Option<@Reader> {
    if "-" == path {
        return Some(stdin());
    }

    match std::io::file_reader(&std::path::Path(path)) {
        Ok(fd) => return Some(fd),
        Err(e) => {
            stderr().write_line(fmt!("cat: %s: %s", path, e));
            os::set_exit_status(1);
        }
    }

    None
}
<commit_msg>Use bytes! and cfg! to improve readability a bit<commit_after>#[link(name="cat", vers="1.0.0", author="Seldaek")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern mod extra;

use std::os;
use std::io::{stdin, stderr, stdout, Writer, Reader};
use extra::getopts::*;

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("A", "show-all", "equivalent to -vET"),
        groups::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        groups::optflag("e", "", "equivalent to -vE"),
        groups::optflag("E", "show-ends", "display $ at end of each line"),
        groups::optflag("n", "number", "number all output lines"),
        groups::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        groups::optflag("t", "", "equivalent to -vT"),
        groups::optflag("T", "show-tabs", "display TAB characters as ^I"),
        groups::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            stderr().write_line("Invalid options");
            stderr().write_line(fail_str(f));
            os::set_exit_status(1);
            return
        }
    };
    if opts_present(&matches, [~"h", ~"help"]) {
        println("cat 1.0.0");
        println("");
        println("Usage:");
        println(fmt!("  %s [OPTION]... [FILE]...", program));
        println("");
        print(groups::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println("");
        println("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if opts_present(&matches, [~"V", ~"version"]) {
        println("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if opts_present(&matches, [~"n", ~"number"]) {
        number_mode = NumberAll;
    }
    if opts_present(&matches, [~"b", ~"number-nonblank"]) {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = opts_present(&matches, [~"v", ~"show-nonprinting", ~"A", ~"show-all", ~"t", ~"e"]);
    let show_ends = opts_present(&matches, [~"E", ~"show-ends", ~"A", ~"show-all", ~"e"]);
    let show_tabs = opts_present(&matches, [~"T", ~"show-tabs",  ~"A", ~"show-all", ~"t"]);
    let squeeze_blank = opts_present(&matches, [~"s", ~"squeeze-blank"]);
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = bytes!("\t");
static CR: u8 = bytes!("\r");
static LF: u8 = bytes!("\n");

fn is_newline_char(byte: u8) -> bool {
    if cfg!("windows") {
        return byte == LF || byte == CR
    }

    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let writer = stdout();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        for path in files.iter() {
            let reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { loop }
            };

            let mut counter: uint = 1;
            let mut at_line_start = true;
            let is_numbering = number == NumberAll || number == NumberNonEmpty;

            loop {
                let buf = reader.read_bytes(2);
                for byte in buf.iter() {
                    if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                        writer.write_str(fmt!("%6u  ", counter));
                        counter += 1;
                        at_line_start = false;
                    }
                    if is_numbering && *byte == LF {
                        at_line_start = true;
                    }
                    if show_tabs && *byte == TAB {
                        writer.write(bytes!("^I"));
                    } else if show_ends && *byte == LF {
                        writer.write(bytes!("$\n"));
                    } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                        let mut byte = *byte;
                        if byte >= 128 {
                            writer.write(bytes!("M-"));
                            byte = byte - 128;
                        }
                        if byte < 32 {
                            writer.write(['^' as u8, byte + 64]);
                        } else if byte == 127 {
                            writer.write(['^' as u8, byte - 64]);
                        } else {
                            writer.write([byte]);
                        }
                    } else {
                        writer.write([*byte]);
                    }
                }

                if reader.eof() {
                    break;
                }
            }
        }

        return;
    }

    // passthru mode
    for path in files.iter() {
        let reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { loop }
        };

        loop {
            writer.write(reader.read_bytes(100000));
            if reader.eof() {
                break;
            }
        }
    }
}

fn open(path: ~str) -> Option<@Reader> {
    if "-" == path {
        return Some(stdin());
    }

    match std::io::file_reader(&std::path::Path(path)) {
        Ok(fd) => return Some(fd),
        Err(e) => {
            stderr().write_line(fmt!("cat: %s: %s", path, e));
            os::set_exit_status(1);
        }
    }

    None
}
<|endoftext|>