<commit_before>use std::prelude::v1::*;

use std::io;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc;
use std::thread;
use std::fmt;
use std::marker::Unpin;

use futures_core::*;
use futures_core::task::{self, Wake, TaskObj, local_waker_from_nonlocal};
use futures_core::executor::{Executor, SpawnObjError};

use enter;
use num_cpus;
use unpark_mutex::UnparkMutex;

/// A general-purpose thread pool for scheduling asynchronous tasks.
///
/// The thread pool multiplexes any number of tasks onto a fixed number of
/// worker threads.
///
/// This type is a clonable handle to the threadpool itself.
/// Cloning it will only create a new reference, not a new threadpool.
pub struct ThreadPool {
    state: Arc<PoolState>,
}

/// Thread pool configuration object.
pub struct ThreadPoolBuilder {
    pool_size: usize,
    stack_size: usize,
    name_prefix: Option<String>,
    after_start: Option<Arc<Fn(usize) + Send + Sync>>,
    before_stop: Option<Arc<Fn(usize) + Send + Sync>>,
}

trait AssertSendSync: Send + Sync {}
impl AssertSendSync for ThreadPool {}

struct PoolState {
    tx: Mutex<mpsc::Sender<Message>>,
    rx: Mutex<mpsc::Receiver<Message>>,
    cnt: AtomicUsize,
    size: usize,
}

impl fmt::Debug for ThreadPool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ThreadPool")
            .field("size", &self.state.size)
            .finish()
    }
}

impl fmt::Debug for ThreadPoolBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ThreadPoolBuilder")
            .field("pool_size", &self.pool_size)
            .field("name_prefix", &self.name_prefix)
            .finish()
    }
}

enum Message {
    Run(TaskContainer),
    Close,
}

impl ThreadPool {
    /// Creates a new thread pool with the default configuration.
    ///
    /// See documentation for the methods in
    /// [`ThreadPoolBuilder`](::ThreadPoolBuilder) for details on the default
    /// configuration.
    pub fn new() -> Result<ThreadPool, io::Error> {
        ThreadPoolBuilder::new().create()
    }

    /// Create a default thread pool configuration, which can then be customized.
    ///
    /// See documentation for the methods in
    /// [`ThreadPoolBuilder`](::ThreadPoolBuilder) for details on the default
    /// configuration.
    pub fn builder() -> ThreadPoolBuilder {
        ThreadPoolBuilder::new()
    }

    /// Runs the given future with this thread pool as the default executor for
    /// spawning tasks.
    ///
    /// **This function will block the calling thread** until the given future
    /// is complete. While executing that future, any tasks spawned onto the
    /// default executor will be routed to this thread pool.
    ///
    /// Note that the function will return when the provided future completes,
    /// even if some of the tasks it spawned are still running.
    pub fn run<F: Future + Unpin>(&mut self, f: F) -> F::Output {
        ::LocalPool::new().run_until(f, self)
    }
}

impl Executor for ThreadPool {
    fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError> {
        let task_container = TaskContainer {
            task,
            wake_handle: Arc::new(WakeHandle {
                exec: self.clone(),
                mutex: UnparkMutex::new(),
            }),
            exec: self.clone(),
        };
        self.state.send(Message::Run(task_container));
        Ok(())
    }
}

impl PoolState {
    fn send(&self, msg: Message) {
        self.tx.lock().unwrap().send(msg).unwrap();
    }

    fn work(&self,
            idx: usize,
            after_start: Option<Arc<Fn(usize) + Send + Sync>>,
            before_stop: Option<Arc<Fn(usize) + Send + Sync>>) {
        let _scope = enter().unwrap();
        after_start.map(|fun| fun(idx));
        loop {
            let msg = self.rx.lock().unwrap().recv().unwrap();
            match msg {
                Message::Run(task_container) => task_container.run(),
                Message::Close => break,
            }
        }
        before_stop.map(|fun| fun(idx));
    }
}

impl Clone for ThreadPool {
    fn clone(&self) -> ThreadPool {
        self.state.cnt.fetch_add(1, Ordering::Relaxed);
        ThreadPool { state: self.state.clone() }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        if self.state.cnt.fetch_sub(1, Ordering::Relaxed) == 1 {
            for _ in 0..self.state.size {
                self.state.send(Message::Close);
            }
        }
    }
}

impl ThreadPoolBuilder {
    /// Create a default thread pool configuration.
    ///
    /// See the other methods on this type for details on the defaults.
    pub fn new() -> ThreadPoolBuilder {
        ThreadPoolBuilder {
            pool_size: num_cpus::get(),
            stack_size: 0,
            name_prefix: None,
            after_start: None,
            before_stop: None,
        }
    }

    /// Set size of a future ThreadPool
    ///
    /// The size of a thread pool is the number of worker threads spawned.  By
    /// default, this is equal to the number of CPU cores.
    pub fn pool_size(&mut self, size: usize) -> &mut Self {
        self.pool_size = size;
        self
    }

    /// Set stack size of threads in the pool.
    ///
    /// By default, worker threads use Rust's standard stack size.
    pub fn stack_size(&mut self, stack_size: usize) -> &mut Self {
        self.stack_size = stack_size;
        self
    }

    /// Set thread name prefix of a future ThreadPool.
    ///
    /// Thread name prefix is used for generating thread names. For example, if prefix is
    /// `my-pool-`, then threads in the pool will get names like `my-pool-1` etc.
    ///
    /// By default, worker threads are assigned Rust's standard thread name.
    pub fn name_prefix<S: Into<String>>(&mut self, name_prefix: S) -> &mut Self {
        self.name_prefix = Some(name_prefix.into());
        self
    }

    /// Execute the closure `f` immediately after each worker thread is started,
    /// but before running any tasks on it.
    ///
    /// This hook is intended for bookkeeping and monitoring.
    /// The closure `f` will be dropped after the `builder` is dropped
    /// and all worker threads in the pool have executed it.
    ///
    /// The closure provided will receive an index corresponding to the worker
    /// thread it's running on.
    pub fn after_start<F>(&mut self, f: F) -> &mut Self
        where F: Fn(usize) + Send + Sync + 'static
    {
        self.after_start = Some(Arc::new(f));
        self
    }

    /// Execute closure `f` just prior to shutting down each worker thread.
    ///
    /// This hook is intended for bookkeeping and monitoring.
    /// The closure `f` will be dropped after the `builder` is droppped
    /// and all threads in the pool have executed it.
    ///
    /// The closure provided will receive an index corresponding to the worker
    /// thread it's running on.
    pub fn before_stop<F>(&mut self, f: F) -> &mut Self
        where F: Fn(usize) + Send + Sync + 'static
    {
        self.before_stop = Some(Arc::new(f));
        self
    }

    /// Create a [`ThreadPool`](::ThreadPool) with the given configuration.
    ///
    /// # Panics
    ///
    /// Panics if `pool_size == 0`.
    pub fn create(&mut self) -> Result<ThreadPool, io::Error> {
        let (tx, rx) = mpsc::channel();
        let pool = ThreadPool {
            state: Arc::new(PoolState {
                tx: Mutex::new(tx),
                rx: Mutex::new(rx),
                cnt: AtomicUsize::new(1),
                size: self.pool_size,
            }),
        };
        assert!(self.pool_size > 0);

        for counter in 0..self.pool_size {
            let state = pool.state.clone();
            let after_start = self.after_start.clone();
            let before_stop = self.before_stop.clone();
            let mut thread_builder = thread::Builder::new();
            if let Some(ref name_prefix) = self.name_prefix {
                thread_builder = thread_builder.name(format!("{}{}", name_prefix, counter));
            }
            if self.stack_size > 0 {
                thread_builder = thread_builder.stack_size(self.stack_size);
            }
            thread_builder.spawn(move || state.work(counter, after_start, before_stop))?;
        }
        Ok(pool)
    }
}

/// Units of work submitted to an `Executor`, currently only created
/// internally.
struct TaskContainer {
    task: TaskObj,
    exec: ThreadPool,
    wake_handle: Arc<WakeHandle>,
}

struct WakeHandle {
    mutex: UnparkMutex<TaskContainer>,
    exec: ThreadPool,
}

impl TaskContainer {
    /// Actually run the task (invoking `poll`) on the current thread.
    pub fn run(self) {
        let TaskContainer { mut task, wake_handle, mut exec } = self;
        let local_waker = local_waker_from_nonlocal(wake_handle.clone());

        // SAFETY: the ownership of this `TaskContainer` object is evidence that
        // we are in the `POLLING`/`REPOLL` state for the mutex.
        unsafe {
            wake_handle.mutex.start_poll();

            loop {
                let res = {
                    let mut cx = task::Context::new(&local_waker, &mut exec);
                    task.poll_unpin(&mut cx)
                };
                match res {
                    Poll::Pending => {}
                    Poll::Ready(()) => return wake_handle.mutex.complete(),
                }
                let task_container = TaskContainer {
                    task,
                    wake_handle: wake_handle.clone(),
                    exec: exec
                };
                match wake_handle.mutex.wait(task_container) {
                    Ok(()) => return, // we've waited
                    Err(task_container) => { // someone's notified us
                        task = task_container.task;
                        exec = task_container.exec;
                    }
                }
            }
        }
    }
}

impl fmt::Debug for TaskContainer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Task")
            .field("contents", &"...")
            .finish()
    }
}

