<commit_before>//! Asynchronous DNS resolver

use std::{
    io::{self, Error, ErrorKind},
    net::SocketAddr,
    time::Duration,
};

use log::{error, trace};
use tokio::{self, runtime::Handle};
use trust_dns_resolver::{
    config::{LookupIpStrategy, ResolverConfig, ResolverOpts},
    TokioAsyncResolver,
};

use super::tokio_dns_resolver::resolve as tokio_resolve;
use crate::context::Context;

/// Create a `trust-dns` asynchronous DNS resolver
pub async fn create_resolver(
    dns: Option<ResolverConfig>,
    timeout: Option<Duration>,
    ipv6_first: bool,
    rt: Handle,
) -> io::Result<TokioAsyncResolver> {
    let mut resolver_opts = ResolverOpts::default();
    if let Some(d) = timeout {
        resolver_opts.timeout = d;
    }

    if ipv6_first {
        resolver_opts.ip_strategy = LookupIpStrategy::Ipv6thenIpv4;
    }

    {
        // To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration:
        #[cfg(any(unix, windows))]
        {
            if let Some(conf) = dns {
                trace!(
                    "initializing DNS resolver with config {:?} opts {:?}",
                    conf,
                    resolver_opts
                );
                TokioAsyncResolver::new(conf, resolver_opts, rt)
            } else {
                use trust_dns_resolver::system_conf::read_system_conf;
                // use the system resolver configuration
                let (config, opts) = match read_system_conf() {
                    Ok(o) => o,
                    Err(err) => {
                        error!("failed to initialize DNS resolver with system-config, error: {}", err);

                        // From::from is required because on error type is different on Windows
                        #[allow(clippy::identity_conversion)]
                        return Err(From::from(err));
                    }
                };

                // NOTE: timeout will be set by config (for example, /etc/resolv.conf on UNIX-like system)

                trace!(
                    "initializing DNS resolver with system-config {:?} opts {:?}",
                    config,
                    opts
                );

                TokioAsyncResolver::new(config, opts, rt)
            }
        }

        // For other operating systems, we can use one of the preconfigured definitions
        #[cfg(not(any(unix, windows)))]
        {
            if let Some(conf) = dns {
                trace!(
                    "initializing DNS resolver with config {:?} opts {:?}",
                    conf,
                    resolver_opts
                );
                TokioAsyncResolver::new(conf, resolver_opts, rt)
            } else {
                // Get a new resolver with the google nameservers as the upstream recursive resolvers
                trace!(
                    "initializing DNS resolver with google-config {:?} opts {:?}",
                    ResolverConfig::google(),
                    resolver_opts
                );
                TokioAsyncResolver::new(ResolverConfig::google(), resolver_opts, rt)
            }
        }
    }
    .await
    .map_err(|err| {
        Error::new(
            ErrorKind::Other,
            format!("failed to create trust-dns DNS resolver, error: {}", err),
        )
    })
}

/// Perform a DNS resolution
pub async fn resolve(context: &Context, addr: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
    match context.dns_resolver() {
        Some(resolver) => match resolver.lookup_ip(addr).await {
            Ok(lookup_result) => Ok(lookup_result.iter().map(|ip| SocketAddr::new(ip, port)).collect()),
            Err(err) => {
                let err = Error::new(
                    ErrorKind::Other,
                    format!("dns resolve {}:{} error: {}", addr, port, err),
                );
                Err(err)
            }
        },
        // Fallback to tokio's DNS resolver
        None => tokio_resolve(context, addr, port).await,
    }
}
<commit_msg>Set ip_strategy by ipv6_first while reading from system config<commit_after>//! Asynchronous DNS resolver

use std::{
    io::{self, Error, ErrorKind},
    net::SocketAddr,
    time::Duration,
};

use log::{error, trace};
use tokio::{self, runtime::Handle};
use trust_dns_resolver::{
    config::{LookupIpStrategy, ResolverConfig, ResolverOpts},
    TokioAsyncResolver,
};

use super::tokio_dns_resolver::resolve as tokio_resolve;
use crate::context::Context;

/// Create a `trust-dns` asynchronous DNS resolver
pub async fn create_resolver(
    dns: Option<ResolverConfig>,
    timeout: Option<Duration>,
    ipv6_first: bool,
    rt: Handle,
) -> io::Result<TokioAsyncResolver> {
    let mut resolver_opts = ResolverOpts::default();
    if let Some(d) = timeout {
        resolver_opts.timeout = d;
    }

    if ipv6_first {
        resolver_opts.ip_strategy = LookupIpStrategy::Ipv6thenIpv4;
    }

    {
        // To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration:
        #[cfg(any(unix, windows))]
        {
            if let Some(conf) = dns {
                trace!(
                    "initializing DNS resolver with config {:?} opts {:?}",
                    conf,
                    resolver_opts
                );
                TokioAsyncResolver::new(conf, resolver_opts, rt)
            } else {
                use trust_dns_resolver::system_conf::read_system_conf;
                // use the system resolver configuration
                let (config, mut opts) = match read_system_conf() {
                    Ok(o) => o,
                    Err(err) => {
                        error!("failed to initialize DNS resolver with system-config, error: {}", err);

                        // From::from is required because on error type is different on Windows
                        #[allow(clippy::identity_conversion)]
                        return Err(From::from(err));
                    }
                };

                // NOTE: timeout will be set by config (for example, /etc/resolv.conf on UNIX-like system)
                //
                // Only ip_strategy should be changed
                if ipv6_first {
                    opts.ip_strategy = LookupIpStrategy::Ipv6thenIpv4;
                }

                trace!(
                    "initializing DNS resolver with system-config {:?} opts {:?}",
                    config,
                    opts
                );

                TokioAsyncResolver::new(config, opts, rt)
            }
        }

        // For other operating systems, we can use one of the preconfigured definitions
        #[cfg(not(any(unix, windows)))]
        {
            if let Some(conf) = dns {
                trace!(
                    "initializing DNS resolver with config {:?} opts {:?}",
                    conf,
                    resolver_opts
                );
                TokioAsyncResolver::new(conf, resolver_opts, rt)
            } else {
                // Get a new resolver with the google nameservers as the upstream recursive resolvers
                trace!(
                    "initializing DNS resolver with google-config {:?} opts {:?}",
                    ResolverConfig::google(),
                    resolver_opts
                );
                TokioAsyncResolver::new(ResolverConfig::google(), resolver_opts, rt)
            }
        }
    }
    .await
    .map_err(|err| {
        Error::new(
            ErrorKind::Other,
            format!("failed to create trust-dns DNS resolver, error: {}", err),
        )
    })
}

/// Perform a DNS resolution
pub async fn resolve(context: &Context, addr: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
    match context.dns_resolver() {
        Some(resolver) => match resolver.lookup_ip(addr).await {
            Ok(lookup_result) => Ok(lookup_result.iter().map(|ip| SocketAddr::new(ip, port)).collect()),
            Err(err) => {
                let err = Error::new(
                    ErrorKind::Other,
                    format!("dns resolve {}:{} error: {}", addr, port, err),
                );
                Err(err)
            }
        },
        // Fallback to tokio's DNS resolver
        None => tokio_resolve(context, addr, port).await,
    }
}
<|endoftext|>


