<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::num::NonZeroU32;
use core::convert::From;
use core::fmt;
#[cfg(not(target_env = "sgx"))]
use std::{io, error};

pub const UNKNOWN_ERROR: Error = Error(unsafe {
    NonZeroU32::new_unchecked(0x756e6b6e) // "unkn"
});

pub const UNAVAILABLE_ERROR: Error = Error(unsafe {
    NonZeroU32::new_unchecked(0x4e416e61) // "NAna"
});

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Error(NonZeroU32);

impl Error {
    pub fn code(&self) -> NonZeroU32 {
        self.0
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"),
            UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"),
            code => write!(f, "Getrandom Error: {}", code.0.get()),
        }
    }
}

#[cfg(not(target_env = "sgx"))]
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        err.raw_os_error()
            .map(|code| Error(unsafe {
                // all supported targets use 0 as success code
                NonZeroU32::new_unchecked(code as u32)
            }))
            // in practice this should never happen
            .unwrap_or(UNKNOWN_ERROR)
    }
}

#[cfg(not(target_env = "sgx"))]
impl Into<io::Error> for Error {
    fn into(self) -> io::Error {
        match self {
            UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other,
                "getrandom error: unknown"),
            UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other,
                "getrandom error: entropy source is unavailable"),
            code => io::Error::from_raw_os_error(code.0.get() as i32),
        }
    }
}

#[cfg(not(target_env = "sgx"))]
impl error::Error for Error { }
<commit_msg>remove unsafe<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::num::NonZeroU32;
use core::convert::From;
use core::fmt;
#[cfg(not(target_env = "sgx"))]
use std::{io, error};

pub const UNKNOWN_ERROR: Error = Error(unsafe {
    NonZeroU32::new_unchecked(0x756e6b6e) // "unkn"
});

pub const UNAVAILABLE_ERROR: Error = Error(unsafe {
    NonZeroU32::new_unchecked(0x4e416e61) // "NAna"
});

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Error(NonZeroU32);

impl Error {
    pub fn code(&self) -> NonZeroU32 {
        self.0
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"),
            UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"),
            code => write!(f, "Getrandom Error: {}", code.0.get()),
        }
    }
}

#[cfg(not(target_env = "sgx"))]
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        err.raw_os_error()
            .and_then(|code| NonZeroU32::new(code as u32))
            .map(|code| Error(code))
            // in practice this should never happen
            .unwrap_or(UNKNOWN_ERROR)
    }
}

#[cfg(not(target_env = "sgx"))]
impl Into<io::Error> for Error {
    fn into(self) -> io::Error {
        match self {
            UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other,
                "getrandom error: unknown"),
            UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other,
                "getrandom error: entropy source is unavailable"),
            code => io::Error::from_raw_os_error(code.0.get() as i32),
        }
    }
}

#[cfg(not(target_env = "sgx"))]
impl error::Error for Error { }
<|endoftext|>


<commit_before>//! Error types.

use std::error;
use std::fmt;

use cssparser::{BasicParseError, BasicParseErrorKind, ParseErrorKind, ToCss};
use markup5ever::QualName;

use crate::node::Node;
use crate::url_resolver::Fragment;

/// A short-lived error.
///
/// The lifetime of the error is the same as the `cssparser::ParserInput` that
/// was used to create a `cssparser::Parser`.  That is, it is the lifetime of
/// the string data that is being parsed.
///
/// The code flow will sometimes require preserving this error as a long-lived struct;
/// see the `impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>>` for that
/// purpose.
pub type ParseError<'i> = cssparser::ParseError<'i, ValueErrorKind>;

/// A simple error which refers to an attribute's value
#[derive(Debug, Clone, PartialEq)]
pub enum ValueErrorKind {
    /// A property with the specified name was not found
    UnknownProperty,

    /// The value could not be parsed
    Parse(String),

    // The value could be parsed, but is invalid
    Value(String),
}

impl ValueErrorKind {
    pub fn parse_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Parse(s.to_string())
    }

    pub fn value_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Value(s.to_string())
    }
}

impl fmt::Display for ValueErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ValueErrorKind::UnknownProperty => write!(f, "unknown property name"),

            ValueErrorKind::Parse(ref s) => write!(f, "parse error: {}", s),

            ValueErrorKind::Value(ref s) => write!(f, "invalid value: {}", s),
        }
    }
}

impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
    fn from(e: BasicParseError<'_>) -> ValueErrorKind {
        let BasicParseError { kind, .. } = e;

        let msg = match kind {
            BasicParseErrorKind::UnexpectedToken(_) => "unexpected token",
            BasicParseErrorKind::EndOfInput => "unexpected end of input",
            BasicParseErrorKind::AtRuleInvalid(_) => "invalid @-rule",
            BasicParseErrorKind::AtRuleBodyInvalid => "invalid @-rule body",
            BasicParseErrorKind::QualifiedRuleInvalid => "invalid qualified rule",
        };

        ValueErrorKind::parse_error(msg)
    }
}

/// A complete error for an attribute and its erroneous value
#[derive(Debug, Clone, PartialEq)]
pub struct ElementError {
    pub attr: QualName,
    pub err: ValueErrorKind,
}

impl error::Error for ElementError {
    fn description(&self) -> &str {
        match self.err {
            ValueErrorKind::UnknownProperty => "unknown property",
            ValueErrorKind::Parse(_) => "parse error",
            ValueErrorKind::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for ElementError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}: {}", self.attr.expanded(), self.err)
    }
}

/// Errors returned when looking up a resource by URL reference.
#[derive(Debug, Clone, PartialEq)]
pub enum DefsLookupErrorKind {
    /// Error when parsing an [`Href`].
    ///
    /// [`Href`]: allowed_url/enum.Href.html
    HrefError(HrefError),

    /// Used when the public API tries to look up an external URL, which is not allowed.
    ///
    /// This catches the case where a public API wants to be misused to access an external
    /// resource.  For example, `SvgHandle.has_sub("https://evil.com/phone_home#element_id") will
    /// fail with this error.
    CannotLookupExternalReferences,

    /// For internal use only.
    ///
    // FIXME: this is returned internally from Handle.lookup_node(), and gets translated
    // to Ok(false).  Don't expose this internal code in the public API.
    NotFound,
}

/// Errors that can happen while rendering or measuring an SVG document.
#[derive(Debug, Clone, PartialEq)]
pub enum RenderingError {
    /// A Cairo error happened during rendering.
    Cairo(cairo::Status),

    /// The maximum number of rendered objects was reached.
    ///
    /// Librsvg has a limit on the number of rendered objects, so that malicious
    /// files cannot consume CPU time arbitrarily.
    InstancingLimit,

    /// Tried to reference an SVG element from a fragment identifier that is incorrect.
    InvalidId(DefsLookupErrorKind),

    /// Not enough memory was available for rendering.
    // FIXME: right now this is only returned from pixbuf_utils.rs
    OutOfMemory,

    /// Cannot occur from librsvg_crate; this is just for the C API.
    HandleIsNotLoaded,
}

impl error::Error for RenderingError {}

impl fmt::Display for RenderingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            RenderingError::InstancingLimit => write!(f, "instancing limit"),
            RenderingError::OutOfMemory => write!(f, "out of memory"),
            RenderingError::HandleIsNotLoaded => write!(f, "SVG data is not loaded into handle"),
            RenderingError::Cairo(ref status) => write!(f, "cairo error: {:?}", status),
            RenderingError::InvalidId(ref id) => write!(f, "invalid id: {:?}", id),
        }
    }
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

pub enum AcquireError {
    LinkNotFound(Fragment),
    InvalidLinkType(Fragment),
    CircularReference(Node),
    MaxReferencesExceeded,
}

impl fmt::Display for AcquireError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            AcquireError::LinkNotFound(ref frag) => write!(f, "link not found: {}", frag),

            AcquireError::InvalidLinkType(ref frag) => {
                write!(f, "link {} is to object of invalid type", frag)
            }

            AcquireError::CircularReference(ref node) => {
                write!(f, "circular reference in node {}", node)
            }

            AcquireError::MaxReferencesExceeded => {
                write!(f, "maximum number of references exceeded")
            }
        }
    }
}

/// Helper for converting `Result<O, E>` into `Result<O, ElementError>`
///
/// A `ElementError` requires a `QualName` that corresponds to the attribute to which the
/// error refers, plus the actual `ValueErrorKind` that describes the error.  However,
/// parsing functions for attribute value types will want to return their own kind of
/// error, instead of `ValueErrorKind`.  If that particular error type has an `impl
/// From<FooError> for ValueErrorKind`, then this trait helps assign attribute values in
/// `set_atts()` methods as follows:
///
/// ```
/// # use librsvg::doctest_only::AttributeResultExt;
/// # use librsvg::doctest_only::ValueErrorKind;
/// # use librsvg::doctest_only::ElementError;
/// # use markup5ever::{QualName, Prefix, Namespace, LocalName};
/// # type FooError = ValueErrorKind;
/// fn parse_foo(value: &str) -> Result<(), FooError>
/// # { Err(ValueErrorKind::value_error("test")) }
///
/// // It is assumed that there is an impl From<FooError> for ValueErrorKind
/// # let attr = QualName::new(
/// #     Some(Prefix::from("")),
/// #     Namespace::from(""),
/// #     LocalName::from(""),
/// # );
/// let result = parse_foo("value").attribute(attr);
/// assert!(result.is_err());
/// # Ok::<(), ElementError>(())
/// ```
///
/// The call to `.attribute(attr)` converts the `Result` from `parse_foo()` into a full
/// `ElementError` with the provided `attr`.
pub trait AttributeResultExt<O> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError>;
}

impl<O, E: Into<ValueErrorKind>> AttributeResultExt<O> for Result<O, E> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| e.into())
            .map_err(|err| ElementError { attr, err })
    }
}