impl Wake for WakeHandle {
    fn wake(arc_self: &Arc<Self>) {
        match arc_self.mutex.notify() {
            Ok(task) => arc_self.exec.state.send(Message::Run(task)),
            Err(()) => {}
        }
    }
}

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

    #[test]
    fn test_drop_after_start() {
        let (tx, rx) = mpsc::sync_channel(2);
        let _cpu_pool = ThreadPoolBuilder::new()
            .pool_size(2)
            .after_start(move |_| tx.send(1).unwrap()).create().unwrap();

        // After ThreadPoolBuilder is deconstructed, the tx should be droped
        // so that we can use rx as an iterator.
        let count = rx.into_iter().count();
        assert_eq!(count, 2);
    }
}
<commit_msg>Prefix free function with module<commit_after>use std::prelude::v1::*;

use std::io;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc;
use std::thread;
use std::fmt;
use std::marker::Unpin;

use futures_core::*;
use futures_core::task::{self, Wake, TaskObj};
use futures_core::executor::{Executor, SpawnObjError};

use enter;
use num_cpus;
use unpark_mutex::UnparkMutex;

/// A general-purpose thread pool for scheduling asynchronous tasks.
///
/// The thread pool multiplexes any number of tasks onto a fixed number of
/// worker threads.
///
/// This type is a clonable handle to the threadpool itself.
/// Cloning it will only create a new reference, not a new threadpool.
pub struct ThreadPool {
    state: Arc<PoolState>,
}

/// Thread pool configuration object.
pub struct ThreadPoolBuilder {
    pool_size: usize,
    stack_size: usize,
    name_prefix: Option<String>,
    after_start: Option<Arc<Fn(usize) + Send + Sync>>,
    before_stop: Option<Arc<Fn(usize) + Send + Sync>>,
}

trait AssertSendSync: Send + Sync {}
impl AssertSendSync for ThreadPool {}

struct PoolState {
    tx: Mutex<mpsc::Sender<Message>>,
    rx: Mutex<mpsc::Receiver<Message>>,
    cnt: AtomicUsize,
    size: usize,
}

impl fmt::Debug for ThreadPool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ThreadPool")
            .field("size", &self.state.size)
            .finish()
    }
}

impl fmt::Debug for ThreadPoolBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ThreadPoolBuilder")
            .field("pool_size", &self.pool_size)
            .field("name_prefix", &self.name_prefix)
            .finish()
    }
}

enum Message {
    Run(TaskContainer),
    Close,
}

impl ThreadPool {
    /// Creates a new thread pool with the default configuration.
    ///
    /// See documentation for the methods in
    /// [`ThreadPoolBuilder`](::ThreadPoolBuilder) for details on the default
    /// configuration.
    pub fn new() -> Result<ThreadPool, io::Error> {
        ThreadPoolBuilder::new().create()
    }

    /// Create a default thread pool configuration, which can then be customized.
    ///
    /// See documentation for the methods in
    /// [`ThreadPoolBuilder`](::ThreadPoolBuilder) for details on the default
    /// configuration.
    pub fn builder() -> ThreadPoolBuilder {
        ThreadPoolBuilder::new()
    }

    /// Runs the given future with this thread pool as the default executor for
    /// spawning tasks.
    ///
    /// **This function will block the calling thread** until the given future
    /// is complete. While executing that future, any tasks spawned onto the
    /// default executor will be routed to this thread pool.
    ///
    /// Note that the function will return when the provided future completes,
    /// even if some of the tasks it spawned are still running.
    pub fn run<F: Future + Unpin>(&mut self, f: F) -> F::Output {
        ::LocalPool::new().run_until(f, self)
    }
}

impl Executor for ThreadPool {
    fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError> {
        let task_container = TaskContainer {
            task,
            wake_handle: Arc::new(WakeHandle {
                exec: self.clone(),
                mutex: UnparkMutex::new(),
            }),
            exec: self.clone(),
        };
        self.state.send(Message::Run(task_container));
        Ok(())
    }
}

impl PoolState {
    fn send(&self, msg: Message) {
        self.tx.lock().unwrap().send(msg).unwrap();
    }

    fn work(&self,
            idx: usize,
            after_start: Option<Arc<Fn(usize) + Send + Sync>>,
            before_stop: Option<Arc<Fn(usize) + Send + Sync>>) {
        let _scope = enter().unwrap();
        after_start.map(|fun| fun(idx));
        loop {
            let msg = self.rx.lock().unwrap().recv().unwrap();
            match msg {
                Message::Run(task_container) => task_container.run(),
                Message::Close => break,
            }
        }
        before_stop.map(|fun| fun(idx));
    }
}

impl Clone for ThreadPool {
    fn clone(&self) -> ThreadPool {
        self.state.cnt.fetch_add(1, Ordering::Relaxed);
        ThreadPool { state: self.state.clone() }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        if self.state.cnt.fetch_sub(1, Ordering::Relaxed) == 1 {
            for _ in 0..self.state.size {
                self.state.send(Message::Close);
            }
        }
    }
}

impl ThreadPoolBuilder {
    /// Create a default thread pool configuration.
    ///
    /// See the other methods on this type for details on the defaults.
    pub fn new() -> ThreadPoolBuilder {
        ThreadPoolBuilder {
            pool_size: num_cpus::get(),
            stack_size: 0,
            name_prefix: None,
            after_start: None,
            before_stop: None,
        }
    }

    /// Set size of a future ThreadPool
    ///
    /// The size of a thread pool is the number of worker threads spawned.  By
    /// default, this is equal to the number of CPU cores.
    pub fn pool_size(&mut self, size: usize) -> &mut Self {
        self.pool_size = size;
        self
    }

    /// Set stack size of threads in the pool.
    ///
    /// By default, worker threads use Rust's standard stack size.
    pub fn stack_size(&mut self, stack_size: usize) -> &mut Self {
        self.stack_size = stack_size;
        self
    }

    /// Set thread name prefix of a future ThreadPool.
    ///
    /// Thread name prefix is used for generating thread names. For example, if prefix is
    /// `my-pool-`, then threads in the pool will get names like `my-pool-1` etc.
    ///
    /// By default, worker threads are assigned Rust's standard thread name.
    pub fn name_prefix<S: Into<String>>(&mut self, name_prefix: S) -> &mut Self {
        self.name_prefix = Some(name_prefix.into());
        self
    }

    /// Execute the closure `f` immediately after each worker thread is started,
    /// but before running any tasks on it.
    ///
    /// This hook is intended for bookkeeping and monitoring.
    /// The closure `f` will be dropped after the `builder` is dropped
    /// and all worker threads in the pool have executed it.
    ///
    /// The closure provided will receive an index corresponding to the worker
    /// thread it's running on.
    pub fn after_start<F>(&mut self, f: F) -> &mut Self
        where F: Fn(usize) + Send + Sync + 'static
    {
        self.after_start = Some(Arc::new(f));
        self
    }

    /// Execute closure `f` just prior to shutting down each worker thread.
    ///
    /// This hook is intended for bookkeeping and monitoring.
    /// The closure `f` will be dropped after the `builder` is droppped
    /// and all threads in the pool have executed it.
    ///
    /// The closure provided will receive an index corresponding to the worker
    /// thread it's running on.
    pub fn before_stop<F>(&mut self, f: F) -> &mut Self
        where F: Fn(usize) + Send + Sync + 'static
    {
        self.before_stop = Some(Arc::new(f));
        self
    }

    /// Create a [`ThreadPool`](::ThreadPool) with the given configuration.
    ///
    /// # Panics
    ///
    /// Panics if `pool_size == 0`.
    pub fn create(&mut self) -> Result<ThreadPool, io::Error> {
        let (tx, rx) = mpsc::channel();
        let pool = ThreadPool {
            state: Arc::new(PoolState {
                tx: Mutex::new(tx),
                rx: Mutex::new(rx),
                cnt: AtomicUsize::new(1),
                size: self.pool_size,
            }),
        };
        assert!(self.pool_size > 0);

        for counter in 0..self.pool_size {
            let state = pool.state.clone();
            let after_start = self.after_start.clone();
            let before_stop = self.before_stop.clone();
            let mut thread_builder = thread::Builder::new();
            if let Some(ref name_prefix) = self.name_prefix {
                thread_builder = thread_builder.name(format!("{}{}", name_prefix, counter));
            }
            if self.stack_size > 0 {
                thread_builder = thread_builder.stack_size(self.stack_size);
            }
            thread_builder.spawn(move || state.work(counter, after_start, before_stop))?;
        }
        Ok(pool)
    }
}

/// Units of work submitted to an `Executor`, currently only created
/// internally.
struct TaskContainer {
    task: TaskObj,
    exec: ThreadPool,
    wake_handle: Arc<WakeHandle>,
}

struct WakeHandle {
    mutex: UnparkMutex<TaskContainer>,
    exec: ThreadPool,
}

