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

use v2::json::{buffer, Extras, Index};

/// Contains data structures for sparse storage.
pub mod sparse {
    use super::*;

    /// Extension specific data for `Indices`.
    #[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
    pub struct IndicesExtensions {
        #[serde(default)]
        _allow_unknown_fields: (),
    }

    /// Indices of those attributes that deviate from their initialization value.
    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
    #[serde(deny_unknown_fields)]
    pub struct Indices {
        /// The parent buffer view containing the sparse indices.
        ///
        /// The referenced buffer view must not have `ARRAY_BUFFER` nor
        /// `ELEMENT_ARRAY_BUFFER` as its target.
        #[serde(rename = "bufferView")]
        pub buffer_view: Index<buffer::View>,

        /// The offset relative to the start of the parent `BufferView` in bytes.
        #[serde(default, rename = "byteOffset")]
        pub byte_offset: u32,

        /// The data type of each index.
        #[serde(rename = "componentType")]
        pub component_type: u32,

        /// Extension specific data.
        pub extensions: IndicesExtensions,

        /// Optional application specific data.
        pub extras: Extras,
    }

    /// Extension specific data for `Storage`.
    #[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
    pub struct StorageExtensions {
        #[serde(default)]
        _allow_unknown_fields: (),
    }

    /// Sparse storage of attributes that deviate from their initialization value.
    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
    #[serde(deny_unknown_fields)]
    pub struct Sparse {
        /// The number of attributes encoded in this sparse accessor.
        pub count: u32,

        /// Index array of size `count` that points to those accessor attributes
        /// that deviate from their initialization value.
        ///
        /// Indices must strictly increase.
        pub indices: Indices,

        /// Array of size `count * number_of_components` storing the displaced
        /// accessor attributes pointed by `indices`.
        ///
        /// Substituted values must have the same `component_type` and number of
        /// components as the base `Accessor`.
        pub values: Values,

        /// Extension specific data.
        pub extensions: StorageExtensions,

        /// Optional application specific data.
        pub extras: Extras,
    }

    /// Extension specific data for `Values`.
    #[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
    pub struct ValuesExtensions {
        #[serde(default)]
        _allow_unknown_fields: (),
    }

    /// Array of size `count * number_of_components` storing the displaced
    /// accessor attributes pointed by `accessor::sparse::Indices`.
    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
    #[serde(deny_unknown_fields)]
    pub struct Values {
        /// The parent buffer view containing the sparse indices.
        ///
        /// The referenced buffer view must not have `ARRAY_BUFFER` nor
        /// `ELEMENT_ARRAY_BUFFER` as its target.
        #[serde(rename = "bufferView")]
        pub buffer_view: Index<buffer::View>,

        /// The offset relative to the start of the parent buffer view in bytes.
        #[serde(default, rename = "byteOffset")]
        pub byte_offset: u32,

        /// Extension specific data.
        pub extensions: ValuesExtensions,

        /// Optional application specific data.
        pub extras: Extras,
    }
}

/// Extension specific data for an `Accessor`.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct AccessorExtensions {
    #[serde(default)]
    _allow_unknown_fields: (),
}

/// A typed view into a buffer view.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[serde(deny_unknown_fields)]
pub struct Accessor {
    /// The parent buffer view this accessor reads from.
    #[serde(rename = "bufferView")]
    pub buffer_view: Index<buffer::View>,

    /// The offset relative to the start of the parent `BufferView` in bytes.
    #[serde(default, rename = "byteOffset")]
    pub byte_offset: u32,

    /// The number of components within the buffer view - not to be confused
    /// with the number of bytes in the buffer view.
    pub count: u32,

    /// The data type of components in the attribute.
    #[serde(rename = "componentType")]
    pub component_type: u32,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: AccessorExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,

    /// Specifies if the attribute is a scalar, vector, or matrix.
    #[serde(rename = "type")]
    pub type_: String,

    /// Minimum value of each component in this attribute.
    pub min: Vec<f32>,

    /// Maximum value of each component in this attribute.
    pub max: Vec<f32>,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// Specifies whether integer data values should be normalized.
    #[serde(default)]
    pub normalized: bool,

    /// Sparse storage of attributes that deviate from their initialization
    /// value.
    pub sparse: Option<sparse::Sparse>,
}

/*
impl Validate for Accessor {
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        self.buffer_view.validate(root, path.field("bufferView"), report);
        self.sparse.validate(root, path.field("sparse"), report);
    }
}
*/
<commit_msg>Removed commented out code<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use v2::json::{buffer, Extras, Index};

/// Contains data structures for sparse storage.
pub mod sparse {
    use super::*;

    /// Extension specific data for `Indices`.
    #[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
    pub struct IndicesExtensions {
        #[serde(default)]
        _allow_unknown_fields: (),
    }

    /// Indices of those attributes that deviate from their initialization value.
    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
    #[serde(deny_unknown_fields)]
    pub struct Indices {
        /// The parent buffer view containing the sparse indices.
        ///
        /// The referenced buffer view must not have `ARRAY_BUFFER` nor
        /// `ELEMENT_ARRAY_BUFFER` as its target.
        #[serde(rename = "bufferView")]
        pub buffer_view: Index<buffer::View>,

        /// The offset relative to the start of the parent `BufferView` in bytes.
        #[serde(default, rename = "byteOffset")]
        pub byte_offset: u32,

        /// The data type of each index.
        #[serde(rename = "componentType")]
        pub component_type: u32,

        /// Extension specific data.
        pub extensions: IndicesExtensions,

        /// Optional application specific data.
        pub extras: Extras,
    }

    /// Extension specific data for `Storage`.
    #[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
    pub struct StorageExtensions {
        #[serde(default)]
        _allow_unknown_fields: (),
    }

    /// Sparse storage of attributes that deviate from their initialization value.
    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
    #[serde(deny_unknown_fields)]
    pub struct Sparse {
        /// The number of attributes encoded in this sparse accessor.
        pub count: u32,

        /// Index array of size `count` that points to those accessor attributes
        /// that deviate from their initialization value.
        ///
        /// Indices must strictly increase.
        pub indices: Indices,

        /// Array of size `count * number_of_components` storing the displaced
        /// accessor attributes pointed by `indices`.
        ///
        /// Substituted values must have the same `component_type` and number of
        /// components as the base `Accessor`.
        pub values: Values,

        /// Extension specific data.
        pub extensions: StorageExtensions,

        /// Optional application specific data.
        pub extras: Extras,
    }

    /// Extension specific data for `Values`.
    #[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
    pub struct ValuesExtensions {
        #[serde(default)]
        _allow_unknown_fields: (),
    }

    /// Array of size `count * number_of_components` storing the displaced
    /// accessor attributes pointed by `accessor::sparse::Indices`.
    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
    #[serde(deny_unknown_fields)]
    pub struct Values {
        /// The parent buffer view containing the sparse indices.
        ///
        /// The referenced buffer view must not have `ARRAY_BUFFER` nor
        /// `ELEMENT_ARRAY_BUFFER` as its target.
        #[serde(rename = "bufferView")]
        pub buffer_view: Index<buffer::View>,

        /// The offset relative to the start of the parent buffer view in bytes.
        #[serde(default, rename = "byteOffset")]
        pub byte_offset: u32,

        /// Extension specific data.
        pub extensions: ValuesExtensions,

        /// Optional application specific data.
        pub extras: Extras,
    }
}

/// Extension specific data for an `Accessor`.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct AccessorExtensions {
    #[serde(default)]
    _allow_unknown_fields: (),
}

/// A typed view into a buffer view.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[serde(deny_unknown_fields)]
pub struct Accessor {
    /// The parent buffer view this accessor reads from.
    #[serde(rename = "bufferView")]
    pub buffer_view: Index<buffer::View>,

    /// The offset relative to the start of the parent `BufferView` in bytes.
    #[serde(default, rename = "byteOffset")]
    pub byte_offset: u32,

    /// The number of components within the buffer view - not to be confused
    /// with the number of bytes in the buffer view.
    pub count: u32,

    /// The data type of components in the attribute.
    #[serde(rename = "componentType")]
    pub component_type: u32,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: AccessorExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,

    /// Specifies if the attribute is a scalar, vector, or matrix.
    #[serde(rename = "type")]
    pub type_: String,

    /// Minimum value of each component in this attribute.
    pub min: Vec<f32>,

    /// Maximum value of each component in this attribute.
    pub max: Vec<f32>,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// Specifies whether integer data values should be normalized.
    #[serde(default)]
    pub normalized: bool,

    /// Sparse storage of attributes that deviate from their initialization
    /// value.
    pub sparse: Option<sparse::Sparse>,
}
<|endoftext|>


<commit_before>use std::fmt;

use super::{AppError, InternalAppErrorStatic};
use crate::util::{json_response, AppResponse};

use chrono::NaiveDateTime;
use conduit::{header, StatusCode};

/// Generates a response with the provided status and description as JSON
fn json_error(detail: &str, status: StatusCode) -> AppResponse {
    #[derive(Serialize)]
    struct StringError<'a> {
        detail: &'a str,
    }
    #[derive(Serialize)]
    struct Bad<'a> {
        errors: [StringError<'a>; 1],
    }

    let mut response = json_response(&Bad {
        errors: [StringError { detail }],
    });
    *response.status_mut() = status;
    response
}

// The following structs are emtpy and do not provide a custom message to the user

#[derive(Debug)]
pub(crate) struct NotFound;

// This struct has this helper impl for use as `NotFound.into()`
impl From<NotFound> for AppResponse {
    fn from(_: NotFound) -> AppResponse {
        json_error("Not Found", StatusCode::NOT_FOUND)
    }
}

impl AppError for NotFound {
    fn response(&self) -> Option<AppResponse> {
        Some(Self.into())
    }
}

impl fmt::Display for NotFound {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Not Found".fmt(f)
    }
}

#[derive(Debug)]
pub(super) struct Forbidden;
#[derive(Debug)]
pub(crate) struct ReadOnlyMode;

impl AppError for Forbidden {
    fn response(&self) -> Option<AppResponse> {
        let detail = "must be logged in to perform that action";
        Some(json_error(detail, StatusCode::FORBIDDEN))
    }
}

