<commit_before>//! JSON Errors
//!
//! This module is centered around the `Error` and `ErrorCode` types, which represents all possible
//! `serde_json` errors.

use std::error;
use std::fmt;
use std::io;
use std::result;
use std::string::FromUtf8Error;

use serde::de;
use serde::ser;

/// The errors that can arise while parsing a JSON stream.
#[derive(Clone, PartialEq)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Custom(String),

    /// Incorrect type from value
    InvalidType(de::Type),

    /// Incorrect value
    InvalidValue(String),

    /// Invalid length
    InvalidLength(usize),

    /// Unknown variant in an enum.
    UnknownVariant(String),

    /// Unknown field in struct.
    UnknownField(String),

    /// Struct is missing a field.
    MissingField(&'static str),

    /// EOF while parsing a list.
    EOFWhileParsingList,

    /// EOF while parsing an object.
    EOFWhileParsingObject,

    /// EOF while parsing a string.
    EOFWhileParsingString,

    /// EOF while parsing a JSON value.
    EOFWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `]`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `}`.
    ExpectedObjectCommaOrEnd,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,
}

impl fmt::Debug for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Debug;

        match *self {
            ErrorCode::Custom(ref msg) => write!(f, "{}", msg),
            ErrorCode::InvalidType(ref ty) => write!(f, "invalid type: {:?}", ty),
            ErrorCode::InvalidValue(ref msg) => write!(f, "invalid value: {}", msg),
            ErrorCode::InvalidLength(ref len) => write!(f, "invalid value length {}", len),
            ErrorCode::UnknownVariant(ref variant) => write!(f, "unknown variant \"{}\"", variant),
            ErrorCode::UnknownField(ref field) => write!(f, "unknown field \"{}\"", field),
            ErrorCode::MissingField(ref field) => write!(f, "missing field \"{}\"", field),
            ErrorCode::EOFWhileParsingList => "EOF while parsing a list".fmt(f),
            ErrorCode::EOFWhileParsingObject => "EOF while parsing an object".fmt(f),
            ErrorCode::EOFWhileParsingString => "EOF while parsing a string".fmt(f),
            ErrorCode::EOFWhileParsingValue => "EOF while parsing a value".fmt(f),
            ErrorCode::ExpectedColon => "expected `:`".fmt(f),
            ErrorCode::ExpectedListCommaOrEnd => "expected `,` or `]`".fmt(f),
            ErrorCode::ExpectedObjectCommaOrEnd => "expected `,` or `}`".fmt(f),
            ErrorCode::ExpectedSomeIdent => "expected ident".fmt(f),
            ErrorCode::ExpectedSomeValue => "expected value".fmt(f),
            ErrorCode::InvalidEscape => "invalid escape".fmt(f),
            ErrorCode::InvalidNumber => "invalid number".fmt(f),
            ErrorCode::InvalidUnicodeCodePoint => "invalid unicode code point".fmt(f),
            ErrorCode::KeyMustBeAString => "key must be a string".fmt(f),
            ErrorCode::LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape".fmt(f),
            ErrorCode::TrailingCharacters => "trailing characters".fmt(f),
            ErrorCode::UnexpectedEndOfHexEscape => "unexpected end of hex escape".fmt(f),
        }
    }
}

/// This type represents all possible errors that can occur when serializing or deserializing a
/// value into JSON.
#[derive(Debug)]
pub enum Error {
    /// The JSON value had some syntatic error.
    Syntax(ErrorCode, usize, usize),

    /// Some IO error occurred when serializing or deserializing a value.
    Io(io::Error),

    /// Some UTF8 error occurred while serializing or deserializing a value.
    FromUtf8(FromUtf8Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Syntax(..) => "syntax error",
            Error::Io(ref error) => error::Error::description(error),
            Error::FromUtf8(ref error) => error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref error) => Some(error),
            Error::FromUtf8(ref error) => Some(error),
            _ => None,
        }
    }

}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Syntax(ref code, line, col) => {
                write!(fmt, "{:?} at line {} column {}", code, line, col)
            }
            Error::Io(ref error) => fmt::Display::fmt(error, fmt),
            Error::FromUtf8(ref error) => fmt::Display::fmt(error, fmt),
        }
    }
}

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

impl From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Error {
        Error::FromUtf8(error)
    }
}

impl From<de::value::Error> for Error {
    fn from(error: de::value::Error) -> Error {
        match error {
            de::value::Error::Custom(e) => {
                Error::Syntax(ErrorCode::Custom(e), 0, 0)
            }
            de::value::Error::EndOfStream => {
                de::Error::end_of_stream()
            }
            de::value::Error::InvalidType(ty) => {
                Error::Syntax(ErrorCode::InvalidType(ty), 0, 0)
            }
            de::value::Error::InvalidValue(msg) => {
                Error::Syntax(ErrorCode::InvalidValue(msg), 0, 0)
            }
            de::value::Error::InvalidLength(len) => {
                Error::Syntax(ErrorCode::InvalidLength(len), 0, 0)
            }
            de::value::Error::UnknownVariant(variant) => {
                Error::Syntax(ErrorCode::UnknownVariant(variant), 0, 0)
            }
            de::value::Error::UnknownField(field) => {
                Error::Syntax(ErrorCode::UnknownField(field), 0, 0)
            }
            de::value::Error::MissingField(field) => {
                Error::Syntax(ErrorCode::MissingField(field), 0, 0)
            }
        }
    }
}

impl de::Error for Error {
    fn custom<T: Into<String>>(msg: T) -> Error {
        Error::Syntax(ErrorCode::Custom(msg.into()), 0, 0)
    }

    fn end_of_stream() -> Error {
        Error::Syntax(ErrorCode::EOFWhileParsingValue, 0, 0)
    }

    fn invalid_type(ty: de::Type) -> Error {
        Error::Syntax(ErrorCode::InvalidType(ty), 0, 0)
    }

    fn invalid_value(msg: &str) -> Error {
        Error::Syntax(ErrorCode::InvalidValue(msg.to_owned()), 0, 0)
    }

    fn invalid_length(len: usize) -> Error {
        Error::Syntax(ErrorCode::InvalidLength(len), 0, 0)
    }

    fn unknown_variant(variant: &str) -> Error {
        Error::Syntax(ErrorCode::UnknownVariant(String::from(variant)), 0, 0)
    }

    fn unknown_field(field: &str) -> Error {
        Error::Syntax(ErrorCode::UnknownField(String::from(field)), 0, 0)
    }

    fn missing_field(field: &'static str) -> Error {
        Error::Syntax(ErrorCode::MissingField(field), 0, 0)
    }
}

impl ser::Error for Error {
    /// Raised when there is general error when deserializing a type.
    fn custom<T: Into<String>>(msg: T) -> Error {
        Error::Syntax(ErrorCode::Custom(msg.into()), 0, 0)
    }
}

/// Helper alias for `Result` objects that return a JSON `Error`.
pub type Result<T> = result::Result<T, Error>;
<commit_msg>Auto merge of #75 - erickt:fix-warning, r=erickt<commit_after>//! JSON Errors
//!
//! This module is centered around the `Error` and `ErrorCode` types, which represents all possible
//! `serde_json` errors.

use std::error;
use std::fmt;
use std::io;
use std::result;
use std::string::FromUtf8Error;

use serde::de;
use serde::ser;

/// The errors that can arise while parsing a JSON stream.
#[derive(Clone, PartialEq)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Custom(String),

    /// Incorrect type from value
    InvalidType(de::Type),

    /// Incorrect value
    InvalidValue(String),

    /// Invalid length
    InvalidLength(usize),

    /// Unknown variant in an enum.
    UnknownVariant(String),

    /// Unknown field in struct.
    UnknownField(String),

    /// Struct is missing a field.
    MissingField(&'static str),

    /// EOF while parsing a list.
    EOFWhileParsingList,

    /// EOF while parsing an object.
    EOFWhileParsingObject,

    /// EOF while parsing a string.
    EOFWhileParsingString,

    /// EOF while parsing a JSON value.
    EOFWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `]`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `}`.
    ExpectedObjectCommaOrEnd,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,
}

impl fmt::Debug for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCode::Custom(ref msg) => write!(f, "{}", msg),
            ErrorCode::InvalidType(ref ty) => write!(f, "invalid type: {:?}", ty),
            ErrorCode::InvalidValue(ref msg) => write!(f, "invalid value: {}", msg),
            ErrorCode::InvalidLength(ref len) => write!(f, "invalid value length {}", len),
            ErrorCode::UnknownVariant(ref variant) => write!(f, "unknown variant \"{}\"", variant),
            ErrorCode::UnknownField(ref field) => write!(f, "unknown field \"{}\"", field),
            ErrorCode::MissingField(ref field) => write!(f, "missing field \"{}\"", field),
            ErrorCode::EOFWhileParsingList => "EOF while parsing a list".fmt(f),
            ErrorCode::EOFWhileParsingObject => "EOF while parsing an object".fmt(f),
            ErrorCode::EOFWhileParsingString => "EOF while parsing a string".fmt(f),
            ErrorCode::EOFWhileParsingValue => "EOF while parsing a value".fmt(f),
            ErrorCode::ExpectedColon => "expected `:`".fmt(f),
            ErrorCode::ExpectedListCommaOrEnd => "expected `,` or `]`".fmt(f),
            ErrorCode::ExpectedObjectCommaOrEnd => "expected `,` or `}`".fmt(f),
            ErrorCode::ExpectedSomeIdent => "expected ident".fmt(f),
            ErrorCode::ExpectedSomeValue => "expected value".fmt(f),
            ErrorCode::InvalidEscape => "invalid escape".fmt(f),
            ErrorCode::InvalidNumber => "invalid number".fmt(f),
            ErrorCode::InvalidUnicodeCodePoint => "invalid unicode code point".fmt(f),
            ErrorCode::KeyMustBeAString => "key must be a string".fmt(f),
            ErrorCode::LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape".fmt(f),
            ErrorCode::TrailingCharacters => "trailing characters".fmt(f),
            ErrorCode::UnexpectedEndOfHexEscape => "unexpected end of hex escape".fmt(f),
        }
    }
}

/// This type represents all possible errors that can occur when serializing or deserializing a
/// value into JSON.
#[derive(Debug)]
pub enum Error {
    /// The JSON value had some syntatic error.
    Syntax(ErrorCode, usize, usize),