/// Turns a short-lived `ParseError` into a long-lived `ElementError`
impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| {
            // FIXME: eventually, here we'll want to preserve the location information

            let ParseError {
                kind,
                location: _location,
            } = e;

            match kind {
                ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(tok)) => {
                    let mut s = String::from("unexpected token '");
                    tok.to_css(&mut s).unwrap(); // FIXME: what do we do with a fmt::Error?
                    s.push_str("'");

                    ElementError {
                        attr,
                        err: ValueErrorKind::Parse(s),
                    }
                }

                ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => ElementError {
                    attr,
                    err: ValueErrorKind::parse_error("unexpected end of input"),
                },

                ParseErrorKind::Basic(_) => {
                    unreachable!("attribute parsers should not return errors for CSS rules")
                }

                ParseErrorKind::Custom(err) => ElementError { attr, err },
            }
        })
    }
}

/// Errors returned when creating an `Href` out of a string
#[derive(Debug, Clone, PartialEq)]
pub enum HrefError {
    /// The href is an invalid URI or has empty components.
    ParseError,

    /// A fragment identifier ("`#foo`") is not allowed here
    ///
    /// For example, the SVG `<image>` element only allows referencing
    /// resources without fragment identifiers like
    /// `xlink:href="foo.png"`.
    FragmentForbidden,

    /// A fragment identifier ("`#foo`") was required but not found.  For example,
    /// the SVG `<use>` element requires one, as in `<use xlink:href="foo.svg#bar">`.
    FragmentRequired,
}

impl From<HrefError> for ValueErrorKind {
    fn from(e: HrefError) -> ValueErrorKind {
        match e {
            HrefError::ParseError => ValueErrorKind::parse_error("url parse error"),
            HrefError::FragmentForbidden => {
                ValueErrorKind::value_error("fragment identifier not allowed")
            }
            HrefError::FragmentRequired => {
                ValueErrorKind::value_error("fragment identifier required")
            }
        }
    }
}

/// Errors that can happen while loading an SVG document.
///
/// All of these codes are for unrecoverable errors that keep an SVG document from being
/// fully loaded and parsed.  Note that SVG is very lenient with respect to document
/// structure and the syntax of CSS property values; most errors there will not lead to a
/// `LoadingError`.  To see those errors, you may want to set the `RSVG_LOG=1` environment
/// variable.
///
/// I/O errors get reported in the `Glib` variant, since librsvg uses GIO internally for
/// all input/output.
#[derive(Debug, Clone)]
pub enum LoadingError {
    // FIXME: C API only
    NoDataPassedToParser,

    /// XML syntax error.
    XmlParseError(String),

    /// Not enough memory to load the document.
    OutOfMemory(String),

    // FIXME: this is OOM in libxml2; we shouldn't expose it.
    CouldNotCreateXmlParser,

    /// A malformed or disallowed URL was used.
    BadUrl,

    /// A `data:` URL could not be decoded.
    BadDataUrl,

    // FIXME: used only if XML processing instruction cannot find the stylesheet.
    BadStylesheet,

    /// An invalid stylesheet was used.
    BadCss,

    /// A Cairo error happened during loading.
    Cairo(cairo::Status),

    // FIXME: only used in load_image()
    EmptyData,

    /// There are no SVG elements in the document.
    SvgHasNoElements,

    /// The outermost element in the document is not `<svg>`.
    RootElementIsNotSvg,

    /// Generally an I/O error, or another error from GIO.
    Glib(glib::Error),

    /// A particular implementation-defined limit was exceeded.
    LimitExceeded(String),

    // FIXME: only used internally when loading pixbufs, and temporarily in c_api.
    Unknown,
}

impl error::Error for LoadingError {}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LoadingError::NoDataPassedToParser => write!(f, "no data passed to parser"),
            LoadingError::XmlParseError(ref s) => write!(f, "XML parse error: {}", s),
            LoadingError::OutOfMemory(ref s) => write!(f, "out of memory: {}", s),
            LoadingError::CouldNotCreateXmlParser => write!(f, "could not create XML parser"),
            LoadingError::BadUrl => write!(f, "invalid URL"),
            LoadingError::BadDataUrl => write!(f, "invalid data: URL"),
            LoadingError::BadStylesheet => write!(f, "invalid stylesheet"),
            LoadingError::BadCss => write!(f, "invalid CSS"),
            LoadingError::Cairo(status) => write!(f, "cairo error: {:?}", status),
            LoadingError::EmptyData => write!(f, "empty data"),
            LoadingError::SvgHasNoElements => write!(f, "SVG has no elements"),
            LoadingError::RootElementIsNotSvg => write!(f, "root element is not <svg>"),
            LoadingError::Glib(ref e) => e.fmt(f),
            LoadingError::LimitExceeded(ref s) => write!(f, "limit exceeded: {}", s),
            LoadingError::Unknown => write!(f, "unknown error"),
        }
    }
}

impl From<cairo::Status> for LoadingError {
    fn from(e: cairo::Status) -> LoadingError {
        assert!(e != cairo::Status::Success);

        LoadingError::Cairo(e)
    }
}

impl From<glib::Error> for LoadingError {
    fn from(e: glib::Error) -> LoadingError {
        LoadingError::Glib(e)
    }
}
<commit_msg>Remove unused LoadingError::Cairo<commit_after>//! Error types.

use std::error;
use std::fmt;

use cssparser::{BasicParseError, BasicParseErrorKind, ParseErrorKind, ToCss};
use markup5ever::QualName;

use crate::node::Node;
use crate::url_resolver::Fragment;

/// A short-lived error.
///
/// The lifetime of the error is the same as the `cssparser::ParserInput` that
/// was used to create a `cssparser::Parser`.  That is, it is the lifetime of
/// the string data that is being parsed.
///
/// The code flow will sometimes require preserving this error as a long-lived struct;
/// see the `impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>>` for that
/// purpose.
pub type ParseError<'i> = cssparser::ParseError<'i, ValueErrorKind>;

/// A simple error which refers to an attribute's value
#[derive(Debug, Clone, PartialEq)]
pub enum ValueErrorKind {
    /// A property with the specified name was not found
    UnknownProperty,

    /// The value could not be parsed
    Parse(String),

    // The value could be parsed, but is invalid
    Value(String),
}

impl ValueErrorKind {
    pub fn parse_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Parse(s.to_string())
    }

    pub fn value_error(s: &str) -> ValueErrorKind {
        ValueErrorKind::Value(s.to_string())
    }
}

impl fmt::Display for ValueErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ValueErrorKind::UnknownProperty => write!(f, "unknown property name"),

            ValueErrorKind::Parse(ref s) => write!(f, "parse error: {}", s),

            ValueErrorKind::Value(ref s) => write!(f, "invalid value: {}", s),
        }
    }
}

impl<'a> From<BasicParseError<'a>> for ValueErrorKind {
    fn from(e: BasicParseError<'_>) -> ValueErrorKind {
        let BasicParseError { kind, .. } = e;

        let msg = match kind {
            BasicParseErrorKind::UnexpectedToken(_) => "unexpected token",
            BasicParseErrorKind::EndOfInput => "unexpected end of input",
            BasicParseErrorKind::AtRuleInvalid(_) => "invalid @-rule",
            BasicParseErrorKind::AtRuleBodyInvalid => "invalid @-rule body",
            BasicParseErrorKind::QualifiedRuleInvalid => "invalid qualified rule",
        };

        ValueErrorKind::parse_error(msg)
    }
}

/// A complete error for an attribute and its erroneous value
#[derive(Debug, Clone, PartialEq)]
pub struct ElementError {
    pub attr: QualName,
    pub err: ValueErrorKind,
}

impl error::Error for ElementError {
    fn description(&self) -> &str {
        match self.err {
            ValueErrorKind::UnknownProperty => "unknown property",
            ValueErrorKind::Parse(_) => "parse error",
            ValueErrorKind::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for ElementError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}: {}", self.attr.expanded(), self.err)
    }
}

/// Errors returned when looking up a resource by URL reference.
#[derive(Debug, Clone, PartialEq)]
pub enum DefsLookupErrorKind {
    /// Error when parsing an [`Href`].
    ///
    /// [`Href`]: allowed_url/enum.Href.html
    HrefError(HrefError),

    /// Used when the public API tries to look up an external URL, which is not allowed.
    ///
    /// This catches the case where a public API wants to be misused to access an external
    /// resource.  For example, `SvgHandle.has_sub("https://evil.com/phone_home#element_id") will
    /// fail with this error.
    CannotLookupExternalReferences,

    /// For internal use only.
    ///
    // FIXME: this is returned internally from Handle.lookup_node(), and gets translated
    // to Ok(false).  Don't expose this internal code in the public API.
    NotFound,
}

/// Errors that can happen while rendering or measuring an SVG document.
#[derive(Debug, Clone, PartialEq)]
pub enum RenderingError {
    /// A Cairo error happened during rendering.
    Cairo(cairo::Status),

    /// The maximum number of rendered objects was reached.
    ///
    /// Librsvg has a limit on the number of rendered objects, so that malicious
    /// files cannot consume CPU time arbitrarily.
    InstancingLimit,

    /// Tried to reference an SVG element from a fragment identifier that is incorrect.
    InvalidId(DefsLookupErrorKind),

    /// Not enough memory was available for rendering.
    // FIXME: right now this is only returned from pixbuf_utils.rs
    OutOfMemory,

    /// Cannot occur from librsvg_crate; this is just for the C API.
    HandleIsNotLoaded,
}

impl error::Error for RenderingError {}