impl fmt::Display for Forbidden {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "must be logged in to perform that action".fmt(f)
    }
}

impl AppError for ReadOnlyMode {
    fn response(&self) -> Option<AppResponse> {
        let detail = "Crates.io is currently in read-only mode for maintenance. \
                      Please try again later.";
        Some(json_error(detail, StatusCode::SERVICE_UNAVAILABLE))
    }
}

impl fmt::Display for ReadOnlyMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Tried to write in read only mode".fmt(f)
    }
}

// The following structs wrap owned data and provide a custom message to the user

#[derive(Debug)]
pub(super) struct Ok(pub(super) String);
#[derive(Debug)]
pub(super) struct BadRequest(pub(super) String);
#[derive(Debug)]
pub(super) struct ServerError(pub(super) String);
#[derive(Debug)]
pub(crate) struct TooManyRequests {
    pub retry_after: NaiveDateTime,
}

impl AppError for Ok {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.0, StatusCode::OK))
    }
}

impl fmt::Display for Ok {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AppError for BadRequest {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.0, StatusCode::BAD_REQUEST))
    }
}

impl fmt::Display for BadRequest {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AppError for ServerError {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.0, StatusCode::INTERNAL_SERVER_ERROR))
    }
}

impl fmt::Display for ServerError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AppError for TooManyRequests {
    fn response(&self) -> Option<AppResponse> {
        use std::convert::TryInto;

        const HTTP_DATE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT";
        let retry_after = self.retry_after.format(HTTP_DATE_FORMAT);

        let detail = format!(
            "You have published too many crates in a \
             short period of time. Please try again after {} or email \
             help@crates.io to have your limit increased.",
            retry_after
        );
        let mut response = json_error(&detail, StatusCode::TOO_MANY_REQUESTS);
        response.headers_mut().insert(
            header::RETRY_AFTER,
            retry_after
                .to_string()
                .try_into()
                .expect("HTTP_DATE_FORMAT contains invalid char"),
        );
        Some(response)
    }
}

impl fmt::Display for TooManyRequests {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Too many requests".fmt(f)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct InsecurelyGeneratedTokenRevoked;

impl InsecurelyGeneratedTokenRevoked {
    pub fn boxed() -> Box<dyn AppError> {
        Box::new(Self)
    }
}

impl AppError for InsecurelyGeneratedTokenRevoked {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::UNAUTHORIZED))
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&InternalAppErrorStatic {
            description: "insecurely generated, revoked 2020-07",
        })
    }
}

pub const TOKEN_FORMAT_ERROR: &str =
    "The given API token does not match the format used by crates.io. \
    \
    Tokens generated before 2020-07-14 were generated with an insecure \
    random number generator, and have been revoked. You can generate a \
    new token at https://crates.io/me. \
    \
    For more information please see \
    https://blog.rust-lang.org/2020/07/14/crates-io-security-advisory.html. \
    We apologize for any inconvenience.";

impl fmt::Display for InsecurelyGeneratedTokenRevoked {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(TOKEN_FORMAT_ERROR)?;
        Result::Ok(())
    }
}

#[derive(Debug)]
pub(super) struct AccountLocked {
    pub(super) reason: String,
    pub(super) until: Option<NaiveDateTime>,
}

impl AppError for AccountLocked {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::FORBIDDEN))
    }
}

impl fmt::Display for AccountLocked {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(until) = self.until {
            let until = until.format("%Y-%m-%d at %H:%M:%S UTC");
            write!(
                f,
                "This account is locked until {}. Reason: {}",
                until, self.reason
            )
        } else {
            write!(
                f,
                "This account is indefinitely locked. Reason: {}",
                self.reason
            )
        }
    }
}

#[derive(Debug)]
pub(crate) struct OwnershipInvitationExpired {
    pub(crate) crate_name: String,
}

impl AppError for OwnershipInvitationExpired {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::GONE))
    }
}

impl fmt::Display for OwnershipInvitationExpired {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "The invitation to become an owner of the {} crate expired. \
             Please reach out to an owner of the crate to request a new invitation.",
            self.crate_name
        )
    }
}

#[derive(Debug)]
pub(crate) struct MetricsDisabled;

impl AppError for MetricsDisabled {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::NOT_FOUND))
    }
}

impl fmt::Display for MetricsDisabled {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Metrics are disabled on this crates.io instance")
    }
}
<commit_msg>errors::json: Use `json!` macro to simplify JSON serialization code<commit_after>use std::fmt;

use super::{AppError, InternalAppErrorStatic};
use crate::util::{json_response, AppResponse};

use chrono::NaiveDateTime;
use conduit::{header, StatusCode};

/// Generates a response with the provided status and description as JSON
fn json_error(detail: &str, status: StatusCode) -> AppResponse {
    let json = json!({ "errors": [{ "detail": detail }] });

    let mut response = json_response(&json);
    *response.status_mut() = status;
    response
}

// The following structs are emtpy and do not provide a custom message to the user

#[derive(Debug)]
pub(crate) struct NotFound;

// This struct has this helper impl for use as `NotFound.into()`
impl From<NotFound> for AppResponse {
    fn from(_: NotFound) -> AppResponse {
        json_error("Not Found", StatusCode::NOT_FOUND)
    }
}

impl AppError for NotFound {
    fn response(&self) -> Option<AppResponse> {
        Some(Self.into())
    }
}

impl fmt::Display for NotFound {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Not Found".fmt(f)
    }
}

#[derive(Debug)]
pub(super) struct Forbidden;
#[derive(Debug)]
pub(crate) struct ReadOnlyMode;

impl AppError for Forbidden {
    fn response(&self) -> Option<AppResponse> {
        let detail = "must be logged in to perform that action";
        Some(json_error(detail, StatusCode::FORBIDDEN))
    }
}

impl fmt::Display for Forbidden {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "must be logged in to perform that action".fmt(f)
    }
}

impl AppError for ReadOnlyMode {
    fn response(&self) -> Option<AppResponse> {
        let detail = "Crates.io is currently in read-only mode for maintenance. \
                      Please try again later.";
        Some(json_error(detail, StatusCode::SERVICE_UNAVAILABLE))
    }
}

impl fmt::Display for ReadOnlyMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Tried to write in read only mode".fmt(f)
    }
}

// The following structs wrap owned data and provide a custom message to the user

#[derive(Debug)]
pub(super) struct Ok(pub(super) String);
#[derive(Debug)]
pub(super) struct BadRequest(pub(super) String);
#[derive(Debug)]
pub(super) struct ServerError(pub(super) String);
#[derive(Debug)]
pub(crate) struct TooManyRequests {
    pub retry_after: NaiveDateTime,
}

impl AppError for Ok {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.0, StatusCode::OK))
    }
}

impl fmt::Display for Ok {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AppError for BadRequest {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.0, StatusCode::BAD_REQUEST))
    }
}

impl fmt::Display for BadRequest {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AppError for ServerError {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.0, StatusCode::INTERNAL_SERVER_ERROR))
    }
}

impl fmt::Display for ServerError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AppError for TooManyRequests {
    fn response(&self) -> Option<AppResponse> {
        use std::convert::TryInto;

        const HTTP_DATE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT";
        let retry_after = self.retry_after.format(HTTP_DATE_FORMAT);

        let detail = format!(
            "You have published too many crates in a \
             short period of time. Please try again after {} or email \
             help@crates.io to have your limit increased.",
            retry_after
        );
        let mut response = json_error(&detail, StatusCode::TOO_MANY_REQUESTS);
        response.headers_mut().insert(
            header::RETRY_AFTER,
            retry_after
                .to_string()
                .try_into()
                .expect("HTTP_DATE_FORMAT contains invalid char"),
        );
        Some(response)
    }
}

impl fmt::Display for TooManyRequests {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Too many requests".fmt(f)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct InsecurelyGeneratedTokenRevoked;

impl InsecurelyGeneratedTokenRevoked {
    pub fn boxed() -> Box<dyn AppError> {
        Box::new(Self)
    }
}

impl AppError for InsecurelyGeneratedTokenRevoked {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::UNAUTHORIZED))
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&InternalAppErrorStatic {
            description: "insecurely generated, revoked 2020-07",
        })
    }
}

pub const TOKEN_FORMAT_ERROR: &str =
    "The given API token does not match the format used by crates.io. \
    \
    Tokens generated before 2020-07-14 were generated with an insecure \
    random number generator, and have been revoked. You can generate a \
    new token at https://crates.io/me. \
    \
    For more information please see \
    https://blog.rust-lang.org/2020/07/14/crates-io-security-advisory.html. \
    We apologize for any inconvenience.";

impl fmt::Display for InsecurelyGeneratedTokenRevoked {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(TOKEN_FORMAT_ERROR)?;
        Result::Ok(())
    }
}

#[derive(Debug)]
pub(super) struct AccountLocked {
    pub(super) reason: String,
    pub(super) until: Option<NaiveDateTime>,
}

impl AppError for AccountLocked {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::FORBIDDEN))
    }
}

impl fmt::Display for AccountLocked {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(until) = self.until {
            let until = until.format("%Y-%m-%d at %H:%M:%S UTC");
            write!(
                f,
                "This account is locked until {}. Reason: {}",
                until, self.reason
            )
        } else {
            write!(
                f,
                "This account is indefinitely locked. Reason: {}",
                self.reason
            )
        }
    }
}

#[derive(Debug)]
pub(crate) struct OwnershipInvitationExpired {
    pub(crate) crate_name: String,
}

impl AppError for OwnershipInvitationExpired {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::GONE))
    }
}

impl fmt::Display for OwnershipInvitationExpired {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "The invitation to become an owner of the {} crate expired. \
             Please reach out to an owner of the crate to request a new invitation.",
            self.crate_name
        )
    }
}

#[derive(Debug)]
pub(crate) struct MetricsDisabled;

impl AppError for MetricsDisabled {
    fn response(&self) -> Option<AppResponse> {
        Some(json_error(&self.to_string(), StatusCode::NOT_FOUND))
    }
}

impl fmt::Display for MetricsDisabled {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Metrics are disabled on this crates.io instance")
    }
}
<|endoftext|>