    /// Some IO error occurred when serializing or deserializing a value.
    Io(io::Error),

    /// Some UTF8 error occurred while serializing or deserializing a value.
    FromUtf8(FromUtf8Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Syntax(..) => "syntax error",
            Error::Io(ref error) => error::Error::description(error),
            Error::FromUtf8(ref error) => error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref error) => Some(error),
            Error::FromUtf8(ref error) => Some(error),
            _ => None,
        }
    }

}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Syntax(ref code, line, col) => {
                write!(fmt, "{:?} at line {} column {}", code, line, col)
            }
            Error::Io(ref error) => fmt::Display::fmt(error, fmt),
            Error::FromUtf8(ref error) => fmt::Display::fmt(error, fmt),
        }
    }
}

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

impl From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Error {
        Error::FromUtf8(error)
    }
}

impl From<de::value::Error> for Error {
    fn from(error: de::value::Error) -> Error {
        match error {
            de::value::Error::Custom(e) => {
                Error::Syntax(ErrorCode::Custom(e), 0, 0)
            }
            de::value::Error::EndOfStream => {
                de::Error::end_of_stream()
            }
            de::value::Error::InvalidType(ty) => {
                Error::Syntax(ErrorCode::InvalidType(ty), 0, 0)
            }
            de::value::Error::InvalidValue(msg) => {
                Error::Syntax(ErrorCode::InvalidValue(msg), 0, 0)
            }
            de::value::Error::InvalidLength(len) => {
                Error::Syntax(ErrorCode::InvalidLength(len), 0, 0)
            }
            de::value::Error::UnknownVariant(variant) => {
                Error::Syntax(ErrorCode::UnknownVariant(variant), 0, 0)
            }
            de::value::Error::UnknownField(field) => {
                Error::Syntax(ErrorCode::UnknownField(field), 0, 0)
            }
            de::value::Error::MissingField(field) => {
                Error::Syntax(ErrorCode::MissingField(field), 0, 0)
            }
        }
    }
}

impl de::Error for Error {
    fn custom<T: Into<String>>(msg: T) -> Error {
        Error::Syntax(ErrorCode::Custom(msg.into()), 0, 0)
    }

    fn end_of_stream() -> Error {
        Error::Syntax(ErrorCode::EOFWhileParsingValue, 0, 0)
    }

    fn invalid_type(ty: de::Type) -> Error {
        Error::Syntax(ErrorCode::InvalidType(ty), 0, 0)
    }

    fn invalid_value(msg: &str) -> Error {
        Error::Syntax(ErrorCode::InvalidValue(msg.to_owned()), 0, 0)
    }

    fn invalid_length(len: usize) -> Error {
        Error::Syntax(ErrorCode::InvalidLength(len), 0, 0)
    }

    fn unknown_variant(variant: &str) -> Error {
        Error::Syntax(ErrorCode::UnknownVariant(String::from(variant)), 0, 0)
    }

    fn unknown_field(field: &str) -> Error {
        Error::Syntax(ErrorCode::UnknownField(String::from(field)), 0, 0)
    }

    fn missing_field(field: &'static str) -> Error {
        Error::Syntax(ErrorCode::MissingField(field), 0, 0)
    }
}

impl ser::Error for Error {
    /// Raised when there is general error when deserializing a type.
    fn custom<T: Into<String>>(msg: T) -> Error {
        Error::Syntax(ErrorCode::Custom(msg.into()), 0, 0)
    }
}

/// Helper alias for `Result` objects that return a JSON `Error`.
pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>use actions::Action;
use notify::Event;
use std::io::{self, Write};
use std::process::{Command, Stdio};

pub struct CommandAction {
    command_line: String
}

impl CommandAction {
    pub fn new(command_line: String) -> CommandAction {
        CommandAction {
            command_line: command_line
        }
    }
}

impl Action for CommandAction {
    fn handle_change(&self, _event: &Event) {
        let mut cmd_pieces = self.command_line.split(" ");
        let mut command = Command::new(cmd_pieces.next().unwrap());
        for piece in cmd_pieces {
            command.arg(piece);
        }

        let command_result = command
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .output();

        if command_result.is_err() {
            println!("Could not execute command: {:?}", self.command_line);
            return;
        }

        let output = command_result.expect("Error: could not get output");
        println!("{}", String::from_utf8_lossy(&output.stdout));

        if !output.stderr.is_empty() {
            let write_result = writeln!(
                &mut io::stderr(),
                "{}",
                String::from_utf8_lossy(&output.stderr)
            );
            match write_result {
                Err(x) => println!("Error: Unable to write to stderr: {}", x),
                Ok(_) => {}
            }
        }

    }
}
<commit_msg>Remove unstable .expect() call<commit_after>use actions::Action;
use notify::Event;
use std::io::{self, Write};
use std::process::{Command, Stdio};

pub struct CommandAction {
    command_line: String
}

impl CommandAction {
    pub fn new(command_line: String) -> CommandAction {
        CommandAction {
            command_line: command_line
        }
    }
}

impl Action for CommandAction {
    fn handle_change(&self, _event: &Event) {
        let mut cmd_pieces = self.command_line.split(" ");
        let mut command = Command::new(cmd_pieces.next().unwrap());
        for piece in cmd_pieces {
            command.arg(piece);
        }

        let command_result = command
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .output();

        if command_result.is_err() {
            println!("Could not execute command: {:?}", self.command_line);
            return;
        }

        let output = command_result.unwrap();
        println!("{}", String::from_utf8_lossy(&output.stdout));

        if !output.stderr.is_empty() {
            let write_result = writeln!(
                &mut io::stderr(),
                "{}",
                String::from_utf8_lossy(&output.stderr)
            );
            match write_result {
                Err(x) => println!("Error: Unable to write to stderr: {}", x),
                Ok(_) => {}
            }
        }

    }
}
<|endoftext|>


<commit_before>/// Asserts that the traits are [object-safe][object].
///
/// This is useful for when changes are made to a trait that accidentally
/// prevent it from being used as an [object]. Such a case would be adding a
/// generic method and forgetting to add `where Self: Sized` after it. If left
/// unnoticed, that mistake will affect crate users and break both forward and
/// backward compatibility.
///
/// # Examples
///
/// When exposing a public API, it's important that traits that could previously
/// use dynamic dispatch can still do so in future compatible crate versions.
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// // Requires a unique label in module scope
/// assert_obj_safe!(basic; Send, Sync, AsRef<str>);
///
/// mod inner {
///     // Works with traits that are not in the calling module
///     pub trait BasicTrait {
///         fn foo(&self);
///     }
/// }
///
/// trait MySafeTrait {
///     fn bar(&self) -> u32;
/// }
///
/// fn main() {
///     assert_obj_safe!(MySafeTrait);
///     assert_obj_safe!(inner::BasicTrait);
/// }
/// ```
///
/// The [labeling limitation](index.html#limitations) is not necessary if
/// compiling on nightly Rust with the `nightly` feature enabled:
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(underscore_const_names)]
/// # #[macro_use] extern crate static_assertions;
///
/// use std::fmt;
///
/// assert_obj_safe!(fmt::Write);
///
/// fn main() {
///     assert_obj_safe!(fmt::Debug);
/// }
/// ```
///
/// Raw pointers cannot be sent between threads safely:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// assert_impl!(*const u8, Send);
/// # }
/// ```
///
/// Generics without `where Self: Sized` are not allowed in
/// [object-safe][object] trait methods:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// trait MyUnsafeTrait {
///     fn baz<T>(&self) -> T;
/// }
///
/// # fn main() {
/// assert_obj_safe!(MyUnsafeTrait);
/// # }
/// ```
///
/// [object]: https://doc.rust-lang.org/book/2018-edition/ch17-02-trait-objects.html#object-safety-is-required-for-trait-objects
#[macro_export(local_inner_macros)]
macro_rules! assert_obj_safe {
    ($($xs:tt)+) => { _assert_obj_safe!($($xs)+); };
}

#[doc(hidden)]
#[cfg(feature = "nightly")]
#[macro_export(local_inner_macros)]
macro_rules! _assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(const _: Option<&$xs> = None;)+
    };
}

#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
#[macro_export(local_inner_macros)]
macro_rules! _assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(let _: &$xs;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_obj_safe!($($xs)+); }
    };
}
<commit_msg>Inline link about object safety<commit_after>// FIXME: Link below is required to render in index
/// Asserts that the traits are [object-safe](https://doc.rust-lang.org/book/2018-edition/ch17-02-trait-objects.html#object-safety-is-required-for-trait-objects).
///
/// This is useful for when changes are made to a trait that accidentally
/// prevent it from being used as an [object]. Such a case would be adding a
/// generic method and forgetting to add `where Self: Sized` after it. If left
/// unnoticed, that mistake will affect crate users and break both forward and
/// backward compatibility.
///
/// # Examples
///
/// When exposing a public API, it's important that traits that could previously
/// use dynamic dispatch can still do so in future compatible crate versions.
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// // Requires a unique label in module scope
/// assert_obj_safe!(basic; Send, Sync, AsRef<str>);
///
/// mod inner {
///     // Works with traits that are not in the calling module
///     pub trait BasicTrait {
///         fn foo(&self);
///     }
/// }
///
/// trait MySafeTrait {
///     fn bar(&self) -> u32;
/// }
///
/// fn main() {
///     assert_obj_safe!(MySafeTrait);
///     assert_obj_safe!(inner::BasicTrait);
/// }
/// ```
///
/// The [labeling limitation](index.html#limitations) is not necessary if
/// compiling on nightly Rust with the `nightly` feature enabled:
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(underscore_const_names)]
/// # #[macro_use] extern crate static_assertions;
///
/// use std::fmt;
///
/// assert_obj_safe!(fmt::Write);
///
/// fn main() {
///     assert_obj_safe!(fmt::Debug);
/// }
/// ```
///
/// Raw pointers cannot be sent between threads safely:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// assert_impl!(*const u8, Send);
/// # }
/// ```
///
/// Generics without `where Self: Sized` are not allowed in
/// [object-safe][object] trait methods:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// trait MyUnsafeTrait {
///     fn baz<T>(&self) -> T;
/// }
///
/// # fn main() {
/// assert_obj_safe!(MyUnsafeTrait);
/// # }
/// ```
///
/// [object]: https://doc.rust-lang.org/book/2018-edition/ch17-02-trait-objects.html#object-safety-is-required-for-trait-objects
#[macro_export(local_inner_macros)]
macro_rules! assert_obj_safe {
    ($($xs:tt)+) => { _assert_obj_safe!($($xs)+); };
}