impl TaskContainer {
    /// Actually run the task (invoking `poll`) on the current thread.
    pub fn run(self) {
        let TaskContainer { mut task, wake_handle, mut exec } = self;
        let local_waker = task::local_waker_from_nonlocal(wake_handle.clone());

        // SAFETY: the ownership of this `TaskContainer` object is evidence that
        // we are in the `POLLING`/`REPOLL` state for the mutex.
        unsafe {
            wake_handle.mutex.start_poll();

            loop {
                let res = {
                    let mut cx = task::Context::new(&local_waker, &mut exec);
                    task.poll_unpin(&mut cx)
                };
                match res {
                    Poll::Pending => {}
                    Poll::Ready(()) => return wake_handle.mutex.complete(),
                }
                let task_container = TaskContainer {
                    task,
                    wake_handle: wake_handle.clone(),
                    exec: exec
                };
                match wake_handle.mutex.wait(task_container) {
                    Ok(()) => return, // we've waited
                    Err(task_container) => { // someone's notified us
                        task = task_container.task;
                        exec = task_container.exec;
                    }
                }
            }
        }
    }
}

impl fmt::Debug for TaskContainer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Task")
            .field("contents", &"...")
            .finish()
    }
}

impl Wake for WakeHandle {
    fn wake(arc_self: &Arc<Self>) {
        match arc_self.mutex.notify() {
            Ok(task) => arc_self.exec.state.send(Message::Run(task)),
            Err(()) => {}
        }
    }
}

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

    #[test]
    fn test_drop_after_start() {
        let (tx, rx) = mpsc::sync_channel(2);
        let _cpu_pool = ThreadPoolBuilder::new()
            .pool_size(2)
            .after_start(move |_| tx.send(1).unwrap()).create().unwrap();

        // After ThreadPoolBuilder is deconstructed, the tx should be droped
        // so that we can use rx as an iterator.
        let count = rx.into_iter().count();
        assert_eq!(count, 2);
    }
}
<|endoftext|>


<commit_before>//! Matrix device identifiers.

use std::{
    fmt::{self, Display},
    mem,
};

#[cfg(feature = "rand")]
use crate::generate_localpart;

/// A Matrix device ID.
///
/// Device identifiers in Matrix are completely opaque character sequences. This type alias is
/// provided simply for its semantic value.
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde1::Serialize), serde(transparent, crate = "serde1"))]
pub struct DeviceId(str);

impl DeviceId {
    #[allow(clippy::transmute_ptr_to_ptr)]
    fn from_borrowed(s: &str) -> &Self {
        unsafe { mem::transmute(s) }
    }

    fn from_owned(s: Box<str>) -> Box<Self> {
        unsafe { mem::transmute(s) }
    }

    fn into_owned(self: Box<Self>) -> Box<str> {
        unsafe { mem::transmute(self) }
    }

    /// Generates a random `DeviceId`, suitable for assignment to a new device.
    #[cfg(feature = "rand")]
    #[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
    pub fn new() -> Box<Self> {
        Self::from_owned(generate_localpart(8))
    }

    /// Creates a string slice from this `DeviceId`.
    pub fn as_str(&self) -> &str {
        &self.0
    }

    /// Creates a byte slice from this `DeviceId`.
    pub fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

impl Clone for Box<DeviceId> {
    fn clone(&self) -> Self {
        (**self).to_owned()
    }
}

impl ToOwned for DeviceId {
    type Owned = Box<DeviceId>;

    fn to_owned(&self) -> Self::Owned {
        Self::from_owned(self.0.to_owned().into_boxed_str())
    }
}

impl From<&DeviceId> for Box<DeviceId> {
    fn from(id: &DeviceId) -> Self {
        id.to_owned()
    }
}

impl AsRef<str> for DeviceId {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<str> for Box<DeviceId> {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<'a> From<&'a str> for &'a DeviceId {
    fn from(s: &'a str) -> Self {
        DeviceId::from_borrowed(s)
    }
}

impl From<&str> for Box<DeviceId> {
    fn from(s: &str) -> Self {
        DeviceId::from_owned(s.into())
    }
}

impl From<String> for Box<DeviceId> {
    fn from(s: String) -> Self {
        DeviceId::from_owned(s.into())
    }
}

impl From<Box<DeviceId>> for String {
    fn from(id: Box<DeviceId>) -> Self {
        id.into_owned().into()
    }
}

impl Display for DeviceId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

#[cfg(feature = "serde")]
impl<'de> serde1::Deserialize<'de> for Box<DeviceId> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde1::Deserializer<'de>,
    {
        crate::deserialize_id(deserializer, "An IP address or hostname")
    }
}

partial_eq_string!(DeviceId);
partial_eq_string!(Box<DeviceId>);

/// Generates a random `DeviceId`, suitable for assignment to a new device.
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
#[deprecated = "use DeviceId::new instead"]
pub fn generate() -> Box<DeviceId> {
    DeviceId::new()
}

#[cfg(all(test, feature = "rand"))]
mod tests {
    use super::DeviceId;

    #[test]
    fn generate_device_id() {
        assert_eq!(DeviceId::new().as_str().len(), 8);
    }
}
<commit_msg>Fix docs for DeviceId<commit_after>//! Matrix device identifiers.

use std::{
    fmt::{self, Display},
    mem,
};

#[cfg(feature = "rand")]
use crate::generate_localpart;

/// A Matrix device ID.
///
/// Device identifiers in Matrix are completely opaque character sequences. This type is provided
/// simply for its semantic value.
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde1::Serialize), serde(transparent, crate = "serde1"))]
pub struct DeviceId(str);

impl DeviceId {
    #[allow(clippy::transmute_ptr_to_ptr)]
    fn from_borrowed(s: &str) -> &Self {
        unsafe { mem::transmute(s) }
    }

    fn from_owned(s: Box<str>) -> Box<Self> {
        unsafe { mem::transmute(s) }
    }

    fn into_owned(self: Box<Self>) -> Box<str> {
        unsafe { mem::transmute(self) }
    }

    /// Generates a random `DeviceId`, suitable for assignment to a new device.
    #[cfg(feature = "rand")]
    #[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
    pub fn new() -> Box<Self> {
        Self::from_owned(generate_localpart(8))
    }

    /// Creates a string slice from this `DeviceId`.
    pub fn as_str(&self) -> &str {
        &self.0
    }

    /// Creates a byte slice from this `DeviceId`.
    pub fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

impl Clone for Box<DeviceId> {
    fn clone(&self) -> Self {
        (**self).to_owned()
    }
}

impl ToOwned for DeviceId {
    type Owned = Box<DeviceId>;

    fn to_owned(&self) -> Self::Owned {
        Self::from_owned(self.0.to_owned().into_boxed_str())
    }
}

impl From<&DeviceId> for Box<DeviceId> {
    fn from(id: &DeviceId) -> Self {
        id.to_owned()
    }
}

impl AsRef<str> for DeviceId {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<str> for Box<DeviceId> {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<'a> From<&'a str> for &'a DeviceId {
    fn from(s: &'a str) -> Self {
        DeviceId::from_borrowed(s)
    }
}

impl From<&str> for Box<DeviceId> {
    fn from(s: &str) -> Self {
        DeviceId::from_owned(s.into())
    }
}

impl From<String> for Box<DeviceId> {
    fn from(s: String) -> Self {
        DeviceId::from_owned(s.into())
    }
}

impl From<Box<DeviceId>> for String {
    fn from(id: Box<DeviceId>) -> Self {
        id.into_owned().into()
    }
}

impl Display for DeviceId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

#[cfg(feature = "serde")]
impl<'de> serde1::Deserialize<'de> for Box<DeviceId> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde1::Deserializer<'de>,
    {
        crate::deserialize_id(deserializer, "An IP address or hostname")
    }
}

partial_eq_string!(DeviceId);
partial_eq_string!(Box<DeviceId>);

/// Generates a random `DeviceId`, suitable for assignment to a new device.
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
#[deprecated = "use DeviceId::new instead"]
pub fn generate() -> Box<DeviceId> {
    DeviceId::new()
}

#[cfg(all(test, feature = "rand"))]
mod tests {
    use super::DeviceId;

    #[test]
    fn generate_device_id() {
        assert_eq!(DeviceId::new().as_str().len(), 8);
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::collections::HashSet;

use clap::{App, AppSettings, Arg, ArgMatches};
use walkdir::WalkDir;

use CliResult;
use api::{Api, NewRelease};
use commands::Config;
use utils::make_subcommand;
use sourcemaps::SourceMapValidator;

#[derive(Debug, Deserialize)]
struct ReleaseInfo {
    version: String,
    #[serde(rename="ref")]
    reference: Option<String>,
    url: Option<String>,
    #[serde(rename="dateCreated")]
    date_created: String,
    #[serde(rename="dateReleased")]
    date_released: Option<String>,
    #[serde(rename="newGroups")]
    new_groups: u64,
}

#[derive(Debug, Deserialize)]
struct Artifact {
    id: String,
    sha1: String,
    name: String,
    size: u64,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
            .about("Create a new release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version identifier for this release"))
            .arg(Arg::with_name("ref")
                 .long("ref")
                 .value_name("REF")
                 .help("Optional commit reference (commit hash)"))
            .arg(Arg::with_name("url")
                 .long("url")
                 .value_name("URL")
                 .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
            .about("Delete a release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version to delete")))
        .subcommand(make_subcommand("list")
            .about("list the most recent releases"))
        .subcommand(make_subcommand("files")
            .about("manage release artifact files")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The release to manage the files of"))
            .subcommand(make_subcommand("list")
                .about("List all release files"))
            .subcommand(make_subcommand("delete")
                .about("Delete a release file")
                .arg(Arg::with_name("all")
                     .short("A")
                     .long("all")
                     .help("deletes all files"))
                .arg(Arg::with_name("names")
                     .value_name("NAMES")
                     .index(1)
                     .multiple(true)
                     .help("a list of filenames to delete.")))
            .subcommand(make_subcommand("upload")
                .about("Uploads a file for a given release")
                .arg(Arg::with_name("path")
                     .value_name("PATH")
                     .index(1)
                     .required(true)
                     .help("The file to upload"))
                .arg(Arg::with_name("name")
                     .index(2)
                     .value_name("NAME")
                     .help("The name of the file on the server.")))
            .subcommand(make_subcommand("upload-sourcemaps")
                .about("Uploads sourcemap information for a given release")
                .arg(Arg::with_name("paths")
                     .value_name("PATHS")
                     .index(1)
                     .required(true)
                     .multiple(true)
                     .help("The files to upload"))
                .arg(Arg::with_name("url_prefix")
                     .short("u")
                     .long("url-prefix")
                     .value_name("PREFIX")
                     .help("The URL prefix to prepend to all filenames"))
                .arg(Arg::with_name("validate")
                     .long("validate")
                     .help("Enable basic sourcemap validation"))
                .arg(Arg::with_name("verbose")
                     .long("verbose")
                     .short("verbose")
                     .help("Enable verbose mode"))
                .arg(Arg::with_name("extensions")
                     .long("ext")
                     .short("x")
                     .value_name("EXT")
                     .multiple(true)
                     .help("Add a file extension to the list of files to upload."))))
}

pub fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                       org: &str, project: &str) -> CliResult<()> {
    let info_rv = Api::new(config).new_release(org, project, &NewRelease {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    })?;
    println!("Created release {}.", info_rv.version);
    Ok(())
}