impl fmt::Display for RenderingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            RenderingError::InstancingLimit => write!(f, "instancing limit"),
            RenderingError::OutOfMemory => write!(f, "out of memory"),
            RenderingError::HandleIsNotLoaded => write!(f, "SVG data is not loaded into handle"),
            RenderingError::Cairo(ref status) => write!(f, "cairo error: {:?}", status),
            RenderingError::InvalidId(ref id) => write!(f, "invalid id: {:?}", id),
        }
    }
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

pub enum AcquireError {
    LinkNotFound(Fragment),
    InvalidLinkType(Fragment),
    CircularReference(Node),
    MaxReferencesExceeded,
}

impl fmt::Display for AcquireError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            AcquireError::LinkNotFound(ref frag) => write!(f, "link not found: {}", frag),

            AcquireError::InvalidLinkType(ref frag) => {
                write!(f, "link {} is to object of invalid type", frag)
            }

            AcquireError::CircularReference(ref node) => {
                write!(f, "circular reference in node {}", node)
            }

            AcquireError::MaxReferencesExceeded => {
                write!(f, "maximum number of references exceeded")
            }
        }
    }
}

/// Helper for converting `Result<O, E>` into `Result<O, ElementError>`
///
/// A `ElementError` requires a `QualName` that corresponds to the attribute to which the
/// error refers, plus the actual `ValueErrorKind` that describes the error.  However,
/// parsing functions for attribute value types will want to return their own kind of
/// error, instead of `ValueErrorKind`.  If that particular error type has an `impl
/// From<FooError> for ValueErrorKind`, then this trait helps assign attribute values in
/// `set_atts()` methods as follows:
///
/// ```
/// # use librsvg::doctest_only::AttributeResultExt;
/// # use librsvg::doctest_only::ValueErrorKind;
/// # use librsvg::doctest_only::ElementError;
/// # use markup5ever::{QualName, Prefix, Namespace, LocalName};
/// # type FooError = ValueErrorKind;
/// fn parse_foo(value: &str) -> Result<(), FooError>
/// # { Err(ValueErrorKind::value_error("test")) }
///
/// // It is assumed that there is an impl From<FooError> for ValueErrorKind
/// # let attr = QualName::new(
/// #     Some(Prefix::from("")),
/// #     Namespace::from(""),
/// #     LocalName::from(""),
/// # );
/// let result = parse_foo("value").attribute(attr);
/// assert!(result.is_err());
/// # Ok::<(), ElementError>(())
/// ```
///
/// The call to `.attribute(attr)` converts the `Result` from `parse_foo()` into a full
/// `ElementError` with the provided `attr`.
pub trait AttributeResultExt<O> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError>;
}

impl<O, E: Into<ValueErrorKind>> AttributeResultExt<O> for Result<O, E> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| e.into())
            .map_err(|err| ElementError { attr, err })
    }
}

/// Turns a short-lived `ParseError` into a long-lived `ElementError`
impl<'i, O> AttributeResultExt<O> for Result<O, ParseError<'i>> {
    fn attribute(self, attr: QualName) -> Result<O, ElementError> {
        self.map_err(|e| {
            // FIXME: eventually, here we'll want to preserve the location information

            let ParseError {
                kind,
                location: _location,
            } = e;

            match kind {
                ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(tok)) => {
                    let mut s = String::from("unexpected token '");
                    tok.to_css(&mut s).unwrap(); // FIXME: what do we do with a fmt::Error?
                    s.push_str("'");

                    ElementError {
                        attr,
                        err: ValueErrorKind::Parse(s),
                    }
                }

                ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => ElementError {
                    attr,
                    err: ValueErrorKind::parse_error("unexpected end of input"),
                },

                ParseErrorKind::Basic(_) => {
                    unreachable!("attribute parsers should not return errors for CSS rules")
                }

                ParseErrorKind::Custom(err) => ElementError { attr, err },
            }
        })
    }
}

/// Errors returned when creating an `Href` out of a string
#[derive(Debug, Clone, PartialEq)]
pub enum HrefError {
    /// The href is an invalid URI or has empty components.
    ParseError,

    /// A fragment identifier ("`#foo`") is not allowed here
    ///
    /// For example, the SVG `<image>` element only allows referencing
    /// resources without fragment identifiers like
    /// `xlink:href="foo.png"`.
    FragmentForbidden,

    /// A fragment identifier ("`#foo`") was required but not found.  For example,
    /// the SVG `<use>` element requires one, as in `<use xlink:href="foo.svg#bar">`.
    FragmentRequired,
}

impl From<HrefError> for ValueErrorKind {
    fn from(e: HrefError) -> ValueErrorKind {
        match e {
            HrefError::ParseError => ValueErrorKind::parse_error("url parse error"),
            HrefError::FragmentForbidden => {
                ValueErrorKind::value_error("fragment identifier not allowed")
            }
            HrefError::FragmentRequired => {
                ValueErrorKind::value_error("fragment identifier required")
            }
        }
    }
}

/// Errors that can happen while loading an SVG document.
///
/// All of these codes are for unrecoverable errors that keep an SVG document from being
/// fully loaded and parsed.  Note that SVG is very lenient with respect to document
/// structure and the syntax of CSS property values; most errors there will not lead to a
/// `LoadingError`.  To see those errors, you may want to set the `RSVG_LOG=1` environment
/// variable.
///
/// I/O errors get reported in the `Glib` variant, since librsvg uses GIO internally for
/// all input/output.
#[derive(Debug, Clone)]
pub enum LoadingError {
    // FIXME: C API only
    NoDataPassedToParser,

    /// XML syntax error.
    XmlParseError(String),

    /// Not enough memory to load the document.
    OutOfMemory(String),

    // FIXME: this is OOM in libxml2; we shouldn't expose it.
    CouldNotCreateXmlParser,

    /// A malformed or disallowed URL was used.
    BadUrl,

    /// A `data:` URL could not be decoded.
    BadDataUrl,

    // FIXME: used only if XML processing instruction cannot find the stylesheet.
    BadStylesheet,

    /// An invalid stylesheet was used.
    BadCss,

    // FIXME: only used in load_image()
    EmptyData,

    /// There are no SVG elements in the document.
    SvgHasNoElements,

    /// The outermost element in the document is not `<svg>`.
    RootElementIsNotSvg,

    /// Generally an I/O error, or another error from GIO.
    Glib(glib::Error),

    /// A particular implementation-defined limit was exceeded.
    LimitExceeded(String),

    // FIXME: only used internally when loading pixbufs, and temporarily in c_api.
    Unknown,
}

impl error::Error for LoadingError {}

impl fmt::Display for LoadingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            LoadingError::NoDataPassedToParser => write!(f, "no data passed to parser"),
            LoadingError::XmlParseError(ref s) => write!(f, "XML parse error: {}", s),
            LoadingError::OutOfMemory(ref s) => write!(f, "out of memory: {}", s),
            LoadingError::CouldNotCreateXmlParser => write!(f, "could not create XML parser"),
            LoadingError::BadUrl => write!(f, "invalid URL"),
            LoadingError::BadDataUrl => write!(f, "invalid data: URL"),
            LoadingError::BadStylesheet => write!(f, "invalid stylesheet"),
            LoadingError::BadCss => write!(f, "invalid CSS"),
            LoadingError::EmptyData => write!(f, "empty data"),
            LoadingError::SvgHasNoElements => write!(f, "SVG has no elements"),
            LoadingError::RootElementIsNotSvg => write!(f, "root element is not <svg>"),
            LoadingError::Glib(ref e) => e.fmt(f),
            LoadingError::LimitExceeded(ref s) => write!(f, "limit exceeded: {}", s),
            LoadingError::Unknown => write!(f, "unknown error"),
        }
    }
}

impl From<glib::Error> for LoadingError {
    fn from(e: glib::Error) -> LoadingError {
        LoadingError::Glib(e)
    }
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::fmt;
use std::io::{self, ErrorKind};
use std::path::{self, Path};
use std::string;

use parser;

/// An enum of all error kinds.
#[derive(Debug)]
pub enum Error {
    /// An error for when a type cannot be parsed to a string because it
    /// contains invalid UTF-8.
    InvalidUtf8,
    /// An IO error was encountered.
    IoError(io::Error),
    /// An error which occurs when a path which is expected to contain a file
    /// name as the final component instead terminates in `.`, `..`, or solely
    /// of a root of prefix.
    MissingFileName,
    /// An error for when the template field is expected but not specified in a
    /// document header.
    MissingTemplateField,
    /// Wraps errors emitted by methods when attempting to parse a document.
    ParserError(parser::Error),
    /// Wraps errors emitted by the `Path::strip_prefix` method.
    StripPrefixError(path::StripPrefixError),
    /// An error which occurs when a specified template cannot be found.
    TemplateNotFound,
}

impl Error {
    /// Create an error for a non-directory path which was expected to be as
    /// directory.
    pub fn path_is_not_a_directory<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::InvalidInput, format!(
                    "specified path is not a directory: {}",
                    path.as_ref().display(),
                )))
    }

    /// Create an error for a path which unexpectedly points at a non-existing
    /// entity.
    pub fn path_not_found<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::NotFound, format!(
                    "specified path not found: {}",
                    path.as_ref().display(),
                )))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::IoError(ref e) => e.fmt(f),
            &Error::ParserError(ref e) => e.fmt(f),
            &Error::StripPrefixError(ref e) => e.fmt(f),
            e => write!(f, "{}", e.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidUtf8 => "a string is not valid UTF-8",
            Error::IoError(ref e) => e.description(),
            Error::MissingFileName => "a path is missing a file name",
            Error::MissingTemplateField => "missing template field in header",
            Error::ParserError(ref e) => e.description(),
            Error::StripPrefixError(ref e) => e.description(),
            Error::TemplateNotFound => "specified template could not be found",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::IoError(ref e) => e.cause(),
            Error::ParserError(ref e) => e.cause(),
            Error::StripPrefixError(ref e) => e.cause(),
            _ => None,
        }
    }
}