#[doc(hidden)]
#[cfg(feature = "nightly")]
#[macro_export(local_inner_macros)]
macro_rules! _assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(const _: Option<&$xs> = None;)+
    };
}

#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
#[macro_export(local_inner_macros)]
macro_rules! _assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(let _: &$xs;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_obj_safe!($($xs)+); }
    };
}
<|endoftext|>


<commit_before>// Deny warnings, except in `dev` mode

// To update this list
// 1. Run `rustc -W help`
// 2. Grab all `default=warn` warnings
// 3. Paste them here, deleting `warnings`, and any with `deprecated` in the name
#![deny(const_err,
        dead_code,
        illegal_floating_point_literal_pattern,
        improper_ctypes,
        non_camel_case_types,
        non_shorthand_field_patterns,
        non_snake_case,
        non_upper_case_globals,
        no_mangle_generic_items,
        overflowing_literals,
        path_statements,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        renamed_and_removed_lints,
        stable_features,
        unconditional_recursion,
        unions_with_drop_fields,
        unknown_lints,
        unreachable_code,
        unreachable_patterns,
        unused_allocation,
        unused_assignments,
        unused_attributes,
        unused_comparisons,
        unused_features,
        unused_imports,
        unused_macros,
        unused_must_use,
        unused_mut,
        unused_parens,
        unused_unsafe,
        unused_variables,
        while_true)]
// This list is select `allow` warnings
#![deny(trivial_casts,
       trivial_numeric_casts,
       unused_extern_crates,
       unused_import_braces)]
#![cfg_attr(feature="cargo-clippy", allow(
        cyclomatic_complexity,
        needless_pass_by_value))]
#![cfg_attr(feature="dev", warn(warnings))]

extern crate cobalt;
extern crate env_logger;
extern crate notify;
extern crate ghp;

extern crate hyper;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;

mod build;
mod error;
mod serve;
mod new;

use std::env;

use clap::{Arg, App, SubCommand, AppSettings};
use cobalt::{ConfigBuilder, Dump, jekyll};
use cobalt::{list_syntaxes, list_syntax_themes};
use env_logger::LogBuilder;
use log::{LogRecord, LogLevelFilter};

use error::*;

quick_main!(run);

fn run() -> Result<()> {
    let app_cli = App::new("Cobalt")
        .version(crate_version!())
        .author("Benny Klotz <r3qnbenni@gmail.com>, Johann Hofmann")
        .about("A static site generator written in Rust.")
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .arg(Arg::with_name("config")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Config file to use [default: .cobalt.yml]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("destination")
                 .short("d")
                 .long("destination")
                 .value_name("DIR")
                 .help("Destination folder [default: ./]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("drafts")
                 .long("drafts")
                 .help("Include drafts.")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("log-level")
                 .short("L")
                 .long("log-level")
                 .possible_values(&["error", "warn", "info", "debug", "trace", "off"])
                 .help("Log level [default: info]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("trace")
                 .long("trace")
                 .help("Log ultra-verbose (trace level) information")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("silent")
                 .long("silent")
                 .help("Suppress all output")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("dump")
                 .long("dump")
                 .possible_values(&Dump::variants())
                 .help("Dump the specified internal state")
                 .global(true)
                 .multiple(true)
                 .takes_value(true))
        .subcommand(new::init_command_args())
        .subcommand(new::new_command_args())
        .subcommand(build::build_command_args())
        .subcommand(build::clean_command_args())
        .subcommand(serve::serve_command_args())
        .subcommand(serve::watch_command_args())
        .subcommand(build::import_command_args())
        .subcommand(SubCommand::with_name("list-syntax-themes").about("list available themes"))
        .subcommand(SubCommand::with_name("list-syntaxes").about("list supported syntaxes"))
        .subcommand(SubCommand::with_name("convert-jekyll")
                        .about("convert jekyll website to cobalt")
                        .arg(Arg::with_name("jksrc")
                                 .long("jksrc")
                                 .value_name("JEKYLL-FILE-OR-DIR")
                                 .help("Jekyll posts' directory")
                                 .required(true)
                                 .takes_value(true))
                        .arg(Arg::with_name("jkdst")
                                 .long("jkdst")
                                 .value_name("DIR")
                                 .help("Output dir of converted posts")
                                 .takes_value(true)
                                 .default_value("./posts")));

    let global_matches = app_cli.get_matches();

    let (command, matches) = match global_matches.subcommand() {
        (command, Some(matches)) => (command, matches),
        (_, None) => unreachable!(),
    };

    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    match matches
              .value_of("log-level")
              .or_else(|| global_matches.value_of("log-level")) {
        Some("error") => builder.filter(None, LogLevelFilter::Error),
        Some("warn") => builder.filter(None, LogLevelFilter::Warn),
        Some("debug") => builder.filter(None, LogLevelFilter::Debug),
        Some("trace") => builder.filter(None, LogLevelFilter::Trace),
        Some("off") => builder.filter(None, LogLevelFilter::Off),
        Some("info") | _ => builder.filter(None, LogLevelFilter::Info),
    };

    if matches.is_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.is_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    builder.init().unwrap();

    let config_path = matches
        .value_of("config")
        .or_else(|| global_matches.value_of("config"));

    // Fetch config information if available
    let mut config = if let Some(config_path) = config_path {
        ConfigBuilder::from_file(config_path)
            .chain_err(|| format!("Error reading config file {:?}", config_path))?
    } else {
        let cwd = env::current_dir().expect("How does this fail?");
        ConfigBuilder::from_cwd(cwd)?
    };

    config.abs_dest = matches
        .value_of("destination")
        .or_else(|| global_matches.value_of("destination"))
        .map(str::to_string);

    config.include_drafts = matches.is_present("drafts");

    if global_matches.is_present("dump") {
        let mut dump = values_t!(global_matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }
    if matches.is_present("dump") {
        let mut dump = values_t!(matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }

    let config = config.build()?;

    match command {
        "init" => new::init_command(config, matches),
        "new" => new::new_command(config, matches),
        "build" => build::build_command(config, matches),
        "clean" => build::clean_command(config, matches),
        "serve" => serve::serve_command(config, matches),
        "watch" => serve::watch_command(config, matches),
        "import" => build::import_command(config, matches),
        "list-syntax-themes" => {
            for name in list_syntax_themes() {
                println!("{}", name);
            }
            Ok(())
        }
        "list-syntaxes" => {
            for name in list_syntaxes() {
                println!("{}", name);
            }
            Ok(())
        }
        "convert-jekyll" => {
            let source = matches.value_of("jksrc").unwrap().to_string();
            let dest = matches.value_of("jkdst").unwrap().to_string();
            jekyll::jk_document::convert_from_jk(std::path::Path::new(&source),
                                                 std::path::Path::new(&dest))
                .chain_err(|| "Jekyll conversion failed.")
        }
        _ => {
            bail!(global_matches.usage());
        }
    }.chain_err(|| format!("{} command failed", command))?;

    Ok(())
}
<commit_msg>refactor(cli): Pull out config/logging<commit_after>// Deny warnings, except in `dev` mode

// To update this list
// 1. Run `rustc -W help`
// 2. Grab all `default=warn` warnings
// 3. Paste them here, deleting `warnings`, and any with `deprecated` in the name
#![deny(const_err,
        dead_code,
        illegal_floating_point_literal_pattern,
        improper_ctypes,
        non_camel_case_types,
        non_shorthand_field_patterns,
        non_snake_case,
        non_upper_case_globals,
        no_mangle_generic_items,
        overflowing_literals,
        path_statements,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        renamed_and_removed_lints,
        stable_features,
        unconditional_recursion,
        unions_with_drop_fields,
        unknown_lints,
        unreachable_code,
        unreachable_patterns,
        unused_allocation,
        unused_assignments,
        unused_attributes,
        unused_comparisons,
        unused_features,
        unused_imports,
        unused_macros,
        unused_must_use,
        unused_mut,
        unused_parens,
        unused_unsafe,
        unused_variables,
        while_true)]
// This list is select `allow` warnings
#![deny(trivial_casts,
       trivial_numeric_casts,
       unused_extern_crates,
       unused_import_braces)]
#![cfg_attr(feature="cargo-clippy", allow(
        cyclomatic_complexity,
        needless_pass_by_value))]
#![cfg_attr(feature="dev", warn(warnings))]

extern crate cobalt;
extern crate env_logger;
extern crate notify;
extern crate ghp;

extern crate hyper;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;

mod build;
mod error;
mod serve;
mod new;

use std::env;

use clap::{Arg, App, SubCommand, AppSettings};
use cobalt::{ConfigBuilder, Dump, jekyll};
use cobalt::{list_syntaxes, list_syntax_themes};
use env_logger::LogBuilder;
use log::{LogRecord, LogLevelFilter};

use error::*;

quick_main!(run);

fn get_config_args() -> Vec<Arg<'static, 'static>> {
    [Arg::with_name("config")
         .short("c")
         .long("config")
         .value_name("FILE")
         .help("Config file to use [default: .cobalt.yml]")
         .global(true)
         .takes_value(true),
     Arg::with_name("destination")
         .short("d")
         .long("destination")
         .value_name("DIR")
         .help("Destination folder [default: ./]")
         .global(true)
         .takes_value(true),
     Arg::with_name("drafts")
         .long("drafts")
         .help("Include drafts.")
         .global(true)
         .takes_value(false),
     Arg::with_name("dump")
         .long("dump")
         .possible_values(&Dump::variants())
         .help("Dump the specified internal state")
         .global(true)
         .multiple(true)
         .takes_value(true)]
        .to_vec()
}