<commit_before>use latex::escape_tex;
use serde_json::Value;
use std::collections::HashMap;
use tera::{Error, Tera};

fn escape_tex_filter(json: Value, _: HashMap<String, Value>) -> Result<Value, Error> {
    Ok(escape_tex(json))
}

pub fn make_tera() -> Tera {
    let mut tera = Tera::default();
    tera.register_filter("escape_tex", escape_tex_filter);
    tera
}
<commit_msg>✅ Test the escape_tex custom tera filter<commit_after>use latex::escape_tex;
use serde_json::Value;
use std::collections::HashMap;
use tera::{Error, Tera};

fn escape_tex_filter(json: Value, _: HashMap<String, Value>) -> Result<Value, Error> {
    Ok(escape_tex(json))
}

pub fn make_tera() -> Tera {
    let mut tera = Tera::default();
    tera.register_filter("escape_tex", escape_tex_filter);
    tera
}

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

    #[test]
    fn make_tera_surfaces_working_escape_filter() {

        static TEMPLATE: &'static str = r"
        \documentclass{article}

        \begin{document}
        {{escape_me | escape_tex}}
        {{do_not_escape}}
        \end{document}
        ";

        static EXPECTED_TEMPLATE_RESULT: &'static str = r"
        \documentclass{article}

        \begin{document}
        Brothers \& Sisters 100\% 0.50\$ Ernst is numero \#1 rust\_convention \{or not\}
        % you shall not compile %
        \end{document}
        ";

        let mut tera = make_tera();
        let variables = json!({
            "escape_me": "Brothers & Sisters 100% 0.50$ Ernst is numero #1 rust_convention {or not}",
            "do_not_escape": "% you shall not compile %",
        });
        tera.add_raw_template("template", TEMPLATE)
            .expect("failed to add raw template");
        let rendered_template = tera.render("template", &variables)
            .expect("failed to render the template");
        assert_eq!(rendered_template, EXPECTED_TEMPLATE_RESULT);
    }
}

<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
# Translation of inline assembly.
*/

use core::prelude::*;

use lib;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::common::*;
use middle::ty;

use syntax::ast;

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {

    let mut bcx = bcx;
    let mut constraints = ~[];
    let mut cleanups = ~[];
    let mut aoutputs = ~[];

    // Prepare the output operands
    let outputs = do ia.outputs.map |&(c, out)| {
        constraints.push(copy *c);

        let aoutty = ty::arg {
            mode: ast::expl(ast::by_copy),
            ty: expr_ty(bcx, out)
        };
        aoutputs.push(unpack_result!(bcx, {
            callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups, None, callee::DontAutorefArg)
        }));

        let e = match out.node {
            ast::expr_addr_of(_, e) => e,
            _ => fail!(~"Expression must be addr of")
        };

        let outty = ty::arg {
            mode: ast::expl(ast::by_copy),
            ty: expr_ty(bcx, e)
        };

        unpack_result!(bcx, {
            callee::trans_arg_expr(bcx, outty, e, &mut cleanups, None, callee::DontAutorefArg)
        })

    };

    for cleanups.each |c| {
        revoke_clean(bcx, *c);
    }
    cleanups.clear();

    // Now the input operands
    let inputs = do ia.inputs.map |&(c, in)| {
        constraints.push(copy *c);

        let inty = ty::arg {
            mode: ast::expl(ast::by_copy),
            ty: expr_ty(bcx, in)
        };

        unpack_result!(bcx, {
            callee::trans_arg_expr(bcx, inty, in, &mut cleanups, None, callee::DontAutorefArg)
        })

    };

    for cleanups.each |c| {
        revoke_clean(bcx, *c);
    }

    let mut constraints = str::connect(constraints, ",");

    let mut clobbers = getClobbers();
    if *ia.clobbers != ~"" && clobbers != ~"" {
        clobbers = *ia.clobbers + ~"," + clobbers;
    } else {
        clobbers += *ia.clobbers;
    };

    // Add the clobbers to our constraints list
    if clobbers != ~"" && constraints != ~"" {
        constraints += ~"," + clobbers;
    } else {
        constraints += clobbers;
    }

    debug!("Asm Constraints: %?", constraints);

    let numOutputs = outputs.len();

    // Depending on how many outputs we have, the return type is different
    let output = if numOutputs == 0 {
        T_void()
    } else if numOutputs == 1 {
        val_ty(outputs[0])
    } else {
        T_struct(outputs.map(|o| val_ty(*o)))
    };

    let dialect = match ia.dialect {
        ast::asm_att   => lib::llvm::AD_ATT,
        ast::asm_intel => lib::llvm::AD_Intel
    };

    let r = do str::as_c_str(*ia.asm) |a| {
        do str::as_c_str(constraints) |c| {
            InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
        }
    };

    // Again, based on how many outputs we have
    if numOutputs == 1 {
        let op = PointerCast(bcx, aoutputs[0], T_ptr(val_ty(outputs[0])));
        Store(bcx, r, op);
    } else {
        for aoutputs.eachi |i, o| {
            let v = ExtractValue(bcx, r, i);
            let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
            Store(bcx, v, op);
        }
    }

    return bcx;

}

// Default per-arch clobbers
// Basically what clang does

#[cfg(target_arch = "arm")]
#[cfg(target_arch = "mips")]
fn getClobbers() -> ~str {
    ~""
}

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
fn getClobbers() -> ~str {
    ~"~{dirflag},~{fpsr},~{flags}"
}
<commit_msg>Tidy.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
# Translation of inline assembly.
*/

use core::prelude::*;

use lib;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::common::*;
use middle::ty;

use syntax::ast;

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {

    let mut bcx = bcx;
    let mut constraints = ~[];
    let mut cleanups = ~[];
    let mut aoutputs = ~[];

    // Prepare the output operands
    let outputs = do ia.outputs.map |&(c, out)| {
        constraints.push(copy *c);

        let aoutty = ty::arg {
            mode: ast::expl(ast::by_copy),
            ty: expr_ty(bcx, out)
        };
        aoutputs.push(unpack_result!(bcx, {
            callee::trans_arg_expr(bcx, aoutty, out, &mut cleanups, None, callee::DontAutorefArg)
        }));

        let e = match out.node {
            ast::expr_addr_of(_, e) => e,
            _ => fail!(~"Expression must be addr of")
        };

        let outty = ty::arg {
            mode: ast::expl(ast::by_copy),
            ty: expr_ty(bcx, e)
        };

        unpack_result!(bcx, {
            callee::trans_arg_expr(bcx, outty, e, &mut cleanups, None, callee::DontAutorefArg)
        })

    };

    for cleanups.each |c| {
        revoke_clean(bcx, *c);
    }
    cleanups.clear();

    // Now the input operands
    let inputs = do ia.inputs.map |&(c, in)| {
        constraints.push(copy *c);

        let inty = ty::arg {
            mode: ast::expl(ast::by_copy),
            ty: expr_ty(bcx, in)
        };

        unpack_result!(bcx, {
            callee::trans_arg_expr(bcx, inty, in, &mut cleanups, None, callee::DontAutorefArg)
        })

    };

    for cleanups.each |c| {
        revoke_clean(bcx, *c);
    }

    let mut constraints = str::connect(constraints, ",");

    let mut clobbers = getClobbers();
    if *ia.clobbers != ~"" && clobbers != ~"" {
        clobbers = *ia.clobbers + ~"," + clobbers;
    } else {
        clobbers += *ia.clobbers;
    };

    // Add the clobbers to our constraints list
    if clobbers != ~"" && constraints != ~"" {
        constraints += ~"," + clobbers;
    } else {
        constraints += clobbers;
    }

    debug!("Asm Constraints: %?", constraints);

    let numOutputs = outputs.len();

    // Depending on how many outputs we have, the return type is different
    let output = if numOutputs == 0 {
        T_void()
    } else if numOutputs == 1 {
        val_ty(outputs[0])
    } else {
        T_struct(outputs.map(|o| val_ty(*o)))
    };

    let dialect = match ia.dialect {
        ast::asm_att   => lib::llvm::AD_ATT,
        ast::asm_intel => lib::llvm::AD_Intel
    };

    let r = do str::as_c_str(*ia.asm) |a| {
        do str::as_c_str(constraints) |c| {
            InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
        }
    };

    // Again, based on how many outputs we have
    if numOutputs == 1 {
        let op = PointerCast(bcx, aoutputs[0], T_ptr(val_ty(outputs[0])));
        Store(bcx, r, op);
    } else {
        for aoutputs.eachi |i, o| {
            let v = ExtractValue(bcx, r, i);
            let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i])));
            Store(bcx, v, op);
        }
    }

    return bcx;

}

// Default per-arch clobbers
// Basically what clang does