/// Application generic result type.
pub type Result<T> = ::std::result::Result<T, self::Error>;

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error::IoError(error)
    }
}

impl From<parser::Error> for Error {
    fn from(error: parser::Error) -> Error {
        Error::ParserError(error)
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_error: string::FromUtf8Error) -> Error {
        Error::InvalidUtf8
    }
}

impl From<path::StripPrefixError> for Error {
    fn from(error: path::StripPrefixError) -> Error {
        Error::StripPrefixError(error)
    }
}

// Implement `PartialEq` manually, since `std::io::Error` does not implement it.
impl PartialEq<Error> for Error {
    fn eq(&self, other: &Error) -> bool {
        use self::Error::{
            InvalidUtf8,
            IoError,
            MissingFileName,
            MissingTemplateField,
            ParserError,
            StripPrefixError,
            TemplateNotFound,
        };

        match (self, other) {
            (&InvalidUtf8, &InvalidUtf8)                 => true,
            (&IoError(_), &IoError(_))                   => true,
            (&MissingFileName, &MissingFileName)         => true,
            (&MissingTemplateField, &MissingFileName)    => true,
            (&ParserError(ref a), &ParserError(ref b))   => a == b,
            (&StripPrefixError(_), &StripPrefixError(_)) => true,
            (&TemplateNotFound, &TemplateNotFound)       => true,
            _ => false,
        }
    }
}
<commit_msg>docs: add documentation strings<commit_after>use std::error::Error as StdError;
use std::fmt;
use std::io::{self, ErrorKind};
use std::path::{self, Path};
use std::string;

use parser;

/// A convenient alias type for results when using Ferrum.
pub type Result<T> = ::std::result::Result<T, self::Error>;

/// An enum of all error kinds.
#[derive(Debug)]
pub enum Error {
    /// An error for when a type cannot be parsed to a string because it
    /// contains invalid UTF-8.
    InvalidUtf8,
    /// An IO error was encountered.
    IoError(io::Error),
    /// An error which occurs when a path which is expected to contain a file
    /// name as the final component instead terminates in `.`, `..`, or solely
    /// of a root of prefix.
    MissingFileName,
    /// An error for when the template field is expected but not specified in a
    /// document header.
    MissingTemplateField,
    /// Wraps errors emitted by methods when attempting to parse a document.
    ParserError(parser::Error),
    /// Wraps errors emitted by the `Path::strip_prefix` method.
    StripPrefixError(path::StripPrefixError),
    /// An error which occurs when a specified template cannot be found.
    TemplateNotFound,
}

impl Error {
    /// Create an error for a non-directory path which was expected to be as
    /// directory.
    pub fn path_is_not_a_directory<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::InvalidInput, format!(
                    "specified path is not a directory: {}",
                    path.as_ref().display(),
                )))
    }

    /// Create an error for a path which unexpectedly points at a non-existing
    /// entity.
    pub fn path_not_found<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::NotFound, format!(
                    "specified path not found: {}",
                    path.as_ref().display(),
                )))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::IoError(ref e) => e.fmt(f),
            &Error::ParserError(ref e) => e.fmt(f),
            &Error::StripPrefixError(ref e) => e.fmt(f),
            e => write!(f, "{}", e.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidUtf8 => "a string is not valid UTF-8",
            Error::IoError(ref e) => e.description(),
            Error::MissingFileName => "a path is missing a file name",
            Error::MissingTemplateField => "missing template field in header",
            Error::ParserError(ref e) => e.description(),
            Error::StripPrefixError(ref e) => e.description(),
            Error::TemplateNotFound => "specified template could not be found",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::IoError(ref e) => e.cause(),
            Error::ParserError(ref e) => e.cause(),
            Error::StripPrefixError(ref e) => e.cause(),
            _ => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error::IoError(error)
    }
}

impl From<parser::Error> for Error {
    fn from(error: parser::Error) -> Error {
        Error::ParserError(error)
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_error: string::FromUtf8Error) -> Error {
        Error::InvalidUtf8
    }
}

impl From<path::StripPrefixError> for Error {
    fn from(error: path::StripPrefixError) -> Error {
        Error::StripPrefixError(error)
    }
}

// Implement `PartialEq` manually, since `std::io::Error` does not implement it.
impl PartialEq<Error> for Error {
    fn eq(&self, other: &Error) -> bool {
        use self::Error::{
            InvalidUtf8,
            IoError,
            MissingFileName,
            MissingTemplateField,
            ParserError,
            StripPrefixError,
            TemplateNotFound,
        };

        match (self, other) {
            (&InvalidUtf8, &InvalidUtf8)                 => true,
            (&IoError(_), &IoError(_))                   => true,
            (&MissingFileName, &MissingFileName)         => true,
            (&MissingTemplateField, &MissingFileName)    => true,
            (&ParserError(ref a), &ParserError(ref b))   => a == b,
            (&StripPrefixError(_), &StripPrefixError(_)) => true,
            (&TemplateNotFound, &TemplateNotFound)       => true,
            _ => false,
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "parsing")]
use crate::buffer::Cursor;
use crate::thread::ThreadBound;
use proc_macro2::{
    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
#[cfg(feature = "printing")]
use quote::ToTokens;
use std::fmt::{self, Debug, Display};
use std::iter::FromIterator;
use std::slice;
use std::vec;

/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;

/// Error returned when a Syn parser cannot parse the input tokens.
///
/// # Error reporting in proc macros
///
/// The correct way to report errors back to the compiler from a procedural
/// macro is by emitting an appropriately spanned invocation of
/// [`compile_error!`] in the generated code. This produces a better diagnostic
/// message than simply panicking the macro.
///
/// [`compile_error!`]: std::compile_error!
///
/// When parsing macro input, the [`parse_macro_input!`] macro handles the
/// conversion to `compile_error!` automatically.
///
/// ```
/// # extern crate proc_macro;
/// #
/// use proc_macro::TokenStream;
/// use syn::{parse_macro_input, AttributeArgs, ItemFn};
///
/// # const IGNORE: &str = stringify! {
/// #[proc_macro_attribute]
/// # };
/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream {
///     let args = parse_macro_input!(args as AttributeArgs);
///     let input = parse_macro_input!(input as ItemFn);
///
///     /* ... */
///     # TokenStream::new()
/// }
/// ```
///
/// For errors that arise later than the initial parsing stage, the
/// [`.to_compile_error()`] method can be used to perform an explicit conversion
/// to `compile_error!`.
///
/// [`.to_compile_error()`]: Error::to_compile_error
///
/// ```
/// # extern crate proc_macro;
/// #
/// # use proc_macro::TokenStream;
/// # use syn::{parse_macro_input, DeriveInput};
/// #
/// # const IGNORE: &str = stringify! {
/// #[proc_macro_derive(MyDerive)]
/// # };
/// pub fn my_derive(input: TokenStream) -> TokenStream {
///     let input = parse_macro_input!(input as DeriveInput);
///
///     // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream>
///     expand::my_derive(input)
///         .unwrap_or_else(|err| err.to_compile_error())
///         .into()
/// }
/// #
/// # mod expand {
/// #     use proc_macro2::TokenStream;
/// #     use syn::{DeriveInput, Result};
/// #
/// #     pub fn my_derive(input: DeriveInput) -> Result<TokenStream> {
/// #         unimplemented!()
/// #     }
/// # }
/// ```
pub struct Error {
    messages: Vec<ErrorMessage>,
}

struct ErrorMessage {
    // Span is implemented as an index into a thread-local interner to keep the
    // size small. It is not safe to access from a different thread. We want
    // errors to be Send and Sync to play nicely with the Failure crate, so pin
    // the span we're given to its original thread and assume it is
    // Span::call_site if accessed from any other thread.
    start_span: ThreadBound<Span>,
    end_span: ThreadBound<Span>,
    message: String,
}

#[cfg(test)]
struct _Test
where
    Error: Send + Sync;

impl Error {
    /// Usually the [`ParseStream::error`] method will be used instead, which
    /// automatically uses the correct span from the current position of the
    /// parse stream.
    ///
    /// Use `Error::new` when the error needs to be triggered on some span other
    /// than where the parse stream is currently positioned.
    ///
    /// [`ParseStream::error`]: crate::parse::ParseBuffer::error
    ///
    /// # Example
    ///
    /// ```
    /// use syn::{Error, Ident, LitStr, Result, Token};
    /// use syn::parse::ParseStream;
    ///
    /// // Parses input that looks like `name = "string"` where the key must be
    /// // the identifier `name` and the value may be any string literal.
    /// // Returns the string literal.
    /// fn parse_name(input: ParseStream) -> Result<LitStr> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         // Trigger an error not on the current position of the stream,
    ///         // but on the position of the unexpected identifier.
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let s: LitStr = input.parse()?;
    ///     Ok(s)
    /// }
    /// ```
    pub fn new<T: Display>(span: Span, message: T) -> Self {
        Error {
            messages: vec![ErrorMessage {
                start_span: ThreadBound::new(span),
                end_span: ThreadBound::new(span),
                message: message.to_string(),
            }],
        }
    }

    /// Creates an error with the specified message spanning the given syntax
    /// tree node.
    ///
    /// Unlike the `Error::new` constructor, this constructor takes an argument
    /// `tokens` which is a syntax tree node. This allows the resulting `Error`
    /// to attempt to span all tokens inside of `tokens`. While you would
    /// typically be able to use the `Spanned` trait with the above `Error::new`
    /// constructor, implementation limitations today mean that
    /// `Error::new_spanned` may provide a higher-quality error message on
    /// stable Rust.
    ///
    /// When in doubt it's recommended to stick to `Error::new` (or
    /// `ParseStream::error`)!
    #[cfg(feature = "printing")]
    pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
        let mut iter = tokens.into_token_stream().into_iter();
        let start = iter.next().map_or_else(Span::call_site, |t| t.span());
        let end = iter.last().map_or(start, |t| t.span());
        Error {
            messages: vec![ErrorMessage {
                start_span: ThreadBound::new(start),
                end_span: ThreadBound::new(end),
                message: message.to_string(),
            }],
        }
    }

    /// The source location of the error.
    ///
    /// Spans are not thread-safe so this function returns `Span::call_site()`
    /// if called from a different thread than the one on which the `Error` was
    /// originally created.
    pub fn span(&self) -> Span {
        let start = match self.messages[0].start_span.get() {
            Some(span) => *span,
            None => return Span::call_site(),
        };
        let end = match self.messages[0].end_span.get() {
            Some(span) => *span,
            None => return Span::call_site(),
        };
        start.join(end).unwrap_or(start)
    }

    /// Render the error as an invocation of [`compile_error!`].
    ///
    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
    /// this method correctly in a procedural macro.
    ///
    /// [`compile_error!`]: std::compile_error!
    pub fn to_compile_error(&self) -> TokenStream {
        self.messages
            .iter()
            .map(ErrorMessage::to_compile_error)
            .collect()
    }

    /// Add another error message to self such that when `to_compile_error()` is
    /// called, both errors will be emitted together.
    pub fn combine(&mut self, another: Error) {
        self.messages.extend(another.messages)
    }
}

impl ErrorMessage {
    fn to_compile_error(&self) -> TokenStream {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);

        // compile_error!($message)
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("compile_error", start)),
            TokenTree::Punct({
                let mut punct = Punct::new('!', Spacing::Alone);
                punct.set_span(start);
                punct
            }),
            TokenTree::Group({
                let mut group = Group::new(Delimiter::Brace, {
                    TokenStream::from_iter(vec![TokenTree::Literal({
                        let mut string = Literal::string(&self.message);
                        string.set_span(end);
                        string
                    })])
                });
                group.set_span(end);
                group
            }),
        ])
    }
}