fn get_config(global_matches: &clap::ArgMatches,
              matches: &clap::ArgMatches)
              -> Result<ConfigBuilder> {
    let config_path = matches
        .value_of("config")
        .or_else(|| global_matches.value_of("config"));

    // Fetch config information if available
    let mut config = if let Some(config_path) = config_path {
        ConfigBuilder::from_file(config_path)
            .chain_err(|| format!("Error reading config file {:?}", config_path))?
    } else {
        let cwd = env::current_dir().expect("How does this fail?");
        ConfigBuilder::from_cwd(cwd)?
    };

    config.abs_dest = matches
        .value_of("destination")
        .or_else(|| global_matches.value_of("destination"))
        .map(str::to_string);

    config.include_drafts = matches.is_present("drafts");

    if global_matches.is_present("dump") {
        let mut dump = values_t!(global_matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }
    if matches.is_present("dump") {
        let mut dump = values_t!(matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }

    Ok(config)
}

fn get_logging_args() -> Vec<Arg<'static, 'static>> {
    [Arg::with_name("log-level")
         .short("L")
         .long("log-level")
         .possible_values(&["error", "warn", "info", "debug", "trace", "off"])
         .help("Log level [default: info]")
         .global(true)
         .takes_value(true),
     Arg::with_name("trace")
         .long("trace")
         .help("Log ultra-verbose (trace level) information")
         .global(true)
         .takes_value(false),
     Arg::with_name("silent")
         .long("silent")
         .help("Suppress all output")
         .global(true)
         .takes_value(false)]
        .to_vec()
}

fn get_logging(global_matches: &clap::ArgMatches,
               matches: &clap::ArgMatches)
               -> Result<LogBuilder> {
    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    match matches
              .value_of("log-level")
              .or_else(|| global_matches.value_of("log-level")) {
        Some("error") => builder.filter(None, LogLevelFilter::Error),
        Some("warn") => builder.filter(None, LogLevelFilter::Warn),
        Some("debug") => builder.filter(None, LogLevelFilter::Debug),
        Some("trace") => builder.filter(None, LogLevelFilter::Trace),
        Some("off") => builder.filter(None, LogLevelFilter::Off),
        Some("info") | _ => builder.filter(None, LogLevelFilter::Info),
    };

    if matches.is_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.is_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    Ok(builder)
}

fn run() -> Result<()> {
    let app_cli = App::new("Cobalt")
        .version(crate_version!())
        .author("Benny Klotz <r3qnbenni@gmail.com>, Johann Hofmann")
        .about("A static site generator written in Rust.")
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .args(&get_config_args())
        .args(&get_logging_args())
        .subcommand(new::init_command_args())
        .subcommand(new::new_command_args())
        .subcommand(build::build_command_args())
        .subcommand(build::clean_command_args())
        .subcommand(serve::serve_command_args())
        .subcommand(serve::watch_command_args())
        .subcommand(build::import_command_args())
        .subcommand(SubCommand::with_name("list-syntax-themes").about("list available themes"))
        .subcommand(SubCommand::with_name("list-syntaxes").about("list supported syntaxes"))
        .subcommand(SubCommand::with_name("convert-jekyll")
                        .about("convert jekyll website to cobalt")
                        .arg(Arg::with_name("jksrc")
                                 .long("jksrc")
                                 .value_name("JEKYLL-FILE-OR-DIR")
                                 .help("Jekyll posts' directory")
                                 .required(true)
                                 .takes_value(true))
                        .arg(Arg::with_name("jkdst")
                                 .long("jkdst")
                                 .value_name("DIR")
                                 .help("Output dir of converted posts")
                                 .takes_value(true)
                                 .default_value("./posts")));

    let global_matches = app_cli.get_matches();

    let (command, matches) = match global_matches.subcommand() {
        (command, Some(matches)) => (command, matches),
        (_, None) => unreachable!(),
    };

    let mut builder = get_logging(&global_matches, matches)?;
    builder.init().unwrap();

    let config = get_config(&global_matches, matches)?;
    let config = config.build()?;

    match command {
        "init" => new::init_command(config, matches),
        "new" => new::new_command(config, matches),
        "build" => build::build_command(config, matches),
        "clean" => build::clean_command(config, matches),
        "serve" => serve::serve_command(config, matches),
        "watch" => serve::watch_command(config, matches),
        "import" => build::import_command(config, matches),
        "list-syntax-themes" => {
            for name in list_syntax_themes() {
                println!("{}", name);
            }
            Ok(())
        }
        "list-syntaxes" => {
            for name in list_syntaxes() {
                println!("{}", name);
            }
            Ok(())
        }
        "convert-jekyll" => {
            let source = matches.value_of("jksrc").unwrap().to_string();
            let dest = matches.value_of("jkdst").unwrap().to_string();
            jekyll::jk_document::convert_from_jk(std::path::Path::new(&source),
                                                 std::path::Path::new(&dest))
                .chain_err(|| "Jekyll conversion failed.")
        }
        _ => {
            bail!(global_matches.usage());
        }
    }.chain_err(|| format!("{} command failed", command))?;

    Ok(())
}
<|endoftext|>


<commit_before>pub struct Position {
    pub line:   u64,
    pub offset: u64,
}
<commit_msg>Implement Copy and Clone traits for Position.<commit_after>#[derive(Copy, Clone)]
pub struct Position {
    pub line:   u64,
    pub offset: u64,
}
<|endoftext|>


<commit_before>import std::ivec;
import std::str;
import std::int;
import std::option;
import std::option::none;
import std::option::some;
import middle::ty;
import middle::ty::*;
import metadata::encoder;
import syntax::print::pp;
import syntax::print::pprust;
import syntax::print::pprust::path_to_str;
import syntax::print::pprust::constr_args_to_str;
import pp::word;
import pp::eof;
import pp::zerobreak;
import pp::hardbreak;
import ast::ty_mach_to_str;
import syntax::ast;

fn mode_str(&ty::mode m) -> str {
    alt (m) {
        case (mo_val) { "" }
        case (mo_alias(false)) { "&" }
        case (mo_alias(true)) { "&mutable " }
    }
}

fn mode_str_1(&ty::mode m) -> str {
    alt (m) {
        case (mo_val) { "val" }
        case (_)      { mode_str(m) }
    }
}

fn fn_ident_to_string(ast::node_id id, &ast::fn_ident i) -> str {
    ret alt (i) {
        case (none) { "anon" + int::str(id) }
        case (some(?s)) { s }
    };
}

fn ty_to_str(&ctxt cx, &t typ) -> str {
    fn fn_input_to_str(&ctxt cx, &rec(middle::ty::mode mode, t ty) input) ->
       str {
        auto s = mode_str(input.mode);
        ret s + ty_to_str(cx, input.ty);
    }
    fn fn_to_str(&ctxt cx, ast::proto proto, option::t[ast::ident] ident,
                 &arg[] inputs, t output, ast::controlflow cf,
                 &(@constr)[] constrs) -> str {
        auto s;
        alt (proto) {
            case (ast::proto_iter) { s = "iter"; }
            case (ast::proto_fn) { s = "fn"; }
        }
        alt (ident) { case (some(?i)) { s += " "; s += i; } case (_) { } }
        s += "(";
        auto strs = [];
        for (arg a in inputs) { strs += [fn_input_to_str(cx, a)]; }
        s += str::connect(strs, ", ");
        s += ")";
        if (struct(cx, output) != ty_nil) {
            alt (cf) {
                case (ast::noreturn) { s += " -> !"; }
                case (ast::return) { s += " -> " + ty_to_str(cx, output); }
            }
        }
        s += constrs_str(constrs);
        ret s;
    }
    fn method_to_str(&ctxt cx, &method m) -> str {
        ret fn_to_str(cx, m.proto, some[ast::ident](m.ident), m.inputs,
                      m.output, m.cf, m.constrs) + ";";
    }
    fn field_to_str(&ctxt cx, &field f) -> str {
        ret mt_to_str(cx, f.mt) + " " + f.ident;
    }
    fn mt_to_str(&ctxt cx, &mt m) -> str {
        auto mstr;
        alt (m.mut) {
            case (ast::mut) { mstr = "mutable "; }
            case (ast::imm) { mstr = ""; }
            case (ast::maybe_mut) { mstr = "mutable? "; }
        }
        ret mstr + ty_to_str(cx, m.ty);
    }
    alt (cname(cx, typ)) { case (some(?cs)) { ret cs; } case (_) { } }
    auto s = "";
    alt (struct(cx, typ)) {
        case (ty_native(_)) { s += "native"; }
        case (ty_nil) { s += "()"; }
        case (ty_bot) { s += "_|_"; }
        case (ty_bool) { s += "bool"; }
        case (ty_int) { s += "int"; }
        case (ty_float) { s += "float"; }
        case (ty_uint) { s += "uint"; }
        case (ty_machine(?tm)) { s += ty_mach_to_str(tm); }
        case (ty_char) { s += "char"; }
        case (ty_str) { s += "str"; }
        case (ty_istr) { s += "istr"; }
        case (ty_box(?tm)) { s += "@" + mt_to_str(cx, tm); }
        case (ty_vec(?tm)) { s += "vec[" + mt_to_str(cx, tm) + "]"; }
        case (ty_ivec(?tm)) { s += "ivec[" + mt_to_str(cx, tm) + "]"; }
        case (ty_port(?t)) { s += "port[" + ty_to_str(cx, t) + "]"; }
        case (ty_chan(?t)) { s += "chan[" + ty_to_str(cx, t) + "]"; }
        case (ty_type) { s += "type"; }
        case (ty_task) { s += "task"; }
        case (ty_tup(?elems)) {
            let str[] strs = ~[];
            for (mt tm in elems) { strs += ~[mt_to_str(cx, tm)]; }
            s += "tup(" + str::connect_ivec(strs, ",") + ")";
        }
        case (ty_rec(?elems)) {
            let str[] strs = ~[];
            for (field fld in elems) { strs += ~[field_to_str(cx, fld)]; }
            s += "rec(" + str::connect_ivec(strs, ",") + ")";
        }
        case (ty_tag(?id, ?tps)) {
            // The user should never see this if the cname is set properly!

            s += "<tag#" + int::str(id._0) + ":" + int::str(id._1) + ">";
            if (ivec::len[t](tps) > 0u) {
                let str[] strs = ~[];
                for (t typ in tps) { strs += ~[ty_to_str(cx, typ)]; }
                s += "[" + str::connect_ivec(strs, ",") + "]";
            }
        }
        case (ty_fn(?proto, ?inputs, ?output, ?cf, ?constrs)) {
            s += fn_to_str(cx, proto, none, inputs, output, cf, constrs);
        }
        case (ty_native_fn(_, ?inputs, ?output)) {
            s += fn_to_str(cx, ast::proto_fn, none, inputs, output,
                           ast::return, ~[]);
        }
        case (ty_obj(?meths)) {
            auto strs = ~[];
            for (method m in meths) { strs += ~[method_to_str(cx, m)]; }
            s += "obj {\n\t" + str::connect_ivec(strs, "\n\t") + "\n}";
        }
        case (ty_res(?id, _, _)) {
            s += "<resource#" + int::str(id._0) + ":" + int::str(id._1) + ">";
        }
        case (ty_var(?v)) { s += "<T" + int::str(v) + ">"; }
        case (ty_param(?id)) {
            s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]);
        }
        case (_) { s += ty_to_short_str(cx, typ); }
    }
    ret s;
}