<commit_before>// no-system-llvm
// compile-flags: -O
#![crate_type = "lib"]

// Make sure no bounds checks are emitted in the loop when upfront slicing
// ensures that the slices are big enough.
// In particular, bounds checks were not always optimized out if the upfront
// check was for a greater len than the loop requires.
// (i.e. `already_sliced_no_bounds_check` was not always optimized even when
// `already_sliced_no_bounds_check_exact` was)
// CHECK-LABEL: @already_sliced_no_bounds_check
#[no_mangle]
pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK-NOT: panic_bounds_check
    let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}

// CHECK-LABEL: @already_sliced_no_bounds_check_exact
#[no_mangle]
pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK-NOT: panic_bounds_check
    let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}

// Make sure we're checking for the right thing: there can be a panic if the slice is too small.
// CHECK-LABEL: @already_sliced_bounds_check
#[no_mangle]
pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK: panic_bounds_check
    let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}
<commit_msg>ignore-debug: debug assertions in slice indexing prevent the optimization<commit_after>// no-system-llvm
// compile-flags: -O
// ignore-debug: the debug assertions get in the way
#![crate_type = "lib"]

// Make sure no bounds checks are emitted in the loop when upfront slicing
// ensures that the slices are big enough.
// In particular, bounds checks were not always optimized out if the upfront
// check was for a greater len than the loop requires.
// (i.e. `already_sliced_no_bounds_check` was not always optimized even when
// `already_sliced_no_bounds_check_exact` was)
// CHECK-LABEL: @already_sliced_no_bounds_check
#[no_mangle]
pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK-NOT: panic_bounds_check
    let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}

// CHECK-LABEL: @already_sliced_no_bounds_check_exact
#[no_mangle]
pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK-NOT: panic_bounds_check
    let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}

// Make sure we're checking for the right thing: there can be a panic if the slice is too small.
// CHECK-LABEL: @already_sliced_bounds_check
#[no_mangle]
pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK: panic_bounds_check
    let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::ops::{Add, Neg};
use num::Integer;

use types::*;

// A "vector" in the world, possibly going up or down levels

// TODO: If memory use becomes a problem, it may be worth converting this to
// using a persistent data structure and sharing the coords deque as
// much as possible

#[derive(Clone)]
pub struct Delta {
    pub zdelta: i16, // How far DOWN the target is

    pub coord_offset: i16, // How far DOWN the coords start
    pub coords: VecDeque<UVec>,
}

impl Delta {
    pub fn new(top: UVec) -> Delta {
        Delta {
            zdelta: 0,
            coord_offset: 0,
            coords: VecDeque::from(vec![top]),
        }
    }

    pub fn zero() -> Delta {
        Delta::new(UVec::new(0, 0))
    }

    fn div_vec(v: UVec) -> UVec {
        v.x = v.x.div_floor(&(zoom_scale as i32));
        v.y = v.y.div_floor(&(zoom_scale as i32));
        v
    }

    fn normalize(&mut self) {
        // Delete 0s from front and end, adjusting coord_offset
        // appropriately

        unimplemented!();
    }

    pub fn shift_target_down(mut self) -> Delta {
        self.coords.push_back(UVec::new(0, 0));
        self.zdelta += 1;
        self
    }

    pub fn shift_target_down_ref(&self) -> Delta {
        self.clone().shift_target_down()
    }

    pub fn truncate_target_up(mut self) -> Delta {
        unimplemented!();

        // This is wrong: Doesn't mod the last coord
        // self.coords.pop_back();
        // self.zdelta -= 1;
        // self
    }

    pub fn truncate_target_up_ref(&self) -> Delta {
        self.clone().truncate_target_up()
    }

    pub fn to_vec2(&self) -> UVec {
        // TODO: Detect overflow

        let mut res = UVec::new(0, 0);

        for (i, v) in self.coords.iter().enumerate() {
            res += UVec::new(
                v.x * zoom_scale.pow(i as u32) as i32,
                v.y * zoom_scale.pow(i as u32) as i32,
            );
        }

        if self.coord_offset < 0 {
            let extra_power = (-self.coord_offset) as u32;
            res = UVec::new(
                res.x * zoom_scale.pow(extra_power) as i32,
                res.y * zoom_scale.pow(extra_power) as i32,
            );
        }

        res
    }
}

impl PartialEq for Delta {
    fn eq(&self, other: &Delta) -> bool {
        unimplemented!();
    }
}

impl Eq for Delta {}

impl Add for Delta {
    type Output = Delta;

    fn add(self, other: Delta) -> Delta {
        unimplemented!();
    }
}

// impl<'a, 'b> Add<&'b Delta> for &'a Delta {
//     type Output = Delta;

//     fn add(self, other: &'b Delta) -> Delta {
//         unimplemented!();
//     }
// }

impl Neg for Delta {
    type Output = Delta;

    fn neg(mut self) -> Delta {
        self.coords.iter_mut().map(|c| c.neg());
        self
    }
}
<commit_msg>Just use a bigint dummy<commit_after>use std::collections::VecDeque;
use std::ops::{Add, Neg};
use num::bigint::BigInt;
use num::Integer;
use num::Zero;

use euclid::*;

use types::*;

// A "vector" in the world, possibly going up or down levels

// TODO: If memory use becomes a problem, it may be worth converting this to
// using a persistent data structure and sharing the coords deque as
// much as possible

#[derive(Clone)]
pub struct Delta {
    pub zdelta: i16, // How far DOWN the target is

    // TODO: maybe find a faster bigint
    pub coords: TypedVector2D<BigInt, UniverseSpace>,
}

impl Delta {
    // TODO: from
    // pub fn new(top: UVec) -> Delta {
    //     Delta {
    //         zdelta: 0,
    //         coords: TypedVector2D::new(BigInt::from(top.x), BigInt::from(top.y)),
    //     }
    // }

    pub fn zero() -> Delta {
        Delta {
            zdelta: 0,
            coords: TypedVector2D::new(BigInt::zero(), BigInt::zero())
        }
    }

    fn div_vec<T : Integer + From<u32>, U>(v: TypedVector2D<T, U>) -> TypedVector2D<T, U> {
        v.x = v.x.div_floor(&T::from(zoom_scale));
        v.y = v.y.div_floor(&T::from(zoom_scale));
        v
    }

    fn mult_vec<T : Integer + From<u32>, U>(v: TypedVector2D<T, U>) -> TypedVector2D<T, U> {
        v.x = v.x * (T::from(zoom_scale));
        v.y = v.y * (T::from(zoom_scale));
        v
    }

    pub fn shift_target_down(mut self) -> Delta {
        self.coords.x = self.coords.x * (BigInt::from(zoom_scale));
        self.coords.y = self.coords.y * (BigInt::from(zoom_scale));

        self.zdelta += 1;
        self
    }