pub fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str) -> CliResult<()> {
    let version = matches.value_of("version").unwrap();
    if Api::new(config).delete_release(org, project, version)? {
        println!("Deleted release {}!", version);
    } else {
        println!("Did nothing. Release with this version ({}) does not exist.", version);
    }
    Ok(())
}

pub fn execute_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                        org: &str, project: &str) -> CliResult<()> {
    for info in Api::new(config).list_releases(org, project)? {
        println!("[{}] {}: {} ({} new groups)",
                 info.date_released.unwrap_or("              unreleased".into()),
                 info.version,
                 info.reference.unwrap_or("-".into()),
                 info.new_groups);
    }
    Ok(())
}

pub fn execute_files_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                              org: &str, project: &str, release: &str) -> CliResult<()> {
    for artifact in Api::new(config).list_release_files(org, project, release)? {
        println!("{}  ({} bytes)", artifact.name, artifact.size);
    }
    Ok(())
}

pub fn execute_files_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                                org: &str, project: &str, release: &str) -> CliResult<()> {
    let files : HashSet<String> = match matches.values_of("names") {
        Some(paths) => paths.map(|x| x.into()).collect(),
        None => HashSet::new(),
    };
    let mut api = Api::new(config);
    for file in api.list_release_files(org, project, release)? {
        if !(matches.is_present("all") || files.contains(&file.name)) {
            continue;
        }
        if api.delete_release_file(org, project, release, &file.id)? {
            println!("D {}", file.name);
        }
    }
    Ok(())
}

pub fn execute_files_upload<'a>(matches: &ArgMatches<'a>, config: &Config,
                                org: &str, project: &str, version: &str) -> CliResult<()> {
    let path = Path::new(matches.value_of("path").unwrap());
    let name = match matches.value_of("name") {
        Some(name) => name,
        None => Path::new(path).file_name()
            .and_then(|x| x.to_str()).ok_or("No filename provided.")?,
    };
    if let Some(artifact) = Api::new(config).upload_release_file(
        org, project, &version, &path, &name)? {
        println!("A {}  ({} bytes)", artifact.sha1, artifact.size);
    } else {
        fail!("File already present!");
    }
    Ok(())
}

pub fn execute_files_upload_sourcemaps<'a>(matches: &ArgMatches<'a>, config: &Config,
                                           org: &str, project: &str, version: &str) -> CliResult<()> {
    let mut api = Api::new(config);
    let release = api.get_release(org, project, version)?.ok_or("release not found")?;
    let url_prefix = matches.value_of("url_prefix").unwrap_or("~").trim_right_matches("/");
    let paths = matches.values_of("paths").unwrap();
    let extensions = match matches.values_of("extensions") {
        Some(matches) => matches.map(|ext| OsStr::new(ext.trim_left_matches("."))).collect(),
        None => vec![OsStr::new("js"), OsStr::new("map")],
    };

    let mut to_process = vec![];

    for path in paths {
        // if we start walking over something that is an actual file then
        // the directory iterator yields that path and terminates.  We
        // handle that case here specifically to figure out what the path is
        // we should strip off.
        let walk_path = PathBuf::from(&path);
        let (base_path, skip_ext_test) = if walk_path.is_file() {
            (walk_path.parent().unwrap(), true)
        } else {
            (walk_path.as_path(), false)
        };

        for dent in WalkDir::new(&walk_path) {
            let dent = dent?;
            if !skip_ext_test {
                let extension = dent.path().extension();
                if !extensions.iter().any(|ext| Some(*ext) == extension) {
                    continue;
                }
            }
            let local_path = dent.path().strip_prefix(&base_path).unwrap();
            let url = format!("{}/{}", url_prefix, local_path.display());
            to_process.push((url, local_path.to_path_buf(),
                             dent.path().to_path_buf()));
        }
    }

    if matches.is_present("validate") {
        println!("Running with sourcemap validation");
        let mut validator = SourceMapValidator::new(matches.is_present("verbose"));
        for &(ref url, _, ref path) in to_process.iter() {
            validator.consider_file(path, url);
        }
        validator.validate_sources()?;
    }

    println!("Uploading sourcemaps for release {}", release.version);
    for (url, local_path, path) in to_process {
        println!("{} -> {}", local_path.display(), url);
        if let Some(artifact) = api.upload_release_file(
            org, project, &release.version, &path, &url)? {
            println!("  {}  ({} bytes)", artifact.sha1, artifact.size);
        } else {
            println!("  already present");
        }
    }

    Ok(())
}

pub fn execute_files<'a>(matches: &ArgMatches<'a>, config: &Config,
                         org: &str, project: &str) -> CliResult<()> {
    let release = matches.value_of("version").unwrap();
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        return execute_files_list(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        return execute_files_delete(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload") {
        return execute_files_upload(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload-sourcemaps") {
        return execute_files_upload_sourcemaps(sub_matches, config, org, project, release);
    }
    unreachable!();
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> CliResult<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_delete(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_list(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("files") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_files(sub_matches, config, &org, &project);
    }
    unreachable!();
}
<commit_msg>Killed some unused code<commit_after>use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::collections::HashSet;

use clap::{App, AppSettings, Arg, ArgMatches};
use walkdir::WalkDir;

use CliResult;
use api::{Api, NewRelease};
use commands::Config;
use utils::make_subcommand;
use sourcemaps::SourceMapValidator;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
            .about("Create a new release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version identifier for this release"))
            .arg(Arg::with_name("ref")
                 .long("ref")
                 .value_name("REF")
                 .help("Optional commit reference (commit hash)"))
            .arg(Arg::with_name("url")
                 .long("url")
                 .value_name("URL")
                 .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
            .about("Delete a release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version to delete")))
        .subcommand(make_subcommand("list")
            .about("list the most recent releases"))
        .subcommand(make_subcommand("files")
            .about("manage release artifact files")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The release to manage the files of"))
            .subcommand(make_subcommand("list")
                .about("List all release files"))
            .subcommand(make_subcommand("delete")
                .about("Delete a release file")
                .arg(Arg::with_name("all")
                     .short("A")
                     .long("all")
                     .help("deletes all files"))
                .arg(Arg::with_name("names")
                     .value_name("NAMES")
                     .index(1)
                     .multiple(true)
                     .help("a list of filenames to delete.")))
            .subcommand(make_subcommand("upload")
                .about("Uploads a file for a given release")
                .arg(Arg::with_name("path")
                     .value_name("PATH")
                     .index(1)
                     .required(true)
                     .help("The file to upload"))
                .arg(Arg::with_name("name")
                     .index(2)
                     .value_name("NAME")
                     .help("The name of the file on the server.")))
            .subcommand(make_subcommand("upload-sourcemaps")
                .about("Uploads sourcemap information for a given release")
                .arg(Arg::with_name("paths")
                     .value_name("PATHS")
                     .index(1)
                     .required(true)
                     .multiple(true)
                     .help("The files to upload"))
                .arg(Arg::with_name("url_prefix")
                     .short("u")
                     .long("url-prefix")
                     .value_name("PREFIX")
                     .help("The URL prefix to prepend to all filenames"))
                .arg(Arg::with_name("validate")
                     .long("validate")
                     .help("Enable basic sourcemap validation"))
                .arg(Arg::with_name("verbose")
                     .long("verbose")
                     .short("verbose")
                     .help("Enable verbose mode"))
                .arg(Arg::with_name("extensions")
                     .long("ext")
                     .short("x")
                     .value_name("EXT")
                     .multiple(true)
                     .help("Add a file extension to the list of files to upload."))))
}

pub fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                       org: &str, project: &str) -> CliResult<()> {
    let info_rv = Api::new(config).new_release(org, project, &NewRelease {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    })?;
    println!("Created release {}.", info_rv.version);
    Ok(())
}