fn ty_to_short_str(&ctxt cx, t typ) -> str {
    auto s = encoder::encoded_ty(cx, typ);
    if (str::byte_len(s) >= 32u) { s = str::substr(s, 0u, 32u); }
    ret s;
}

fn constr_to_str(&@constr c) -> str {
    ret path_to_str(c.node.path) +
        pprust::constr_args_to_str(pprust::uint_to_str, c.node.args);
}

fn constrs_str(&(@constr)[] constrs) -> str {
    auto s = "";
    auto colon = true;
    for (@constr c in constrs) {
        if (colon) { s += " : "; colon = false; } else { s += ", "; }
        s += constr_to_str(c);
    }
    ret s;
}

fn ty_constr_to_str[Q](&@ast::spanned[ast::constr_general_[ast::path,Q]]
                       c) -> str {
    ret path_to_str(c.node.path) +
          constr_args_to_str[ast::path](path_to_str, c.node.args);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Have fn_to_str use proto_to_str.<commit_after>import std::ivec;
import std::str;
import std::int;
import std::option;
import std::option::none;
import std::option::some;
import middle::ty;
import middle::ty::*;
import metadata::encoder;
import syntax::print::pp;
import syntax::print::pprust;
import syntax::print::pprust::path_to_str;
import syntax::print::pprust::constr_args_to_str;
import syntax::print::pprust::proto_to_str;
import pp::word;
import pp::eof;
import pp::zerobreak;
import pp::hardbreak;
import ast::ty_mach_to_str;
import syntax::ast;

fn mode_str(&ty::mode m) -> str {
    alt (m) {
        case (mo_val) { "" }
        case (mo_alias(false)) { "&" }
        case (mo_alias(true)) { "&mutable " }
    }
}

fn mode_str_1(&ty::mode m) -> str {
    alt (m) {
        case (mo_val) { "val" }
        case (_)      { mode_str(m) }
    }
}

fn fn_ident_to_string(ast::node_id id, &ast::fn_ident i) -> str {
    ret alt (i) {
        case (none) { "anon" + int::str(id) }
        case (some(?s)) { s }
    };
}

fn ty_to_str(&ctxt cx, &t typ) -> str {
    fn fn_input_to_str(&ctxt cx, &rec(middle::ty::mode mode, t ty) input) ->
       str {
        auto s = mode_str(input.mode);
        ret s + ty_to_str(cx, input.ty);
    }
    fn fn_to_str(&ctxt cx, ast::proto proto, option::t[ast::ident] ident,
                 &arg[] inputs, t output, ast::controlflow cf,
                 &(@constr)[] constrs) -> str {
        auto s = proto_to_str(proto);
        alt (ident) { case (some(?i)) { s += " "; s += i; } case (_) { } }
        s += "(";
        auto strs = [];
        for (arg a in inputs) { strs += [fn_input_to_str(cx, a)]; }
        s += str::connect(strs, ", ");
        s += ")";
        if (struct(cx, output) != ty_nil) {
            alt (cf) {
                case (ast::noreturn) { s += " -> !"; }
                case (ast::return) { s += " -> " + ty_to_str(cx, output); }
            }
        }
        s += constrs_str(constrs);
        ret s;
    }
    fn method_to_str(&ctxt cx, &method m) -> str {
        ret fn_to_str(cx, m.proto, some[ast::ident](m.ident), m.inputs,
                      m.output, m.cf, m.constrs) + ";";
    }
    fn field_to_str(&ctxt cx, &field f) -> str {
        ret mt_to_str(cx, f.mt) + " " + f.ident;
    }
    fn mt_to_str(&ctxt cx, &mt m) -> str {
        auto mstr;
        alt (m.mut) {
            case (ast::mut) { mstr = "mutable "; }
            case (ast::imm) { mstr = ""; }
            case (ast::maybe_mut) { mstr = "mutable? "; }
        }
        ret mstr + ty_to_str(cx, m.ty);
    }
    alt (cname(cx, typ)) { case (some(?cs)) { ret cs; } case (_) { } }
    auto s = "";
    alt (struct(cx, typ)) {
        case (ty_native(_)) { s += "native"; }
        case (ty_nil) { s += "()"; }
        case (ty_bot) { s += "_|_"; }
        case (ty_bool) { s += "bool"; }
        case (ty_int) { s += "int"; }
        case (ty_float) { s += "float"; }
        case (ty_uint) { s += "uint"; }
        case (ty_machine(?tm)) { s += ty_mach_to_str(tm); }
        case (ty_char) { s += "char"; }
        case (ty_str) { s += "str"; }
        case (ty_istr) { s += "istr"; }
        case (ty_box(?tm)) { s += "@" + mt_to_str(cx, tm); }
        case (ty_vec(?tm)) { s += "vec[" + mt_to_str(cx, tm) + "]"; }
        case (ty_ivec(?tm)) { s += "ivec[" + mt_to_str(cx, tm) + "]"; }
        case (ty_port(?t)) { s += "port[" + ty_to_str(cx, t) + "]"; }
        case (ty_chan(?t)) { s += "chan[" + ty_to_str(cx, t) + "]"; }
        case (ty_type) { s += "type"; }
        case (ty_task) { s += "task"; }
        case (ty_tup(?elems)) {
            let str[] strs = ~[];
            for (mt tm in elems) { strs += ~[mt_to_str(cx, tm)]; }
            s += "tup(" + str::connect_ivec(strs, ",") + ")";
        }
        case (ty_rec(?elems)) {
            let str[] strs = ~[];
            for (field fld in elems) { strs += ~[field_to_str(cx, fld)]; }
            s += "rec(" + str::connect_ivec(strs, ",") + ")";
        }
        case (ty_tag(?id, ?tps)) {
            // The user should never see this if the cname is set properly!

            s += "<tag#" + int::str(id._0) + ":" + int::str(id._1) + ">";
            if (ivec::len[t](tps) > 0u) {
                let str[] strs = ~[];
                for (t typ in tps) { strs += ~[ty_to_str(cx, typ)]; }
                s += "[" + str::connect_ivec(strs, ",") + "]";
            }
        }
        case (ty_fn(?proto, ?inputs, ?output, ?cf, ?constrs)) {
            s += fn_to_str(cx, proto, none, inputs, output, cf, constrs);
        }
        case (ty_native_fn(_, ?inputs, ?output)) {
            s += fn_to_str(cx, ast::proto_fn, none, inputs, output,
                           ast::return, ~[]);
        }
        case (ty_obj(?meths)) {
            auto strs = ~[];
            for (method m in meths) { strs += ~[method_to_str(cx, m)]; }
            s += "obj {\n\t" + str::connect_ivec(strs, "\n\t") + "\n}";
        }
        case (ty_res(?id, _, _)) {
            s += "<resource#" + int::str(id._0) + ":" + int::str(id._1) + ">";
        }
        case (ty_var(?v)) { s += "<T" + int::str(v) + ">"; }
        case (ty_param(?id)) {
            s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]);
        }
        case (_) { s += ty_to_short_str(cx, typ); }
    }
    ret s;
}

fn ty_to_short_str(&ctxt cx, t typ) -> str {
    auto s = encoder::encoded_ty(cx, typ);
    if (str::byte_len(s) >= 32u) { s = str::substr(s, 0u, 32u); }
    ret s;
}

fn constr_to_str(&@constr c) -> str {
    ret path_to_str(c.node.path) +
        pprust::constr_args_to_str(pprust::uint_to_str, c.node.args);
}

fn constrs_str(&(@constr)[] constrs) -> str {
    auto s = "";
    auto colon = true;
    for (@constr c in constrs) {
        if (colon) { s += " : "; colon = false; } else { s += ", "; }
        s += constr_to_str(c);
    }
    ret s;
}

fn ty_constr_to_str[Q](&@ast::spanned[ast::constr_general_[ast::path,Q]]
                       c) -> str {
    ret path_to_str(c.node.path) +
          constr_args_to_str[ast::path](path_to_str, c.node.args);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>//! Parser for the `viewBox` attribute.

use cssparser::Parser;

use crate::error::*;
use crate::number_list::{NumberList, NumberListLength};
use crate::parsers::Parse;
use crate::rect::Rect;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ViewBox(pub Rect);

impl Parse for ViewBox {
    // Parse a viewBox attribute
    // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
    //
    // viewBox: double [,] double [,] double [,] double [,]
    //
    // x, y, w, h
    //
    // Where w and h must be nonnegative.
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<ViewBox, ParseError<'i>> {
        let loc = parser.current_source_location();

        let NumberList(v) = NumberList::parse(parser, NumberListLength::Exact(4))?;

        let (x, y, width, height) = (v[0], v[1], v[2], v[3]);

        if width >= 0.0 && height >= 0.0 {
            Ok(ViewBox(Rect::new(x, y, x + width, y + height)))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error(
                "width and height must not be negative",
            )))
        }
    }
}

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

    #[test]
    fn parses_valid_viewboxes() {
        assert_eq!(
            ViewBox::parse_str("  1 2 3 4"),
            Ok(ViewBox(Rect::new(1.0, 2.0, 4.0, 6.0)))
        );

        assert_eq!(
            ViewBox::parse_str(" -1.5 -2.5e1,34,56e2  "),
            Ok(ViewBox(Rect::new(-1.5, -25.0, 32.5, 5575.0)))
        );
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error() {
        assert!(ViewBox::parse_str("").is_err());
        assert!(ViewBox::parse_str(" 1,2,-3,-4 ").is_err());
        assert!(ViewBox::parse_str("qwerasdfzxcv").is_err());
        assert!(ViewBox::parse_str(" 1 2 3 4   5").is_err());
        assert!(ViewBox::parse_str(" 1 2 foo 3 4").is_err());

        // https://gitlab.gnome.org/GNOME/librsvg/issues/344
        assert!(ViewBox::parse_str("0 0 9E80.7").is_err());
    }
}
<commit_msg>Document ViewBox<commit_after>//! Parser for the `viewBox` attribute.