    pub fn shift_target_down_ref(&self) -> Delta {
        self.clone().shift_target_down()
    }

    pub fn truncate_target_up(&mut self) -> () {
        self.coords.x = self.coords.x.div_floor(&BigInt::from(zoom_scale));
        self.coords.y = self.coords.y.div_floor(&BigInt::from(zoom_scale));

        self.zdelta -= 1;
    }

}

impl PartialEq for Delta {
    fn eq(&self, other: &Delta) -> bool {
        unimplemented!();
    }
}

impl Eq for Delta {}

impl<'a> Add<&'a Delta> for &'a Delta {
    type Output = Delta;

    fn add(self, other: &Delta) -> Delta {
        unimplemented!();
    }
}

// impl<'a, 'b> Add<&'b Delta> for &'a Delta {
//     type Output = Delta;

//     fn add(self, other: &'b Delta) -> Delta {
//         unimplemented!();
//     }
// }

impl Neg for Delta {
    type Output = Delta;

    fn neg(mut self) -> Delta {
        self.coords.iter_mut().map(|c| c.neg());
        self
    }
}
<|endoftext|>


<commit_before>use crate::context::ContextError;
use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Self
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        let backtrace = match error.backtrace() {
            Some(_) => None,
            None => Some(Backtrace::capture()),
        };

        unsafe {
            let obj = mem::transmute::<&dyn StdError, TraitObject>(&error);
            let vtable = obj.vtable;
            let inner = Box::new(ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            });
            Error {
                inner: mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner),
            }
        }
    }

    /// Wrap the error value with additional context.
    pub fn context<C>(self, context: C) -> Self
    where
        C: Display + Send + Sync + 'static,
    {
        Error::from(ContextError {
            error: self,
            context,
        })
    }

    /// View this error object as the underlying error.
    pub fn as_dyn_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        &**self
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_dyn_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        &mut **self
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of the chain of source errors contained by this Error.
    ///
    /// This iterator will visit every error in the cause chain of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn chain(&self) -> Chain {
        Chain {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Self>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut errors = self.chain().skip(1).enumerate();

        if let Some((n, error)) = errors.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in errors {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();

        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_LIB_BACKTRACE=1 environment variable to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M);

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &self.error,
            vtable: self.vtable,
        };

        unsafe { mem::transmute::<TraitObject, &(dyn StdError + Send + Sync + 'static)>(object) }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &mut self.error,
            vtable: self.vtable,
        };

        unsafe {
            mem::transmute::<TraitObject, &mut (dyn StdError + Send + Sync + 'static)>(object)
        }
    }
}

/// Iterator of a chain of source errors.
pub struct Chain<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

#[cfg(test)]
mod repr_correctness {
    use super::*;
    use std::marker::Unpin;
    use std::mem;
    use std::sync::atomic::AtomicBool;
    use std::sync::atomic::Ordering::SeqCst;
    use std::sync::Arc;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn error_autotraits() {
        fn assert<E: Unpin + Send + Sync + 'static>() {}
        assert::<Error>();
    }

    #[test]
    fn destructors_work() {
        #[derive(Debug)]
        struct HasDrop(Arc<AtomicBool>);
        impl StdError for HasDrop {}
        impl Display for HasDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }
        impl Drop for HasDrop {
            fn drop(&mut self) {
                let has_dropped = self.0.swap(true, SeqCst);
                assert!(!has_dropped);
            }
        }

        let has_dropped = Arc::new(AtomicBool::new(false));

        drop(Error::from(HasDrop(has_dropped.clone())));

        assert!(has_dropped.load(SeqCst));
    }
}
<commit_msg>Improve naming in Drop test<commit_after>use crate::context::ContextError;
use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Self
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        let backtrace = match error.backtrace() {
            Some(_) => None,
            None => Some(Backtrace::capture()),
        };

        unsafe {
            let obj = mem::transmute::<&dyn StdError, TraitObject>(&error);
            let vtable = obj.vtable;
            let inner = Box::new(ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            });
            Error {
                inner: mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner),
            }
        }
    }

    /// Wrap the error value with additional context.
    pub fn context<C>(self, context: C) -> Self
    where
        C: Display + Send + Sync + 'static,
    {
        Error::from(ContextError {
            error: self,
            context,
        })
    }

    /// View this error object as the underlying error.
    pub fn as_dyn_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        &**self
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_dyn_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        &mut **self
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of the chain of source errors contained by this Error.
    ///
    /// This iterator will visit every error in the cause chain of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn chain(&self) -> Chain {
        Chain {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Self>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut errors = self.chain().skip(1).enumerate();

        if let Some((n, error)) = errors.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in errors {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();

        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_LIB_BACKTRACE=1 environment variable to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M);

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &self.error,
            vtable: self.vtable,
        };

        unsafe { mem::transmute::<TraitObject, &(dyn StdError + Send + Sync + 'static)>(object) }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &mut self.error,
            vtable: self.vtable,
        };

        unsafe {
            mem::transmute::<TraitObject, &mut (dyn StdError + Send + Sync + 'static)>(object)
        }
    }
}

/// Iterator of a chain of source errors.
pub struct Chain<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

#[cfg(test)]
mod repr_correctness {
    use super::*;
    use std::marker::Unpin;
    use std::mem;
    use std::sync::atomic::AtomicBool;
    use std::sync::atomic::Ordering::SeqCst;
    use std::sync::Arc;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn error_autotraits() {
        fn assert<E: Unpin + Send + Sync + 'static>() {}
        assert::<Error>();
    }

    #[test]
    fn drop_works() {
        #[derive(Debug)]
        struct DetectDrop {
            has_dropped: Arc<AtomicBool>,
        }

        impl StdError for DetectDrop {}

        impl Display for DetectDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }

        impl Drop for DetectDrop {
            fn drop(&mut self) {
                let already_dropped = self.has_dropped.swap(true, SeqCst);
                assert!(!already_dropped);
            }
        }

        let has_dropped = Arc::new(AtomicBool::new(false));

        drop(Error::from(DetectDrop {
            has_dropped: has_dropped.clone(),
        }));

        assert!(has_dropped.load(SeqCst));
    }
}
<|endoftext|>


<commit_before>use bins::error::*;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg};
use hyper::Url;
use std::process;