#[cfg(target_arch = "arm")]
#[cfg(target_arch = "mips")]
fn getClobbers() -> ~str {
    ~""
}

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
fn getClobbers() -> ~str {
    ~"~{dirflag},~{fpsr},~{flags}"
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::cmp::{max, min};
use std::convert::AsRef;
use std::io;
use std::fs;
use std::path::Path;

use bio::io::gff::{self, GffType};
use itertools::{GroupBy, Group, Itertools};
use linked_hash_map::LinkedHashMap;

use {Coord, Exon, ExonFeatureKind as EFK, Gene, GBuilder, Strand, Transcript, Error};

// Various commonly-used feature column values
const GENE_STR: &'static str = "gene";
const TRANSCRIPT_STR: &'static str = "transcript";
const EXON_STR: &'static str = "exon";
const UTR_STR: &'static str = "UTR";
const UTR5_STR: &'static str = "UTR5";
const UTR3_STR: &'static str = "UTR3";
const CDS_STR: &'static str = "CDS";
const START_CODON_STR: &'static str = "start_codon";
const STOP_CODON_STR: &'static str = "stop_codon";

// Value for unknown columns.
const UNK_STR: &'static str = ".";

// Commonly-used attribute keys.
const GENE_ID_STR: &'static str = "gene_id";
const TRANSCRIPT_ID_STR: &'static str = "transcript_id";

// Initial coordinate for features.
const INIT_COORD: (u64, u64) = (::std::u64::MAX, ::std::u64::MIN);

pub struct Reader<R: io::Read> {
    inner: gff::Reader<R>,
}

impl<R: io::Read> Reader<R> {

    pub fn from_reader(in_reader: R, gff_type: GffType) -> Reader<R> {
        Reader {
            inner: gff::Reader::new(in_reader, gff_type),
        }
    }

    pub fn genes(&mut self) -> GffGenes<R> {
        GffGenes {
            inner: self.records().group_by(GffGenes::<R>::gene_groupf),
        }
    }

    fn records(&mut self) -> GffRecords<R> {
        GffRecords {
            inner: self.inner.records()
        }
    }
}

impl Reader<fs::File> {
    pub fn from_file<P: AsRef<Path>>(path: P, gff_type: GffType) -> io::Result<Self> {
        fs::File::open(path).map(|file| Reader::from_reader(file, gff_type))
    }
}

struct GffRecords<'a, R: 'a> where R: io::Read {
    inner: gff::Records<'a, R>,
}

impl<'a, R> Iterator for GffRecords<'a, R> where R: io::Read {

    type Item = Result<gff::Record, Error>;

    fn next(&mut self) -> Option<Result<gff::Record, Error>> {
        self.inner.next()
            .map(|row| {
                row.or_else(|err| Err(Error::from(err)))
            })
    }
}

pub struct GffGenes<'a, R: 'a> where R: io::Read, {
    inner: GroupBy<GxGroupKey, GffRecords<'a, R>, GxGroupFunc>,
}

type GxGroupKey = Option<(String, String, Strand)>;

type GxGroupFunc = fn(&Result<gff::Record, Error>) -> GxGroupKey;

type GxGroupedRecs<'a, 'b, R> = Group<'b, GxGroupKey, GffRecords<'a, R>, GxGroupFunc>;

type RawTrxCoord = (Coord<u64>, Vec<Coord<u64>>, Option<Coord<u64>>);

impl<'a, R> GffGenes<'a, R> where R: io::Read {

    fn gene_groupf(result: &Result<gff::Record, Error>) -> GxGroupKey {
        result.as_ref().ok()
            .map(|res| {
                let gene_id = res.attributes().get(GENE_ID_STR)
                    .map(|gid| gid.as_str())
                    .unwrap_or("");
                let seq_name = String::from(res.seqname());
                let strand = res.strand().unwrap_or(Strand::Unknown);

                (String::from(gene_id), seq_name, strand)
            })
    }

    fn group_to_gene<'b>(group: (GxGroupKey, GxGroupedRecs<'a, 'b, R>)) -> Result<Gene, Error> {
        let (group_key, records) = group;
        match group_key {

            None => Err(records.filter_map(|x| x.err()).next().unwrap()),

            Some((gid, seq_name, strand)) => {

                let mut gene_coord = INIT_COORD;
                let mut trx_coords: LinkedHashMap<String, RawTrxCoord> = LinkedHashMap::new();

                for record in records {

                    let mut rec = record?;
                    rec.attributes_mut().remove(GENE_ID_STR);

                    let rtrx_entry = rec.attributes_mut()
                        .remove(TRANSCRIPT_ID_STR)
                        .ok_or(Error::Gff("required 'transcript_id' attribute not found"))
                        .map(|id| trx_coords.entry(id).or_insert((INIT_COORD, vec![], None)));

                    match rec.feature_type() {
                        GENE_STR => {
                            gene_coord = adjust_coord(gene_coord, &rec);
                        },
                        TRANSCRIPT_STR => {
                            let trx_entry = rtrx_entry?;
                            trx_entry.0 = adjust_coord(trx_entry.0, &rec);
                        },
                        EXON_STR => {
                            let trx_entry = rtrx_entry?;
                            (trx_entry.1).push((*rec.start() - 1, *rec.end()));
                        },
                        CDS_STR => {
                            let trx_entry = rtrx_entry?;
                            trx_entry.2 = (trx_entry.2).or(Some(INIT_COORD))
                                .map(|coord| adjust_coord(coord, &rec));
                        },
                        // TODO: How to best handle nested features? They may be out of order ...
                        _ => {},
                    }
                }

                GBuilder::new(seq_name, gene_coord.0, gene_coord.1)
                    .id(gid)
                    .strand(strand)
                    .transcript_coords(trx_coords)
                    .build()
            },
        }
    }
}

impl<'a, R> Iterator for GffGenes<'a, R> where R: io::Read {

    type Item = Result<Gene, Error>;

    fn next(&mut self) -> Option<Result<Gene, Error>> {
        self.inner.into_iter().map(Self::group_to_gene).next()
    }
}

struct GffRow(String, String, String, u64, u64, String, String, String, HashMap<String, String>);

impl From<GffRow> for gff::Record {
    fn from(row: GffRow) -> Self {
        let mut rec = gff::Record::default();
        *rec.seqname_mut() = row.0;
        *rec.source_mut() = row.1;
        *rec.feature_type_mut() = row.2;
        *rec.start_mut() = row.3 + 1;
        *rec.end_mut() = row.4;
        *rec.score_mut() = row.5;
        *rec.strand_mut() = row.6;
        *rec.frame_mut() = row.7;
        *rec.attributes_mut() = row.8;
        rec
    }
}

impl Gene {

    #[inline(always)]
    fn num_records(&self) -> usize {
        1 + self.transcripts().values()
            .map(|ref trx| trx.num_records())
            .fold(0, |acc, x| acc + x)
    }

    // TODO: also handle gene-level features
    fn to_gff_records(mut self) -> Result<Vec<gff::Record>, Error> {

        let (source, score) = extract_source_score(&mut self.attributes);
        let strand = strand_to_string(self.strand());
        let gene_id = match self.id.take() {
            Some(gid) => {
                self.attributes.insert(GENE_ID_STR.to_owned(), gid.clone());
                gid
            },
            None =>  {
                self.attributes.get(GENE_ID_STR)
                    .ok_or(Error::Gff("required 'gene_id' attribute not found"))
                    .map(|gid| gid.clone())?
            },
        };

        let mut recs = Vec::with_capacity(self.num_records());

        let row = GffRow(
            self.seq_name().to_owned(), source, GENE_STR.to_owned(),
            self.interval().start, self.interval().end, score, strand.to_owned(),
            UNK_STR.to_owned(), self.attributes.clone());
        recs.push(gff::Record::from(row));

        for (_, mut transcript) in self.into_transcripts() {
            let mut trx_recs = transcript.to_gff_records(gene_id.as_str())?;
            recs.append(&mut trx_recs);
        }

        Ok(recs)
    }
}

impl Transcript {

    #[inline(always)]
    fn num_records(&self) -> usize {
        1 + self.exons().iter()
            .map(|ref exn| 1 + exn.features.len())
            .fold(0, |acc, x| acc + x)
    }

    // TODO: also handle transcript-level features
    fn to_gff_records(mut self, gene_id: &str) -> Result<Vec<gff::Record>, Error> {

        self.attributes.insert(GENE_ID_STR.to_owned(), gene_id.to_owned());
        let (source, score) = extract_source_score(&mut self.attributes);
        let strand = strand_to_string(self.strand());
        let transcript_id = match self.id.take() {
            Some(tid) => {
                self.attributes.insert(TRANSCRIPT_ID_STR.to_owned(), tid.clone());
                tid
            },
            None =>  {
                self.attributes.get(TRANSCRIPT_ID_STR)
                    .ok_or(Error::Gff("required 'transcript_id' attribute not found"))
                    .map(|tid| tid.clone())?
            },
        };

        let mut recs = Vec::with_capacity(self.num_records());

        let trx_row =
            GffRow(self.seq_name().to_owned(), source, TRANSCRIPT_STR.to_owned(),
                   self.interval().start, self.interval().end, score,
                   strand.to_owned(), UNK_STR.to_owned(), self.attributes.clone());
        recs.push(gff::Record::from(trx_row));

        for exon in self.into_exons() {
            let mut exon_recs = exon.to_gff_records(gene_id, transcript_id.as_str())?;
            recs.append(&mut exon_recs);
        }

        Ok(recs)
    }
}

impl EFK {

    #[inline(always)]
    fn get_feature_frame(&self) -> (String, String) {
        let (feature, frame) = match self {
            &EFK::UTR => (UTR_STR, UNK_STR),
            &EFK::UTR5 => (UTR5_STR, UNK_STR),
            &EFK::UTR3 => (UTR3_STR, UNK_STR),
            &EFK::CDS { frame: ref f } => (CDS_STR, frame_to_str(f)),
            &EFK::StopCodon { frame: ref f } => (STOP_CODON_STR, frame_to_str(f)),
            &EFK::StartCodon { frame: ref f } => (START_CODON_STR, frame_to_str(f)),
            &EFK::Any(ref s) => (s.as_str(), UNK_STR),
        };
        (feature.to_owned(), frame.to_owned())
    }
}

impl Exon {

    fn to_gff_records(mut self, gene_id: &str, transcript_id: &str
    ) -> Result<Vec<gff::Record>, Error> {

        self.attributes.insert(GENE_ID_STR.to_owned(), gene_id.to_owned());
        self.attributes.insert(TRANSCRIPT_ID_STR.to_owned(), transcript_id.to_owned());
        let (source, score) = extract_source_score(&mut self.attributes);
        let strand = strand_to_string(self.strand());

        let mut recs = Vec::with_capacity(1 + self.features.len());

        let exon_row =
            GffRow(self.seq_name().to_owned(), source.clone(), EXON_STR.to_owned(),
                   self.interval().start, self.interval().end, score, strand.to_owned(),
                   UNK_STR.to_owned(), self.attributes.clone());
        recs.push(gff::Record::from(exon_row));

        for fx in self.features.iter() {
            let (feature, frame) = fx.kind.get_feature_frame();
            let fx_row =
                GffRow(self.seq_name().to_owned(), source.clone(), feature,
                       self.interval().start, self.interval().end, UNK_STR.to_owned(),
                       strand.to_owned(), UNK_STR.to_owned(), self.attributes.clone());
            recs.push(gff::Record::from(fx_row));
        }

        Ok(recs)
    }
}