use cssparser::Parser;

use crate::error::*;
use crate::number_list::{NumberList, NumberListLength};
use crate::parsers::Parse;
use crate::rect::Rect;

/// Newtype around a [`Rect`], used to represent the `viewBox` attribute.
///
/// [`Rect`]: rect/type.Rect.html
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ViewBox(pub Rect);

impl Parse for ViewBox {
    // Parse a viewBox attribute
    // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
    //
    // viewBox: double [,] double [,] double [,] double [,]
    //
    // x, y, w, h
    //
    // Where w and h must be nonnegative.
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<ViewBox, ParseError<'i>> {
        let loc = parser.current_source_location();

        let NumberList(v) = NumberList::parse(parser, NumberListLength::Exact(4))?;

        let (x, y, width, height) = (v[0], v[1], v[2], v[3]);

        if width >= 0.0 && height >= 0.0 {
            Ok(ViewBox(Rect::new(x, y, x + width, y + height)))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error(
                "width and height must not be negative",
            )))
        }
    }
}

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

    #[test]
    fn parses_valid_viewboxes() {
        assert_eq!(
            ViewBox::parse_str("  1 2 3 4"),
            Ok(ViewBox(Rect::new(1.0, 2.0, 4.0, 6.0)))
        );

        assert_eq!(
            ViewBox::parse_str(" -1.5 -2.5e1,34,56e2  "),
            Ok(ViewBox(Rect::new(-1.5, -25.0, 32.5, 5575.0)))
        );
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error() {
        assert!(ViewBox::parse_str("").is_err());
        assert!(ViewBox::parse_str(" 1,2,-3,-4 ").is_err());
        assert!(ViewBox::parse_str("qwerasdfzxcv").is_err());
        assert!(ViewBox::parse_str(" 1 2 3 4   5").is_err());
        assert!(ViewBox::parse_str(" 1 2 foo 3 4").is_err());

        // https://gitlab.gnome.org/GNOME/librsvg/issues/344
        assert!(ViewBox::parse_str("0 0 9E80.7").is_err());
    }
}
<|endoftext|>


<commit_before>//! Common types for the [third party networks module][thirdparty]
//!
//! [thirdparty]: https://matrix.org/docs/spec/client_server/r0.6.1#id153

use std::collections::BTreeMap;

use ruma_common::StringEnum;
use ruma_identifiers::{RoomAliasId, UserId};

use serde::{Deserialize, Serialize};

/// Metadata about a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInit` and convert it via
/// `Protocol::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Protocol {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    #[cfg(not(feature = "unstable-synapse-quirks"))]
    pub icon: String,

    /// A content URI representing an icon for the third party protocol.
    #[cfg(feature = "unstable-synapse-quirks")]
    pub icon: Option<String>,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
pub struct ProtocolInit {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    #[cfg(not(feature = "unstable-synapse-quirks"))]
    pub icon: String,

    /// A content URI representing an icon for the third party protocol.
    #[cfg(feature = "unstable-synapse-quirks")]
    pub icon: Option<String>,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

impl From<ProtocolInit> for Protocol {
    fn from(init: ProtocolInit) -> Self {
        let ProtocolInit { user_fields, location_fields, icon, field_types, instances } = init;
        Self { user_fields, location_fields, icon, field_types, instances }
    }
}

/// Metadata about an instance of a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInstanceInit` and convert it via
/// `ProtocolInstance::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ProtocolInstance {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// An optional content URI representing the protocol.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub icon: Option<String>,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
pub struct ProtocolInstanceInit {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,
}

impl From<ProtocolInstanceInit> for ProtocolInstance {
    fn from(init: ProtocolInstanceInit) -> Self {
        let ProtocolInstanceInit { desc, fields, network_id } = init;
        Self { desc, icon: None, fields, network_id }
    }
}

/// A type definition for a field used to identify third party users or locations.
///
/// To create an instance of this type, first create a `FieldTypeInit` and convert it via
/// `FieldType::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct FieldType {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

/// Initial set of fields of `FieldType`.
///
/// This struct will not be updated even if additional fields are added to `FieldType` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
pub struct FieldTypeInit {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

impl From<FieldTypeInit> for FieldType {
    fn from(init: FieldTypeInit) -> Self {
        let FieldTypeInit { regexp, placeholder } = init;
        Self { regexp, placeholder }
    }
}

/// A third party network location.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Location {
    /// An alias for a matrix room.
    pub alias: RoomAliasId,

    /// The protocol ID that the third party location is a part of.
    pub protocol: String,

    /// Information used to identify this third party location.
    pub fields: BTreeMap<String, String>,
}

impl Location {
    /// Creates a new `Location` with the given alias, protocol and fields.
    pub fn new(alias: RoomAliasId, protocol: String, fields: BTreeMap<String, String>) -> Self {
        Self { alias, protocol, fields }
    }
}

/// A third party network user.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct User {
    /// A matrix user ID representing a third party user.
    pub userid: UserId,

    /// The protocol ID that the third party user is a part of.
    pub protocol: String,

    /// Information used to identify this third party user.
    pub fields: BTreeMap<String, String>,
}

impl User {
    /// Creates a new `User` with the given userid, protocol and fields.
    pub fn new(userid: UserId, protocol: String, fields: BTreeMap<String, String>) -> Self {
        Self { userid, protocol, fields }
    }
}

/// The medium of a third party identifier.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "lowercase")]
pub enum Medium {
    /// Email address identifier
    Email,

    /// Phone number identifier
    MSISDN,

    #[doc(hidden)]
    _Custom(String),
}
<commit_msg>common: Don't change fields in thirdparty::Protocol with `unstable-synapse-quirks`<commit_after>//! Common types for the [third party networks module][thirdparty]
//!
//! [thirdparty]: https://matrix.org/docs/spec/client_server/r0.6.1#id153

use std::collections::BTreeMap;

use ruma_common::StringEnum;
use ruma_identifiers::{RoomAliasId, UserId};

use serde::{Deserialize, Serialize};

/// Metadata about a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInit` and convert it via
/// `Protocol::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Protocol {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    ///
    /// If you activate the `unstable-synapse-quirks` feature, this field being absent in JSON will
    /// give you an empty string here.
    #[cfg_attr(feature = "unstable-synapse-quirks", serde(default))]
    pub icon: String,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
pub struct ProtocolInit {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    pub icon: String,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

impl From<ProtocolInit> for Protocol {
    fn from(init: ProtocolInit) -> Self {
        let ProtocolInit { user_fields, location_fields, icon, field_types, instances } = init;
        Self { user_fields, location_fields, icon, field_types, instances }
    }
}

/// Metadata about an instance of a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInstanceInit` and convert it via
/// `ProtocolInstance::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ProtocolInstance {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// An optional content URI representing the protocol.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub icon: Option<String>,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
pub struct ProtocolInstanceInit {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,
}

impl From<ProtocolInstanceInit> for ProtocolInstance {
    fn from(init: ProtocolInstanceInit) -> Self {
        let ProtocolInstanceInit { desc, fields, network_id } = init;
        Self { desc, icon: None, fields, network_id }
    }
}

/// A type definition for a field used to identify third party users or locations.
///
/// To create an instance of this type, first create a `FieldTypeInit` and convert it via
/// `FieldType::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct FieldType {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

/// Initial set of fields of `FieldType`.
///
/// This struct will not be updated even if additional fields are added to `FieldType` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
pub struct FieldTypeInit {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

impl From<FieldTypeInit> for FieldType {
    fn from(init: FieldTypeInit) -> Self {
        let FieldTypeInit { regexp, placeholder } = init;
        Self { regexp, placeholder }
    }
}

/// A third party network location.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Location {
    /// An alias for a matrix room.
    pub alias: RoomAliasId,

    /// The protocol ID that the third party location is a part of.
    pub protocol: String,

    /// Information used to identify this third party location.
    pub fields: BTreeMap<String, String>,
}

impl Location {
    /// Creates a new `Location` with the given alias, protocol and fields.
    pub fn new(alias: RoomAliasId, protocol: String, fields: BTreeMap<String, String>) -> Self {
        Self { alias, protocol, fields }
    }
}

/// A third party network user.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct User {
    /// A matrix user ID representing a third party user.
    pub userid: UserId,

    /// The protocol ID that the third party user is a part of.
    pub protocol: String,

    /// Information used to identify this third party user.
    pub fields: BTreeMap<String, String>,
}

impl User {
    /// Creates a new `User` with the given userid, protocol and fields.
    pub fn new(userid: UserId, protocol: String, fields: BTreeMap<String, String>) -> Self {
        Self { userid, protocol, fields }
    }
}

/// The medium of a third party identifier.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "lowercase")]
pub enum Medium {
    /// Email address identifier
    Email,

    /// Phone number identifier
    MSISDN,

    #[doc(hidden)]
    _Custom(String),
}
<|endoftext|>


<commit_before><commit_msg>minor style; redundant unsafe<commit_after><|endoftext|>


<commit_before>use std;
use winapi;

use winapi::um::libloaderapi::{FreeLibrary, GetProcAddress, LoadLibraryW};
use winapi::shared::minwindef::{FARPROC, HMODULE};

use std::ffi::OsString;

#[derive(Debug, Clone)]
pub enum HookError {
    ProtectFailed,
    LoadLibFailed(String),
    GetProcAddressFailed(String),
    CLRInitFailed(String),
    NulError(std::ffi::NulError),
    GlobalStateCopyFailed,
    Direct3D9InstanceNotFound,
    CreateDeviceFailed(i32),
    ConfReadFailed(String),
    FailedToConvertString(OsString),
    ModuleNameError(String),
    UnableToLocatedManagedDLL(String),
    D3D9HookFailed,
    D3D9DeviceHookFailed,
    GlobalLockError,
}

impl std::convert::From<std::ffi::NulError> for HookError {
    fn from(error: std::ffi::NulError) -> Self {
        HookError::NulError(error)
    }
}

impl std::convert::From<std::ffi::OsString> for HookError {
    fn from(error: std::ffi::OsString) -> Self {
        HookError::FailedToConvertString(error)
    }
}

pub type Result<T> = std::result::Result<T, HookError>;