pub struct Arguments {
  pub files: Vec<String>,
  pub message: Option<String>,
  pub service: Option<String>,
  pub private: bool,
  pub auth: bool,
  pub copy: bool,
  pub input: Option<String>,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub urls: bool,
  pub all: bool,
  pub server: Option<Url>,
  pub name: Option<String>,
  pub force: bool,
  pub number_lines: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

cfg_if! {
  if #[cfg(feature = "clipboard_support")] {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      vec![Arg::with_name("copy")
             .short("C")
             .long("copy")
             .help("copies the output of the command to the clipboard without a newline")
             .conflicts_with("no-copy"),
           Arg::with_name("no-copy")
             .short("c")
             .long("no-copy")
             .help("does not copy the output of the command to the clipboard")]
    }
  } else {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      Vec::new()
    }
  }
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    files: Vec::new(),
    message: None,
    service: config.get_defaults_service().map(|s| s.to_owned()),
    private: config.get_defaults_private(),
    auth: config.get_defaults_auth(),
    copy: config.get_defaults_copy(),
    input: None,
    range: None,
    raw_urls: false,
    urls: false,
    all: false,
    server: None,
    name: None,
    force: false,
    number_lines: false
  };
  let name = get_name();
  let version = get_version();
  let mut app = App::new(name.as_ref())
    .version(version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("pastebin service to use")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names())
      .required(arguments.service.is_none()))
    .arg(Arg::with_name("list-services")
      .short("l")
      .long("list-services")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "service", "input"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"));
  for arg in get_clipboard_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(service) = res.value_of("service") {
    arguments.service = Some(service.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref service) = arguments.service {
      if service.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    arguments.name = Some(name.to_owned());
  }
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.number_lines = res.is_present("number_lines");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<commit_msg>fix(arguments): prevent invalid file names when using --name<commit_after>use bins::error::*;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg};
use hyper::Url;
use std::path::{Component, Path};
use std::process;

pub struct Arguments {
  pub files: Vec<String>,
  pub message: Option<String>,
  pub service: Option<String>,
  pub private: bool,
  pub auth: bool,
  pub copy: bool,
  pub input: Option<String>,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub urls: bool,
  pub all: bool,
  pub server: Option<Url>,
  pub name: Option<String>,
  pub force: bool,
  pub number_lines: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

cfg_if! {
  if #[cfg(feature = "clipboard_support")] {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      vec![Arg::with_name("copy")
             .short("C")
             .long("copy")
             .help("copies the output of the command to the clipboard without a newline")
             .conflicts_with("no-copy"),
           Arg::with_name("no-copy")
             .short("c")
             .long("no-copy")
             .help("does not copy the output of the command to the clipboard")]
    }
  } else {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      Vec::new()
    }
  }
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    files: Vec::new(),
    message: None,
    service: config.get_defaults_service().map(|s| s.to_owned()),
    private: config.get_defaults_private(),
    auth: config.get_defaults_auth(),
    copy: config.get_defaults_copy(),
    input: None,
    range: None,
    raw_urls: false,
    urls: false,
    all: false,
    server: None,
    name: None,
    force: false,
    number_lines: false
  };
  let name = get_name();
  let version = get_version();
  let mut app = App::new(name.as_ref())
    .version(version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("pastebin service to use")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names())
      .required(arguments.service.is_none()))
    .arg(Arg::with_name("list-services")
      .short("l")
      .long("list-services")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "service", "input"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"));
  for arg in get_clipboard_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(service) = res.value_of("service") {
    arguments.service = Some(service.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref service) = arguments.service {
      if service.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    let name = some_or_err!(Path::new(name)
                              .components()
                              .filter_map(|s| {
                                match s {
                                  Component::Normal(x) => Some(x),
                                  _ => None
                                }
                              })
                              .last()
                              .and_then(|s| s.to_str()),
                            "--name had no valid path components".into());
    arguments.name = Some(name.to_owned());
  }
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.number_lines = res.is_present("number_lines");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::fmt;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::result;
use std::time::{SystemTime, UNIX_EPOCH};

use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use serde_json;

/// Sample envelope JSON payload
/// {
///   "timestamp": "1479330000.13442404",
///   "version": 1,
///   "event": {
///     "name": "project-create",
///     "origin" : "myorigin"
///     "package" : "mypackage"
///     "account" : "133508078967455744"
///   }
/// }
pub const SCHEMA_VERSION: u32 = 1;

// Macros to help hooking in the event logger into an Iron chain,
// and calling into the chained event logger.
#[macro_export]
macro_rules! define_event_log {
    () => {
        pub struct EventLog;
        impl typemap::Key for EventLog {
            type Value = EventLogger;
        }
    };
}

#[macro_export]
macro_rules! log_event {
    ($req:ident, $evt:expr) => {{
        let el = ($req).get::<persistent::Read<EventLog>>().unwrap();
        el.record_event($evt)
    }};
}

#[derive(Debug, Clone)]
pub enum Event {
    ProjectCreate {
        origin: String,
        package: String,
        account: String,
    },
    PackageUpload {
        origin: String,
        package: String,
        version: String,
        release: String,
        target: String,
        account: String,
    },
    OriginKeyUpload {
        origin: String,
        version: String,
        account: String,
    },
    OriginSigningKeyUpload {
        origin: String,
        version: String,
        account: String,
    },
    OriginInvitationSend {
        origin: String,
        user: String,
        id: String,
        account: String,
    },
    OriginInvitationAccept {
        id: String,
        account: String,
    },
    OriginInvitationIgnore {
        id: String,
        account: String,
    },
    JobCreate {
        package: String,
        account: String,
    },
    GithubAuthenticate {
        user: String,
        account: String,
    },
}

impl fmt::Display for Event {
    // TODO fn: As of rustfmt 0.7.1 the following match block is not well understood. The tool puts
    // all match arms on the same line which blows over the 100-column max which then fails the
    // tool with a `"line exceeded maximum length"` error. This ignore should be removed when we
    // upgrade rustfmt and retry.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let msg = match *self {
            Event::ProjectCreate { .. } => "project-create",
            Event::PackageUpload { .. } => { "package-upload" }
            Event::OriginKeyUpload { .. } => "origin-key-upload",
            Event::OriginSigningKeyUpload { .. } => { "origin-secret-key-upload" }
            Event::OriginInvitationSend { .. } => { "origin-invitation-send" }
            Event::OriginInvitationAccept { .. } => "origin-invitation-accept",
            Event::OriginInvitationIgnore { .. } => "origin-invitation-ignore",
            Event::JobCreate { .. } => "job-create",
            Event::GithubAuthenticate { .. } => "github-authenticate",
        };

        write!(f, "{}", msg)
    }
}