pub fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str) -> CliResult<()> {
    let version = matches.value_of("version").unwrap();
    if Api::new(config).delete_release(org, project, version)? {
        println!("Deleted release {}!", version);
    } else {
        println!("Did nothing. Release with this version ({}) does not exist.", version);
    }
    Ok(())
}

pub fn execute_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                        org: &str, project: &str) -> CliResult<()> {
    for info in Api::new(config).list_releases(org, project)? {
        println!("[{}] {}: {} ({} new groups)",
                 info.date_released.unwrap_or("              unreleased".into()),
                 info.version,
                 info.reference.unwrap_or("-".into()),
                 info.new_groups);
    }
    Ok(())
}

pub fn execute_files_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                              org: &str, project: &str, release: &str) -> CliResult<()> {
    for artifact in Api::new(config).list_release_files(org, project, release)? {
        println!("{}  ({} bytes)", artifact.name, artifact.size);
    }
    Ok(())
}

pub fn execute_files_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                                org: &str, project: &str, release: &str) -> CliResult<()> {
    let files : HashSet<String> = match matches.values_of("names") {
        Some(paths) => paths.map(|x| x.into()).collect(),
        None => HashSet::new(),
    };
    let mut api = Api::new(config);
    for file in api.list_release_files(org, project, release)? {
        if !(matches.is_present("all") || files.contains(&file.name)) {
            continue;
        }
        if api.delete_release_file(org, project, release, &file.id)? {
            println!("D {}", file.name);
        }
    }
    Ok(())
}

pub fn execute_files_upload<'a>(matches: &ArgMatches<'a>, config: &Config,
                                org: &str, project: &str, version: &str) -> CliResult<()> {
    let path = Path::new(matches.value_of("path").unwrap());
    let name = match matches.value_of("name") {
        Some(name) => name,
        None => Path::new(path).file_name()
            .and_then(|x| x.to_str()).ok_or("No filename provided.")?,
    };
    if let Some(artifact) = Api::new(config).upload_release_file(
        org, project, &version, &path, &name)? {
        println!("A {}  ({} bytes)", artifact.sha1, artifact.size);
    } else {
        fail!("File already present!");
    }
    Ok(())
}

pub fn execute_files_upload_sourcemaps<'a>(matches: &ArgMatches<'a>, config: &Config,
                                           org: &str, project: &str, version: &str) -> CliResult<()> {
    let mut api = Api::new(config);
    let release = api.get_release(org, project, version)?.ok_or("release not found")?;
    let url_prefix = matches.value_of("url_prefix").unwrap_or("~").trim_right_matches("/");
    let paths = matches.values_of("paths").unwrap();
    let extensions = match matches.values_of("extensions") {
        Some(matches) => matches.map(|ext| OsStr::new(ext.trim_left_matches("."))).collect(),
        None => vec![OsStr::new("js"), OsStr::new("map")],
    };

    let mut to_process = vec![];

    for path in paths {
        // if we start walking over something that is an actual file then
        // the directory iterator yields that path and terminates.  We
        // handle that case here specifically to figure out what the path is
        // we should strip off.
        let walk_path = PathBuf::from(&path);
        let (base_path, skip_ext_test) = if walk_path.is_file() {
            (walk_path.parent().unwrap(), true)
        } else {
            (walk_path.as_path(), false)
        };

        for dent in WalkDir::new(&walk_path) {
            let dent = dent?;
            if !skip_ext_test {
                let extension = dent.path().extension();
                if !extensions.iter().any(|ext| Some(*ext) == extension) {
                    continue;
                }
            }
            let local_path = dent.path().strip_prefix(&base_path).unwrap();
            let url = format!("{}/{}", url_prefix, local_path.display());
            to_process.push((url, local_path.to_path_buf(),
                             dent.path().to_path_buf()));
        }
    }

    if matches.is_present("validate") {
        println!("Running with sourcemap validation");
        let mut validator = SourceMapValidator::new(matches.is_present("verbose"));
        for &(ref url, _, ref path) in to_process.iter() {
            validator.consider_file(path, url);
        }
        validator.validate_sources()?;
    }

    println!("Uploading sourcemaps for release {}", release.version);
    for (url, local_path, path) in to_process {
        println!("{} -> {}", local_path.display(), url);
        if let Some(artifact) = api.upload_release_file(
            org, project, &release.version, &path, &url)? {
            println!("  {}  ({} bytes)", artifact.sha1, artifact.size);
        } else {
            println!("  already present");
        }
    }

    Ok(())
}

pub fn execute_files<'a>(matches: &ArgMatches<'a>, config: &Config,
                         org: &str, project: &str) -> CliResult<()> {
    let release = matches.value_of("version").unwrap();
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        return execute_files_list(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        return execute_files_delete(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload") {
        return execute_files_upload(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload-sourcemaps") {
        return execute_files_upload_sourcemaps(sub_matches, config, org, project, release);
    }
    unreachable!();
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> CliResult<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_delete(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_list(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("files") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_files(sub_matches, config, &org, &project);
    }
    unreachable!();
}
<|endoftext|>


<commit_before>macro_rules! expand_align {
    () => {
        s! {
            #[cfg_attr(any(target_pointer_width = "32",
                           target_arch = "x86_64",
                           target_arch = "powerpc64",
                           target_arch = "mips64",
                           target_arch = "s390x",
                           target_arch = "sparc64",
                           target_arch = "aarch64",
                           target_arch = "riscv64",
                           target_arch = "riscv32"),
                       repr(align(4)))]
            #[cfg_attr(not(any(target_pointer_width = "32",
                               target_arch = "x86_64",
                               target_arch = "powerpc64",
                               target_arch = "mips64",
                               target_arch = "s390x",
                               target_arch = "sparc64",
                               target_arch = "aarch64",
                               target_arch = "riscv64",
                               target_arch = "riscv32")),
                       repr(align(8)))]
            pub struct pthread_mutexattr_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T],
            }

            #[cfg_attr(any(target_env = "musl", target_pointer_width = "32"),
                       repr(align(4)))]
            #[cfg_attr(all(not(target_env = "musl"),
                           target_pointer_width = "64"),
                       repr(align(8)))]
            pub struct pthread_rwlockattr_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_condattr_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T],
            }

            #[repr(align(8))]
            pub struct fanotify_event_metadata {
                pub event_len: __u32,
                pub vers: __u8,
                pub reserved: __u8,
                pub metadata_len: __u16,
                pub mask: __u64,
                pub fd: ::c_int,
                pub pid: ::c_int,
            }

            // linux/can.h
            #[repr(align(8))]
            pub struct can_frame {
                pub can_id: canid_t,
                pub can_dlc: u8,
                __pad: u8,
                __res0: u8,
                __res1: u8,
                pub data: [u8; CAN_MAX_DLEN],
            }

            #[repr(align(8))]
            pub struct canfd_frame {
                pub can_id: canid_t,
                pub len: u8,
                pub flags: u8,
                __res0: u8,
                __res1: u8,
                pub data: [u8; CANFD_MAX_DLEN],
            }
        }

        s_no_extra_traits! {
            #[cfg_attr(all(target_env = "musl",
                           target_pointer_width = "32"),
                       repr(align(4)))]
            #[cfg_attr(all(target_env = "musl",
                           target_pointer_width = "64"),
                       repr(align(8)))]
            #[cfg_attr(all(not(target_env = "musl"),
                           target_arch = "x86"),
                       repr(align(4)))]
            #[cfg_attr(all(not(target_env = "musl"),
                           not(target_arch = "x86")),
                       repr(align(8)))]
            pub struct pthread_cond_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_COND_T],
            }

            #[cfg_attr(all(target_pointer_width = "32",
                           any(target_arch = "mips",
                               target_arch = "arm",
                               target_arch = "hexagon",
                               target_arch = "powerpc",
                               target_arch = "sparc",
                               target_arch = "x86_64",
                               target_arch = "x86")),
                       repr(align(4)))]
            #[cfg_attr(any(target_pointer_width = "64",
                           not(any(target_arch = "mips",
                                   target_arch = "arm",
                                   target_arch = "hexagon",
                                   target_arch = "powerpc",
                                   target_arch = "sparc",
                                   target_arch = "x86_64",
                                   target_arch = "x86"))),
                       repr(align(8)))]
            pub struct pthread_mutex_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T],
            }

            #[cfg_attr(all(target_pointer_width = "32",
                           any(target_arch = "mips",
                               target_arch = "arm",
                               target_arch = "hexagon",
                               target_arch = "powerpc",
                               target_arch = "sparc",
                               target_arch = "x86_64",
                               target_arch = "x86")),
                       repr(align(4)))]
            #[cfg_attr(any(target_pointer_width = "64",
                           not(any(target_arch = "mips",
                                   target_arch = "arm",
                                   target_arch = "hexagon",
                                   target_arch = "powerpc",
                                   target_arch = "sparc",
                                   target_arch = "x86_64",
                                   target_arch = "x86"))),
                       repr(align(8)))]
            pub struct pthread_rwlock_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T],
            }
        }
    };
}
<commit_msg>Move structs to `s_no_extra_traits`<commit_after>macro_rules! expand_align {
    () => {
        s! {
            #[cfg_attr(any(target_pointer_width = "32",
                           target_arch = "x86_64",
                           target_arch = "powerpc64",
                           target_arch = "mips64",
                           target_arch = "s390x",
                           target_arch = "sparc64",
                           target_arch = "aarch64",
                           target_arch = "riscv64",
                           target_arch = "riscv32"),
                       repr(align(4)))]
            #[cfg_attr(not(any(target_pointer_width = "32",
                               target_arch = "x86_64",
                               target_arch = "powerpc64",
                               target_arch = "mips64",
                               target_arch = "s390x",
                               target_arch = "sparc64",
                               target_arch = "aarch64",
                               target_arch = "riscv64",
                               target_arch = "riscv32")),
                       repr(align(8)))]
            pub struct pthread_mutexattr_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T],
            }

            #[cfg_attr(any(target_env = "musl", target_pointer_width = "32"),
                       repr(align(4)))]
            #[cfg_attr(all(not(target_env = "musl"),
                           target_pointer_width = "64"),
                       repr(align(8)))]
            pub struct pthread_rwlockattr_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T],
            }

            #[repr(align(4))]
            pub struct pthread_condattr_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T],
            }

            #[repr(align(8))]
            pub struct fanotify_event_metadata {
                pub event_len: __u32,
                pub vers: __u8,
                pub reserved: __u8,
                pub metadata_len: __u16,
                pub mask: __u64,
                pub fd: ::c_int,
                pub pid: ::c_int,
            }
        }

        s_no_extra_traits! {
            #[cfg_attr(all(target_env = "musl",
                           target_pointer_width = "32"),
                       repr(align(4)))]
            #[cfg_attr(all(target_env = "musl",
                           target_pointer_width = "64"),
                       repr(align(8)))]
            #[cfg_attr(all(not(target_env = "musl"),
                           target_arch = "x86"),
                       repr(align(4)))]
            #[cfg_attr(all(not(target_env = "musl"),
                           not(target_arch = "x86")),
                       repr(align(8)))]
            pub struct pthread_cond_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_COND_T],
            }

            #[cfg_attr(all(target_pointer_width = "32",
                           any(target_arch = "mips",
                               target_arch = "arm",
                               target_arch = "hexagon",
                               target_arch = "powerpc",
                               target_arch = "sparc",
                               target_arch = "x86_64",
                               target_arch = "x86")),
                       repr(align(4)))]
            #[cfg_attr(any(target_pointer_width = "64",
                           not(any(target_arch = "mips",
                                   target_arch = "arm",
                                   target_arch = "hexagon",
                                   target_arch = "powerpc",
                                   target_arch = "sparc",
                                   target_arch = "x86_64",
                                   target_arch = "x86"))),
                       repr(align(8)))]
            pub struct pthread_mutex_t {
                #[doc(hidden)]
                size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T],
            }

            #[cfg_attr(all(target_pointer_width = "32",
                           any(target_arch = "mips",
                               target_arch = "arm",
                               target_arch = "hexagon",
                               target_arch = "powerpc",
                               target_arch = "sparc",
                               target_arch = "x86_64",
                               target_arch = "x86")),
                       repr(align(4)))]
            #[cfg_attr(any(target_pointer_width = "64",
                           not(any(target_arch = "mips",
                                   target_arch = "arm",
                                   target_arch = "hexagon",
                                   target_arch = "powerpc",
                                   target_arch = "sparc",
                                   target_arch = "x86_64",
                                   target_arch = "x86"))),
                       repr(align(8)))]
            pub struct pthread_rwlock_t {
                size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T],
            }

            // linux/can.h
            #[repr(align(8))]
            #[allow(missing_debug_implementations)]
            pub struct can_frame {
                pub can_id: canid_t,
                pub can_dlc: u8,
                __pad: u8,
                __res0: u8,
                __res1: u8,
                pub data: [u8; CAN_MAX_DLEN],
            }

            #[repr(align(8))]
            #[allow(missing_debug_implementations)]
            pub struct canfd_frame {
                pub can_id: canid_t,
                pub len: u8,
                pub flags: u8,
                __res0: u8,
                __res1: u8,
                pub data: [u8; CANFD_MAX_DLEN],
            }
        }
    };
}
<|endoftext|>