pub struct Writer<W: io::Write> {
    inner: gff::Writer<W>,
}

impl<W: io::Write> Writer<W> {

    pub fn from_writer(in_writer: W, gff_type: GffType) -> Writer<W> {
        Writer {
            inner: gff::Writer::new(in_writer, gff_type),
        }
    }

    pub fn write_gene(&mut self, mut gene: Gene) -> Result<(), Error> {
        for record in gene.to_gff_records()?.iter() {
            self.inner.write(&record)?;
        }
        Ok(())
    }
}

#[inline(always)]
fn adjust_coord(cur_coord: Coord<u64>, record: &gff::Record) -> Coord<u64> {
    (min(cur_coord.0, *record.start() - 1),
     max(cur_coord.1, *record.end()))
}

#[inline(always)]
fn extract_source_score(attributes: &mut HashMap<String, String>) -> (String, String) {
    let source = attributes.remove("source").unwrap_or(UNK_STR.to_owned());
    let score = attributes.remove("score").unwrap_or(UNK_STR.to_owned());
    (source, score)
}

#[inline(always)]
fn strand_to_string(strand: &Strand) -> String {
    let value = match strand {
        &Strand::Forward => "+",
        &Strand::Reverse => "-",
        &Strand::Unknown => UNK_STR,
    };
    value.to_owned()
}

#[inline(always)]
fn frame_to_str(frame: &Option<u8>) -> &str {
    match frame {
        &Some(0) => "0",
        &Some(1) => "1",
        &Some(2) => "2",
        _ => UNK_STR,
    }
}
<commit_msg>Add filter function before grouping in GTF genes() iterator<commit_after>use std::collections::HashMap;
use std::cmp::{max, min};
use std::convert::AsRef;
use std::io;
use std::iter::Filter;
use std::fs;
use std::path::Path;

use bio::io::gff::{self, GffType};
use itertools::{GroupBy, Group, Itertools};
use linked_hash_map::LinkedHashMap;

use {Coord, Exon, ExonFeatureKind as EFK, Gene, GBuilder, Strand, Transcript, Error};

// Various commonly-used feature column values
const GENE_STR: &'static str = "gene";
const TRANSCRIPT_STR: &'static str = "transcript";
const EXON_STR: &'static str = "exon";
const UTR_STR: &'static str = "UTR";
const UTR5_STR: &'static str = "UTR5";
const UTR3_STR: &'static str = "UTR3";
const CDS_STR: &'static str = "CDS";
const START_CODON_STR: &'static str = "start_codon";
const STOP_CODON_STR: &'static str = "stop_codon";

// Value for unknown columns.
const UNK_STR: &'static str = ".";

// Commonly-used attribute keys.
const GENE_ID_STR: &'static str = "gene_id";
const TRANSCRIPT_ID_STR: &'static str = "transcript_id";

// Initial coordinate for features.
const INIT_COORD: (u64, u64) = (::std::u64::MAX, ::std::u64::MIN);

pub struct Reader<R: io::Read> {
    inner: gff::Reader<R>,
}

impl<R: io::Read> Reader<R> {

    pub fn from_reader(in_reader: R, gff_type: GffType) -> Reader<R> {
        Reader {
            inner: gff::Reader::new(in_reader, gff_type),
        }
    }

    pub fn genes(&mut self) -> GffGenes<R> {
        GffGenes {
            inner: self.records()
                .filter(GffGenes::<R>::gene_filter_func as GxFilterFunc)
                .group_by(GffGenes::<R>::gene_group_func),
        }
    }

    fn records(&mut self) -> GffRecords<R> {
        GffRecords {
            inner: self.inner.records()
        }
    }
}

impl Reader<fs::File> {
    pub fn from_file<P: AsRef<Path>>(path: P, gff_type: GffType) -> io::Result<Self> {
        fs::File::open(path).map(|file| Reader::from_reader(file, gff_type))
    }
}

struct GffRecords<'a, R: 'a> where R: io::Read {
    inner: gff::Records<'a, R>,
}

impl<'a, R> Iterator for GffRecords<'a, R> where R: io::Read {

    type Item = Result<gff::Record, Error>;

    fn next(&mut self) -> Option<Result<gff::Record, Error>> {
        self.inner.next()
            .map(|row| {
                row.or_else(|err| Err(Error::from(err)))
            })
    }
}

pub struct GffGenes<'a, R: 'a> where R: io::Read, {
    inner: GroupBy<GxGroupKey, GxRecords<'a, R>, GxGroupFunc>,
}

type GxFilterFunc = fn(&Result<gff::Record, Error>) -> bool;

type GxRecords<'a, R> = Filter<GffRecords<'a, R>, GxFilterFunc>;

type GxGroupKey = Option<(String, String, Strand)>;

type GxGroupFunc = fn(&Result<gff::Record, Error>) -> GxGroupKey;

type GxGroupedRecs<'a, 'b, R> = Group<'b, GxGroupKey, GxRecords<'a, R>, GxGroupFunc>;

type RawTrxCoord = (Coord<u64>, Vec<Coord<u64>>, Option<Coord<u64>>);

impl<'a, R> GffGenes<'a, R> where R: io::Read {

    fn gene_filter_func(result: &Result<gff::Record, Error>) -> bool {
        match result {
            &Ok(ref rec) => rec.attributes().contains_key(GENE_ID_STR),
            &Err(_) => true,  // Err(_) is supposed to be handled elsewhere
        }
    }

    fn gene_group_func(result: &Result<gff::Record, Error>) -> GxGroupKey {
        result.as_ref().ok()
            .map(|res| {
                let gene_id = res.attributes().get(GENE_ID_STR)
                    .expect("'gene_id' attribute not found")
                    .clone();
                let seq_name = String::from(res.seqname());
                let strand = res.strand().unwrap_or(Strand::Unknown);

                (gene_id, seq_name, strand)
            })
    }

    fn group_to_gene<'b>(group: (GxGroupKey, GxGroupedRecs<'a, 'b, R>)) -> Result<Gene, Error> {
        let (group_key, records) = group;
        match group_key {

            None => Err(records.filter_map(|x| x.err()).next().unwrap()),

            Some((gid, seq_name, strand)) => {

                let mut gene_coord = INIT_COORD;
                let mut trx_coords: LinkedHashMap<String, RawTrxCoord> = LinkedHashMap::new();

                for record in records {

                    let mut rec = record?;
                    rec.attributes_mut().remove(GENE_ID_STR);

                    let rtrx_entry = rec.attributes_mut()
                        .remove(TRANSCRIPT_ID_STR)
                        .ok_or(Error::Gff("required 'transcript_id' attribute not found"))
                        .map(|id| trx_coords.entry(id).or_insert((INIT_COORD, vec![], None)));

                    match rec.feature_type() {
                        GENE_STR => {
                            gene_coord = adjust_coord(gene_coord, &rec);
                        },
                        TRANSCRIPT_STR => {
                            let trx_entry = rtrx_entry?;
                            trx_entry.0 = adjust_coord(trx_entry.0, &rec);
                        },
                        EXON_STR => {
                            let trx_entry = rtrx_entry?;
                            (trx_entry.1).push((*rec.start() - 1, *rec.end()));
                        },
                        CDS_STR => {
                            let trx_entry = rtrx_entry?;
                            trx_entry.2 = (trx_entry.2).or(Some(INIT_COORD))
                                .map(|coord| adjust_coord(coord, &rec));
                        },
                        // TODO: How to best handle nested features? They may be out of order ...
                        _ => {},
                    }
                }

                GBuilder::new(seq_name, gene_coord.0, gene_coord.1)
                    .id(gid)
                    .strand(strand)
                    .transcript_coords(trx_coords)
                    .build()
            },
        }
    }
}

impl<'a, R> Iterator for GffGenes<'a, R> where R: io::Read {

    type Item = Result<Gene, Error>;

    fn next(&mut self) -> Option<Result<Gene, Error>> {
        self.inner.into_iter().map(Self::group_to_gene).next()
    }
}

struct GffRow(String, String, String, u64, u64, String, String, String, HashMap<String, String>);

impl From<GffRow> for gff::Record {
    fn from(row: GffRow) -> Self {
        let mut rec = gff::Record::default();
        *rec.seqname_mut() = row.0;
        *rec.source_mut() = row.1;
        *rec.feature_type_mut() = row.2;
        *rec.start_mut() = row.3 + 1;
        *rec.end_mut() = row.4;
        *rec.score_mut() = row.5;
        *rec.strand_mut() = row.6;
        *rec.frame_mut() = row.7;
        *rec.attributes_mut() = row.8;
        rec
    }
}

impl Gene {

    #[inline(always)]
    fn num_records(&self) -> usize {
        1 + self.transcripts().values()
            .map(|ref trx| trx.num_records())
            .fold(0, |acc, x| acc + x)
    }

    // TODO: also handle gene-level features
    fn to_gff_records(mut self) -> Result<Vec<gff::Record>, Error> {

        let (source, score) = extract_source_score(&mut self.attributes);
        let strand = strand_to_string(self.strand());
        let gene_id = match self.id.take() {
            Some(gid) => {
                self.attributes.insert(GENE_ID_STR.to_owned(), gid.clone());
                gid
            },
            None =>  {
                self.attributes.get(GENE_ID_STR)
                    .ok_or(Error::Gff("required 'gene_id' attribute not found"))
                    .map(|gid| gid.clone())?
            },
        };

        let mut recs = Vec::with_capacity(self.num_records());

        let row = GffRow(
            self.seq_name().to_owned(), source, GENE_STR.to_owned(),
            self.interval().start, self.interval().end, score, strand.to_owned(),
            UNK_STR.to_owned(), self.attributes.clone());
        recs.push(gff::Record::from(row));

        for (_, mut transcript) in self.into_transcripts() {
            let mut trx_recs = transcript.to_gff_records(gene_id.as_str())?;
            recs.append(&mut trx_recs);
        }

        Ok(recs)
    }
}

impl Transcript {

    #[inline(always)]
    fn num_records(&self) -> usize {
        1 + self.exons().iter()
            .map(|ref exn| 1 + exn.features.len())
            .fold(0, |acc, x| acc + x)
    }