impl Serialize for Event {
    #[allow(clippy::many_single_char_names)]
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let strukt = match *self {
            Event::ProjectCreate {
                origin: ref o,
                package: ref p,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 4)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("package", p)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::PackageUpload {
                origin: ref o,
                package: ref p,
                version: ref v,
                release: ref r,
                target: ref t,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 6)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("package", p)?;
                strukt.serialize_field("version", v)?;
                strukt.serialize_field("release", r)?;
                strukt.serialize_field("target", t)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginInvitationSend {
                origin: ref o,
                user: ref u,
                id: ref i,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 5)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("user", u)?;
                strukt.serialize_field("id", i)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginInvitationAccept {
                id: ref i,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("id", i)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginInvitationIgnore {
                id: ref i,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("id", i)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::JobCreate {
                package: ref p,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("package", p)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::GithubAuthenticate {
                user: ref u,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("user", u)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginKeyUpload {
                origin: ref o,
                version: ref v,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 4)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("version", v)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginSigningKeyUpload {
                origin: ref o,
                version: ref v,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 4)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("version", v)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
        };
        strukt.end()
    }
}

#[derive(Debug, Clone)]
pub struct Envelope {
    pub version: u32,
    pub timestamp: String,
    pub event: Event,
}

impl Envelope {
    pub fn new(event: &Event) -> Self {
        Envelope {
            version: SCHEMA_VERSION,
            timestamp: timestamp(),
            event: event.clone(),
        }
    }
}

impl Serialize for Envelope {
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut strukt = serializer.serialize_struct("envelope", 3)?;
        strukt.serialize_field("version", &self.version)?;
        strukt.serialize_field("timestamp", &self.timestamp)?;
        strukt.serialize_field("event", &self.event)?;
        strukt.end()
    }
}

fn write_file<T>(parent_dir: &Path, file_path: &Path, val: &T)
where
    T: Serialize + ?Sized,
{
    fs::create_dir_all(parent_dir).expect("Unable to create directory");
    let mut file = File::create(&file_path).expect("Unable to create file");
    serde_json::ser::to_writer(&mut file, val).expect("Unable to write file");
}

fn timestamp() -> String {
    let (secs, subsec_nanos) = match SystemTime::now().duration_since(UNIX_EPOCH) {
        Ok(duration) => (duration.as_secs(), duration.subsec_nanos()),
        Err(e) => {
            error!("Cannot generate system time: {}", e);
            return "0.0".to_string();
        }
    };
    format!("{}.{}", secs, subsec_nanos)
}

pub struct EventLogger {
    log_dir: PathBuf,
    enabled: bool,
}

impl EventLogger {
    pub fn new<T: Into<PathBuf>>(log_dir: T, enabled: bool) -> Self {
        EventLogger {
            log_dir: log_dir.into(),
            enabled: enabled,
        }
    }

    pub fn record_event(&self, event: Event) {
        if self.enabled {
            let envelope = Envelope::new(&event);
            let file_path = self
                .log_dir
                .join(format!("event-{}.json", &envelope.timestamp));
            write_file(&self.log_dir, &file_path, &envelope);
        }
    }
}

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

    #[test]
    fn event_logger_path() {
        let event_logger: EventLogger = EventLogger::new("/hab/svc/foo/var", true);
        let expected = r#"foo"#;
        match event_logger.log_dir.to_str() {
            Some(s) => assert!(s.contains(expected)),
            None => assert!(false),
        }
    }
}
<commit_msg>Remove obsolete rustfmt_skip<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::fmt;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::result;
use std::time::{SystemTime, UNIX_EPOCH};

use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use serde_json;

/// Sample envelope JSON payload
/// {
///   "timestamp": "1479330000.13442404",
///   "version": 1,
///   "event": {
///     "name": "project-create",
///     "origin" : "myorigin"
///     "package" : "mypackage"
///     "account" : "133508078967455744"
///   }
/// }
pub const SCHEMA_VERSION: u32 = 1;

// Macros to help hooking in the event logger into an Iron chain,
// and calling into the chained event logger.
#[macro_export]
macro_rules! define_event_log {
    () => {
        pub struct EventLog;
        impl typemap::Key for EventLog {
            type Value = EventLogger;
        }
    };
}

#[macro_export]
macro_rules! log_event {
    ($req:ident, $evt:expr) => {{
        let el = ($req).get::<persistent::Read<EventLog>>().unwrap();
        el.record_event($evt)
    }};
}

#[derive(Debug, Clone)]
pub enum Event {
    ProjectCreate {
        origin: String,
        package: String,
        account: String,
    },
    PackageUpload {
        origin: String,
        package: String,
        version: String,
        release: String,
        target: String,
        account: String,
    },
    OriginKeyUpload {
        origin: String,
        version: String,
        account: String,
    },
    OriginSigningKeyUpload {
        origin: String,
        version: String,
        account: String,
    },
    OriginInvitationSend {
        origin: String,
        user: String,
        id: String,
        account: String,
    },
    OriginInvitationAccept {
        id: String,
        account: String,
    },
    OriginInvitationIgnore {
        id: String,
        account: String,
    },
    JobCreate {
        package: String,
        account: String,
    },
    GithubAuthenticate {
        user: String,
        account: String,
    },
}

impl fmt::Display for Event {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let msg = match *self {
            Event::ProjectCreate { .. } => "project-create",
            Event::PackageUpload { .. } => "package-upload",
            Event::OriginKeyUpload { .. } => "origin-key-upload",
            Event::OriginSigningKeyUpload { .. } => "origin-secret-key-upload",
            Event::OriginInvitationSend { .. } => "origin-invitation-send",
            Event::OriginInvitationAccept { .. } => "origin-invitation-accept",
            Event::OriginInvitationIgnore { .. } => "origin-invitation-ignore",
            Event::JobCreate { .. } => "job-create",
            Event::GithubAuthenticate { .. } => "github-authenticate",
        };

        write!(f, "{}", msg)
    }
}

impl Serialize for Event {
    #[allow(clippy::many_single_char_names)]
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let strukt = match *self {
            Event::ProjectCreate {
                origin: ref o,
                package: ref p,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 4)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("package", p)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::PackageUpload {
                origin: ref o,
                package: ref p,
                version: ref v,
                release: ref r,
                target: ref t,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 6)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("package", p)?;
                strukt.serialize_field("version", v)?;
                strukt.serialize_field("release", r)?;
                strukt.serialize_field("target", t)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginInvitationSend {
                origin: ref o,
                user: ref u,
                id: ref i,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 5)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("user", u)?;
                strukt.serialize_field("id", i)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginInvitationAccept {
                id: ref i,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("id", i)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginInvitationIgnore {
                id: ref i,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("id", i)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::JobCreate {
                package: ref p,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("package", p)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::GithubAuthenticate {
                user: ref u,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 3)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("user", u)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginKeyUpload {
                origin: ref o,
                version: ref v,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 4)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("version", v)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
            Event::OriginSigningKeyUpload {
                origin: ref o,
                version: ref v,
                account: ref a,
            } => {
                let mut strukt = serializer.serialize_struct("event", 4)?;
                strukt.serialize_field("name", &self.to_string())?;
                strukt.serialize_field("origin", o)?;
                strukt.serialize_field("version", v)?;
                strukt.serialize_field("account", a)?;
                strukt
            }
        };
        strukt.end()
    }
}

#[derive(Debug, Clone)]
pub struct Envelope {
    pub version: u32,
    pub timestamp: String,
    pub event: Event,
}

impl Envelope {
    pub fn new(event: &Event) -> Self {
        Envelope {
            version: SCHEMA_VERSION,
            timestamp: timestamp(),
            event: event.clone(),
        }
    }
}

impl Serialize for Envelope {
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut strukt = serializer.serialize_struct("envelope", 3)?;
        strukt.serialize_field("version", &self.version)?;
        strukt.serialize_field("timestamp", &self.timestamp)?;
        strukt.serialize_field("event", &self.event)?;
        strukt.end()
    }
}

fn write_file<T>(parent_dir: &Path, file_path: &Path, val: &T)
where
    T: Serialize + ?Sized,
{
    fs::create_dir_all(parent_dir).expect("Unable to create directory");
    let mut file = File::create(&file_path).expect("Unable to create file");
    serde_json::ser::to_writer(&mut file, val).expect("Unable to write file");
}

fn timestamp() -> String {
    let (secs, subsec_nanos) = match SystemTime::now().duration_since(UNIX_EPOCH) {
        Ok(duration) => (duration.as_secs(), duration.subsec_nanos()),
        Err(e) => {
            error!("Cannot generate system time: {}", e);
            return "0.0".to_string();
        }
    };
    format!("{}.{}", secs, subsec_nanos)
}

pub struct EventLogger {
    log_dir: PathBuf,
    enabled: bool,
}

impl EventLogger {
    pub fn new<T: Into<PathBuf>>(log_dir: T, enabled: bool) -> Self {
        EventLogger {
            log_dir: log_dir.into(),
            enabled: enabled,
        }
    }