<commit_before>#![feature(trace_macros)]

#[macro_use]
extern crate nom;

use nom::{IResult, digit, alphanumeric};

use std::str::{self,FromStr};
use std::collections::HashMap;

#[derive(Debug,PartialEq)]
pub enum JsonValue {
  Str(String),
  Num(f32),
  Array(Vec<JsonValue>),
  Object(HashMap<String,JsonValue>)
}

// FIXME: since we already parsed a serie of digits and dots,
// we know it is correct UTF-8. no need to use from_utf8 to
// verify it is correct
// FIXME: use alt_complete (implement ws for alt_complete)
named!(unsigned_float <f32>, map_res!(
  map_res!(
    recognize!(
      alt!(
        delimited!(digit, tag!("."), opt!(complete!(digit))) |
        delimited!(opt!(digit), tag!("."), digit)            |
        digit
      )
    ),
    str::from_utf8
  ),
  FromStr::from_str
));
named!(float<f32>, map!(
  pair!(
    opt!(alt!(tag!("+") | tag!("-"))),
    unsigned_float
  ),
  |(sign, value): (Option<&[u8]>, f32)| {
    sign.and_then(|s| if s[0] == ('-' as u8) { Some(-1f32) } else { None }).unwrap_or(1f32) * value
  }
));

//FIXME: verify how json strings are formatted
named!(string<&str>,
  dbg_dmp!(
  delimited!(
    tag!("\""),
    map_res!(escaped!(call!(alphanumeric), '\\', is_a!("\"n\\")), str::from_utf8),
    tag!("\"")
  )
  )
);

named!(array < Vec<JsonValue> >,
  ws!(
    delimited!(
      tag!("["),
      separated_list!(tag!(","), value),
      tag!("]")
    )
  )
);

trace_macros!(true);
named!(key_value<(&str,JsonValue)>,
  ws!(
    separated_pair!(
      string,
      tag!(":"),
      value
    )
  )
);
trace_macros!(false);

named!(hash< HashMap<String,JsonValue> >,
  dbg_dmp!(
  ws!(
    map!(
      delimited!(
        tag!("{"),
        separated_list!(tag!(","), key_value),
        tag!("}")
        ),
      |tuple_vec| {
        let mut h: HashMap<String, JsonValue> = HashMap::new();
        for (k, v) in tuple_vec {
          h.insert(String::from(k), v);
        }
        h
      }
    )
  )
  )
);

named!(value<JsonValue>,
  ws!(
    alt!(
      dbg_dmp!(hash)   => { |h|   JsonValue::Object(h)            } |
      array  => { |v|   JsonValue::Array(v)             } |
      string => { |s|   JsonValue::Str(String::from(s)) } |
      float  => { |num| JsonValue::Num(num)             }
    )
  )
);

//trace_macros!(false);

#[test]
fn hash_test() {
  let test = &b"  { \"a\"\t: 42,
  \"b\": \"x\"
  }";

//FIXME: top level value must be an object?
  println!("{:?}", value(&test[..]));
  assert!(false);
}

#[test]
fn parse_example_test() {
  let test = &b"  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { \"hello\" : \"world\"
  }
  }";

//FIXME: top level value must be an object?
  println!("{:?}", value(&test[..]));
  assert!(false);
}

<commit_msg>use alt_complete for floats<commit_after>#![feature(trace_macros)]

#[macro_use]
extern crate nom;

use nom::{IResult, digit, alphanumeric};

use std::str::{self,FromStr};
use std::collections::HashMap;

#[derive(Debug,PartialEq)]
pub enum JsonValue {
  Str(String),
  Num(f32),
  Array(Vec<JsonValue>),
  Object(HashMap<String,JsonValue>)
}

// FIXME: since we already parsed a serie of digits and dots,
// we know it is correct UTF-8. no need to use from_utf8 to
// verify it is correct
// FIXME: use alt_complete (implement ws for alt_complete)
named!(unsigned_float <f32>, map_res!(
  map_res!(
    recognize!(
      alt_complete!(
        delimited!(digit, tag!("."), opt!(complete!(digit))) |
        delimited!(opt!(digit), tag!("."), digit)            |
        digit
      )
    ),
    str::from_utf8
  ),
  FromStr::from_str
));
named!(float<f32>, map!(
  pair!(
    opt!(alt!(tag!("+") | tag!("-"))),
    unsigned_float
  ),
  |(sign, value): (Option<&[u8]>, f32)| {
    sign.and_then(|s| if s[0] == ('-' as u8) { Some(-1f32) } else { None }).unwrap_or(1f32) * value
  }
));

//FIXME: verify how json strings are formatted
named!(string<&str>,
  dbg_dmp!(
  delimited!(
    tag!("\""),
    map_res!(escaped!(call!(alphanumeric), '\\', is_a!("\"n\\")), str::from_utf8),
    tag!("\"")
  )
  )
);

named!(array < Vec<JsonValue> >,
  ws!(
    delimited!(
      tag!("["),
      separated_list!(tag!(","), value),
      tag!("]")
    )
  )
);

trace_macros!(true);
named!(key_value<(&str,JsonValue)>,
  ws!(
    separated_pair!(
      string,
      tag!(":"),
      value
    )
  )
);
trace_macros!(false);

named!(hash< HashMap<String,JsonValue> >,
  dbg_dmp!(
  ws!(
    map!(
      delimited!(
        tag!("{"),
        separated_list!(tag!(","), key_value),
        tag!("}")
        ),
      |tuple_vec| {
        let mut h: HashMap<String, JsonValue> = HashMap::new();
        for (k, v) in tuple_vec {
          h.insert(String::from(k), v);
        }
        h
      }
    )
  )
  )
);