#[cfg(feature = "parsing")]
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
    if cursor.eof() {
        Error::new(scope, format!("unexpected end of input, {}", message))
    } else {
        let span = crate::buffer::open_span_of_group(cursor);
        Error::new(span, message)
    }
}

#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
pub fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
    Error {
        messages: vec![ErrorMessage {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: message.to_string(),
        }],
    }
}

impl Debug for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        if self.messages.len() == 1 {
            formatter
                .debug_tuple("Error")
                .field(&self.messages[0])
                .finish()
        } else {
            formatter
                .debug_tuple("Error")
                .field(&self.messages)
                .finish()
        }
    }
}

impl Debug for ErrorMessage {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.message, formatter)
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&self.messages[0].message)
    }
}

impl Clone for Error {
    fn clone(&self) -> Self {
        Error {
            messages: self.messages.clone(),
        }
    }
}

impl Clone for ErrorMessage {
    fn clone(&self) -> Self {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
        ErrorMessage {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: self.message.clone(),
        }
    }
}

impl std::error::Error for Error {}

impl From<LexError> for Error {
    fn from(err: LexError) -> Self {
        Error::new(Span::call_site(), format!("{:?}", err))
    }
}

impl IntoIterator for Error {
    type Item = Error;
    type IntoIter = IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            messages: self.messages.into_iter(),
        }
    }
}

pub struct IntoIter {
    messages: vec::IntoIter<ErrorMessage>,
}

impl Iterator for IntoIter {
    type Item = Error;

    fn next(&mut self) -> Option<Self::Item> {
        Some(Error {
            messages: vec![self.messages.next()?],
        })
    }
}

impl<'a> IntoIterator for &'a Error {
    type Item = Error;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            messages: self.messages.iter(),
        }
    }
}

pub struct Iter<'a> {
    messages: slice::Iter<'a, ErrorMessage>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Error;

    fn next(&mut self) -> Option<Self::Item> {
        Some(Error {
            messages: vec![self.messages.next()?.clone()],
        })
    }
}

impl Extend<Error> for Error {
    fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
        for err in iter {
            self.combine(err);
        }
    }
}
<commit_msg>Add Error::into_compile_error<commit_after>#[cfg(feature = "parsing")]
use crate::buffer::Cursor;
use crate::thread::ThreadBound;
use proc_macro2::{
    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
#[cfg(feature = "printing")]
use quote::ToTokens;
use std::fmt::{self, Debug, Display};
use std::iter::FromIterator;
use std::slice;
use std::vec;

/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;

/// Error returned when a Syn parser cannot parse the input tokens.
///
/// # Error reporting in proc macros
///
/// The correct way to report errors back to the compiler from a procedural
/// macro is by emitting an appropriately spanned invocation of
/// [`compile_error!`] in the generated code. This produces a better diagnostic
/// message than simply panicking the macro.
///
/// [`compile_error!`]: std::compile_error!
///
/// When parsing macro input, the [`parse_macro_input!`] macro handles the
/// conversion to `compile_error!` automatically.
///
/// ```
/// # extern crate proc_macro;
/// #
/// use proc_macro::TokenStream;
/// use syn::{parse_macro_input, AttributeArgs, ItemFn};
///
/// # const IGNORE: &str = stringify! {
/// #[proc_macro_attribute]
/// # };
/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream {
///     let args = parse_macro_input!(args as AttributeArgs);
///     let input = parse_macro_input!(input as ItemFn);
///
///     /* ... */
///     # TokenStream::new()
/// }
/// ```
///
/// For errors that arise later than the initial parsing stage, the
/// [`.to_compile_error()`] method can be used to perform an explicit conversion
/// to `compile_error!`.
///
/// [`.to_compile_error()`]: Error::to_compile_error
///
/// ```
/// # extern crate proc_macro;
/// #
/// # use proc_macro::TokenStream;
/// # use syn::{parse_macro_input, DeriveInput};
/// #
/// # const IGNORE: &str = stringify! {
/// #[proc_macro_derive(MyDerive)]
/// # };
/// pub fn my_derive(input: TokenStream) -> TokenStream {
///     let input = parse_macro_input!(input as DeriveInput);
///
///     // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream>
///     expand::my_derive(input)
///         .unwrap_or_else(|err| err.to_compile_error())
///         .into()
/// }
/// #
/// # mod expand {
/// #     use proc_macro2::TokenStream;
/// #     use syn::{DeriveInput, Result};
/// #
/// #     pub fn my_derive(input: DeriveInput) -> Result<TokenStream> {
/// #         unimplemented!()
/// #     }
/// # }
/// ```
pub struct Error {
    messages: Vec<ErrorMessage>,
}

struct ErrorMessage {
    // Span is implemented as an index into a thread-local interner to keep the
    // size small. It is not safe to access from a different thread. We want
    // errors to be Send and Sync to play nicely with the Failure crate, so pin
    // the span we're given to its original thread and assume it is
    // Span::call_site if accessed from any other thread.
    start_span: ThreadBound<Span>,
    end_span: ThreadBound<Span>,
    message: String,
}

#[cfg(test)]
struct _Test
where
    Error: Send + Sync;

impl Error {
    /// Usually the [`ParseStream::error`] method will be used instead, which
    /// automatically uses the correct span from the current position of the
    /// parse stream.
    ///
    /// Use `Error::new` when the error needs to be triggered on some span other
    /// than where the parse stream is currently positioned.
    ///
    /// [`ParseStream::error`]: crate::parse::ParseBuffer::error
    ///
    /// # Example
    ///
    /// ```
    /// use syn::{Error, Ident, LitStr, Result, Token};
    /// use syn::parse::ParseStream;
    ///
    /// // Parses input that looks like `name = "string"` where the key must be
    /// // the identifier `name` and the value may be any string literal.
    /// // Returns the string literal.
    /// fn parse_name(input: ParseStream) -> Result<LitStr> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         // Trigger an error not on the current position of the stream,
    ///         // but on the position of the unexpected identifier.
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let s: LitStr = input.parse()?;
    ///     Ok(s)
    /// }
    /// ```
    pub fn new<T: Display>(span: Span, message: T) -> Self {
        Error {
            messages: vec![ErrorMessage {
                start_span: ThreadBound::new(span),
                end_span: ThreadBound::new(span),
                message: message.to_string(),
            }],
        }
    }

    /// Creates an error with the specified message spanning the given syntax
    /// tree node.
    ///
    /// Unlike the `Error::new` constructor, this constructor takes an argument
    /// `tokens` which is a syntax tree node. This allows the resulting `Error`
    /// to attempt to span all tokens inside of `tokens`. While you would
    /// typically be able to use the `Spanned` trait with the above `Error::new`
    /// constructor, implementation limitations today mean that
    /// `Error::new_spanned` may provide a higher-quality error message on
    /// stable Rust.
    ///
    /// When in doubt it's recommended to stick to `Error::new` (or
    /// `ParseStream::error`)!
    #[cfg(feature = "printing")]
    pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
        let mut iter = tokens.into_token_stream().into_iter();
        let start = iter.next().map_or_else(Span::call_site, |t| t.span());
        let end = iter.last().map_or(start, |t| t.span());
        Error {
            messages: vec![ErrorMessage {
                start_span: ThreadBound::new(start),
                end_span: ThreadBound::new(end),
                message: message.to_string(),
            }],
        }
    }

    /// The source location of the error.
    ///
    /// Spans are not thread-safe so this function returns `Span::call_site()`
    /// if called from a different thread than the one on which the `Error` was
    /// originally created.
    pub fn span(&self) -> Span {
        let start = match self.messages[0].start_span.get() {
            Some(span) => *span,
            None => return Span::call_site(),
        };
        let end = match self.messages[0].end_span.get() {
            Some(span) => *span,
            None => return Span::call_site(),
        };
        start.join(end).unwrap_or(start)
    }

    /// Render the error as an invocation of [`compile_error!`].
    ///
    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
    /// this method correctly in a procedural macro.
    ///
    /// [`compile_error!`]: std::compile_error!
    pub fn to_compile_error(&self) -> TokenStream {
        self.messages
            .iter()
            .map(ErrorMessage::to_compile_error)
            .collect()
    }

    /// Render the error as an invocation of [`compile_error!`].
    ///
    /// [`compile_error!`]: std::compile_error!
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate proc_macro;
    /// #
    /// use proc_macro::TokenStream;
    /// use syn::{parse_macro_input, DeriveInput, Error};
    ///
    /// # const _: &str = stringify! {
    /// #[proc_macro_derive(MyTrait)]
    /// # };
    /// pub fn derive_my_trait(input: TokenStream) -> TokenStream {
    ///     let input = parse_macro_input!(input as DeriveInput);
    ///     my_trait::expand(input)
    ///         .unwrap_or_else(Error::into_compile_error)
    ///         .into()
    /// }
    ///
    /// mod my_trait {
    ///     use proc_macro2::TokenStream;
    ///     use syn::{DeriveInput, Result};
    ///
    ///     pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> {
    ///         /* ... */
    ///         # unimplemented!()
    ///     }
    /// }
    /// ```
    pub fn into_compile_error(self) -> TokenStream {
        self.to_compile_error()
    }

    /// Add another error message to self such that when `to_compile_error()` is
    /// called, both errors will be emitted together.
    pub fn combine(&mut self, another: Error) {
        self.messages.extend(another.messages)
    }
}

impl ErrorMessage {
    fn to_compile_error(&self) -> TokenStream {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);

        // compile_error!($message)
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("compile_error", start)),
            TokenTree::Punct({
                let mut punct = Punct::new('!', Spacing::Alone);
                punct.set_span(start);
                punct
            }),
            TokenTree::Group({
                let mut group = Group::new(Delimiter::Brace, {
                    TokenStream::from_iter(vec![TokenTree::Literal({
                        let mut string = Literal::string(&self.message);
                        string.set_span(end);
                        string
                    })])
                });
                group.set_span(end);
                group
            }),
        ])
    }
}