pub fn write_log_file(format: &str) -> () {
    use std::io::Write;
    use std::fs::OpenOptions;

    let tid = std::thread::current().id();

    let w = || -> std::io::Result<()> {
        let mut f = OpenOptions::new()
            .create(true)
            .append(true)
            .open("D:\\Temp\\rd3dlog.txt")?; // TODO: duh, unhardcode
        writeln!(f, "{:?}: {}\r", tid, format)?;
        Ok(())
    };

    w().unwrap_or_else(|e| eprintln!("oops can't write log file: {}", e));
}

pub unsafe fn protect_memory(
    target: *mut winapi::ctypes::c_void,
    size: usize,
    protection: u32,
) -> Result<u32> {
    let process = winapi::um::processthreadsapi::GetCurrentProcess();
    let mut old_protection = winapi::um::winnt::PAGE_READWRITE;
    if winapi::um::memoryapi::VirtualProtectEx(
        process,
        target as *mut winapi::ctypes::c_void,
        size,
        protection,
        (&mut old_protection) as *mut u32,
    ) > 0
    {
        Ok(old_protection)
    } else {
        Err(HookError::ProtectFailed)
    }
}

pub unsafe fn unprotect_memory(target: *mut winapi::ctypes::c_void, size: usize) -> Result<u32> {
    protect_memory(target, size, winapi::um::winnt::PAGE_READWRITE)
}

pub fn load_lib(name: &str) -> Result<HMODULE> {
    let wide: Vec<u16> = to_wide_str(name);
    let handle = unsafe { LoadLibraryW(wide.as_ptr()) };
    if handle == std::ptr::null_mut() {
        Err(HookError::LoadLibFailed(name.to_owned()))
    } else {
        Ok(handle)
    }
}

pub fn unload_lib(h: HMODULE) -> Result<()> {
    if unsafe { FreeLibrary(h) } == 0 {
        Err(HookError::LoadLibFailed(format!(
            "Unload of the library {:?} failed",
            h
        )))
    } else {
        Ok(())
    }
}

pub fn get_proc_address(h: HMODULE, name: &str) -> Result<FARPROC> {
    use std::ffi::CString;

    if h == std::ptr::null_mut() {
        return Err(HookError::GetProcAddressFailed("null handle".to_owned()));
    }
    let csname = CString::new(name)?;
    let addr = unsafe { GetProcAddress(h, csname.as_ptr()) };
    if addr == std::ptr::null_mut() {
        Err(HookError::GetProcAddressFailed(format!(
            "{} not found in module",
            name
        )))
    } else {
        Ok(addr)
    }
}

#[cfg(test)]
fn get_mm_reg_key() -> &'static str {
    "Software\\ModelModTEST"
}
#[cfg(not(test))]
fn get_mm_reg_key() -> &'static str {
    "Software\\ModelMod"
}
pub fn get_mm_conf_info() -> Result<(bool, Option<String>)> {
    unsafe {
        let reg_root = get_mm_reg_key();
        // find the MM install directory, this must be set in the registry by the launcher.
        // the launcher will also set whether MM is active.
        use winapi::um::winreg::*;
        use winapi::shared::minwindef::DWORD;
        use winapi::shared::winerror::ERROR_SUCCESS;
        use winapi::ctypes::c_void;

        use std::os::windows::prelude::*;

        // first check if it is active
        {
            let sk = to_wide_str(reg_root);
            let kv = to_wide_str("Active");
            let mut active: DWORD = 0;
            let p_active: *mut c_void = std::mem::transmute(&mut active);
            let mut out_active_sz: DWORD = std::mem::size_of::<DWORD>() as DWORD;
            let res = RegGetValueW(
                HKEY_CURRENT_USER,
                sk.as_ptr(),
                kv.as_ptr(),
                RRF_RT_REG_DWORD,
                std::ptr::null_mut(),
                p_active,
                &mut out_active_sz,
            );
            if res as DWORD != ERROR_SUCCESS {
                return Err(HookError::ConfReadFailed(format!("Error reading Active registry key: {}.  You must start ModelMod using its launcher.", res)));
            }
            if active != 1 {
                return Ok((false, None));
            }
        }

        // its active, so get path and make sure it exists
        {
            let sk = to_wide_str(reg_root);
            let kv = to_wide_str("MMRoot");
            let mut max_path: DWORD = 65535;
            // path could have wide chars, use u16
            let mut out_buf: Vec<u16> = Vec::with_capacity(max_path as usize);

            // max path input is in bytes
            max_path = max_path * 2;
            let res = RegGetValueW(
                HKEY_CURRENT_USER,
                sk.as_ptr(),
                kv.as_ptr(),
                RRF_RT_REG_SZ,
                std::ptr::null_mut(),
                out_buf.as_mut_ptr() as *mut c_void,
                &mut max_path,
            );
            if res as DWORD != ERROR_SUCCESS {
                return Err(HookError::ConfReadFailed(format!(
                    "Error reading MMRoot registry key: {}",
                    res
                )));
            }
            //println!("bytes read from registry {}", max_path);
            // convert bytes read to chars and remove null terminator
            let nchars = (max_path / 2) - 1;
            let wslice = std::slice::from_raw_parts(out_buf.as_mut_ptr(), nchars as usize);
            let wpath = OsString::from_wide(wslice).into_string()?;

            // check if path exists

            use std::path::Path;
            if !Path::new(&wpath).exists() {
                return Err(HookError::ConfReadFailed(format!(
                    "ModelMod path read from registry, {}, does not exist",
                    wpath
                )));
            }

            return Ok((true, Some(wpath)));
        }
    }
}

pub fn get_managed_dll_path(mm_root: &str) -> Result<String> {
    use std::path::PathBuf;

    let subdir_paths = ["", "Bin", "Release", "Debug"];
    // save the full path list so that we can reference it in case of err
    let full_paths: Vec<PathBuf> = subdir_paths
        .iter()
        .map(|spath| {
            let mut path = PathBuf::from(mm_root);
            path.push(spath);
            path.push("MMManaged.dll");
            path
        })
        .collect();
    full_paths
        .iter()
        .filter(|p| p.as_path().exists())
        .take(1)
        .next()
        .ok_or(HookError::UnableToLocatedManagedDLL(format!(
            "Searched: {:?}",
            full_paths
        )))
        .and_then(|found| {
            found
                .as_path()
                .to_str()
                .ok_or(HookError::UnableToLocatedManagedDLL(format!(
                    "could not convert located path to string: {:?}",
                    found
                )))
                .and_then(|spath| Ok(String::from(spath)))
        })
}

pub fn to_wide_str(s: &str) -> Vec<u16> {
    use std::ffi::OsStr;
    use std::iter::once;
    use std::os::windows::ffi::OsStrExt;

    OsStr::new(s).encode_wide().chain(once(0)).collect()
}

pub fn get_module_name() -> Result<String> {
    use winapi::um::libloaderapi::*;
    use std::ffi::OsString;
    use std::os::windows::prelude::*;
    use winapi::shared::minwindef::DWORD;

    unsafe {
        let ssize = 65535;
        let mut mpath: Vec<u16> = Vec::with_capacity(ssize);

        let handle = GetModuleHandleW(std::ptr::null_mut());
        let r = GetModuleFileNameW(handle, mpath.as_mut_ptr(), ssize as DWORD);
        if r == 0 {
            return Err(HookError::ModuleNameError(format!(
                "failed to get module file name: {}",
                r
            )));
        } else {
            let s = std::slice::from_raw_parts(mpath.as_mut_ptr(), r as usize);
            let s = OsString::from_wide(&s).into_string()?;
            Ok(s)
        }
    }
}

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

    #[test]
    pub fn test_get_mm_conf_info() {
        // TODO: actually add the requisite values to the registry instead of
        // just assuming they are there.
        let res = get_mm_conf_info();
        match res {
            Err(e) => assert!(false, format!("conf test failed: {:?}", e)),
            Ok((ref active, ref _path)) if *active == false => {
                assert!(false, format!("mm should be active"))
            }
            Ok((ref active, ref path)) if *active == true && path.is_none() => {
                assert!(false, format!("if active, path must be set"))
            }
            Ok(_) => {}
        }
    }

    #[test]
    pub fn test_get_managed_dll_path() {
        if let Err(e) = get_managed_dll_path("C:\\Dev\\modelmod.new") {
            // TODO unhardcode
            assert!(false, format!("file should exist: {:?}", e))
        }
        if let Ok(f) = get_managed_dll_path("C:\\Dev\\modelmod.foo") {
            // TODO unhardcode
            assert!(false, format!("file should not exist: {:?}", f))
        }
    }

    #[test]
    pub fn test_load_lib() {
        let _r = load_lib("unlikely_ducksarecool.dll")
            .map(|h| assert!(false, "Expected Err but got {:?}", h));

        let _r = load_lib("d3d9.dll")
            .map(|h| {
                let _r = get_proc_address(h, "Direct3DCreate9")
                    .map_err(|err| assert!(false, "Expected Ok but got {:?}", err));

                let _r = get_proc_address(h, "NOTTHEREDirect3DCreate9")
                    .map(|res| assert!(false, "Expected Err but got {:?}", res));

                unload_lib(h).map_err(|err| assert!(false, "Expected Ok but got {:?}", err))
            })
            .map_err(|err| assert!(false, "Expected Ok but got {:?}", err));
    }
}
<commit_msg>Native: if no other path set, put log in temp dir<commit_after>use std;
use winapi;

use winapi::um::libloaderapi::{FreeLibrary, GetProcAddress, LoadLibraryW};
use winapi::shared::minwindef::{FARPROC, HMODULE};

use std::ffi::OsString;

lazy_static! {
    static ref LOG_FILE_NAME: std::sync::Mutex<String> = std::sync::Mutex::new(String::new());
}

#[derive(Debug, Clone)]
pub enum HookError {
    ProtectFailed,
    LoadLibFailed(String),
    GetProcAddressFailed(String),
    CLRInitFailed(String),
    NulError(std::ffi::NulError),
    GlobalStateCopyFailed,
    Direct3D9InstanceNotFound,
    CreateDeviceFailed(i32),
    ConfReadFailed(String),
    FailedToConvertString(OsString),
    WinApiError(String),
    ModuleNameError(String),
    UnableToLocatedManagedDLL(String),
    D3D9HookFailed,
    D3D9DeviceHookFailed,
    GlobalLockError,
}

impl std::convert::From<std::ffi::NulError> for HookError {
    fn from(error: std::ffi::NulError) -> Self {
        HookError::NulError(error)
    }
}

impl std::convert::From<std::ffi::OsString> for HookError {
    fn from(error: std::ffi::OsString) -> Self {
        HookError::FailedToConvertString(error)
    }
}