named!(value<JsonValue>,
  ws!(
    alt!(
      dbg_dmp!(hash)   => { |h|   JsonValue::Object(h)            } |
      array  => { |v|   JsonValue::Array(v)             } |
      string => { |s|   JsonValue::Str(String::from(s)) } |
      float  => { |num| JsonValue::Num(num)             }
    )
  )
);

//trace_macros!(false);

#[test]
fn hash_test() {
  let test = &b"  { \"a\"\t: 42,
  \"b\": \"x\"
  }";

//FIXME: top level value must be an object?
  println!("{:?}", value(&test[..]));
  assert!(false);
}

#[test]
fn parse_example_test() {
  let test = &b"  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { \"hello\" : \"world\"
  }
  }";

//FIXME: top level value must be an object?
  println!("{:?}", value(&test[..]));
  assert!(false);
}

<|endoftext|>


<commit_before>extern crate juju;
use std::collections::HashMap;

#[test]
fn test_relation_ids(){

}

#[test]
fn test_relation_list(){

}

#[test]
fn test_leadership_election(){
    //create a context
    //pass into is_leader
    //check if it selects the proper leader
    let mut has_bigger_relations = HashMap::new();

    let mut has_lower_relations = HashMap::new();

    let should_be_leader = juju::Context{
        relation_type: "server".to_string(),
        relation_id: 1,
        unit: "gluster/1".to_string(),
        relations: has_bigger_relations,
    };
    let should_not_be_leader = juju::Context{
        relation_type: "server".to_string(),
        relation_id: 2,
        unit: "gluster/2".to_string(),
        relations: has_lower_relations,
    };
    assert!(juju::is_leader(&should_be_leader));
    assert_eq!(false, juju::is_leader(&should_not_be_leader));
}
<commit_msg>Removed the bogus tests file.  Nothing in there was actually working with the newest code<commit_after><|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Harris <mail@bharr.is>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Interface to Nested Vector Interrupt Controller.
//  Link: http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CIHIGCIF.html

/// Enable an interrupt
pub fn enable_irq(irqn: uint) {
  reg::NVIC.iser[irqn / 32].clear_iser(irqn % 32);
}

/// Disable an interrupt
pub fn disable_irq(irqn: uint) {
  reg::NVIC.icer[irqn / 32].clear_icer(irqn % 32);
}

/// Return whether the given interrupt is enabled
pub fn is_enabled(irqn: uint) -> bool {
  reg::NVIC.iser[irqn / 32].iser(irqn % 32)
}

/// Clear the pending flag for the given interrupt
pub fn clear_pending(irqn: uint) {
  reg::NVIC.icpr[irqn / 32].clear_icpr(irqn % 32);
}

/// Return whether the given interrupt is pending
pub fn is_pending(irqn: uint) -> bool {
  reg::NVIC.ispr[irqn / 32].ispr(irqn % 32)
}

/// Return whether the given interrupt is active
pub fn is_active(irqn: uint) -> bool {
  reg::NVIC.iabr[irqn / 32].iabr(irqn % 32)
}

/// Set the priority for the given interrupt
pub fn set_priority(irqn: uint, prio: u8) {
  reg::NVIC.ipr[irqn / 4].set_ipr(irqn % 4, prio as u32);
}

/// Return the priority for the given interrupt
pub fn get_priority(irqn: uint) -> u8 {
  reg::NVIC.ipr[irqn / 4].ipr(irqn % 4) as u8
}

mod reg {
  use util::volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(NVIC = {
    0x0     => reg32 iser[8] {
      0..31   => iser[32]: set_to_clear,
    }
    0x80     => reg32 icer[8] {
      0..31   => icer[32]: set_to_clear,
    }
    0x100     => reg32 ispr[8] {
      0..31   => ispr[32]: set_to_clear,
    }
    0x180     => reg32 icpr[8] {
      0..31   => icpr[32]: set_to_clear,
    }
    0x200     => reg32 iabr[8] {
      0..31   => iabr[32]: ro,
    }
    0x300     => reg32 ipr[8] {
      0..31   => ipr[4],
    }
  })

  #[allow(dead_code)]
  extern {
    #[link_name="armmem_NVIC"] pub static NVIC: NVIC;
  }
}
<commit_msg>nvic: Add comments and STIR<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Harris <mail@bharr.is>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Interface to Nested Vector Interrupt Controller.
//  Link: http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CIHIGCIF.html

/// Enable an interrupt
pub fn enable_irq(irqn: uint) {
  reg::NVIC.iser[irqn / 32].clear_iser(irqn % 32);
}

/// Disable an interrupt
pub fn disable_irq(irqn: uint) {
  reg::NVIC.icer[irqn / 32].clear_icer(irqn % 32);
}

/// Return whether the given interrupt is enabled
pub fn is_enabled(irqn: uint) -> bool {
  reg::NVIC.iser[irqn / 32].iser(irqn % 32)
}

/// Clear the pending flag for the given interrupt
pub fn clear_pending(irqn: uint) {
  reg::NVIC.icpr[irqn / 32].clear_icpr(irqn % 32);
}

/// Return whether the given interrupt is pending
pub fn is_pending(irqn: uint) -> bool {
  reg::NVIC.ispr[irqn / 32].ispr(irqn % 32)
}

/// Return whether the given interrupt is active
pub fn is_active(irqn: uint) -> bool {
  reg::NVIC.iabr[irqn / 32].iabr(irqn % 32)
}

/// Set the priority for the given interrupt
pub fn set_priority(irqn: uint, prio: u8) {
  reg::NVIC.ipr[irqn / 4].set_ipr(irqn % 4, prio as u32);
}

/// Return the priority for the given interrupt
pub fn get_priority(irqn: uint) -> u8 {
  reg::NVIC.ipr[irqn / 4].ipr(irqn % 4) as u8
}

mod reg {
  use util::volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(NVIC = {
    0x100     => reg32 iser[8] {      //! Interrupt set enable register
      0..31   => iser[32]: set_to_clear,
    }
    0x180     => reg32 icer[8] {      //! Interrupt clear enable register
      0..31   => icer[32]: set_to_clear,
    }
    0x200     => reg32 ispr[8] {      //! Interrupt set pending register
      0..31   => ispr[32]: set_to_clear,
    }
    0x280     => reg32 icpr[8] {      //! Interrupt clear pending register
      0..31   => icpr[32]: set_to_clear,
    }
    0x300     => reg32 iabr[8] {      //! Interrupt active bit register
      0..31   => iabr[32]: ro,
    }
    0x400     => reg32 ipr[8] {       //! Interrupt priority register
      0..31   => ipr[4],
    }
    0xF00     => reg32 stir[8] {      //! Software triggered interrupt register
      0..8    => stir,
    }
  })