    // TODO: also handle transcript-level features
    fn to_gff_records(mut self, gene_id: &str) -> Result<Vec<gff::Record>, Error> {

        self.attributes.insert(GENE_ID_STR.to_owned(), gene_id.to_owned());
        let (source, score) = extract_source_score(&mut self.attributes);
        let strand = strand_to_string(self.strand());
        let transcript_id = match self.id.take() {
            Some(tid) => {
                self.attributes.insert(TRANSCRIPT_ID_STR.to_owned(), tid.clone());
                tid
            },
            None =>  {
                self.attributes.get(TRANSCRIPT_ID_STR)
                    .ok_or(Error::Gff("required 'transcript_id' attribute not found"))
                    .map(|tid| tid.clone())?
            },
        };

        let mut recs = Vec::with_capacity(self.num_records());

        let trx_row =
            GffRow(self.seq_name().to_owned(), source, TRANSCRIPT_STR.to_owned(),
                   self.interval().start, self.interval().end, score,
                   strand.to_owned(), UNK_STR.to_owned(), self.attributes.clone());
        recs.push(gff::Record::from(trx_row));

        for exon in self.into_exons() {
            let mut exon_recs = exon.to_gff_records(gene_id, transcript_id.as_str())?;
            recs.append(&mut exon_recs);
        }

        Ok(recs)
    }
}

impl EFK {

    #[inline(always)]
    fn get_feature_frame(&self) -> (String, String) {
        let (feature, frame) = match self {
            &EFK::UTR => (UTR_STR, UNK_STR),
            &EFK::UTR5 => (UTR5_STR, UNK_STR),
            &EFK::UTR3 => (UTR3_STR, UNK_STR),
            &EFK::CDS { frame: ref f } => (CDS_STR, frame_to_str(f)),
            &EFK::StopCodon { frame: ref f } => (STOP_CODON_STR, frame_to_str(f)),
            &EFK::StartCodon { frame: ref f } => (START_CODON_STR, frame_to_str(f)),
            &EFK::Any(ref s) => (s.as_str(), UNK_STR),
        };
        (feature.to_owned(), frame.to_owned())
    }
}

impl Exon {

    fn to_gff_records(mut self, gene_id: &str, transcript_id: &str
    ) -> Result<Vec<gff::Record>, Error> {

        self.attributes.insert(GENE_ID_STR.to_owned(), gene_id.to_owned());
        self.attributes.insert(TRANSCRIPT_ID_STR.to_owned(), transcript_id.to_owned());
        let (source, score) = extract_source_score(&mut self.attributes);
        let strand = strand_to_string(self.strand());

        let mut recs = Vec::with_capacity(1 + self.features.len());

        let exon_row =
            GffRow(self.seq_name().to_owned(), source.clone(), EXON_STR.to_owned(),
                   self.interval().start, self.interval().end, score, strand.to_owned(),
                   UNK_STR.to_owned(), self.attributes.clone());
        recs.push(gff::Record::from(exon_row));

        for fx in self.features.iter() {
            let (feature, frame) = fx.kind.get_feature_frame();
            let fx_row =
                GffRow(self.seq_name().to_owned(), source.clone(), feature,
                       self.interval().start, self.interval().end, UNK_STR.to_owned(),
                       strand.to_owned(), UNK_STR.to_owned(), self.attributes.clone());
            recs.push(gff::Record::from(fx_row));
        }

        Ok(recs)
    }
}

pub struct Writer<W: io::Write> {
    inner: gff::Writer<W>,
}

impl<W: io::Write> Writer<W> {

    pub fn from_writer(in_writer: W, gff_type: GffType) -> Writer<W> {
        Writer {
            inner: gff::Writer::new(in_writer, gff_type),
        }
    }

    pub fn write_gene(&mut self, mut gene: Gene) -> Result<(), Error> {
        for record in gene.to_gff_records()?.iter() {
            self.inner.write(&record)?;
        }
        Ok(())
    }
}

#[inline(always)]
fn adjust_coord(cur_coord: Coord<u64>, record: &gff::Record) -> Coord<u64> {
    (min(cur_coord.0, *record.start() - 1),
     max(cur_coord.1, *record.end()))
}

#[inline(always)]
fn extract_source_score(attributes: &mut HashMap<String, String>) -> (String, String) {
    let source = attributes.remove("source").unwrap_or(UNK_STR.to_owned());
    let score = attributes.remove("score").unwrap_or(UNK_STR.to_owned());
    (source, score)
}

#[inline(always)]
fn strand_to_string(strand: &Strand) -> String {
    let value = match strand {
        &Strand::Forward => "+",
        &Strand::Reverse => "-",
        &Strand::Unknown => UNK_STR,
    };
    value.to_owned()
}

#[inline(always)]
fn frame_to_str(frame: &Option<u8>) -> &str {
    match frame {
        &Some(0) => "0",
        &Some(1) => "1",
        &Some(2) => "2",
        _ => UNK_STR,
    }
}
<|endoftext|>


<commit_before>use clap::{App, Arg};
use rav1e::*;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::slice;
use std::sync::Arc;
use y4m;

pub struct EncoderIO {
  pub input: Box<dyn Read>,
  pub output: Box<dyn Write>,
  pub rec: Option<Box<dyn Write>>
}

pub fn parse_cli() -> (EncoderIO, EncoderConfig, usize) {
  let matches = App::new("rav1e")
    .version("0.1.0")
    .about("AV1 video encoder")
    .arg(
      Arg::with_name("INPUT")
        .help("Uncompressed YUV4MPEG2 video input")
        .required(true)
        .index(1)
    ).arg(
      Arg::with_name("OUTPUT")
        .help("Compressed AV1 in IVF video output")
        .short("o")
        .long("output")
        .required(true)
        .takes_value(true)
    ).arg(Arg::with_name("RECONSTRUCTION").short("r").takes_value(true))
    .arg(
      Arg::with_name("LIMIT")
        .help("Maximum number of frames to encode")
        .short("l")
        .long("limit")
        .takes_value(true)
        .default_value("0")
    ).arg(
      Arg::with_name("QP")
        .help("Quantizer (0-255)")
        .long("quantizer")
        .takes_value(true)
        .default_value("100")
    ).arg(
      Arg::with_name("SPEED")
        .help("Speed level (0(slow)-10(fast))")
        .short("s")
        .long("speed")
        .takes_value(true)
        .default_value("3")
    ).arg(
      Arg::with_name("TUNE")
        .help("Quality tuning (Will enforce partition sizes >= 8x8)")
        .long("tune")
        .possible_values(&Tune::variants())
        .default_value("psnr")
        .case_insensitive(true)
    ).get_matches();

  let io = EncoderIO {
    input: match matches.value_of("INPUT").unwrap() {
      "-" => Box::new(io::stdin()) as Box<dyn Read>,
      f => Box::new(File::open(&f).unwrap()) as Box<dyn Read>
    },
    output: match matches.value_of("OUTPUT").unwrap() {
      "-" => Box::new(io::stdout()) as Box<dyn Write>,
      f => Box::new(File::create(&f).unwrap()) as Box<dyn Write>
    },
    rec: matches
      .value_of("RECONSTRUCTION")
      .map(|f| Box::new(File::create(&f).unwrap()) as Box<dyn Write>)
  };

  let config = EncoderConfig {
    quantizer: matches.value_of("QP").unwrap().parse().unwrap(),
    speed: matches.value_of("SPEED").unwrap().parse().unwrap(),
    tune: matches.value_of("TUNE").unwrap().parse().unwrap()
  };

  // Validate arguments
  if config.quantizer == 0 {
    unimplemented!();
  } else if config.quantizer > 255 || config.speed > 10 {
    panic!("argument out of range");
  }

  let limit = matches.value_of("LIMIT").unwrap().parse().unwrap();

  (io, config, limit)
}

/// Encode and write a frame.
/// returns wheter done with sequence
pub fn process_frame(
  ctx: &mut Context, output_file: &mut dyn Write,
  y4m_dec: &mut y4m::Decoder<'_, Box<dyn Read>>,
  y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>
) -> bool {
  unsafe {
    av1_rtcd();
    aom_dsp_rtcd();
  }
  let width = y4m_dec.get_width();
  let height = y4m_dec.get_height();
  let y4m_bits = y4m_dec.get_bit_depth();
  let y4m_bytes = y4m_dec.get_bytes_per_sample();
  let bit_depth = y4m_dec.get_colorspace().get_bit_depth();

  let read_frame =
  match y4m_dec.read_frame() {
    Ok(y4m_frame) => {
      let y4m_y = y4m_frame.get_y_plane();
      let y4m_u = y4m_frame.get_u_plane();
      let y4m_v = y4m_frame.get_v_plane();
      let mut input = ctx.new_frame();
      {
        let input = Arc::get_mut(&mut input).unwrap();
        input.planes[0].copy_from_raw_u8(&y4m_y, width * y4m_bytes, y4m_bytes);
        input.planes[1].copy_from_raw_u8(
          &y4m_u,
          width * y4m_bytes / 2,
          y4m_bytes
        );
        input.planes[2].copy_from_raw_u8(
          &y4m_v,
          width * y4m_bytes / 2,
          y4m_bytes
        );
      }

      match y4m_bits {
        8 | 10 | 12 => {}
        _ => panic!("unknown input bit depth!")
      }

      let _ = ctx.send_frame(input);
      true
    }
    _ => {
      ctx.flush();
      false
    }
  };

  let y4m_enc_uw = y4m_enc.unwrap();

  let mut has_data = true;
  while has_data {
    let pkt_wrapped = ctx.receive_packet();
    match pkt_wrapped {
    Ok(pkt) => {
      eprintln!("{}", pkt);
      write_ivf_frame(output_file, pkt.number as u64, pkt.data.as_ref());
      if let Some(rec) = pkt.rec {
        let pitch_y = if bit_depth > 8 { width * 2 } else { width };
        let pitch_uv = pitch_y / 2;

        let (mut rec_y, mut rec_u, mut rec_v) = (
          vec![128u8; pitch_y * height],
          vec![128u8; pitch_uv * (height / 2)],
          vec![128u8; pitch_uv * (height / 2)]
        );

        let (stride_y, stride_u, stride_v) = (
          rec.planes[0].cfg.stride,
          rec.planes[1].cfg.stride,
          rec.planes[2].cfg.stride
        );

        for (line, line_out) in rec.planes[0]
          .data_origin()
          .chunks(stride_y)
          .zip(rec_y.chunks_mut(pitch_y))
        {
          if bit_depth > 8 {
            unsafe {
              line_out.copy_from_slice(slice::from_raw_parts::<u8>(
                line.as_ptr() as (*const u8),
                pitch_y
              ));
            }
          } else {
            line_out.copy_from_slice(
              &line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_y]
            );
          }
        }
        for (line, line_out) in rec.planes[1]
          .data_origin()
          .chunks(stride_u)
          .zip(rec_u.chunks_mut(pitch_uv))
        {
          if bit_depth > 8 {
            unsafe {
              line_out.copy_from_slice(slice::from_raw_parts::<u8>(
                line.as_ptr() as (*const u8),
                pitch_uv
              ));
            }
          } else {
            line_out.copy_from_slice(
              &line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_uv]
            );
          }
        }
        for (line, line_out) in rec.planes[2]
          .data_origin()
          .chunks(stride_v)
          .zip(rec_v.chunks_mut(pitch_uv))
        {
          if bit_depth > 8 {
            unsafe {
              line_out.copy_from_slice(slice::from_raw_parts::<u8>(
                line.as_ptr() as (*const u8),
                pitch_uv
              ));
            }
          } else {
            line_out.copy_from_slice(
              &line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_uv]
            );
          }
        }

        let rec_frame = y4m::Frame::new([&rec_y, &rec_u, &rec_v], None);
        y4m_enc_uw.write_frame(&rec_frame).unwrap();
      }
    },
    _ => { has_data = false; }
    }
  }
  read_frame
}
<commit_msg>Check for the y4m encoder presence<commit_after>use clap::{App, Arg};
use rav1e::*;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::slice;
use std::sync::Arc;
use y4m;