    pub fn record_event(&self, event: Event) {
        if self.enabled {
            let envelope = Envelope::new(&event);
            let file_path = self
                .log_dir
                .join(format!("event-{}.json", &envelope.timestamp));
            write_file(&self.log_dir, &file_path, &envelope);
        }
    }
}

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

    #[test]
    fn event_logger_path() {
        let event_logger: EventLogger = EventLogger::new("/hab/svc/foo/var", true);
        let expected = r#"foo"#;
        match event_logger.log_dir.to_str() {
            Some(s) => assert!(s.contains(expected)),
            None => assert!(false),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

use ast::{Atom, Expr, Function, Symbol};
use error::*;
use eval::Env;
use std::collections::HashMap;

type Form = Fn(&[Expr], &mut Env) -> Result<Expr> + Sync;

lazy_static! {
    static ref SPECIAL_FORMS: HashMap<String, Box<Form>> = {
        let mut forms = HashMap::<String, Box<Form>>::new();
        forms.insert("def".into(), Box::new(def_form));
        forms.insert("if".into(), Box::new(if_form));
        forms.insert("let".into(), Box::new(let_form));
        forms.insert("do".into(), Box::new(do_form));
        forms.insert("fn".into(), Box::new(fn_form));
        forms.insert("quote".into(), Box::new(quote_form));
        forms
    };
}

pub fn is_special_form(form: &Symbol) -> bool {
    SPECIAL_FORMS.contains_key(&form.0)
}

pub fn eval(form: &Symbol, args: &[Expr], env: &mut Env) -> Result<Expr> {
    assert!(is_special_form(form));
    (SPECIAL_FORMS.get(&form.0))
        .ok_or("did not find special form".into())
        .and_then(|f| (f)(args, env))
}

// (def symbol init)
fn def_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() != 2 {
        return Err("#[def] expected 2 arguments".into());
    }

    if let Expr::Atom(Atom::Sym(ref sym)) = args[0] {
        args[1].eval(env).map(|expr| env.define(&sym.0, expr)).map(
            |_| {
                args[0].clone()
            },
        )
    } else {
        Err("#[def] expected symbol".into())
    }
}

// (if cond then else?)
fn if_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() == 2 {
        if args[0].eval(env)?.truthiness() {
            args[1].eval(env)
        } else {
            Ok(Expr::Nil)
        }
    } else if args.len() == 3 {
        if args[0].eval(env)?.truthiness() {
            args[1].eval(env)
        } else {
            args[2].eval(env)
        }
    } else {
        Err("#[if] expected body clause".into())
    }
}

// (let [bindings*] exprs*)
fn let_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    unimplemented!()
}

// (do exprs*)
fn do_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    match args.split_last() {
        Some((last, rest)) => {
            for arg in rest {
                arg.eval(env)?;
            }
            last.eval(env)
        }
        None => Ok(Expr::Nil),
    }
}

// (quote form)
fn quote_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() == 1 {
        Ok(args[0].clone())
    } else {
        Err("#[quote] expected 1 argument".into())
    }
}

// (fn name? [params* ] exprs*)
fn fn_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() >= 2 {
        let name = args[0].clone().atom().and_then(|a| a.sym().cloned());
        if name.is_some() {
            let params = args[1]
                .clone()
                .vector()
                .ok_or("#[fn] expected arg vector")?
                .0
                .iter()
                .map(|ref x| x.atom().and_then(|x2| x2.sym().cloned()))
                .collect::<Option<Vec<_>>>()
                .ok_or("#[fn] expected argument symbol")?;
            let body = args[2..].to_vec();
            Ok(Expr::Func(Function::User {
                name: name.map(|n| n.0),
                params: params,
                body: body,
            }))
        } else {
            let params = args[0]
                .clone()
                .vector()
                .ok_or("#[fn] expected arg vector")?
                .0
                .iter()
                .map(|ref x| x.atom().and_then(|x2| x2.sym().cloned()))
                .collect::<Option<Vec<_>>>()
                .ok_or("#[fn] expected argument symbol")?;
            let body = args[1..].to_vec();
            Ok(Expr::Func(Function::User {
                name: None,
                params: params,
                body: body,
            }))
        }
    } else {
        Err("#[fn] expected arguments (fn name? [params] exprs*)".into())
    }
}
<commit_msg>Simplify special forms creation<commit_after>#![allow(unused_variables)]

use ast::{Atom, Expr, Function, Symbol};
use error::*;
use eval::Env;
use std::collections::HashMap;

type Form = fn(&[Expr], &mut Env) -> Result<Expr>;

lazy_static! {
    static ref SPECIAL_FORMS: HashMap<&'static str, Form> = {
        let forms: Vec<(&'static str, Form)> = vec![
            ("def", def_form),
            ("if",  if_form),
            ("let", let_form),
            ("do",  do_form),
            ("fn",  fn_form),
            ("quote", quote_form),
        ];
        forms.into_iter().collect()
    };
}

pub fn is_special_form(form: &Symbol) -> bool {
    SPECIAL_FORMS.contains_key(form.0.as_str())
}

pub fn eval(form: &Symbol, args: &[Expr], env: &mut Env) -> Result<Expr> {
    assert!(is_special_form(form));
    (SPECIAL_FORMS.get(form.0.as_str()))
        .ok_or("did not find special form".into())
        .and_then(|f| (f)(args, env))
}

// (def symbol init)
fn def_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() != 2 {
        return Err("#[def] expected 2 arguments".into());
    }

    if let Expr::Atom(Atom::Sym(ref sym)) = args[0] {
        args[1].eval(env).map(|expr| env.define(&sym.0, expr)).map(
            |_| {
                args[0].clone()
            },
        )
    } else {
        Err("#[def] expected symbol".into())
    }
}

// (if cond then else?)
fn if_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() == 2 {
        if args[0].eval(env)?.truthiness() {
            args[1].eval(env)
        } else {
            Ok(Expr::Nil)
        }
    } else if args.len() == 3 {
        if args[0].eval(env)?.truthiness() {
            args[1].eval(env)
        } else {
            args[2].eval(env)
        }
    } else {
        Err("#[if] expected body clause".into())
    }
}