#[cfg(feature = "parsing")]
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
    if cursor.eof() {
        Error::new(scope, format!("unexpected end of input, {}", message))
    } else {
        let span = crate::buffer::open_span_of_group(cursor);
        Error::new(span, message)
    }
}

#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
pub fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
    Error {
        messages: vec![ErrorMessage {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: message.to_string(),
        }],
    }
}

impl Debug for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        if self.messages.len() == 1 {
            formatter
                .debug_tuple("Error")
                .field(&self.messages[0])
                .finish()
        } else {
            formatter
                .debug_tuple("Error")
                .field(&self.messages)
                .finish()
        }
    }
}

impl Debug for ErrorMessage {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.message, formatter)
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&self.messages[0].message)
    }
}

impl Clone for Error {
    fn clone(&self) -> Self {
        Error {
            messages: self.messages.clone(),
        }
    }
}

impl Clone for ErrorMessage {
    fn clone(&self) -> Self {
        let start = self
            .start_span
            .get()
            .cloned()
            .unwrap_or_else(Span::call_site);
        let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
        ErrorMessage {
            start_span: ThreadBound::new(start),
            end_span: ThreadBound::new(end),
            message: self.message.clone(),
        }
    }
}

impl std::error::Error for Error {}

impl From<LexError> for Error {
    fn from(err: LexError) -> Self {
        Error::new(Span::call_site(), format!("{:?}", err))
    }
}

impl IntoIterator for Error {
    type Item = Error;
    type IntoIter = IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            messages: self.messages.into_iter(),
        }
    }
}

pub struct IntoIter {
    messages: vec::IntoIter<ErrorMessage>,
}

impl Iterator for IntoIter {
    type Item = Error;

    fn next(&mut self) -> Option<Self::Item> {
        Some(Error {
            messages: vec![self.messages.next()?],
        })
    }
}

impl<'a> IntoIterator for &'a Error {
    type Item = Error;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            messages: self.messages.iter(),
        }
    }
}

pub struct Iter<'a> {
    messages: slice::Iter<'a, ErrorMessage>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Error;

    fn next(&mut self) -> Option<Self::Item> {
        Some(Error {
            messages: vec![self.messages.next()?.clone()],
        })
    }
}

impl Extend<Error> for Error {
    fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
        for err in iter {
            self.combine(err);
        }
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use std::f64::consts::PI;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;
use rpsrtsrs::client::*;

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).samples(8).build().unwrap();

    // Create a new game and run it.
    let mut app = App::new(GlGraphics::new(opengl));
    let world_state = app.world_state.clone();
    let commands = app.commands.clone();
    let mut network_client = NetworkClient::new(("127.0.0.1", 8080), world_state.clone(), commands);

    network_client.connect();
    network_client.update();

    let mut cursor = [0.0,0.0];

    let mut events = Events::new(EventSettings::new());
    while let Some(e) = events.next(&mut window) {

        let world_lock = world_state.lock().unwrap();
        //app.units = vec![];
        if let Some(player) = world_lock.game.players.get(0) {
            for unit in player.units.iter() {
                app.units.get_mut(unit.id.0 as usize)
                    .map(|app_unit| app_unit.position = unit.position)
                    .or_else(|| {
                        app.units.push(Unit::new(unit.position.clone(), 0.0f64));
                        None
                    }
                    );
            }
        }

        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<commit_msg>Remove unused PI constant<commit_after>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;
use rpsrtsrs::client::*;

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).samples(8).build().unwrap();

    // Create a new game and run it.
    let mut app = App::new(GlGraphics::new(opengl));
    let world_state = app.world_state.clone();
    let commands = app.commands.clone();
    let mut network_client = NetworkClient::new(("127.0.0.1", 8080), world_state.clone(), commands);

    network_client.connect();
    network_client.update();

    let mut cursor = [0.0,0.0];

    let mut events = Events::new(EventSettings::new());
    while let Some(e) = events.next(&mut window) {

        let world_lock = world_state.lock().unwrap();
        //app.units = vec![];
        if let Some(player) = world_lock.game.players.get(0) {
            for unit in player.units.iter() {
                app.units.get_mut(unit.id.0 as usize)
                    .map(|app_unit| app_unit.position = unit.position)
                    .or_else(|| {
                        app.units.push(Unit::new(unit.position.clone(), 0.0f64));
                        None
                    }
                    );
            }
        }

        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<|endoftext|>


<commit_before>use super::{Result, Response, DropboxClient, ApiError};
use std::default::Default;
use std::io;
use std::fmt;
use std::collections::BTreeMap;
use rustc_serialize::json;

use structs::{FolderList, Metadata, FileMetadata, NewFolder};

/// Instructs dropbox what to do when a conflict happens during upload
#[derive(Debug, PartialEq, Clone)]
pub enum WriteMode {
    Add,
    Overwrite,
    Update,
}

impl fmt::Display for WriteMode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WriteMode::Add => write!(f, "add"),
            WriteMode::Overwrite => write!(f, "overwrite"),
            WriteMode::Update => write!(f, "update"),
        }
    }
}

/// Optional arguments to the `upload` API call
#[derive(Debug, PartialEq, Clone)]
pub struct UploadOptions {
    pub mode: WriteMode,
    pub autorename: bool,
    pub client_modified: Option<String>,
    pub mute: bool,
}