pub struct EncoderIO {
  pub input: Box<dyn Read>,
  pub output: Box<dyn Write>,
  pub rec: Option<Box<dyn Write>>
}

pub fn parse_cli() -> (EncoderIO, EncoderConfig, usize) {
  let matches = App::new("rav1e")
    .version("0.1.0")
    .about("AV1 video encoder")
    .arg(
      Arg::with_name("INPUT")
        .help("Uncompressed YUV4MPEG2 video input")
        .required(true)
        .index(1)
    ).arg(
      Arg::with_name("OUTPUT")
        .help("Compressed AV1 in IVF video output")
        .short("o")
        .long("output")
        .required(true)
        .takes_value(true)
    ).arg(Arg::with_name("RECONSTRUCTION").short("r").takes_value(true))
    .arg(
      Arg::with_name("LIMIT")
        .help("Maximum number of frames to encode")
        .short("l")
        .long("limit")
        .takes_value(true)
        .default_value("0")
    ).arg(
      Arg::with_name("QP")
        .help("Quantizer (0-255)")
        .long("quantizer")
        .takes_value(true)
        .default_value("100")
    ).arg(
      Arg::with_name("SPEED")
        .help("Speed level (0(slow)-10(fast))")
        .short("s")
        .long("speed")
        .takes_value(true)
        .default_value("3")
    ).arg(
      Arg::with_name("TUNE")
        .help("Quality tuning (Will enforce partition sizes >= 8x8)")
        .long("tune")
        .possible_values(&Tune::variants())
        .default_value("psnr")
        .case_insensitive(true)
    ).get_matches();

  let io = EncoderIO {
    input: match matches.value_of("INPUT").unwrap() {
      "-" => Box::new(io::stdin()) as Box<dyn Read>,
      f => Box::new(File::open(&f).unwrap()) as Box<dyn Read>
    },
    output: match matches.value_of("OUTPUT").unwrap() {
      "-" => Box::new(io::stdout()) as Box<dyn Write>,
      f => Box::new(File::create(&f).unwrap()) as Box<dyn Write>
    },
    rec: matches
      .value_of("RECONSTRUCTION")
      .map(|f| Box::new(File::create(&f).unwrap()) as Box<dyn Write>)
  };

  let config = EncoderConfig {
    quantizer: matches.value_of("QP").unwrap().parse().unwrap(),
    speed: matches.value_of("SPEED").unwrap().parse().unwrap(),
    tune: matches.value_of("TUNE").unwrap().parse().unwrap()
  };

  // Validate arguments
  if config.quantizer == 0 {
    unimplemented!();
  } else if config.quantizer > 255 || config.speed > 10 {
    panic!("argument out of range");
  }

  let limit = matches.value_of("LIMIT").unwrap().parse().unwrap();

  (io, config, limit)
}

/// Encode and write a frame.
/// returns wheter done with sequence
pub fn process_frame(
  ctx: &mut Context, output_file: &mut dyn Write,
  y4m_dec: &mut y4m::Decoder<'_, Box<dyn Read>>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>
) -> bool {
  unsafe {
    av1_rtcd();
    aom_dsp_rtcd();
  }
  let width = y4m_dec.get_width();
  let height = y4m_dec.get_height();
  let y4m_bits = y4m_dec.get_bit_depth();
  let y4m_bytes = y4m_dec.get_bytes_per_sample();
  let bit_depth = y4m_dec.get_colorspace().get_bit_depth();

  let read_frame =
  match y4m_dec.read_frame() {
    Ok(y4m_frame) => {
      let y4m_y = y4m_frame.get_y_plane();
      let y4m_u = y4m_frame.get_u_plane();
      let y4m_v = y4m_frame.get_v_plane();
      let mut input = ctx.new_frame();
      {
        let input = Arc::get_mut(&mut input).unwrap();
        input.planes[0].copy_from_raw_u8(&y4m_y, width * y4m_bytes, y4m_bytes);
        input.planes[1].copy_from_raw_u8(
          &y4m_u,
          width * y4m_bytes / 2,
          y4m_bytes
        );
        input.planes[2].copy_from_raw_u8(
          &y4m_v,
          width * y4m_bytes / 2,
          y4m_bytes
        );
      }

      match y4m_bits {
        8 | 10 | 12 => {}
        _ => panic!("unknown input bit depth!")
      }

      let _ = ctx.send_frame(input);
      true
    }
    _ => {
      ctx.flush();
      false
    }
  };

  let mut has_data = true;
  while has_data {
    let pkt_wrapped = ctx.receive_packet();
    match pkt_wrapped {
    Ok(pkt) => {
      eprintln!("{}", pkt);
      write_ivf_frame(output_file, pkt.number as u64, pkt.data.as_ref());
      if let Some(y4m_enc_uw) = y4m_enc.as_mut() {
      if let Some(rec) = pkt.rec {
        let pitch_y = if bit_depth > 8 { width * 2 } else { width };
        let pitch_uv = pitch_y / 2;

        let (mut rec_y, mut rec_u, mut rec_v) = (
          vec![128u8; pitch_y * height],
          vec![128u8; pitch_uv * (height / 2)],
          vec![128u8; pitch_uv * (height / 2)]
        );

        let (stride_y, stride_u, stride_v) = (
          rec.planes[0].cfg.stride,
          rec.planes[1].cfg.stride,
          rec.planes[2].cfg.stride
        );

        for (line, line_out) in rec.planes[0]
          .data_origin()
          .chunks(stride_y)
          .zip(rec_y.chunks_mut(pitch_y))
        {
          if bit_depth > 8 {
            unsafe {
              line_out.copy_from_slice(slice::from_raw_parts::<u8>(
                line.as_ptr() as (*const u8),
                pitch_y
              ));
            }
          } else {
            line_out.copy_from_slice(
              &line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_y]
            );
          }
        }
        for (line, line_out) in rec.planes[1]
          .data_origin()
          .chunks(stride_u)
          .zip(rec_u.chunks_mut(pitch_uv))
        {
          if bit_depth > 8 {
            unsafe {
              line_out.copy_from_slice(slice::from_raw_parts::<u8>(
                line.as_ptr() as (*const u8),
                pitch_uv
              ));
            }
          } else {
            line_out.copy_from_slice(
              &line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_uv]
            );
          }
        }
        for (line, line_out) in rec.planes[2]
          .data_origin()
          .chunks(stride_v)
          .zip(rec_v.chunks_mut(pitch_uv))
        {
          if bit_depth > 8 {
            unsafe {
              line_out.copy_from_slice(slice::from_raw_parts::<u8>(
                line.as_ptr() as (*const u8),
                pitch_uv
              ));
            }
          } else {
            line_out.copy_from_slice(
              &line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_uv]
            );
          }
        }

        let rec_frame = y4m::Frame::new([&rec_y, &rec_u, &rec_v], None);
        y4m_enc_uw.write_frame(&rec_frame).unwrap();
      }
      }
    },
    _ => { has_data = false; }
    }
  }
  read_frame
}
<|endoftext|>


<commit_before>#[macro_use(crate_version, crate_authors)]
extern crate clap;

extern crate jailer;
extern crate seccomp;

use clap::{App, Arg};
use std::env;

use jailer::JailerArgs;

const SECCOMP_ENVVAR: &str = "USE_SECCOMP";

fn main() -> jailer::Result<()> {
    if is_seccomp_enabled() {
        // If the seccomp filters installation fails, it's OK to panic.
        seccomp::setup_seccomp().unwrap();
    }

    // Initially, the uid and gid params had default values, but it turns out that it's quite
    // easy to shoot yourself in the foot by not setting proper permissions when preparing the
    // contents of the jail, so I think their values should be provided explicitly.
    let cmd_arguments = App::new("jailer")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Jail a microVM.")
        .arg(
            Arg::with_name("numa_node")
                .long("node")
                .help("NUMA node to assign this microVM to.")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("id")
                .long("id")
                .help("Jail ID")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("exec_file")
                .long("exec-file")
                .help("File path to exec into.")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("uid")
                .long("uid")
                .help("Chroot uid")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("gid")
                .long("gid")
                .help("Chroot gid")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("chroot_base")
                .long("chroot-base-dir")
                .help("The base folder where chroot jails are located.")
                .required(false)
                .default_value("/srv/jailer")
                .takes_value(true),
        )
        .get_matches();

    // All arguments are either mandatory, or have default values, so the unwraps should not fail.
    let args = JailerArgs::new(
        cmd_arguments.value_of("id").unwrap(),
        cmd_arguments.value_of("numa_node").unwrap(),
        cmd_arguments.value_of("exec_file").unwrap(),
        cmd_arguments.value_of("chroot_base").unwrap(),
        cmd_arguments.value_of("uid").unwrap(),
        cmd_arguments.value_of("gid").unwrap(),
    )?;

    jailer::run(args)
}