// (let [bindings*] exprs*)
fn let_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    unimplemented!()
}

// (do exprs*)
fn do_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    match args.split_last() {
        Some((last, rest)) => {
            for arg in rest {
                arg.eval(env)?;
            }
            last.eval(env)
        }
        None => Ok(Expr::Nil),
    }
}

// (quote form)
fn quote_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() == 1 {
        Ok(args[0].clone())
    } else {
        Err("#[quote] expected 1 argument".into())
    }
}

// (fn name? [params* ] exprs*)
fn fn_form(args: &[Expr], env: &mut Env) -> Result<Expr> {
    if args.len() >= 2 {
        let name = args[0].clone().atom().and_then(|a| a.sym().cloned());
        if name.is_some() {
            let params = args[1]
                .clone()
                .vector()
                .ok_or("#[fn] expected arg vector")?
                .0
                .iter()
                .map(|ref x| x.atom().and_then(|x2| x2.sym().cloned()))
                .collect::<Option<Vec<_>>>()
                .ok_or("#[fn] expected argument symbol")?;
            let body = args[2..].to_vec();
            Ok(Expr::from(Function::User {
                name: name.map(|n| n.0),
                params: params,
                body: body,
            }))
        } else {
            let params = args[0]
                .clone()
                .vector()
                .ok_or("#[fn] expected arg vector")?
                .0
                .iter()
                .map(|ref x| x.atom().and_then(|x2| x2.sym().cloned()))
                .collect::<Option<Vec<_>>>()
                .ok_or("#[fn] expected argument symbol")?;
            let body = args[1..].to_vec();
            Ok(Expr::from(Function::User {
                name: None,
                params: params,
                body: body,
            }))
        }
    } else {
        Err("#[fn] expected arguments (fn name? [params] exprs*)".into())
    }
}
<|endoftext|>


<commit_before>use {HashSet, HashMap};
use std::collections::{RingBuf, Deque};
use std::fmt;

// call this Unigraph instead?
pub trait Graph<T> {
    /// Insert a new node, returning its index
    fn add_node(&mut self, val: T) -> NodeIndex;

    /// Insert a new edge, returning an error if one of the indices is invalid
    /// and a result otherwise
    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool>;

    /// Return an iterator over the out-neighbors for a given node
    fn adj(&self, i: NodeIndex) -> NodeIndices;

    /// Return the number of nodes in the graph
    fn num_nodes(&self) -> uint;

    fn node_indices(&self) -> NodeIndices;
}

struct GraphError {
    error_type: GraphErrorType,
}

impl GraphError {
    fn invalid_index(ind: NodeIndex) -> GraphError {
        GraphError { error_type: InvalidNodeIndex(ind) }
    }
}

type GraphResult<T> = Result<T, GraphError>;

enum GraphErrorType {
    InvalidNodeIndex(NodeIndex),
}

pub type NodeIndex = uint;
type NodeIndexSet = HashSet<NodeIndex>;

#[deriving(Show, Clone)]
struct Node<T> {
    data: T,
    index: NodeIndex,
}

/// Undirected graph. Allows loops.
pub struct Ungraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

impl<T: fmt::Show> fmt::Show for Ungraph<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        write!(fmt, "{{");
        for n in self.nodes.values() {
            write!(fmt, " {} ", n.data);
        }
        write!(fmt, "}}  ");

        for (&i, adj) in self.adj.iter() {
            for &j in adj.iter() {
                write!(fmt, "({}, {})", self.get_node(i).data,
                                        self.get_node(j).data);
            }
        }

        Ok(())
    }
}

/// Directed graph. Allows loops.
pub struct Digraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    in_adj: HashMap<NodeIndex, NodeIndexSet>,
    out_adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

impl<T: fmt::Show> fmt::Show for Digraph<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        write!(fmt, "{{");
        for n in self.nodes.values() {
            write!(fmt, " {} ", n.data);
        }
        write!(fmt, "}}  ");

        for (&i, adj) in self.out_adj.iter() {
            for &j in adj.iter() {
                write!(fmt, "({}, {})", self.get_node(i).data,
                                        self.get_node(j).data);
            }
        }

        Ok(())
    }
}

impl<T> Ungraph<T> {
    pub fn new() -> Ungraph<T> {
        Ungraph { nodes: HashMap::new(), adj: HashMap::new(), num_nodes: 0 }
    }

    pub fn degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.adj.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok( self.get_adj(ind).len() )
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.adj.find(&i).unwrap()
    }
}

impl<T: Clone> Ungraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Ungraph<T> {
        let mut new = Ungraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for &ind in nodes.iter() {
            let new_ind = new.add_node(self.get_node(ind).data.clone());
            ind_map.insert(ind, new_ind);
        }

        for i in nodes.iter() {
            let actual_i = *ind_map.find(i).unwrap();
            for j in self.get_adj(*i).iter() {
                if nodes.contains(j) {
                    new.add_edge(actual_i, *ind_map.find(j).unwrap());
                }
            }
        }

        new
    }
}

impl<T> Graph<T> for Ungraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.adj.find_mut(&i).unwrap().insert(j);
                self.adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

impl<T> Digraph<T> {
    pub fn new() -> Digraph<T> {
        Digraph { nodes: HashMap::new(),
                  in_adj: HashMap::new(),
                  out_adj: HashMap::new(),
                  num_nodes: 0 }
    }

    pub fn out_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.nodes.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_out_adj(ind).len())
        }
    }

    pub fn in_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if ind >= self.num_nodes {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_in_adj(ind).len())
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_in_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.in_adj.find(&i).unwrap()
    }

    pub fn get_out_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.out_adj.find(&i).unwrap()
    }
}

impl<T: Clone> Digraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Digraph<T> {
        let mut new = Digraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for (i, &ind) in nodes.iter().enumerate() {
            ind_map.insert(ind, i);
            new.add_node(self.get_node(ind).data.clone());
        }

        for &i in nodes.iter() {
            for j in self.get_in_adj(i).iter() {
                if nodes.contains(j) {
                    new.add_edge(i, *ind_map.find(j).unwrap());
                }
            }

            for j in self.get_out_adj(i).iter() {
                if nodes.contains(j) {
                    new.add_edge(i, *ind_map.find(j).unwrap());
                }
            }
        }

        new
    }

    // Returns the transpose of the graph
    pub fn transpose(&self) -> Digraph<T> {
        let mut new = Digraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for n in self.nodes.values() {
            let new_ind = new.add_node(n.data.clone());
            ind_map.insert(n.index, new_ind);
        }

        for &i in self.nodes.keys() {
            let actual_i = *ind_map.find(&i).unwrap();

            for j in self.get_in_adj(i).iter() {
                new.add_edge(actual_i, *ind_map.find(j).unwrap());
            }

            for j in self.get_out_adj(i).iter() {
                new.add_edge(*ind_map.find(j).unwrap(), actual_i);
             }
        }
        new
    }
}