impl Default for UploadOptions {
    fn default() -> UploadOptions {
        UploadOptions {
            mode: WriteMode::Add,
            autorename: false,
            client_modified: None,
            mute: false,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum ThumbnailFormat {
    Jpeg,
    Png,
    Gif,
}

#[derive(Debug, PartialEq, Clone)]
pub enum ThumbnailSize {
    W16H16,
    W32H32,
    W64H64,
    Other(usize, usize),
}

#[derive(Debug, PartialEq, Clone)]
pub struct ThumbnailOptions {
    format: ThumbnailFormat,
    size: ThumbnailSize,
}

impl Default for ThumbnailOptions {
    fn default() -> ThumbnailOptions {
        ThumbnailOptions {
            format: ThumbnailFormat::Jpeg,
            size: ThumbnailSize::W64H64,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct GetCursorOptions {
    recursive: bool,
    include_media_info: bool,
    include_deleted: bool,
}

impl Default for GetCursorOptions {
    fn default() -> GetCursorOptions {
        GetCursorOptions {
            recursive: false,
            include_media_info: false,
            include_deleted: false,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct FolderListLongpoll {
    changes: bool,
    backoff: Option<bool>,
}

#[derive(Debug, PartialEq, Clone)]
pub struct ListRevisions {
    is_deleted: bool,
    entries: Vec<Metadata>,
}

#[derive(Debug, PartialEq, Clone)]
pub enum SearchMode {
    Filename,
    FilenameAndContent,
    DeletedFilename,
}

#[derive(Debug, PartialEq, Clone)]
pub struct SearchOptions {
    start: usize,
    max_results: usize,
    mode: SearchMode,
}

impl Default for SearchOptions {
    fn default() -> SearchOptions {
        SearchOptions {
            start: 0,
            max_results: 100,
            mode: SearchMode::Filename,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum SearchMatchType {
    Filename(String),
    Content(String),
    Both(String),
}

#[derive(Debug, PartialEq, Clone)]
pub struct SearchMatch {
    match_type: SearchMatchType,
    metadata: Metadata,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Search {
    matches: Vec<SearchMatch>,
    more: bool,
    start: usize,
}

#[derive(Debug, PartialEq, Clone)]
pub struct CommitInfo {
    path: String,
    mode: WriteMode,
    autorename: bool,
    client_modified: String,
    mute: bool,
}

#[derive(Debug, PartialEq, Clone)]
pub struct UploadSessionCursor {
    session_id: String,
    offset: usize,
}

// Functions

/// Copy a file
///
/// # Example
///
/// ```ignore
/// use std::env;
/// use dbox::client::Client;
/// use dbox::files;
///
/// let client = Client::new(env::var("DROPBOX_TOKEN"));
/// let metadata = try!(files::copy_(&client, "/Path/to/existing/file", "/Path/to/new/file"));
/// ```
pub fn copy_<T>(client: &T, from: &str, to: &str) -> Result<Metadata>
                where T: DropboxClient
{
    let mut map = BTreeMap::new();
    map.insert("from_path".to_string(), json::Json::String(from.to_string()));
    map.insert("to_path".to_string(), json::Json::String(to.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    let resp = try!(client.api("files/copy", &mut headers, Some(&map)));
    json::decode(&resp.body).map_err(|e| ApiError::from(e))
}

/// Create a folder
///
/// # Example
///
/// ```ignore
/// use std::env;
/// use dbox::client::Client;
/// use dbox::files;
///
/// let client = Client::new(env::var("DROPBOX_TOKEN"));
/// let metadata = try!(files::create_folder(&client, "/Path/to/new/folder"));
/// ```
pub fn create_folder<T>(client: &T, path: &str) -> Result<NewFolder>
                where T: DropboxClient
{
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    let resp = try!(client.api("files/create_folder", &mut headers, Some(map)));
    {
        println!("create folder: {:?}", &resp.body);
    }
    json::decode(&resp.body).map_err(|e| ApiError::from(e))
}

/// TODO implement
pub fn delete<T: DropboxClient>(client: &T, path: &str) -> Result<Metadata> {
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    let resp = try!(client.api("files/delete", &mut headers, Some(map)));
    json::decode(&resp.body).map_err(|e| ApiError::from(e))
}

/// Download a file
///
/// # Example
///
/// ```ignore
/// use std::env;
/// use dbox::client::Client;
/// use dbox::files;
///
/// let token = env::var("DROPBOX_TOKEN");
/// let client = Client::new(token);
/// let (metadata, response) = try!(files::download(&client, "/Path/to/file"));
/// ```
pub fn download<T: DropboxClient>(client: &T, path: &str) -> Result<(FileMetadata, Response)> {
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Dropbox-API-Arg".to_string(), json::encode(&map).unwrap());
    let resp = try!(client.content("files/download", &mut headers, None::<&str>));
    let metadata: FileMetadata = match resp.api_result {
        Some(ref data) => {
            try!(json::decode(data))
        },
        None => return Err(ApiError::ClientError)
    };
    Ok((
        metadata,
        resp,
    ))
}

/// TODO implement
pub fn download_to_file<T>(client: &T, dest_path: &str, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

/// TODO implement
pub fn get_metadata<T>(client: &T, path: &str, include_media_info: bool) -> Result<Metadata>
                where T: DropboxClient
{
    Ok(Default::default())
}

/// TODO implement
pub fn get_preview<T>(client: &T, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

/// TODO implement
pub fn get_preview_to_file<T>(client: &T, dest_path: &str, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

pub fn get_thumbnail<T>(client: &T, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    get_thumbnail_with_options(client, path, Default::default())
}

/// TODO implement
pub fn get_thumbnail_with_options<T>(client: &T, path: &str, options: ThumbnailOptions) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

pub fn get_thumbnail_to_file<T>(client: &T, dest_path: &str, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    get_thumbnail_to_file_with_options(client, dest_path, path, Default::default())
}

/// TODO implement
pub fn get_thumbnail_to_file_with_options<T>(client: &T, dest_path: &str, path: &str, options: ThumbnailOptions) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

/// TODO error handling
pub fn list_folder<T: DropboxClient>(client: &T, path: &str) -> Result<FolderList> {
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    map.insert("recursive".to_string(), json::Json::Boolean(false));
    map.insert("include_media_info".to_string(), json::Json::Boolean(false));
    map.insert("include_deleted".to_string(), json::Json::Boolean(false));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    match client.api("files/list_folder", &mut headers, Some(&map)) {
        Ok(ref resp) => {
            let folderlist: FolderList = json::decode(&resp.body).unwrap();
            Ok(folderlist)
        },
        Err(e) => Err(ApiError::ClientError),
    }
}

/// TODO implement
pub fn list_folder_continue<T>(client: &T, cursor: &str) -> Result<FolderList>
                where T: DropboxClient
{
    Ok(Default::default())
}

pub fn list_folder_get_latest_cursor<T>(client: &T, path: &str) -> Result<String>
                where T: DropboxClient
{
    list_folder_get_latest_cursor_with_options(client, path, Default::default())
}

/// TODO implement
pub fn list_folder_get_latest_cursor_with_options<T>(client: &T, path: &str, options: GetCursorOptions) -> Result<String>
                where T: DropboxClient
{
    Ok("".to_string())
}

/// TODO implement
pub fn list_folder_longpoll<T>(client: &T, cursor: &str, timeout: usize) -> Result<FolderListLongpoll>
                where T: DropboxClient
{
    Ok(FolderListLongpoll {
        changes: false,
        backoff: None,
    })
}

/// TODO implement
pub fn list_revisions<T>(client: &T, path: &str, limit: usize) -> Result<ListRevisions>
                where T: DropboxClient
{
    Ok(ListRevisions {
        is_deleted: false,
        entries: vec![],
    })
}

/// TODO implement
pub fn move_<T>(client: &T, from: &str, to: &str) -> Result<Metadata>
                where T: DropboxClient
{
    Ok(Default::default())
}

/// TODO implement
pub fn permanently_delete<T>(client: &T, path: &str) -> Result<()>
                where T: DropboxClient
{
    Ok(())
}

/// TODO implement
pub fn restore<T>(client: &T, path: &str, rev: &str) -> Result<Metadata>
                where T: DropboxClient
{
    Ok(Default::default())
}

pub fn search<T>(client: &T, path: &str, query: &str) -> Result<Search>
                where T: DropboxClient
{
    search_with_options(client, path, query, Default::default())
}

/// TODO implement
pub fn search_with_options<T>(client: &T, path: &str, query: &str, options: SearchOptions) -> Result<Search>
                where T: DropboxClient
{
    Ok(Search {
        matches: vec![],
        more: false,
        start: 0,
    })
}

pub fn upload<T>(client: &T, contents: &str, path: &str) -> Result<Metadata>
                where T: DropboxClient
{
    upload_with_options(client, contents, path, Default::default())
}

/// TODO implement
pub fn upload_with_options<T>(client: &T, contents: &str, path: &str, options: UploadOptions) -> Result<Metadata>
                where T: DropboxClient
{
    let mut map = BTreeMap::new();
    map.insert("path", json::Json::String(path.to_string()));
    map.insert("mode", json::Json::String(format!("{}", options.mode)));
    map.insert("autorename", json::Json::Boolean(options.autorename));
    map.insert("mute", json::Json::Boolean(options.mute));
    let mut headers = BTreeMap::new();
    headers.insert("Dropbox-API-Arg".to_string(), json::encode(&map).unwrap());
    headers.insert("Content-Type".to_string(), "application/octet-stream".to_string());
    let resp = client.content("files/upload", &mut headers, Some(contents.to_owned()));
    Ok(Default::default())
}

/// TODO implement
pub fn upload_session_append<T, U>(client: &T, f: U, session_id: &str, offset: usize) -> Result<()>
                where T: DropboxClient, U: io::Read
{
    Ok(())
}

/// TODO implement
pub fn upload_session_finish<T, U>(client: &T, f: U, cursor: &UploadSessionCursor, commit: &CommitInfo) -> Result<Metadata>
                where T: DropboxClient,
                      U: io::Read
{
    Ok(Default::default())
}

/// TODO implement
pub fn upload_session_start<T, U>(client: &T, f: U) -> Result<String>
                where T: DropboxClient,
                      U: io::Read
{
    Ok("".to_string())
}
<commit_msg>remove stray println<commit_after>use super::{Result, Response, DropboxClient, ApiError};
use std::default::Default;
use std::io;
use std::fmt;
use std::collections::BTreeMap;
use rustc_serialize::json;

use structs::{FolderList, Metadata, FileMetadata, NewFolder};

/// Instructs dropbox what to do when a conflict happens during upload
#[derive(Debug, PartialEq, Clone)]
pub enum WriteMode {
    Add,
    Overwrite,
    Update,
}

impl fmt::Display for WriteMode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WriteMode::Add => write!(f, "add"),
            WriteMode::Overwrite => write!(f, "overwrite"),
            WriteMode::Update => write!(f, "update"),
        }
    }
}

/// Optional arguments to the `upload` API call
#[derive(Debug, PartialEq, Clone)]
pub struct UploadOptions {
    pub mode: WriteMode,
    pub autorename: bool,
    pub client_modified: Option<String>,
    pub mute: bool,
}

impl Default for UploadOptions {
    fn default() -> UploadOptions {
        UploadOptions {
            mode: WriteMode::Add,
            autorename: false,
            client_modified: None,
            mute: false,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum ThumbnailFormat {
    Jpeg,
    Png,
    Gif,
}

#[derive(Debug, PartialEq, Clone)]
pub enum ThumbnailSize {
    W16H16,
    W32H32,
    W64H64,
    Other(usize, usize),
}

#[derive(Debug, PartialEq, Clone)]
pub struct ThumbnailOptions {
    format: ThumbnailFormat,
    size: ThumbnailSize,
}

impl Default for ThumbnailOptions {
    fn default() -> ThumbnailOptions {
        ThumbnailOptions {
            format: ThumbnailFormat::Jpeg,
            size: ThumbnailSize::W64H64,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct GetCursorOptions {
    recursive: bool,
    include_media_info: bool,
    include_deleted: bool,
}

impl Default for GetCursorOptions {
    fn default() -> GetCursorOptions {
        GetCursorOptions {
            recursive: false,
            include_media_info: false,
            include_deleted: false,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct FolderListLongpoll {
    changes: bool,
    backoff: Option<bool>,
}

#[derive(Debug, PartialEq, Clone)]
pub struct ListRevisions {
    is_deleted: bool,
    entries: Vec<Metadata>,
}

#[derive(Debug, PartialEq, Clone)]
pub enum SearchMode {
    Filename,
    FilenameAndContent,
    DeletedFilename,
}

#[derive(Debug, PartialEq, Clone)]
pub struct SearchOptions {
    start: usize,
    max_results: usize,
    mode: SearchMode,
}

impl Default for SearchOptions {
    fn default() -> SearchOptions {
        SearchOptions {
            start: 0,
            max_results: 100,
            mode: SearchMode::Filename,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum SearchMatchType {
    Filename(String),
    Content(String),
    Both(String),
}

#[derive(Debug, PartialEq, Clone)]
pub struct SearchMatch {
    match_type: SearchMatchType,
    metadata: Metadata,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Search {
    matches: Vec<SearchMatch>,
    more: bool,
    start: usize,
}

#[derive(Debug, PartialEq, Clone)]
pub struct CommitInfo {
    path: String,
    mode: WriteMode,
    autorename: bool,
    client_modified: String,
    mute: bool,
}

#[derive(Debug, PartialEq, Clone)]
pub struct UploadSessionCursor {
    session_id: String,
    offset: usize,
}

// Functions

/// Copy a file
///
/// # Example
///
/// ```ignore
/// use std::env;
/// use dbox::client::Client;
/// use dbox::files;
///
/// let client = Client::new(env::var("DROPBOX_TOKEN"));
/// let metadata = try!(files::copy_(&client, "/Path/to/existing/file", "/Path/to/new/file"));
/// ```
pub fn copy_<T>(client: &T, from: &str, to: &str) -> Result<Metadata>
                where T: DropboxClient
{
    let mut map = BTreeMap::new();
    map.insert("from_path".to_string(), json::Json::String(from.to_string()));
    map.insert("to_path".to_string(), json::Json::String(to.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    let resp = try!(client.api("files/copy", &mut headers, Some(&map)));
    json::decode(&resp.body).map_err(|e| ApiError::from(e))
}

/// Create a folder
///
/// # Example
///
/// ```ignore
/// use std::env;
/// use dbox::client::Client;
/// use dbox::files;
///
/// let client = Client::new(env::var("DROPBOX_TOKEN"));
/// let metadata = try!(files::create_folder(&client, "/Path/to/new/folder"));
/// ```
pub fn create_folder<T>(client: &T, path: &str) -> Result<NewFolder>
                where T: DropboxClient
{
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    let resp = try!(client.api("files/create_folder", &mut headers, Some(map)));
    json::decode(&resp.body).map_err(|e| ApiError::from(e))
}

/// TODO implement
pub fn delete<T: DropboxClient>(client: &T, path: &str) -> Result<Metadata> {
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    let resp = try!(client.api("files/delete", &mut headers, Some(map)));
    json::decode(&resp.body).map_err(|e| ApiError::from(e))
}

/// Download a file
///
/// # Example
///
/// ```ignore
/// use std::env;
/// use dbox::client::Client;
/// use dbox::files;
///
/// let token = env::var("DROPBOX_TOKEN");
/// let client = Client::new(token);
/// let (metadata, response) = try!(files::download(&client, "/Path/to/file"));
/// ```
pub fn download<T: DropboxClient>(client: &T, path: &str) -> Result<(FileMetadata, Response)> {
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    let mut headers = BTreeMap::new();
    headers.insert("Dropbox-API-Arg".to_string(), json::encode(&map).unwrap());
    let resp = try!(client.content("files/download", &mut headers, None::<&str>));
    let metadata: FileMetadata = match resp.api_result {
        Some(ref data) => {
            try!(json::decode(data))
        },
        None => return Err(ApiError::ClientError)
    };
    Ok((
        metadata,
        resp,
    ))
}

/// TODO implement
pub fn download_to_file<T>(client: &T, dest_path: &str, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

/// TODO implement
pub fn get_metadata<T>(client: &T, path: &str, include_media_info: bool) -> Result<Metadata>
                where T: DropboxClient
{
    Ok(Default::default())
}

/// TODO implement
pub fn get_preview<T>(client: &T, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

/// TODO implement
pub fn get_preview_to_file<T>(client: &T, dest_path: &str, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

pub fn get_thumbnail<T>(client: &T, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    get_thumbnail_with_options(client, path, Default::default())
}

/// TODO implement
pub fn get_thumbnail_with_options<T>(client: &T, path: &str, options: ThumbnailOptions) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

pub fn get_thumbnail_to_file<T>(client: &T, dest_path: &str, path: &str) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    get_thumbnail_to_file_with_options(client, dest_path, path, Default::default())
}

/// TODO implement
pub fn get_thumbnail_to_file_with_options<T>(client: &T, dest_path: &str, path: &str, options: ThumbnailOptions) -> Result<(Metadata, Response)>
                where T: DropboxClient
{
    Ok((
        Default::default(),
        Response {
            status: 200,
            api_result: None,
            body: "".to_string(),
        },
    ))
}

/// TODO error handling
pub fn list_folder<T: DropboxClient>(client: &T, path: &str) -> Result<FolderList> {
    let mut map = BTreeMap::new();
    map.insert("path".to_string(), json::Json::String(path.to_string()));
    map.insert("recursive".to_string(), json::Json::Boolean(false));
    map.insert("include_media_info".to_string(), json::Json::Boolean(false));
    map.insert("include_deleted".to_string(), json::Json::Boolean(false));
    let mut headers = BTreeMap::new();
    headers.insert("Content-Type".to_string(), "application/json".to_string());
    match client.api("files/list_folder", &mut headers, Some(&map)) {
        Ok(ref resp) => {
            let folderlist: FolderList = json::decode(&resp.body).unwrap();
            Ok(folderlist)
        },
        Err(e) => Err(ApiError::ClientError),
    }
}

/// TODO implement
pub fn list_folder_continue<T>(client: &T, cursor: &str) -> Result<FolderList>
                where T: DropboxClient
{
    Ok(Default::default())
}

pub fn list_folder_get_latest_cursor<T>(client: &T, path: &str) -> Result<String>
                where T: DropboxClient
{
    list_folder_get_latest_cursor_with_options(client, path, Default::default())
}

/// TODO implement
pub fn list_folder_get_latest_cursor_with_options<T>(client: &T, path: &str, options: GetCursorOptions) -> Result<String>
                where T: DropboxClient
{
    Ok("".to_string())
}

/// TODO implement
pub fn list_folder_longpoll<T>(client: &T, cursor: &str, timeout: usize) -> Result<FolderListLongpoll>
                where T: DropboxClient
{
    Ok(FolderListLongpoll {
        changes: false,
        backoff: None,
    })
}

/// TODO implement
pub fn list_revisions<T>(client: &T, path: &str, limit: usize) -> Result<ListRevisions>
                where T: DropboxClient
{
    Ok(ListRevisions {
        is_deleted: false,
        entries: vec![],
    })
}

/// TODO implement
pub fn move_<T>(client: &T, from: &str, to: &str) -> Result<Metadata>
                where T: DropboxClient
{
    Ok(Default::default())
}

/// TODO implement
pub fn permanently_delete<T>(client: &T, path: &str) -> Result<()>
                where T: DropboxClient
{
    Ok(())
}

/// TODO implement
pub fn restore<T>(client: &T, path: &str, rev: &str) -> Result<Metadata>
                where T: DropboxClient
{
    Ok(Default::default())
}

pub fn search<T>(client: &T, path: &str, query: &str) -> Result<Search>
                where T: DropboxClient
{
    search_with_options(client, path, query, Default::default())
}

/// TODO implement
pub fn search_with_options<T>(client: &T, path: &str, query: &str, options: SearchOptions) -> Result<Search>
                where T: DropboxClient
{
    Ok(Search {
        matches: vec![],
        more: false,
        start: 0,
    })
}

pub fn upload<T>(client: &T, contents: &str, path: &str) -> Result<Metadata>
                where T: DropboxClient
{
    upload_with_options(client, contents, path, Default::default())
}

/// TODO implement
pub fn upload_with_options<T>(client: &T, contents: &str, path: &str, options: UploadOptions) -> Result<Metadata>
                where T: DropboxClient
{
    let mut map = BTreeMap::new();
    map.insert("path", json::Json::String(path.to_string()));
    map.insert("mode", json::Json::String(format!("{}", options.mode)));
    map.insert("autorename", json::Json::Boolean(options.autorename));
    map.insert("mute", json::Json::Boolean(options.mute));
    let mut headers = BTreeMap::new();
    headers.insert("Dropbox-API-Arg".to_string(), json::encode(&map).unwrap());
    headers.insert("Content-Type".to_string(), "application/octet-stream".to_string());
    let resp = client.content("files/upload", &mut headers, Some(contents.to_owned()));
    Ok(Default::default())
}

/// TODO implement
pub fn upload_session_append<T, U>(client: &T, f: U, session_id: &str, offset: usize) -> Result<()>
                where T: DropboxClient, U: io::Read
{
    Ok(())
}

/// TODO implement
pub fn upload_session_finish<T, U>(client: &T, f: U, cursor: &UploadSessionCursor, commit: &CommitInfo) -> Result<Metadata>
                where T: DropboxClient,
                      U: io::Read
{
    Ok(Default::default())
}

/// TODO implement
pub fn upload_session_start<T, U>(client: &T, f: U) -> Result<String>
                where T: DropboxClient,
                      U: io::Read
{
    Ok("".to_string())
}
<|endoftext|>