fn is_seccomp_enabled() -> bool {
    match env::var(SECCOMP_ENVVAR) {
        Ok(val) => val == "1",
        Err(_) => false,
    }
}
<commit_msg>jailer: check that `USE_SECCOMP` is set<commit_after>#[macro_use(crate_version, crate_authors)]
extern crate clap;

extern crate jailer;
extern crate seccomp;

use clap::{App, Arg};
use std::env;

use jailer::JailerArgs;

const SECCOMP_ENVVAR: &str = "USE_SECCOMP";

fn main() -> jailer::Result<()> {
    if is_seccomp_enabled() {
        // If the seccomp filters installation fails, it's OK to panic.
        seccomp::setup_seccomp().unwrap();
    }

    // Initially, the uid and gid params had default values, but it turns out that it's quite
    // easy to shoot yourself in the foot by not setting proper permissions when preparing the
    // contents of the jail, so I think their values should be provided explicitly.
    let cmd_arguments = App::new("jailer")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Jail a microVM.")
        .arg(
            Arg::with_name("numa_node")
                .long("node")
                .help("NUMA node to assign this microVM to.")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("id")
                .long("id")
                .help("Jail ID")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("exec_file")
                .long("exec-file")
                .help("File path to exec into.")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("uid")
                .long("uid")
                .help("Chroot uid")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("gid")
                .long("gid")
                .help("Chroot gid")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("chroot_base")
                .long("chroot-base-dir")
                .help("The base folder where chroot jails are located.")
                .required(false)
                .default_value("/srv/jailer")
                .takes_value(true),
        )
        .get_matches();

    // All arguments are either mandatory, or have default values, so the unwraps should not fail.
    let args = JailerArgs::new(
        cmd_arguments.value_of("id").unwrap(),
        cmd_arguments.value_of("numa_node").unwrap(),
        cmd_arguments.value_of("exec_file").unwrap(),
        cmd_arguments.value_of("chroot_base").unwrap(),
        cmd_arguments.value_of("uid").unwrap(),
        cmd_arguments.value_of("gid").unwrap(),
    )?;

    jailer::run(args)
}

fn is_seccomp_enabled() -> bool {
    match env::var(SECCOMP_ENVVAR) {
        Ok(_) => true,
        Err(_) => false,
    }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::HashMap;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

pub struct VectorClock<S> {
    map: HashMap<S, u64>
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_after(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                // We only check servers that existed in the clock
                // Because we can't tell sequences from missing servers
                if ac > bc {return true;}
            }
        }
        return false;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_after(clock_b) {
            return Relation::After;
        }
        if clock_b.happened_after(self) {
            return Relation::Before;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
}
<commit_msg>make vector clock serializeable<commit_after>use std::hash::Hash;
use std::collections::HashMap;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_after(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                // We only check servers that existed in the clock
                // Because we can't tell sequences from missing servers
                if ac > bc {return true;}
            }
        }
        return false;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_after(clock_b) {
            return Relation::After;
        }
        if clock_b.happened_after(self) {
            return Relation::Before;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>propagate constants into branch conditions<commit_after><|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Utilities to throw exceptions from Rust bindings.

use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::GlobalRef;
use dom::domexception::DOMException;

use js::jsapi::{JSContext, JSBool, JSObject};
use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException};
use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR};
use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain};
use js::glue::{ReportError};
use js::rust::with_compartment;

use libc;
use std::ptr;

/// DOM exceptions that can be thrown by a native DOM method.
#[deriving(Show, Clone)]
pub enum Error {
    IndexSize,
    FailureUnknown,
    NotFound,
    HierarchyRequest,
    InvalidCharacter,
    NotSupported,
    InvalidState,
    Syntax,
    NamespaceError,
    InvalidAccess,
    Security,
    Network,
    Abort,
    Timeout,
    DataClone,
    NoModificationAllowedError
}

/// The return type for IDL operations that can throw DOM exceptions.
pub type Fallible<T> = Result<T, Error>;

/// The return type for IDL operations that can throw DOM exceptions and
/// return `()`.
pub type ErrorResult = Fallible<()>;

/// Set a pending DOM exception for the given `result` on `cx`.
pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef,
                           result: Error) {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let exception = DOMException::new_from_error(global, result).root();
    let thrown = exception.to_jsval(cx);
    unsafe {
        JS_SetPendingException(cx, thrown);
    }
}

/// Report a pending exception, thereby clearing it.
pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) {
    unsafe {
        if JS_IsExceptionPending(cx) != 0 {
            let saved = JS_SaveFrameChain(cx);
            with_compartment(cx, obj, || {
                JS_ReportPendingException(cx);
            });
            if saved != 0 {
                JS_RestoreFrameChain(cx);
            }
        }
    }
}

/// Throw an exception to signal that a `JSVal` can not be converted to any of
/// the types in an IDL union type.
pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let message = format!("argument could not be converted to any of: {}", names);
    message.with_c_str(|string| {
        unsafe { ReportError(cx, string) };
    });
    return 0;
}

/// Format string used to throw `TypeError`s.
static ERROR_FORMAT_STRING_STRING: [libc::c_char, ..4] = [
    '{' as libc::c_char,
    '0' as libc::c_char,
    '}' as libc::c_char,
    0 as libc::c_char,
];

/// Format string struct used to throw `TypeError`s.
static ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
    format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char,
    argCount: 1,
    exnType: JSEXN_TYPEERR as i16,
};

/// Callback used to throw `TypeError`s.
unsafe extern fn get_error_message(_user_ref: *mut libc::c_void,
                            _locale: *const libc::c_char,
                            error_number: libc::c_uint) -> *const JSErrorFormatString
{
    assert_eq!(error_number, 0);
    &ERROR_FORMAT_STRING as *const JSErrorFormatString
}

/// Throw a `TypeError` with the given message.
pub fn throw_type_error(cx: *mut JSContext, error: &str) {
    let error = error.to_c_str();
    unsafe {
        JS_ReportErrorNumber(cx, Some(get_error_message), ptr::null_mut(), 0, error.as_ptr());
    }
}
<commit_msg>Document error.rs.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Utilities to throw exceptions from Rust bindings.

#![deny(missing_docs)]

use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::GlobalRef;
use dom::domexception::DOMException;

use js::jsapi::{JSContext, JSBool, JSObject};
use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException};
use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR};
use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain};
use js::glue::{ReportError};
use js::rust::with_compartment;

use libc;
use std::ptr;

/// DOM exceptions that can be thrown by a native DOM method.
#[deriving(Show, Clone)]
pub enum Error {
    /// IndexSizeError
    IndexSize,
    /// NotFoundError
    NotFound,
    /// HierarchyRequestError
    HierarchyRequest,
    /// InvalidCharacterError
    InvalidCharacter,
    /// NotSupportedError
    NotSupported,
    /// InvalidStateError
    InvalidState,
    /// SyntaxError
    Syntax,
    /// NamespaceError
    NamespaceError,
    /// InvalidAccessError
    InvalidAccess,
    /// SecurityError
    Security,
    /// NetworkError
    Network,
    /// AbortError
    Abort,
    /// TimeoutError
    Timeout,
    /// DataCloneError
    DataClone,
    /// NoModificationAllowedError
    NoModificationAllowedError,
    /// Unknown failure
    FailureUnknown,
}

/// The return type for IDL operations that can throw DOM exceptions.
pub type Fallible<T> = Result<T, Error>;

/// The return type for IDL operations that can throw DOM exceptions and
/// return `()`.
pub type ErrorResult = Fallible<()>;

/// Set a pending DOM exception for the given `result` on `cx`.
pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef,
                           result: Error) {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let exception = DOMException::new_from_error(global, result).root();
    let thrown = exception.to_jsval(cx);
    unsafe {
        JS_SetPendingException(cx, thrown);
    }
}

/// Report a pending exception, thereby clearing it.
pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) {
    unsafe {
        if JS_IsExceptionPending(cx) != 0 {
            let saved = JS_SaveFrameChain(cx);
            with_compartment(cx, obj, || {
                JS_ReportPendingException(cx);
            });
            if saved != 0 {
                JS_RestoreFrameChain(cx);
            }
        }
    }
}

/// Throw an exception to signal that a `JSVal` can not be converted to any of
/// the types in an IDL union type.
pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let message = format!("argument could not be converted to any of: {}", names);
    message.with_c_str(|string| {
        unsafe { ReportError(cx, string) };
    });
    return 0;
}

/// Format string used to throw `TypeError`s.
static ERROR_FORMAT_STRING_STRING: [libc::c_char, ..4] = [
    '{' as libc::c_char,
    '0' as libc::c_char,
    '}' as libc::c_char,
    0 as libc::c_char,
];

/// Format string struct used to throw `TypeError`s.
static ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
    format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char,
    argCount: 1,
    exnType: JSEXN_TYPEERR as i16,
};

/// Callback used to throw `TypeError`s.
unsafe extern fn get_error_message(_user_ref: *mut libc::c_void,
                            _locale: *const libc::c_char,
                            error_number: libc::c_uint) -> *const JSErrorFormatString
{
    assert_eq!(error_number, 0);
    &ERROR_FORMAT_STRING as *const JSErrorFormatString
}

/// Throw a `TypeError` with the given message.
pub fn throw_type_error(cx: *mut JSContext, error: &str) {
    let error = error.to_c_str();
    unsafe {
        JS_ReportErrorNumber(cx, Some(get_error_message), ptr::null_mut(), 0, error.as_ptr());
    }
}
<|endoftext|>