pub type Result<T> = std::result::Result<T, HookError>;

pub fn set_log_file_path(path: &str, name: &str) -> Result<()> {
    let lock = LOG_FILE_NAME.lock();
    match lock {
        Err(e) => Err(HookError::WinApiError(format!("lock error: {}", e))),
        Ok(mut fname) => {
            let mut p = path.to_owned();
            p.push_str(name);
            *fname = p;
            Ok(())
        }
    }
}

pub fn write_log_file(msg: &str) -> () {
    use std::io::Write;
    use std::fs::OpenOptions;
    use std::env::temp_dir;

    let lock = LOG_FILE_NAME.lock();
    match lock {
        Err(e) => {
            eprintln!(
                "ModelMod: derp, can't write log file due to lock error: {}",
                e
            );
        }
        Ok(mut fname) => {
            if (*fname).is_empty() {
                let mut td = temp_dir();
                td.push("ModelMod.log");
                match td.as_path().to_str() {
                    None => {
                        eprintln!("ModelMod: error getting temp path");
                        return;
                    }
                    Some(mut p) => {
                        *fname = p.to_owned();
                    }
                }
            }

            let tid = std::thread::current().id();

            let w = || -> std::io::Result<()> {
                let mut f = OpenOptions::new().create(true).append(true).open(&*fname)?;
                writeln!(f, "{:?}: {}\r", tid, msg)?;
                Ok(())
            };

            w().unwrap_or_else(|e| eprintln!("ModelMod: log file write error: {}", e));
        }
    };
}

pub unsafe fn protect_memory(
    target: *mut winapi::ctypes::c_void,
    size: usize,
    protection: u32,
) -> Result<u32> {
    let process = winapi::um::processthreadsapi::GetCurrentProcess();
    let mut old_protection = winapi::um::winnt::PAGE_READWRITE;
    if winapi::um::memoryapi::VirtualProtectEx(
        process,
        target as *mut winapi::ctypes::c_void,
        size,
        protection,
        (&mut old_protection) as *mut u32,
    ) > 0
    {
        Ok(old_protection)
    } else {
        Err(HookError::ProtectFailed)
    }
}

pub unsafe fn unprotect_memory(target: *mut winapi::ctypes::c_void, size: usize) -> Result<u32> {
    protect_memory(target, size, winapi::um::winnt::PAGE_READWRITE)
}

pub fn load_lib(name: &str) -> Result<HMODULE> {
    let wide: Vec<u16> = to_wide_str(name);
    let handle = unsafe { LoadLibraryW(wide.as_ptr()) };
    if handle == std::ptr::null_mut() {
        Err(HookError::LoadLibFailed(name.to_owned()))
    } else {
        Ok(handle)
    }
}

pub fn unload_lib(h: HMODULE) -> Result<()> {
    if unsafe { FreeLibrary(h) } == 0 {
        Err(HookError::LoadLibFailed(format!(
            "Unload of the library {:?} failed",
            h
        )))
    } else {
        Ok(())
    }
}

pub fn get_proc_address(h: HMODULE, name: &str) -> Result<FARPROC> {
    use std::ffi::CString;

    if h == std::ptr::null_mut() {
        return Err(HookError::GetProcAddressFailed("null handle".to_owned()));
    }
    let csname = CString::new(name)?;
    let addr = unsafe { GetProcAddress(h, csname.as_ptr()) };
    if addr == std::ptr::null_mut() {
        Err(HookError::GetProcAddressFailed(format!(
            "{} not found in module",
            name
        )))
    } else {
        Ok(addr)
    }
}

#[cfg(test)]
fn get_mm_reg_key() -> &'static str {
    "Software\\ModelModTEST"
}
#[cfg(not(test))]
fn get_mm_reg_key() -> &'static str {
    "Software\\ModelMod"
}
pub fn get_mm_conf_info() -> Result<(bool, Option<String>)> {
    unsafe {
        let reg_root = get_mm_reg_key();
        // find the MM install directory, this must be set in the registry by the launcher.
        // the launcher will also set whether MM is active.
        use winapi::um::winreg::*;
        use winapi::shared::minwindef::DWORD;
        use winapi::shared::winerror::ERROR_SUCCESS;
        use winapi::ctypes::c_void;

        use std::os::windows::prelude::*;

        // first check if it is active
        {
            let sk = to_wide_str(reg_root);
            let kv = to_wide_str("Active");
            let mut active: DWORD = 0;
            let p_active: *mut c_void = std::mem::transmute(&mut active);
            let mut out_active_sz: DWORD = std::mem::size_of::<DWORD>() as DWORD;
            let res = RegGetValueW(
                HKEY_CURRENT_USER,
                sk.as_ptr(),
                kv.as_ptr(),
                RRF_RT_REG_DWORD,
                std::ptr::null_mut(),
                p_active,
                &mut out_active_sz,
            );
            if res as DWORD != ERROR_SUCCESS {
                return Err(HookError::ConfReadFailed(format!("Error reading Active registry key: {}.  You must start ModelMod using its launcher.", res)));
            }
            if active != 1 {
                return Ok((false, None));
            }
        }

        // its active, so get path and make sure it exists
        {
            let sk = to_wide_str(reg_root);
            let kv = to_wide_str("MMRoot");
            let mut max_path: DWORD = 65535;
            // path could have wide chars, use u16
            let mut out_buf: Vec<u16> = Vec::with_capacity(max_path as usize);

            // max path input is in bytes
            max_path = max_path * 2;
            let res = RegGetValueW(
                HKEY_CURRENT_USER,
                sk.as_ptr(),
                kv.as_ptr(),
                RRF_RT_REG_SZ,
                std::ptr::null_mut(),
                out_buf.as_mut_ptr() as *mut c_void,
                &mut max_path,
            );
            if res as DWORD != ERROR_SUCCESS {
                return Err(HookError::ConfReadFailed(format!(
                    "Error reading MMRoot registry key: {}",
                    res
                )));
            }
            //println!("bytes read from registry {}", max_path);
            // convert bytes read to chars and remove null terminator
            let nchars = (max_path / 2) - 1;
            let wslice = std::slice::from_raw_parts(out_buf.as_mut_ptr(), nchars as usize);
            let wpath = OsString::from_wide(wslice).into_string()?;

            // check if path exists

            use std::path::Path;
            if !Path::new(&wpath).exists() {
                return Err(HookError::ConfReadFailed(format!(
                    "ModelMod path read from registry, {}, does not exist",
                    wpath
                )));
            }

            return Ok((true, Some(wpath)));
        }
    }
}

pub fn get_managed_dll_path(mm_root: &str) -> Result<String> {
    use std::path::PathBuf;

    let subdir_paths = ["", "Bin", "Release", "Debug"];
    // save the full path list so that we can reference it in case of err
    let full_paths: Vec<PathBuf> = subdir_paths
        .iter()
        .map(|spath| {
            let mut path = PathBuf::from(mm_root);
            path.push(spath);
            path.push("MMManaged.dll");
            path
        })
        .collect();
    full_paths
        .iter()
        .filter(|p| p.as_path().exists())
        .take(1)
        .next()
        .ok_or(HookError::UnableToLocatedManagedDLL(format!(
            "Searched: {:?}",
            full_paths
        )))
        .and_then(|found| {
            found
                .as_path()
                .to_str()
                .ok_or(HookError::UnableToLocatedManagedDLL(format!(
                    "could not convert located path to string: {:?}",
                    found
                )))
                .and_then(|spath| Ok(String::from(spath)))
        })
}

pub fn to_wide_str(s: &str) -> Vec<u16> {
    use std::ffi::OsStr;
    use std::iter::once;
    use std::os::windows::ffi::OsStrExt;

    OsStr::new(s).encode_wide().chain(once(0)).collect()
}

pub fn get_module_name() -> Result<String> {
    use winapi::um::libloaderapi::*;
    use std::ffi::OsString;
    use std::os::windows::prelude::*;
    use winapi::shared::minwindef::DWORD;

    unsafe {
        let ssize = 65535;
        let mut mpath: Vec<u16> = Vec::with_capacity(ssize);

        let handle = GetModuleHandleW(std::ptr::null_mut());
        let r = GetModuleFileNameW(handle, mpath.as_mut_ptr(), ssize as DWORD);
        if r == 0 {
            return Err(HookError::ModuleNameError(format!(
                "failed to get module file name: {}",
                r
            )));
        } else {
            let s = std::slice::from_raw_parts(mpath.as_mut_ptr(), r as usize);
            let s = OsString::from_wide(&s).into_string()?;
            Ok(s)
        }
    }
}

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

    #[test]
    pub fn test_get_mm_conf_info() {
        // TODO: actually add the requisite values to the registry instead of
        // just assuming they are there.
        let res = get_mm_conf_info();
        match res {
            Err(e) => assert!(false, format!("conf test failed: {:?}", e)),
            Ok((ref active, ref _path)) if *active == false => {
                assert!(false, format!("mm should be active"))
            }
            Ok((ref active, ref path)) if *active == true && path.is_none() => {
                assert!(false, format!("if active, path must be set"))
            }
            Ok(_) => {}
        }
    }

    #[test]
    pub fn test_get_managed_dll_path() {
        if let Err(e) = get_managed_dll_path("C:\\Dev\\modelmod.new") {
            // TODO unhardcode
            assert!(false, format!("file should exist: {:?}", e))
        }
        if let Ok(f) = get_managed_dll_path("C:\\Dev\\modelmod.foo") {
            // TODO unhardcode
            assert!(false, format!("file should not exist: {:?}", f))
        }
    }

    #[test]
    pub fn test_load_lib() {
        let _r = load_lib("unlikely_ducksarecool.dll")
            .map(|h| assert!(false, "Expected Err but got {:?}", h));

        let _r = load_lib("d3d9.dll")
            .map(|h| {
                let _r = get_proc_address(h, "Direct3DCreate9")
                    .map_err(|err| assert!(false, "Expected Ok but got {:?}", err));

                let _r = get_proc_address(h, "NOTTHEREDirect3DCreate9")
                    .map(|res| assert!(false, "Expected Err but got {:?}", res));

                unload_lib(h).map_err(|err| assert!(false, "Expected Ok but got {:?}", err))
            })
            .map_err(|err| assert!(false, "Expected Ok but got {:?}", err));
    }
}
<|endoftext|>