  #[allow(dead_code)]
  extern {
    #[link_name="armmem_NVIC"] pub static NVIC: NVIC;
  }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Data-driven tests

use std::ops::Deref;
use std::str::FromStr;

use serde_json::Value;
use url::{quirks, Url};

#[test]
fn urltestdata() {
    // Copied form https://github.com/w3c/web-platform-tests/blob/master/url/
    let mut json = Value::from_str(include_str!("urltestdata.json"))
        .expect("JSON parse error in urltestdata.json");

    let mut passed = true;
    for entry in json.as_array_mut().unwrap() {
        if entry.is_string() {
            continue; // ignore comments
        }

        let base = entry.take_string("base");
        let input = entry.take_string("input");
        let failure = entry.take_key("failure").is_some();

        let base = match Url::parse(&base) {
            Ok(base) => base,
            Err(_) if failure => continue,
            Err(message) => {
                eprint_failure(
                    format!("  failed: error parsing base {:?}: {}", base, message),
                    &format!("parse base for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        let url = match (base.join(&input), failure) {
            (Ok(url), false) => url,
            (Err(_), true) => continue,
            (Err(message), false) => {
                eprint_failure(
                    format!("  failed: {}", message),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
            (Ok(_), true) => {
                eprint_failure(
                    format!("  failed: expected parse error for URL {:?}", input),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        passed &= check_invariants(&url, &format!("invariants for {:?}", input), None);

        for &attr in ATTRIBS {
            passed &= test_eq_eprint(
                entry.take_string(attr),
                get(&url, attr),
                &format!("{:?} - {}", input, attr),
                None,
            );
        }

        if let Some(expected_origin) = entry.take_key("origin").map(|s| s.string()) {
            passed &= test_eq_eprint(
                expected_origin,
                &quirks::origin(&url),
                &format!("origin for {:?}", input),
                None,
            );
        }
    }

    assert!(passed)
}

#[test]
fn setters_tests() {
    let mut json = Value::from_str(include_str!("setters_tests.json"))
        .expect("JSON parse error in setters_tests.json");

    let mut passed = true;
    for &attr in ATTRIBS {
        if attr == "href" {
            continue;
        }

        let mut tests = json.take_key(attr).unwrap();
        for mut test in tests.as_array_mut().unwrap().drain(..) {
            let comment = test.take_key("comment").map(|s| s.string());
            let href = test.take_string("href");
            let new_value = test.take_string("new_value");
            let name = format!("{:?}.{} = {:?}", href, attr, new_value);
            let mut expected = test.take_key("expected").unwrap();

            let mut url = Url::parse(&href).unwrap();
            let comment_ref = comment.as_ref().map(|s| s.deref());
            passed &= check_invariants(&url, &name, comment_ref);
            let _ = set(&mut url, attr, &new_value);

            for attr in ATTRIBS {
                if let Some(value) = expected.take_key(attr) {
                    passed &= test_eq_eprint(value.string(), get(&url, attr), &name, comment_ref);
                };
            }

            passed &= check_invariants(&url, &name, comment_ref);
        }
    }

    assert!(passed);
}

fn check_invariants(url: &Url, name: &str, comment: Option<&str>) -> bool {
    let mut passed = true;
    if let Err(e) = url.check_invariants() {
        passed = false;
        eprint_failure(
            format!("  failed: invariants checked -> {:?}", e),
            name,
            comment,
        );
    }

    #[cfg(feature = "serde")]
    {
        let bytes = serde_json::to_vec(url).unwrap();
        let new_url: Url = serde_json::from_slice(&bytes).unwrap();
        passed &= test_eq(url, &new_url, name, comment);
    }

    passed
}

trait JsonExt {
    fn take_key(&mut self, key: &str) -> Option<Value>;
    fn string(self) -> String;
    fn take_string(&mut self, key: &str) -> String;
}

impl JsonExt for Value {
    fn take_key(&mut self, key: &str) -> Option<Value> {
        self.as_object_mut().unwrap().remove(key)
    }

    fn string(self) -> String {
        if let Value::String(s) = self {
            s
        } else {
            panic!("Not a Value::String")
        }
    }

    fn take_string(&mut self, key: &str) -> String {
        self.take_key(key).unwrap().string()
    }
}

fn get<'a>(url: &'a Url, attr: &str) -> &'a str {
    match attr {
        "href" => quirks::href(url),
        "protocol" => quirks::protocol(url),
        "username" => quirks::username(url),
        "password" => quirks::password(url),
        "hostname" => quirks::hostname(url),
        "host" => quirks::host(url),
        "port" => quirks::port(url),
        "pathname" => quirks::pathname(url),
        "search" => quirks::search(url),
        "hash" => quirks::hash(url),
        _ => unreachable!(),
    }
}

#[allow(clippy::unit_arg)]
fn set<'a>(url: &'a mut Url, attr: &str, new: &str) {
    let _ = match attr {
        "protocol" => quirks::set_protocol(url, new),
        "username" => quirks::set_username(url, new),
        "password" => quirks::set_password(url, new),
        "hostname" => quirks::set_hostname(url, new),
        "host" => quirks::set_host(url, new),
        "port" => quirks::set_port(url, new),
        "pathname" => Ok(quirks::set_pathname(url, new)),
        "search" => Ok(quirks::set_search(url, new)),
        "hash" => Ok(quirks::set_hash(url, new)),
        _ => unreachable!(),
    };
}

fn test_eq_eprint(expected: String, actual: &str, name: &str, comment: Option<&str>) -> bool {
    if expected == actual {
        return true;
    }
    eprint_failure(
        format!("expected: {}\n  actual: {}", expected, actual),
        name,
        comment,
    );
    false
}

fn eprint_failure(err: String, name: &str, comment: Option<&str>) {
    eprintln!("    test: {}\n{}", name, err);
    if let Some(comment) = comment {
        eprintln!("{}\n", comment);
    } else {
        eprintln!("");
    }
}

const ATTRIBS: &[&str] = &[
    "href", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search",
    "hash",
];
<commit_msg>chore: pacify clippy some more<commit_after>// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Data-driven tests

use std::ops::Deref;
use std::str::FromStr;

use serde_json::Value;
use url::{quirks, Url};

#[test]
fn urltestdata() {
    // Copied form https://github.com/w3c/web-platform-tests/blob/master/url/
    let mut json = Value::from_str(include_str!("urltestdata.json"))
        .expect("JSON parse error in urltestdata.json");

    let mut passed = true;
    for entry in json.as_array_mut().unwrap() {
        if entry.is_string() {
            continue; // ignore comments
        }

        let base = entry.take_string("base");
        let input = entry.take_string("input");
        let failure = entry.take_key("failure").is_some();

        let base = match Url::parse(&base) {
            Ok(base) => base,
            Err(_) if failure => continue,
            Err(message) => {
                eprint_failure(
                    format!("  failed: error parsing base {:?}: {}", base, message),
                    &format!("parse base for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        let url = match (base.join(&input), failure) {
            (Ok(url), false) => url,
            (Err(_), true) => continue,
            (Err(message), false) => {
                eprint_failure(
                    format!("  failed: {}", message),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
            (Ok(_), true) => {
                eprint_failure(
                    format!("  failed: expected parse error for URL {:?}", input),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        passed &= check_invariants(&url, &format!("invariants for {:?}", input), None);

        for &attr in ATTRIBS {
            passed &= test_eq_eprint(
                entry.take_string(attr),
                get(&url, attr),
                &format!("{:?} - {}", input, attr),
                None,
            );
        }

        if let Some(expected_origin) = entry.take_key("origin").map(|s| s.string()) {
            passed &= test_eq_eprint(
                expected_origin,
                &quirks::origin(&url),
                &format!("origin for {:?}", input),
                None,
            );
        }
    }

    assert!(passed)
}

#[allow(clippy::option_as_ref_deref)] // introduced in 1.40, MSRV is 1.36
#[test]
fn setters_tests() {
    let mut json = Value::from_str(include_str!("setters_tests.json"))
        .expect("JSON parse error in setters_tests.json");

    let mut passed = true;
    for &attr in ATTRIBS {
        if attr == "href" {
            continue;
        }

        let mut tests = json.take_key(attr).unwrap();
        for mut test in tests.as_array_mut().unwrap().drain(..) {
            let comment = test.take_key("comment").map(|s| s.string());
            let href = test.take_string("href");
            let new_value = test.take_string("new_value");
            let name = format!("{:?}.{} = {:?}", href, attr, new_value);
            let mut expected = test.take_key("expected").unwrap();

            let mut url = Url::parse(&href).unwrap();
            let comment_ref = comment.as_ref().map(|s| s.deref());
            passed &= check_invariants(&url, &name, comment_ref);
            let _ = set(&mut url, attr, &new_value);

            for attr in ATTRIBS {
                if let Some(value) = expected.take_key(attr) {
                    passed &= test_eq_eprint(value.string(), get(&url, attr), &name, comment_ref);
                };
            }

            passed &= check_invariants(&url, &name, comment_ref);
        }
    }

    assert!(passed);
}

fn check_invariants(url: &Url, name: &str, comment: Option<&str>) -> bool {
    let mut passed = true;
    if let Err(e) = url.check_invariants() {
        passed = false;
        eprint_failure(
            format!("  failed: invariants checked -> {:?}", e),
            name,
            comment,
        );
    }

    #[cfg(feature = "serde")]
    {
        let bytes = serde_json::to_vec(url).unwrap();
        let new_url: Url = serde_json::from_slice(&bytes).unwrap();
        passed &= test_eq(url, &new_url, name, comment);
    }

    passed
}

trait JsonExt {
    fn take_key(&mut self, key: &str) -> Option<Value>;
    fn string(self) -> String;
    fn take_string(&mut self, key: &str) -> String;
}

impl JsonExt for Value {
    fn take_key(&mut self, key: &str) -> Option<Value> {
        self.as_object_mut().unwrap().remove(key)
    }

    fn string(self) -> String {
        if let Value::String(s) = self {
            s
        } else {
            panic!("Not a Value::String")
        }
    }

    fn take_string(&mut self, key: &str) -> String {
        self.take_key(key).unwrap().string()
    }
}

fn get<'a>(url: &'a Url, attr: &str) -> &'a str {
    match attr {
        "href" => quirks::href(url),
        "protocol" => quirks::protocol(url),
        "username" => quirks::username(url),
        "password" => quirks::password(url),
        "hostname" => quirks::hostname(url),
        "host" => quirks::host(url),
        "port" => quirks::port(url),
        "pathname" => quirks::pathname(url),
        "search" => quirks::search(url),
        "hash" => quirks::hash(url),
        _ => unreachable!(),
    }
}

#[allow(clippy::unit_arg)]
fn set<'a>(url: &'a mut Url, attr: &str, new: &str) {
    let _ = match attr {
        "protocol" => quirks::set_protocol(url, new),
        "username" => quirks::set_username(url, new),
        "password" => quirks::set_password(url, new),
        "hostname" => quirks::set_hostname(url, new),
        "host" => quirks::set_host(url, new),
        "port" => quirks::set_port(url, new),
        "pathname" => Ok(quirks::set_pathname(url, new)),
        "search" => Ok(quirks::set_search(url, new)),
        "hash" => Ok(quirks::set_hash(url, new)),
        _ => unreachable!(),
    };
}

fn test_eq_eprint(expected: String, actual: &str, name: &str, comment: Option<&str>) -> bool {
    if expected == actual {
        return true;
    }
    eprint_failure(
        format!("expected: {}\n  actual: {}", expected, actual),
        name,
        comment,
    );
    false
}

fn eprint_failure(err: String, name: &str, comment: Option<&str>) {
    eprintln!("    test: {}\n{}", name, err);
    if let Some(comment) = comment {
        eprintln!("{}\n", comment);
    } else {
        eprintln!("");
    }
}

const ATTRIBS: &[&str] = &[
    "href", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search",
    "hash",
];
<|endoftext|>