impl<T> Graph<T> for Digraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.in_adj.insert(ind, HashSet::new());
        self.out_adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_out_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.out_adj.find_mut(&i).unwrap().insert(j);
                self.in_adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_out_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

struct NodeIndices {
    indices: Vec<NodeIndex>,
    curr: uint,
}

impl Iterator<NodeIndex> for NodeIndices {
    fn next(&mut self) -> Option<NodeIndex> {
        if self.curr < self.indices.len() {
            self.curr += 1;
            Some(self.indices[self.curr - 1])
        } else {
            None
        }
    }
}

impl FromIterator<NodeIndex> for NodeIndices {
    fn from_iter<T: Iterator<NodeIndex>>(mut it: T) -> NodeIndices {
        let mut vec = vec!();
        for i in it {
            vec.push(i);
        }
        NodeIndices { indices: vec, curr: 0 }
    }

}
<commit_msg>Fix induced_subgraph() for Digraphs<commit_after>use {HashSet, HashMap};
use std::collections::{RingBuf, Deque};
use std::fmt;

// call this Unigraph instead?
pub trait Graph<T> {
    /// Insert a new node, returning its index
    fn add_node(&mut self, val: T) -> NodeIndex;

    /// Insert a new edge, returning an error if one of the indices is invalid
    /// and a result otherwise
    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool>;

    /// Return an iterator over the out-neighbors for a given node
    fn adj(&self, i: NodeIndex) -> NodeIndices;

    /// Return the number of nodes in the graph
    fn num_nodes(&self) -> uint;

    fn node_indices(&self) -> NodeIndices;
}

struct GraphError {
    error_type: GraphErrorType,
}

impl GraphError {
    fn invalid_index(ind: NodeIndex) -> GraphError {
        GraphError { error_type: InvalidNodeIndex(ind) }
    }
}

type GraphResult<T> = Result<T, GraphError>;

enum GraphErrorType {
    InvalidNodeIndex(NodeIndex),
}

pub type NodeIndex = uint;
type NodeIndexSet = HashSet<NodeIndex>;

#[deriving(Show, Clone)]
struct Node<T> {
    data: T,
    index: NodeIndex,
}

/// Undirected graph. Allows loops.
pub struct Ungraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

impl<T: fmt::Show> fmt::Show for Ungraph<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        write!(fmt, "{{");
        for n in self.nodes.values() {
            write!(fmt, " {} ", n.data);
        }
        write!(fmt, "}}  ");

        for (&i, adj) in self.adj.iter() {
            for &j in adj.iter() {
                write!(fmt, "({}, {})", self.get_node(i).data,
                                        self.get_node(j).data);
            }
        }

        Ok(())
    }
}

/// Directed graph. Allows loops.
pub struct Digraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    in_adj: HashMap<NodeIndex, NodeIndexSet>,
    out_adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

impl<T: fmt::Show> fmt::Show for Digraph<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        write!(fmt, "{{");
        for n in self.nodes.values() {
            write!(fmt, " {} ", n.data);
        }
        write!(fmt, "}}  ");

        for (&i, adj) in self.out_adj.iter() {
            for &j in adj.iter() {
                write!(fmt, "({}, {})", self.get_node(i).data,
                                        self.get_node(j).data);
            }
        }

        Ok(())
    }
}

impl<T> Ungraph<T> {
    pub fn new() -> Ungraph<T> {
        Ungraph { nodes: HashMap::new(), adj: HashMap::new(), num_nodes: 0 }
    }

    pub fn degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.adj.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok( self.get_adj(ind).len() )
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.adj.find(&i).unwrap()
    }
}

impl<T: Clone> Ungraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Ungraph<T> {
        let mut new = Ungraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for &ind in nodes.iter() {
            let new_ind = new.add_node(self.get_node(ind).data.clone());
            ind_map.insert(ind, new_ind);
        }

        for i in nodes.iter() {
            let actual_i = *ind_map.find(i).unwrap();
            for j in self.get_adj(*i).iter() {
                if nodes.contains(j) {
                    new.add_edge(actual_i, *ind_map.find(j).unwrap());
                }
            }
        }

        new
    }
}

impl<T> Graph<T> for Ungraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.adj.find_mut(&i).unwrap().insert(j);
                self.adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

impl<T> Digraph<T> {
    pub fn new() -> Digraph<T> {
        Digraph { nodes: HashMap::new(),
                  in_adj: HashMap::new(),
                  out_adj: HashMap::new(),
                  num_nodes: 0 }
    }

    pub fn out_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.nodes.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_out_adj(ind).len())
        }
    }

    pub fn in_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if ind >= self.num_nodes {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_in_adj(ind).len())
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_in_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.in_adj.find(&i).unwrap()
    }

    pub fn get_out_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.out_adj.find(&i).unwrap()
    }
}

impl<T: Clone> Digraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Digraph<T> {
        let mut new = Digraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for &ind in nodes.iter() {
            let new_ind = new.add_node(self.get_node(ind).data.clone());
            ind_map.insert(ind, new_ind);
        }

        for i in nodes.iter() {
            let actual_i = *ind_map.find(i).unwrap();
            for j in self.get_in_adj(*i).iter() {
                if nodes.contains(j) {
                    new.add_edge(*ind_map.find(j).unwrap(), actual_i);
                }
            }

            for j in self.get_out_adj(*i).iter() {
                if nodes.contains(j) {
                    new.add_edge(actual_i, *ind_map.find(j).unwrap());
                }
            }
        }

        new
    }

    // Returns the transpose of the graph
    pub fn transpose(&self) -> Digraph<T> {
        let mut new = Digraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for n in self.nodes.values() {
            let new_ind = new.add_node(n.data.clone());
            ind_map.insert(n.index, new_ind);
        }

        for &i in self.nodes.keys() {
            let actual_i = *ind_map.find(&i).unwrap();

            for j in self.get_in_adj(i).iter() {
                new.add_edge(actual_i, *ind_map.find(j).unwrap());
            }

            for j in self.get_out_adj(i).iter() {
                new.add_edge(*ind_map.find(j).unwrap(), actual_i);
            }
        }
        new
    }
}

impl<T> Graph<T> for Digraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.in_adj.insert(ind, HashSet::new());
        self.out_adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_out_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.out_adj.find_mut(&i).unwrap().insert(j);
                self.in_adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_out_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

struct NodeIndices {
    indices: Vec<NodeIndex>,
    curr: uint,
}

impl Iterator<NodeIndex> for NodeIndices {
    fn next(&mut self) -> Option<NodeIndex> {
        if self.curr < self.indices.len() {
            self.curr += 1;
            Some(self.indices[self.curr - 1])
        } else {
            None
        }
    }
}

impl FromIterator<NodeIndex> for NodeIndices {
    fn from_iter<T: Iterator<NodeIndex>>(mut it: T) -> NodeIndices {
        let mut vec = vec!();
        for i in it {
            vec.push(i);
        }
        NodeIndices { indices: vec, curr: 0 }
    }

}
<|endoftext|>