<commit_before>extern crate pq_sys;

use self::pq_sys::*;
use std::ffi::CStr;
use std::num::NonZeroU32;
use std::os::raw as libc;
use std::{slice, str};

use super::raw::RawResult;
use super::row::PgRow;
use crate::result::{DatabaseErrorInformation, DatabaseErrorKind, Error, QueryResult};

// Message after a database connection has been unexpectedly closed.
const CLOSED_CONNECTION_MSG: &str = "server closed the connection unexpectedly\n\t\
This probably means the server terminated abnormally\n\tbefore or while processing the request.\n";

pub struct PgResult {
    internal_result: RawResult,
    column_count: usize,
    row_count: usize,
}

impl PgResult {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(internal_result: RawResult) -> QueryResult<Self> {
        let result_status = unsafe { PQresultStatus(internal_result.as_ptr()) };
        match result_status {
            ExecStatusType::PGRES_COMMAND_OK | ExecStatusType::PGRES_TUPLES_OK => {
                let column_count = unsafe { PQnfields(internal_result.as_ptr()) as usize };
                let row_count = unsafe { PQntuples(internal_result.as_ptr()) as usize };
                Ok(PgResult {
                    internal_result,
                    column_count,
                    row_count,
                })
            }
            ExecStatusType::PGRES_EMPTY_QUERY => {
                let error_message = "Received an empty query".to_string();
                Err(Error::DatabaseError(
                    DatabaseErrorKind::Unknown,
                    Box::new(error_message),
                ))
            }
            _ => {
                let mut error_kind =
                    match get_result_field(internal_result.as_ptr(), ResultField::SqlState) {
                        Some(error_codes::UNIQUE_VIOLATION) => DatabaseErrorKind::UniqueViolation,
                        Some(error_codes::FOREIGN_KEY_VIOLATION) => {
                            DatabaseErrorKind::ForeignKeyViolation
                        }
                        Some(error_codes::SERIALIZATION_FAILURE) => {
                            DatabaseErrorKind::SerializationFailure
                        }
                        Some(error_codes::READ_ONLY_TRANSACTION) => {
                            DatabaseErrorKind::ReadOnlyTransaction
                        }
                        Some(error_codes::NOT_NULL_VIOLATION) => {
                            DatabaseErrorKind::NotNullViolation
                        }
                        Some(error_codes::CHECK_VIOLATION) => DatabaseErrorKind::CheckViolation,
                        Some(error_codes::CONNECTION_EXCEPTION)
                        | Some(error_codes::CONNECTION_FAILURE)
                        | Some(error_codes::SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION)
                        | Some(error_codes::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION) => {
                            DatabaseErrorKind::ClosedConnection
                        }
                        e => {
                            eprintln!("Unknown error code: {:?}", e);
                            DatabaseErrorKind::Unknown
                        }
                    };
                let error_information = Box::new(PgErrorInformation(internal_result));
                // NOTE: Ideally, we'd remove this check, in favor of matching
                // on an error code (instead of the more brittle description
                // string).
                //
                // Unfortunately, this particular error is often propagated in
                // cases - such as network disconnect - without any accompanying
                // "SqlState", and therefore without an error code..
                if error_information.message() == CLOSED_CONNECTION_MSG {
                    error_kind = DatabaseErrorKind::ClosedConnection;
                }
                Err(Error::DatabaseError(error_kind, error_information))
            }
        }
    }

    pub fn rows_affected(&self) -> usize {
        unsafe {
            let count_char_ptr = PQcmdTuples(self.internal_result.as_ptr());
            let count_bytes = CStr::from_ptr(count_char_ptr).to_bytes();
            // Using from_utf8_unchecked is ok here because, we've set the
            // client encoding to utf8
            let count_str = str::from_utf8_unchecked(count_bytes);
            match count_str {
                "" => 0,
                _ => count_str
                    .parse()
                    .expect("Error parsing `rows_affected` as integer value"),
            }
        }
    }

    pub fn num_rows(&self) -> usize {
        self.row_count
    }

    pub fn get_row(&self, idx: usize) -> PgRow {
        PgRow::new(self, idx)
    }

    pub fn get(&self, row_idx: usize, col_idx: usize) -> Option<&[u8]> {
        if self.is_null(row_idx, col_idx) {
            None
        } else {
            let row_idx = row_idx as libc::c_int;
            let col_idx = col_idx as libc::c_int;
            unsafe {
                let value_ptr =
                    PQgetvalue(self.internal_result.as_ptr(), row_idx, col_idx) as *const u8;
                let num_bytes = PQgetlength(self.internal_result.as_ptr(), row_idx, col_idx);
                Some(slice::from_raw_parts(value_ptr, num_bytes as usize))
            }
        }
    }

    pub fn is_null(&self, row_idx: usize, col_idx: usize) -> bool {
        unsafe {
            0 != PQgetisnull(
                self.internal_result.as_ptr(),
                row_idx as libc::c_int,
                col_idx as libc::c_int,
            )
        }
    }

    pub fn column_type(&self, col_idx: usize) -> NonZeroU32 {
        let type_oid = unsafe { PQftype(self.internal_result.as_ptr(), col_idx as libc::c_int) };
        NonZeroU32::new(type_oid).expect(
            "Got a zero oid from postgres. If you see this error message \
             please report it as issue on the diesel github bug tracker.",
        )
    }

    pub fn column_name(&self, col_idx: usize) -> Option<&str> {
        unsafe {
            let ptr = PQfname(self.internal_result.as_ptr(), col_idx as libc::c_int);
            if ptr.is_null() {
                None
            } else {
                Some(CStr::from_ptr(ptr).to_str().expect(
                    "Expect postgres field names to be UTF-8, because we \
                     requested UTF-8 encoding on connection setup",
                ))
            }
        }
    }

    pub fn column_count(&self) -> usize {
        self.column_count
    }
}

struct PgErrorInformation(RawResult);

impl DatabaseErrorInformation for PgErrorInformation {
    fn message(&self) -> &str {
        get_result_field(self.0.as_ptr(), ResultField::MessagePrimary)
            .unwrap_or_else(|| self.0.error_message())
    }

    fn details(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageDetail)
    }

    fn hint(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageHint)
    }

    fn table_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::TableName)
    }

    fn column_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ColumnName)
    }

    fn constraint_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ConstraintName)
    }

    fn statement_position(&self) -> Option<i32> {
        let str_pos = get_result_field(self.0.as_ptr(), ResultField::StatementPosition)?;
        str_pos.parse::<i32>().ok()
    }
}

/// Represents valid options to
/// [`PQresultErrorField`](https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQRESULTERRORFIELD)
/// Their values are defined as C preprocessor macros, and therefore are not exported by libpq-sys.
/// Their values can be found in `postgres_ext.h`
#[repr(i32)]
enum ResultField {
    SqlState = 'C' as i32,
    MessagePrimary = 'M' as i32,
    MessageDetail = 'D' as i32,
    MessageHint = 'H' as i32,
    TableName = 't' as i32,
    ColumnName = 'c' as i32,
    ConstraintName = 'n' as i32,
    StatementPosition = 'P' as i32,
}

fn get_result_field<'a>(res: *mut PGresult, field: ResultField) -> Option<&'a str> {
    let ptr = unsafe { PQresultErrorField(res, field as libc::c_int) };
    if ptr.is_null() {
        return None;
    }

    let c_str = unsafe { CStr::from_ptr(ptr) };
    c_str.to_str().ok()
}

mod error_codes {
    //! These error codes are documented at
    //! <https://www.postgresql.org/docs/current/errcodes-appendix.html>
    //!
    //! They are not exposed programmatically through libpq.
    pub const CONNECTION_EXCEPTION: &str = "08000";
    pub const CONNECTION_FAILURE: &str = "08006";
    pub const SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION: &str = "08001";
    pub const SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION: &str = "08004";
    pub const NOT_NULL_VIOLATION: &str = "23502";
    pub const FOREIGN_KEY_VIOLATION: &str = "23503";
    pub const UNIQUE_VIOLATION: &str = "23505";
    pub const CHECK_VIOLATION: &str = "23514";
    pub const READ_ONLY_TRANSACTION: &str = "25006";
    pub const SERIALIZATION_FAILURE: &str = "40001";
}
<commit_msg>Remove debugging<commit_after>extern crate pq_sys;

use self::pq_sys::*;
use std::ffi::CStr;
use std::num::NonZeroU32;
use std::os::raw as libc;
use std::{slice, str};

use super::raw::RawResult;
use super::row::PgRow;
use crate::result::{DatabaseErrorInformation, DatabaseErrorKind, Error, QueryResult};

// Message after a database connection has been unexpectedly closed.
const CLOSED_CONNECTION_MSG: &str = "server closed the connection unexpectedly\n\t\
This probably means the server terminated abnormally\n\tbefore or while processing the request.\n";

pub struct PgResult {
    internal_result: RawResult,
    column_count: usize,
    row_count: usize,
}

impl PgResult {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(internal_result: RawResult) -> QueryResult<Self> {
        let result_status = unsafe { PQresultStatus(internal_result.as_ptr()) };
        match result_status {
            ExecStatusType::PGRES_COMMAND_OK | ExecStatusType::PGRES_TUPLES_OK => {
                let column_count = unsafe { PQnfields(internal_result.as_ptr()) as usize };
                let row_count = unsafe { PQntuples(internal_result.as_ptr()) as usize };
                Ok(PgResult {
                    internal_result,
                    column_count,
                    row_count,
                })
            }
            ExecStatusType::PGRES_EMPTY_QUERY => {
                let error_message = "Received an empty query".to_string();
                Err(Error::DatabaseError(
                    DatabaseErrorKind::Unknown,
                    Box::new(error_message),
                ))
            }
            _ => {
                let mut error_kind =
                    match get_result_field(internal_result.as_ptr(), ResultField::SqlState) {
                        Some(error_codes::UNIQUE_VIOLATION) => DatabaseErrorKind::UniqueViolation,
                        Some(error_codes::FOREIGN_KEY_VIOLATION) => {
                            DatabaseErrorKind::ForeignKeyViolation
                        }
                        Some(error_codes::SERIALIZATION_FAILURE) => {
                            DatabaseErrorKind::SerializationFailure
                        }
                        Some(error_codes::READ_ONLY_TRANSACTION) => {
                            DatabaseErrorKind::ReadOnlyTransaction
                        }
                        Some(error_codes::NOT_NULL_VIOLATION) => {
                            DatabaseErrorKind::NotNullViolation
                        }
                        Some(error_codes::CHECK_VIOLATION) => DatabaseErrorKind::CheckViolation,
                        Some(error_codes::CONNECTION_EXCEPTION)
                        | Some(error_codes::CONNECTION_FAILURE)
                        | Some(error_codes::SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION)
                        | Some(error_codes::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION) => {
                            DatabaseErrorKind::ClosedConnection
                        }
                        _ => DatabaseErrorKind::Unknown,
                    };
                let error_information = Box::new(PgErrorInformation(internal_result));
                // NOTE: Ideally, we'd remove this check, in favor of matching
                // on an error code (instead of the more brittle description
                // string).
                //
                // Unfortunately, this particular error is often propagated in
                // cases - such as network disconnect - without any accompanying
                // "SqlState", and therefore without an error code..
                if error_information.message() == CLOSED_CONNECTION_MSG {
                    error_kind = DatabaseErrorKind::ClosedConnection;
                }
                Err(Error::DatabaseError(error_kind, error_information))
            }
        }
    }

    pub fn rows_affected(&self) -> usize {
        unsafe {
            let count_char_ptr = PQcmdTuples(self.internal_result.as_ptr());
            let count_bytes = CStr::from_ptr(count_char_ptr).to_bytes();
            // Using from_utf8_unchecked is ok here because, we've set the
            // client encoding to utf8
            let count_str = str::from_utf8_unchecked(count_bytes);
            match count_str {
                "" => 0,
                _ => count_str
                    .parse()
                    .expect("Error parsing `rows_affected` as integer value"),
            }
        }
    }

    pub fn num_rows(&self) -> usize {
        self.row_count
    }

    pub fn get_row(&self, idx: usize) -> PgRow {
        PgRow::new(self, idx)
    }

    pub fn get(&self, row_idx: usize, col_idx: usize) -> Option<&[u8]> {
        if self.is_null(row_idx, col_idx) {
            None
        } else {
            let row_idx = row_idx as libc::c_int;
            let col_idx = col_idx as libc::c_int;
            unsafe {
                let value_ptr =
                    PQgetvalue(self.internal_result.as_ptr(), row_idx, col_idx) as *const u8;
                let num_bytes = PQgetlength(self.internal_result.as_ptr(), row_idx, col_idx);
                Some(slice::from_raw_parts(value_ptr, num_bytes as usize))
            }
        }
    }

    pub fn is_null(&self, row_idx: usize, col_idx: usize) -> bool {
        unsafe {
            0 != PQgetisnull(
                self.internal_result.as_ptr(),
                row_idx as libc::c_int,
                col_idx as libc::c_int,
            )
        }
    }

    pub fn column_type(&self, col_idx: usize) -> NonZeroU32 {
        let type_oid = unsafe { PQftype(self.internal_result.as_ptr(), col_idx as libc::c_int) };
        NonZeroU32::new(type_oid).expect(
            "Got a zero oid from postgres. If you see this error message \
             please report it as issue on the diesel github bug tracker.",
        )
    }

    pub fn column_name(&self, col_idx: usize) -> Option<&str> {
        unsafe {
            let ptr = PQfname(self.internal_result.as_ptr(), col_idx as libc::c_int);
            if ptr.is_null() {
                None
            } else {
                Some(CStr::from_ptr(ptr).to_str().expect(
                    "Expect postgres field names to be UTF-8, because we \
                     requested UTF-8 encoding on connection setup",
                ))
            }
        }
    }

    pub fn column_count(&self) -> usize {
        self.column_count
    }
}

struct PgErrorInformation(RawResult);

impl DatabaseErrorInformation for PgErrorInformation {
    fn message(&self) -> &str {
        get_result_field(self.0.as_ptr(), ResultField::MessagePrimary)
            .unwrap_or_else(|| self.0.error_message())
    }

    fn details(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageDetail)
    }

    fn hint(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageHint)
    }

    fn table_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::TableName)
    }

    fn column_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ColumnName)
    }

    fn constraint_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ConstraintName)
    }

    fn statement_position(&self) -> Option<i32> {
        let str_pos = get_result_field(self.0.as_ptr(), ResultField::StatementPosition)?;
        str_pos.parse::<i32>().ok()
    }
}

/// Represents valid options to
/// [`PQresultErrorField`](https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQRESULTERRORFIELD)
/// Their values are defined as C preprocessor macros, and therefore are not exported by libpq-sys.
/// Their values can be found in `postgres_ext.h`
#[repr(i32)]
enum ResultField {
    SqlState = 'C' as i32,
    MessagePrimary = 'M' as i32,
    MessageDetail = 'D' as i32,
    MessageHint = 'H' as i32,
    TableName = 't' as i32,
    ColumnName = 'c' as i32,
    ConstraintName = 'n' as i32,
    StatementPosition = 'P' as i32,
}

fn get_result_field<'a>(res: *mut PGresult, field: ResultField) -> Option<&'a str> {
    let ptr = unsafe { PQresultErrorField(res, field as libc::c_int) };
    if ptr.is_null() {
        return None;
    }

    let c_str = unsafe { CStr::from_ptr(ptr) };
    c_str.to_str().ok()
}

mod error_codes {
    //! These error codes are documented at
    //! <https://www.postgresql.org/docs/current/errcodes-appendix.html>
    //!
    //! They are not exposed programmatically through libpq.
    pub const CONNECTION_EXCEPTION: &str = "08000";
    pub const CONNECTION_FAILURE: &str = "08006";
    pub const SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION: &str = "08001";
    pub const SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION: &str = "08004";
    pub const NOT_NULL_VIOLATION: &str = "23502";
    pub const FOREIGN_KEY_VIOLATION: &str = "23503";
    pub const UNIQUE_VIOLATION: &str = "23505";
    pub const CHECK_VIOLATION: &str = "23514";
    pub const READ_ONLY_TRANSACTION: &str = "25006";
    pub const SERIALIZATION_FAILURE: &str = "40001";
}
<|endoftext|>


<commit_before>use std::error::Error;

use quote;
use syn;

use table_data::TableData;
use data_structures::ColumnInformation;
use inference::{establish_connection, get_table_data, determine_column_type, get_primary_keys,
                InferConnection};

pub fn expand_infer_table_from_schema(database_url: &str, table: &TableData)
    -> Result<quote::Tokens, Box<Error>>
{
    let connection = establish_connection(database_url)?;
    let data = get_table_data(&connection, table)?;
    let primary_keys = get_primary_keys(&connection, table)?
        .into_iter()
        .map(syn::Ident::new);
    let table_name = syn::Ident::new(&*table.name);

    let mut tokens = Vec::with_capacity(data.len());

    for a in data {
        tokens.push(column_def_tokens(&a, &connection)?);
    }
    if let Some(ref schema) = table.schema {
        if cfg!(not(feature = "postgres")) || schema != "public" {
            let schema_name = syn::Ident::new(&schema[..]);
            return Ok(quote!(table! {
                #schema_name.#table_name (#(#primary_keys),*) {
                    #(#tokens),*,
                }
            }));
        }
    }
    Ok(quote!(table! {
        #table_name (#(#primary_keys),*) {
            #(#tokens),*,
        }
    }))
}

pub fn handle_schema<I>(tables: I, schema_name: Option<&str>) -> quote::Tokens
    where I: Iterator<Item = quote::Tokens>
{
    match schema_name {
        Some(name) => {
            let schema_ident = syn::Ident::new(name);
            quote! { pub mod #schema_ident { #(#tables)* } }
        }
        None => quote!(#(#tables)*),
    }
}

fn column_def_tokens(
    column: &ColumnInformation,
    connection: &InferConnection,
) -> Result<quote::Tokens, Box<Error>> {
    let column_name = syn::Ident::new(&*column.column_name);
    let column_type = try!(determine_column_type(column, connection));
    let tpe = if column_type.path[0] == "diesel" && column_type.path[1] == "types" {
        let path_segments = column_type.path
            .into_iter()
            .skip(2)
            .map(syn::PathSegment::from)
            .collect();
        syn::Path { global: false, segments: path_segments }
    } else {
        let path_segments = column_type.path
            .into_iter()
            .map(syn::PathSegment::from)
            .collect();
        syn::Path { global: true, segments: path_segments }
    };
    let mut tpe = quote!(#tpe);

    if column_type.is_array {
        tpe = quote!(Array<#tpe>);
    }
    if column_type.is_nullable {
        tpe = quote!(Nullable<#tpe>);
    }
    Ok(quote!(#column_name -> #tpe))
}
<commit_msg>Don't include the default schema name on MySQL<commit_after>use std::error::Error;

use quote;
use syn;

use table_data::TableData;
use data_structures::ColumnInformation;
use inference::{establish_connection, get_table_data, determine_column_type, get_primary_keys,
                InferConnection};

pub fn expand_infer_table_from_schema(database_url: &str, table: &TableData)
    -> Result<quote::Tokens, Box<Error>>
{
    let connection = establish_connection(database_url)?;
    let data = get_table_data(&connection, table)?;
    let primary_keys = get_primary_keys(&connection, table)?
        .into_iter()
        .map(syn::Ident::new);
    let table_name = syn::Ident::new(&*table.name);

    let mut tokens = Vec::with_capacity(data.len());

    for a in data {
        tokens.push(column_def_tokens(&a, &connection)?);
    }
    let default_schema = default_schema(&connection);
    if table.schema != default_schema {
        if let Some(ref schema) = table.schema {
            let schema_name = syn::Ident::new(&schema[..]);
            return Ok(quote!(table! {
                #schema_name.#table_name (#(#primary_keys),*) {
                    #(#tokens),*,
                }
            }));
        }
    }
    Ok(quote!(table! {
        #table_name (#(#primary_keys),*) {
            #(#tokens),*,
        }
    }))
}

pub fn handle_schema<I>(tables: I, schema_name: Option<&str>) -> quote::Tokens
    where I: Iterator<Item = quote::Tokens>
{
    match schema_name {
        Some(name) => {
            let schema_ident = syn::Ident::new(name);
            quote! { pub mod #schema_ident { #(#tables)* } }
        }
        None => quote!(#(#tables)*),
    }
}

fn column_def_tokens(
    column: &ColumnInformation,
    connection: &InferConnection,
) -> Result<quote::Tokens, Box<Error>> {
    let column_name = syn::Ident::new(&*column.column_name);
    let column_type = try!(determine_column_type(column, connection));
    let tpe = if column_type.path[0] == "diesel" && column_type.path[1] == "types" {
        let path_segments = column_type.path
            .into_iter()
            .skip(2)
            .map(syn::PathSegment::from)
            .collect();
        syn::Path { global: false, segments: path_segments }
    } else {
        let path_segments = column_type.path
            .into_iter()
            .map(syn::PathSegment::from)
            .collect();
        syn::Path { global: true, segments: path_segments }
    };
    let mut tpe = quote!(#tpe);

    if column_type.is_array {
        tpe = quote!(Array<#tpe>);
    }
    if column_type.is_nullable {
        tpe = quote!(Nullable<#tpe>);
    }
    Ok(quote!(#column_name -> #tpe))
}

fn default_schema(conn: &InferConnection) -> Option<String> {
    #[cfg(feature="mysql")]
    use information_schema::UsesInformationSchema;
    #[cfg(feature="mysql")]
    use diesel::mysql::Mysql;

    match *conn {
        #[cfg(feature="sqlite")]
        InferConnection::Sqlite(_) => None,
        #[cfg(feature="postgres")]
        InferConnection::Pg(_) => Some("public".into()),
        #[cfg(feature="mysql")]
        InferConnection::Mysql(ref c) => Mysql::default_schema(c).ok(),
    }
}
<|endoftext|>


<commit_before>use core::convert::TryInto;

use crate::decoder::MAX_COMPONENTS;
use crate::error::Result;
use crate::idct::dequantize_and_idct_block;
use crate::parser::Component;

use std::sync::{Arc, Mutex};

use super::{RowData, Worker};

/// Technically similar to `immediate::ImmediateWorker` but we copy it since we may prefer
/// different style of managing the memory allocation, something that multiple actors can access in
/// parallel.
#[derive(Default)]
struct ImmediateWorker {
    offsets: [usize; MAX_COMPONENTS],
    results: [Vec<u8>; MAX_COMPONENTS],
    components: [Option<Component>; MAX_COMPONENTS],
    quantization_tables: [Option<Arc<[u16; 64]>>; MAX_COMPONENTS],
}

struct ComponentMetadata {
    block_count: usize,
    line_stride: usize,
    dct_scale: usize,
}

pub struct Scoped {
    inner: Mutex<ImmediateWorker>,
}

pub fn with_rayon<T>(f: impl FnOnce(&mut dyn Worker) -> T) -> T {
    rayon::in_place_scope(|_| {
        let inner = ImmediateWorker::default();
        f(&mut Scoped {
            inner: Mutex::new(inner),
        })
    })
}

impl ImmediateWorker {
    pub fn start_immediate(&mut self, data: RowData) {
        let elements = data.component.block_size.width as usize
            * data.component.block_size.height as usize
            * data.component.dct_scale
            * data.component.dct_scale;
        self.offsets[data.index] = 0;
        self.results[data.index].resize(elements, 0u8);
        self.components[data.index] = Some(data.component);
        self.quantization_tables[data.index] = Some(data.quantization_table);
    }

    pub fn get_result_immediate(&mut self, index: usize) -> Vec<u8> {
        core::mem::take(&mut self.results[index])
    }

    pub fn component_metadata(&self, index: usize) -> ComponentMetadata {
        let component = self.components[index].as_ref().unwrap();
        let block_size = component.block_size;
        let block_count = block_size.width as usize * component.vertical_sampling_factor as usize;
        let line_stride = block_size.width as usize * component.dct_scale;
        let dct_scale = component.dct_scale;

        ComponentMetadata {
            block_count,
            line_stride,
            dct_scale,
        }
    }

    pub fn append_row_locked(
        mutex: &Mutex<ImmediateWorker>,
        (index, data): (usize, Vec<i16>),
        result_offset: usize,
    ) {
        // Convert coefficients from a MCU row to samples.
        let quantization_table;
        let block_count;
        let line_stride;
        let block_size;
        let dct_scale;

        {
            let inner = mutex.lock().unwrap();
            quantization_table = inner.quantization_tables[index].as_ref().unwrap().clone();
            block_size = inner.components[index].as_ref().unwrap().block_size;
            let metadata = inner.component_metadata(index);

            block_count = metadata.block_count;
            line_stride = metadata.line_stride;
            dct_scale = metadata.dct_scale;
        }

        assert_eq!(data.len(), block_count * 64);

        let mut output_buffer = [0; 64];
        for i in 0..block_count {
            let x = (i % block_size.width as usize) * dct_scale;
            let y = (i / block_size.width as usize) * dct_scale;

            let coefficients: &[i16; 64] = &data[i * 64..(i + 1) * 64].try_into().unwrap();

            // Write to a temporary intermediate buffer, a 8x8 'image'.
            dequantize_and_idct_block(
                dct_scale,
                coefficients,
                &*quantization_table,
                8,
                &mut output_buffer,
            );

            // Lock the mutex only for this write back, not the main computation.
            // FIXME: we are only copying image data. Can we use some atomic backing buffer and a
            // `Relaxed` write instead?
            let mut write_back = mutex.lock().unwrap();
            let write_back = &mut write_back.results[index][result_offset + y * line_stride + x..];

            let buffered_lines = output_buffer.chunks_mut(8);
            let back_lines = write_back.chunks_mut(line_stride);

            for (buf, back) in buffered_lines.zip(back_lines).take(dct_scale) {
                back[..dct_scale].copy_from_slice(&buf[..dct_scale]);
            }
        }
    }
}

impl super::Worker for Scoped {
    fn start(&mut self, row_data: RowData) -> Result<()> {
        self.inner.get_mut().unwrap().start_immediate(row_data);
        Ok(())
    }

    fn append_row(&mut self, row: (usize, Vec<i16>)) -> Result<()> {
        let (index, data) = row;
        let result_offset;

        {
            let mut inner = self.inner.get_mut().unwrap();
            let metadata = inner.component_metadata(index);

            result_offset = inner.offsets[index];
            inner.offsets[index] += metadata.bytes_used();
        }

        ImmediateWorker::append_row_locked(&self.inner, (index, data), result_offset);
        Ok(())
    }

    fn get_result(&mut self, index: usize) -> Result<Vec<u8>> {
        let result = self.inner.get_mut().unwrap().get_result_immediate(index);
        Ok(result)
    }

    // Magic sauce, these _may_ run in parallel.
    fn append_rows(&mut self, iter: &mut dyn Iterator<Item = (usize, Vec<i16>)>) -> Result<()> {
        rayon::in_place_scope(|scope| {
            let mut inner = self.inner.lock().unwrap();
            // First we schedule everything, making sure their index is right etc.
            for (index, data) in iter {
                let metadata = inner.component_metadata(index);

                let result_offset = inner.offsets[index];
                inner.offsets[index] += metadata.bytes_used();

                let mutex = &self.inner;
                scope.spawn(move |_| {
                    ImmediateWorker::append_row_locked(mutex, (index, data), result_offset)
                });
            }

            // Then the mutex is released, allowing all tasks to run.
        });

        Ok(())
    }
}

impl ComponentMetadata {
    fn bytes_used(&self) -> usize {
        self.block_count * self.dct_scale * self.dct_scale
    }
}
<commit_msg>Remove unhelpful rayon scoping<commit_after>use core::convert::TryInto;

use crate::decoder::MAX_COMPONENTS;
use crate::error::Result;
use crate::idct::dequantize_and_idct_block;
use crate::parser::Component;

use std::sync::{Arc, Mutex};

use super::{RowData, Worker};

/// Technically similar to `immediate::ImmediateWorker` but we copy it since we may prefer
/// different style of managing the memory allocation, something that multiple actors can access in
/// parallel.
#[derive(Default)]
struct ImmediateWorker {
    offsets: [usize; MAX_COMPONENTS],
    results: [Vec<u8>; MAX_COMPONENTS],
    components: [Option<Component>; MAX_COMPONENTS],
    quantization_tables: [Option<Arc<[u16; 64]>>; MAX_COMPONENTS],
}

struct ComponentMetadata {
    block_count: usize,
    line_stride: usize,
    dct_scale: usize,
}

pub struct Scoped {
    inner: Mutex<ImmediateWorker>,
}

pub fn with_rayon<T>(f: impl FnOnce(&mut dyn Worker) -> T) -> T {
    let inner = ImmediateWorker::default();
    f(&mut Scoped {
        inner: Mutex::new(inner),
    })
}

impl ImmediateWorker {
    pub fn start_immediate(&mut self, data: RowData) {
        let elements = data.component.block_size.width as usize
            * data.component.block_size.height as usize
            * data.component.dct_scale
            * data.component.dct_scale;
        self.offsets[data.index] = 0;
        self.results[data.index].resize(elements, 0u8);
        self.components[data.index] = Some(data.component);
        self.quantization_tables[data.index] = Some(data.quantization_table);
    }

    pub fn get_result_immediate(&mut self, index: usize) -> Vec<u8> {
        core::mem::take(&mut self.results[index])
    }

    pub fn component_metadata(&self, index: usize) -> ComponentMetadata {
        let component = self.components[index].as_ref().unwrap();
        let block_size = component.block_size;
        let block_count = block_size.width as usize * component.vertical_sampling_factor as usize;
        let line_stride = block_size.width as usize * component.dct_scale;
        let dct_scale = component.dct_scale;

        ComponentMetadata {
            block_count,
            line_stride,
            dct_scale,
        }
    }

    pub fn append_row_locked(
        mutex: &Mutex<ImmediateWorker>,
        (index, data): (usize, Vec<i16>),
        result_offset: usize,
    ) {
        // Convert coefficients from a MCU row to samples.
        let quantization_table;
        let block_count;
        let line_stride;
        let block_size;
        let dct_scale;

        {
            let inner = mutex.lock().unwrap();
            quantization_table = inner.quantization_tables[index].as_ref().unwrap().clone();
            block_size = inner.components[index].as_ref().unwrap().block_size;
            let metadata = inner.component_metadata(index);

            block_count = metadata.block_count;
            line_stride = metadata.line_stride;
            dct_scale = metadata.dct_scale;
        }

        assert_eq!(data.len(), block_count * 64);

        let mut output_buffer = [0; 64];
        for i in 0..block_count {
            let x = (i % block_size.width as usize) * dct_scale;
            let y = (i / block_size.width as usize) * dct_scale;

            let coefficients: &[i16; 64] = &data[i * 64..(i + 1) * 64].try_into().unwrap();

            // Write to a temporary intermediate buffer, a 8x8 'image'.
            dequantize_and_idct_block(
                dct_scale,
                coefficients,
                &*quantization_table,
                8,
                &mut output_buffer,
            );

            // Lock the mutex only for this write back, not the main computation.
            // FIXME: we are only copying image data. Can we use some atomic backing buffer and a
            // `Relaxed` write instead?
            let mut write_back = mutex.lock().unwrap();
            let write_back = &mut write_back.results[index][result_offset + y * line_stride + x..];

            let buffered_lines = output_buffer.chunks_mut(8);
            let back_lines = write_back.chunks_mut(line_stride);

            for (buf, back) in buffered_lines.zip(back_lines).take(dct_scale) {
                back[..dct_scale].copy_from_slice(&buf[..dct_scale]);
            }
        }
    }
}

impl super::Worker for Scoped {
    fn start(&mut self, row_data: RowData) -> Result<()> {
        self.inner.get_mut().unwrap().start_immediate(row_data);
        Ok(())
    }

    fn append_row(&mut self, row: (usize, Vec<i16>)) -> Result<()> {
        let (index, data) = row;
        let result_offset;

        {
            let mut inner = self.inner.get_mut().unwrap();
            let metadata = inner.component_metadata(index);

            result_offset = inner.offsets[index];
            inner.offsets[index] += metadata.bytes_used();
        }

        ImmediateWorker::append_row_locked(&self.inner, (index, data), result_offset);
        Ok(())
    }

    fn get_result(&mut self, index: usize) -> Result<Vec<u8>> {
        let result = self.inner.get_mut().unwrap().get_result_immediate(index);
        Ok(result)
    }

    // Magic sauce, these _may_ run in parallel.
    fn append_rows(&mut self, iter: &mut dyn Iterator<Item = (usize, Vec<i16>)>) -> Result<()> {
        rayon::in_place_scope(|scope| {
            let mut inner = self.inner.lock().unwrap();
            // First we schedule everything, making sure their index is right etc.
            for (index, data) in iter {
                let metadata = inner.component_metadata(index);

                let result_offset = inner.offsets[index];
                inner.offsets[index] += metadata.bytes_used();

                let mutex = &self.inner;
                scope.spawn(move |_| {
                    ImmediateWorker::append_row_locked(mutex, (index, data), result_offset)
                });
            }

            // Then the mutex is released, allowing all tasks to run.
        });

        Ok(())
    }
}

impl ComponentMetadata {
    fn bytes_used(&self) -> usize {
        self.block_count * self.dct_scale * self.dct_scale
    }
}
<|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/. */

#![feature(box_syntax)]
#![feature(collections)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(step_by)]

extern crate geom;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate png;
extern crate stb_image;
extern crate url;
extern crate util;
extern crate msg;

use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
use hyper::method::Method;
use hyper::mime::{Mime, Attr};
use msg::constellation_msg::{PipelineId};
use url::Url;

use std::sync::mpsc::{channel, Receiver, Sender};

pub mod image_cache_task;
pub mod storage_task;

/// Image handling.
///
/// It may be surprising that this goes in the network crate as opposed to the graphics crate.
/// However, image handling is generally very integrated with the network stack (especially where
/// caching is involved) and as a result it must live in here.
pub mod image {
    pub mod base;
}

#[derive(Clone)]
pub struct LoadData {
    pub url: Url,
    pub method: Method,
    /// Headers that will apply to the initial request only
    pub headers: Headers,
    /// Headers that will apply to the initial request and any redirects
    pub preserved_headers: Headers,
    pub data: Option<Vec<u8>>,
    pub cors: Option<ResourceCORSData>,
    pub pipeline_id: Option<PipelineId>,
}

impl LoadData {
    pub fn new(url: Url, id: Option<PipelineId>) -> LoadData {
        LoadData {
            url: url,
            method: Method::Get,
            headers: Headers::new(),
            preserved_headers: Headers::new(),
            data: None,
            cors: None,
            pipeline_id: id,
        }
    }
}

/// A listener for asynchronous network events. Cancelling the underlying request is unsupported.
pub trait AsyncResponseListener {
    /// The response headers for a request have been received.
    fn headers_available(&self, metadata: Metadata);
    /// A portion of the response body has been received. This data is unavailable after
    /// this method returned, and must be stored accordingly.
    fn data_available(&self, payload: Vec<u8>);
    /// The response is complete. If the provided status is an Err value, there is no guarantee
    /// that the response body was completely read.
    fn response_complete(&self, status: Result<(), String>);
}

/// Data for passing between threads/processes to indicate a particular action to
/// take on a provided network listener.
pub enum ResponseAction {
    /// Invoke headers_available
    HeadersAvailable(Metadata),
    /// Invoke data_available
    DataAvailable(Vec<u8>),
    /// Invoke response_complete
    ResponseComplete(Result<(), String>)
}

impl ResponseAction {
    /// Execute the default action on a provided listener.
    pub fn process(self, listener: &AsyncResponseListener) {
        match self {
            ResponseAction::HeadersAvailable(m) => listener.headers_available(m),
            ResponseAction::DataAvailable(d) => listener.data_available(d),
            ResponseAction::ResponseComplete(r) => listener.response_complete(r),
        }
    }
}

/// A target for async networking events. Commonly used to dispatch a runnable event to another
/// thread storing the wrapped closure for later execution.
pub trait AsyncResponseTarget {
    fn invoke_with_listener(&self, action: ResponseAction);
}

/// A wrapper for a network load that can either be channel or event-based.
pub enum LoadConsumer {
    Channel(Sender<LoadResponse>),
    Listener(Box<AsyncResponseTarget + Send>),
}

/// Handle to a resource task
pub type ResourceTask = Sender<ControlMsg>;

pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(LoadData, LoadConsumer),
    /// Store a set of cookies for a given originating URL
    SetCookiesForUrl(Url, String, CookieSource),
    /// Retrieve the stored cookies for a given URL
    GetCookiesForUrl(Url, Sender<Option<String>>, CookieSource),
    Exit
}

/// Initialized but unsent request. Encapsulates everything necessary to instruct
/// the resource task to make a new request. The `load` method *must* be called before
/// destruction or the task will panic.
pub struct PendingAsyncLoad {
    resource_task: ResourceTask,
    url: Url,
    pipeline: Option<PipelineId>,
    guard: PendingLoadGuard,
}

struct PendingLoadGuard {
    loaded: bool,
}

impl PendingLoadGuard {
    fn neuter(&mut self) {
        self.loaded = true;
    }
}

impl Drop for PendingLoadGuard {
    fn drop(&mut self) {
        assert!(self.loaded)
    }
}

impl PendingAsyncLoad {
    pub fn new(resource_task: ResourceTask, url: Url, pipeline: Option<PipelineId>)
               -> PendingAsyncLoad {
        PendingAsyncLoad {
            resource_task: resource_task,
            url: url,
            pipeline: pipeline,
            guard: PendingLoadGuard { loaded: false, },
        }
    }

    /// Initiate the network request associated with this pending load.
    pub fn load(mut self) -> Receiver<LoadResponse> {
        self.guard.neuter();
        let load_data = LoadData::new(self.url, self.pipeline);
        let (sender, receiver) = channel();
        let consumer = LoadConsumer::Channel(sender);
        self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
        receiver
    }

    /// Initiate the network request associated with this pending load, using the provided target.
    pub fn load_async(mut self, listener: Box<AsyncResponseTarget + Send>) {
        self.guard.neuter();
        let load_data = LoadData::new(self.url, self.pipeline);
        let consumer = LoadConsumer::Listener(listener);
        self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
    }
}

/// Message sent in response to `Load`.  Contains metadata, and a port
/// for receiving the data.
///
/// Even if loading fails immediately, we send one of these and the
/// progress_port will provide the error.
pub struct LoadResponse {
    /// Metadata, such as from HTTP headers.
    pub metadata: Metadata,
    /// Port for reading data.
    pub progress_port: Receiver<ProgressMsg>,
}

#[derive(Clone)]
pub struct ResourceCORSData {
    /// CORS Preflight flag
    pub preflight: bool,
    /// Origin of CORS Request
    pub origin: Url
}

/// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone)]
pub struct Metadata {
    /// Final URL after redirects.
    pub final_url: Url,

    /// MIME type / subtype.
    pub content_type: Option<(ContentType)>,

    /// Character set.
    pub charset: Option<String>,

    /// Headers
    pub headers: Option<Headers>,

    /// HTTP Status
    pub status: Option<RawStatus>,
}

impl Metadata {
    /// Metadata with defaults for everything optional.
    pub fn default(url: Url) -> Self {
        Metadata {
            final_url:    url,
            content_type: None,
            charset:      None,
            headers: None,
            // https://fetch.spec.whatwg.org/#concept-response-status-message
            status: Some(RawStatus(200, "OK".into())),
        }
    }

    /// Extract the parts of a Mime that we care about.
    pub fn set_content_type(&mut self, content_type: Option<&Mime>) {
        match content_type {
            None => (),
            Some(mime) => {
                self.content_type = Some(ContentType(mime.clone()));
                let &Mime(_, _, ref parameters) = mime;
                for &(ref k, ref v) in parameters.iter() {
                    if &Attr::Charset == k {
                        self.charset = Some(v.to_string());
                    }
                }
            }
        }
    }
}

/// The creator of a given cookie
#[derive(PartialEq, Copy, Clone)]
pub enum CookieSource {
    /// An HTTP API
    HTTP,
    /// A non-HTTP API
    NonHTTP,
}

/// Messages sent in response to a `Load` message
#[derive(PartialEq,Debug)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(Vec<u8>),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), String>)
}

/// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
        -> Result<(Metadata, Vec<u8>), String> {
    let (start_chan, start_port) = channel();
    resource_task.send(ControlMsg::Load(LoadData::new(url, None), LoadConsumer::Channel(start_chan))).unwrap();
    let response = start_port.recv().unwrap();

    let mut buf = vec!();
    loop {
        match response.progress_port.recv().unwrap() {
            ProgressMsg::Payload(data) => buf.push_all(&data),
            ProgressMsg::Done(Ok(()))  => return Ok((response.metadata, buf)),
            ProgressMsg::Done(Err(e))  => return Err(e)
        }
    }
}

/// Load a URL asynchronously and iterate over chunks of bytes from the response.
pub fn load_bytes_iter(pending: PendingAsyncLoad) -> (Metadata, ProgressMsgPortIterator) {
    let input_port = pending.load();
    let response = input_port.recv().unwrap();
    let iter = ProgressMsgPortIterator { progress_port: response.progress_port };
    (response.metadata, iter)
}

/// Iterator that reads chunks of bytes from a ProgressMsg port
pub struct ProgressMsgPortIterator {
    progress_port: Receiver<ProgressMsg>
}

impl Iterator for ProgressMsgPortIterator {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Vec<u8>> {
        match self.progress_port.recv().unwrap() {
            ProgressMsg::Payload(data) => Some(data),
            ProgressMsg::Done(Ok(()))  => None,
            ProgressMsg::Done(Err(e))  => {
                error!("error receiving bytes: {}", e);
                None
            }
        }
    }
}

<commit_msg>if thread panics then assertion for PendingLoadGuard destructor is not run<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/. */

#![feature(box_syntax)]
#![feature(collections)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(step_by)]

extern crate geom;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate png;
extern crate stb_image;
extern crate url;
extern crate util;
extern crate msg;

use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
use hyper::method::Method;
use hyper::mime::{Mime, Attr};
use msg::constellation_msg::{PipelineId};
use url::Url;

use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

pub mod image_cache_task;
pub mod storage_task;

/// Image handling.
///
/// It may be surprising that this goes in the network crate as opposed to the graphics crate.
/// However, image handling is generally very integrated with the network stack (especially where
/// caching is involved) and as a result it must live in here.
pub mod image {
    pub mod base;
}

#[derive(Clone)]
pub struct LoadData {
    pub url: Url,
    pub method: Method,
    /// Headers that will apply to the initial request only
    pub headers: Headers,
    /// Headers that will apply to the initial request and any redirects
    pub preserved_headers: Headers,
    pub data: Option<Vec<u8>>,
    pub cors: Option<ResourceCORSData>,
    pub pipeline_id: Option<PipelineId>,
}

impl LoadData {
    pub fn new(url: Url, id: Option<PipelineId>) -> LoadData {
        LoadData {
            url: url,
            method: Method::Get,
            headers: Headers::new(),
            preserved_headers: Headers::new(),
            data: None,
            cors: None,
            pipeline_id: id,
        }
    }
}

/// A listener for asynchronous network events. Cancelling the underlying request is unsupported.
pub trait AsyncResponseListener {
    /// The response headers for a request have been received.
    fn headers_available(&self, metadata: Metadata);
    /// A portion of the response body has been received. This data is unavailable after
    /// this method returned, and must be stored accordingly.
    fn data_available(&self, payload: Vec<u8>);
    /// The response is complete. If the provided status is an Err value, there is no guarantee
    /// that the response body was completely read.
    fn response_complete(&self, status: Result<(), String>);
}

/// Data for passing between threads/processes to indicate a particular action to
/// take on a provided network listener.
pub enum ResponseAction {
    /// Invoke headers_available
    HeadersAvailable(Metadata),
    /// Invoke data_available
    DataAvailable(Vec<u8>),
    /// Invoke response_complete
    ResponseComplete(Result<(), String>)
}

impl ResponseAction {
    /// Execute the default action on a provided listener.
    pub fn process(self, listener: &AsyncResponseListener) {
        match self {
            ResponseAction::HeadersAvailable(m) => listener.headers_available(m),
            ResponseAction::DataAvailable(d) => listener.data_available(d),
            ResponseAction::ResponseComplete(r) => listener.response_complete(r),
        }
    }
}

/// A target for async networking events. Commonly used to dispatch a runnable event to another
/// thread storing the wrapped closure for later execution.
pub trait AsyncResponseTarget {
    fn invoke_with_listener(&self, action: ResponseAction);
}

/// A wrapper for a network load that can either be channel or event-based.
pub enum LoadConsumer {
    Channel(Sender<LoadResponse>),
    Listener(Box<AsyncResponseTarget + Send>),
}

/// Handle to a resource task
pub type ResourceTask = Sender<ControlMsg>;

pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(LoadData, LoadConsumer),
    /// Store a set of cookies for a given originating URL
    SetCookiesForUrl(Url, String, CookieSource),
    /// Retrieve the stored cookies for a given URL
    GetCookiesForUrl(Url, Sender<Option<String>>, CookieSource),
    Exit
}

/// Initialized but unsent request. Encapsulates everything necessary to instruct
/// the resource task to make a new request. The `load` method *must* be called before
/// destruction or the task will panic.
pub struct PendingAsyncLoad {
    resource_task: ResourceTask,
    url: Url,
    pipeline: Option<PipelineId>,
    guard: PendingLoadGuard,
}

struct PendingLoadGuard {
    loaded: bool,
}

impl PendingLoadGuard {
    fn neuter(&mut self) {
        self.loaded = true;
    }
}

impl Drop for PendingLoadGuard {
    fn drop(&mut self) {
        if !thread::panicking() {
            assert!(self.loaded)
        }
    }
}

impl PendingAsyncLoad {
    pub fn new(resource_task: ResourceTask, url: Url, pipeline: Option<PipelineId>)
               -> PendingAsyncLoad {
        PendingAsyncLoad {
            resource_task: resource_task,
            url: url,
            pipeline: pipeline,
            guard: PendingLoadGuard { loaded: false, },
        }
    }

    /// Initiate the network request associated with this pending load.
    pub fn load(mut self) -> Receiver<LoadResponse> {
        self.guard.neuter();
        let load_data = LoadData::new(self.url, self.pipeline);
        let (sender, receiver) = channel();
        let consumer = LoadConsumer::Channel(sender);
        self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
        receiver
    }

    /// Initiate the network request associated with this pending load, using the provided target.
    pub fn load_async(mut self, listener: Box<AsyncResponseTarget + Send>) {
        self.guard.neuter();
        let load_data = LoadData::new(self.url, self.pipeline);
        let consumer = LoadConsumer::Listener(listener);
        self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
    }
}

/// Message sent in response to `Load`.  Contains metadata, and a port
/// for receiving the data.
///
/// Even if loading fails immediately, we send one of these and the
/// progress_port will provide the error.
pub struct LoadResponse {
    /// Metadata, such as from HTTP headers.
    pub metadata: Metadata,
    /// Port for reading data.
    pub progress_port: Receiver<ProgressMsg>,
}

#[derive(Clone)]
pub struct ResourceCORSData {
    /// CORS Preflight flag
    pub preflight: bool,
    /// Origin of CORS Request
    pub origin: Url
}

/// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone)]
pub struct Metadata {
    /// Final URL after redirects.
    pub final_url: Url,

    /// MIME type / subtype.
    pub content_type: Option<(ContentType)>,

    /// Character set.
    pub charset: Option<String>,

    /// Headers
    pub headers: Option<Headers>,

    /// HTTP Status
    pub status: Option<RawStatus>,
}

impl Metadata {
    /// Metadata with defaults for everything optional.
    pub fn default(url: Url) -> Self {
        Metadata {
            final_url:    url,
            content_type: None,
            charset:      None,
            headers: None,
            // https://fetch.spec.whatwg.org/#concept-response-status-message
            status: Some(RawStatus(200, "OK".into())),
        }
    }

    /// Extract the parts of a Mime that we care about.
    pub fn set_content_type(&mut self, content_type: Option<&Mime>) {
        match content_type {
            None => (),
            Some(mime) => {
                self.content_type = Some(ContentType(mime.clone()));
                let &Mime(_, _, ref parameters) = mime;
                for &(ref k, ref v) in parameters.iter() {
                    if &Attr::Charset == k {
                        self.charset = Some(v.to_string());
                    }
                }
            }
        }
    }
}

/// The creator of a given cookie
#[derive(PartialEq, Copy, Clone)]
pub enum CookieSource {
    /// An HTTP API
    HTTP,
    /// A non-HTTP API
    NonHTTP,
}

/// Messages sent in response to a `Load` message
#[derive(PartialEq,Debug)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(Vec<u8>),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), String>)
}

/// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
        -> Result<(Metadata, Vec<u8>), String> {
    let (start_chan, start_port) = channel();
    resource_task.send(ControlMsg::Load(LoadData::new(url, None), LoadConsumer::Channel(start_chan))).unwrap();
    let response = start_port.recv().unwrap();

    let mut buf = vec!();
    loop {
        match response.progress_port.recv().unwrap() {
            ProgressMsg::Payload(data) => buf.push_all(&data),
            ProgressMsg::Done(Ok(()))  => return Ok((response.metadata, buf)),
            ProgressMsg::Done(Err(e))  => return Err(e)
        }
    }
}

/// Load a URL asynchronously and iterate over chunks of bytes from the response.
pub fn load_bytes_iter(pending: PendingAsyncLoad) -> (Metadata, ProgressMsgPortIterator) {
    let input_port = pending.load();
    let response = input_port.recv().unwrap();
    let iter = ProgressMsgPortIterator { progress_port: response.progress_port };
    (response.metadata, iter)
}

/// Iterator that reads chunks of bytes from a ProgressMsg port
pub struct ProgressMsgPortIterator {
    progress_port: Receiver<ProgressMsg>
}

impl Iterator for ProgressMsgPortIterator {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Vec<u8>> {
        match self.progress_port.recv().unwrap() {
            ProgressMsg::Payload(data) => Some(data),
            ProgressMsg::Done(Ok(()))  => None,
            ProgressMsg::Done(Err(e))  => {
                error!("error receiving bytes: {}", e);
                None
            }
        }
    }
}

<|endoftext|>


<commit_before>//! Serialization/Deserialization for the Game Maker Studio GEN8 format.
//!
//! Game Maker Studio uses a pseudo IFF-like format.
//!
//! It doesn't actually conform to the IFF spec, so it doesn't make sense
//! to use a generic IFF library.
//!
//! A couple assumptions are made about the format.
//!
//! - The root chunk is always a FORM chunk
//!
//! - The chunks are the following in the following order
//!   (optional chunks are marked with parentheses):
//!
//!    1. GEN8
//!    2. OPTN
//!    3. EXTN
//!    4. SOND
//!    5. (AGRP)
//!    6. SPRT
//!    7. BGND
//!    8. PATH
//!    9. SCPT
//!   10. SHDR
//!   11. FONT
//!   12. TMLN
//!   13. OBJT
//!   14. ROOM
//!   15. DAFL
//!   16. TPAG
//!   17. CODE
//!   18. VARI
//!   19. FUNC
//!   20. STRG
//!   21. TXTR
//!   22. AUDO
//!   23. (LANG)
//!   24. (GLOB)
//!
//! - Chunks are aligned on even byte offsets. Padding bytes are always zero.
//!
//! - You can rely on the fact that chunks always have sizes (indicated by their
//!   IFF chunk size property) that land you on even alignment when reading,
//!   so you don't have to manually adjust alignment.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::error::Error;
use std::io::{self, SeekFrom, Read};
use {GameData, GameDataWrite};

pub fn read_from<R: Read>(reader: &mut R) -> Result<GameData, Box<Error>> {
    read_form_chunk(reader)?;
    Ok(GameData {
        gen8: read_opt_chunk(reader, b"GEN8")?.ok_or("missing GEN8 chunk")?,
        optn: read_opt_chunk(reader, b"OPTN")?.ok_or("missing OPTN chunk")?,
        extn: read_opt_chunk(reader, b"EXTN")?.ok_or("missing EXTN chunk")?,
        sond: read_opt_chunk(reader, b"SOND")?.ok_or("missing SOND chunk")?,
        agrp: read_opt_chunk(reader, b"AGRP")?,
        sprt: read_opt_chunk(reader, b"SPRT")?.ok_or("missing SPRT chunk")?,
        bgnd: read_opt_chunk(reader, b"BGND")?.ok_or("missing BGND chunk")?,
        path: read_opt_chunk(reader, b"PATH")?.ok_or("missing PATH chunk")?,
        scpt: read_opt_chunk(reader, b"SCPT")?.ok_or("missing SCPT chunk")?,
        shdr: read_opt_chunk(reader, b"SHDR")?.ok_or("missing SHDR chunk")?,
        font: read_opt_chunk(reader, b"FONT")?.ok_or("missing FONT chunk")?,
        tmln: read_opt_chunk(reader, b"TMLN")?.ok_or("missing TMLN chunk")?,
        objt: read_opt_chunk(reader, b"OBJT")?.ok_or("missing OBJT chunk")?,
        room: read_opt_chunk(reader, b"ROOM")?.ok_or("missing ROOM chunk")?,
        dafl: read_opt_chunk(reader, b"DAFL")?.ok_or("missing DAFL chunk")?,
        tpag: read_opt_chunk(reader, b"TPAG")?.ok_or("missing TPAG chunk")?,
        code: read_opt_chunk(reader, b"CODE")?.ok_or("missing CODE chunk")?,
        vari: read_opt_chunk(reader, b"VARI")?.ok_or("missing VARI chunk")?,
        func: read_opt_chunk(reader, b"FUNC")?.ok_or("missing FUNC chunk")?,
        strg: read_opt_chunk(reader, b"STRG")?.ok_or("missing STRG chunk")?,
        txtr: read_opt_chunk(reader, b"TXTR")?.ok_or("missing TXTR chunk")?,
        audo: read_opt_chunk(reader, b"AUDO")?.ok_or("missing AUDO chunk")?,
        lang: read_opt_chunk(reader, b"LANG")?,
        glob: read_opt_chunk(reader, b"GLOB")?,
    })
}

pub fn write_to<W: GameDataWrite>(gdat: &GameData, writer: &mut W) -> io::Result<()> {
    writer.write_all(b"FORM")?;
    // Skip writing the FORM length, because we don't know it yet.
    let after_form_len = writer.seek(SeekFrom::Current(4))?;
    macro_rules! write {
        ($field:expr, $id:expr) => {
            writer.write_all($id)?;
            writer.write_i32::<LittleEndian>($field.len() as i32)?;
            writer.write_all(&$field)?;
        }
    }
    write!(gdat.gen8, b"GEN8");
    write!(gdat.optn, b"OPTN");
    write!(gdat.extn, b"EXTN");
    write!(gdat.sond, b"SOND");
    if let Some(ref data) = gdat.agrp {
        write!(data, b"AGRP");
    }
    write!(gdat.sprt, b"SPRT");
    write!(gdat.bgnd, b"BGND");
    write!(gdat.path, b"PATH");
    write!(gdat.scpt, b"SCPT");
    write!(gdat.shdr, b"SHDR");
    write!(gdat.font, b"FONT");
    write!(gdat.tmln, b"TMLN");
    write!(gdat.objt, b"OBJT");
    write!(gdat.room, b"ROOM");
    write!(gdat.dafl, b"DAFL");
    write!(gdat.tpag, b"TPAG");
    write!(gdat.code, b"CODE");
    write!(gdat.vari, b"VARI");
    write!(gdat.func, b"FUNC");
    write!(gdat.strg, b"STRG");
    write!(gdat.txtr, b"TXTR");
    write!(gdat.audo, b"AUDO");
    if let Some(ref data) = gdat.lang {
        write!(data, b"LANG");
    }
    if let Some(ref data) = gdat.glob {
        write!(data, b"GLOB");
    }
    let end = writer.seek(SeekFrom::Current(0))?;
    let form_len = end - after_form_len;
    // Finally write the form length
    writer.seek(SeekFrom::Start(after_form_len - 4))?;
    writer.write_i32::<LittleEndian>(form_len as i32)?;
    Ok(())
}

fn read_form_chunk<R: Read>(reader: &mut R) -> Result<(), Box<Error>> {
    let mut type_id = [0; 4];
    reader.read_exact(&mut type_id)?;
    let _len = reader.read_i32::<LittleEndian>();

    if &type_id[..] != b"FORM" {
        return Err(
            "Invalid data.win file. Must start with a FORM chunk.".into(),
        );
    }
    Ok(())
}

fn read_opt_chunk<R: Read>(
    reader: &mut R,
    expected_type: &'static [u8; 4],
) -> Result<Option<Box<[u8]>>, Box<Error>> {
    use std::io::ErrorKind;

    let mut type_id = [0; 4];
    if let Err(e) = reader.read_exact(&mut type_id) {
        match e.kind() {
            ErrorKind::UnexpectedEof => return Ok(None),
            _ => return Err(Box::new(e)),
        }
    }

    if type_id != *expected_type {
        // TODO: You can't just return None here, you already read the type id,
        // Which consumed the type id of the next item you're about to read.
        panic!("Optional chunks are not properly implemented.");
    }

    let size = reader.read_i32::<LittleEndian>()?;
    let mut data = vec![0; size as usize];
    reader.read_exact(&mut data[..])?;

    Ok(Some(data.into_boxed_slice()))
}
<commit_msg>Add (un)assumption about chunk sizes<commit_after>//! Serialization/Deserialization for the Game Maker Studio GEN8 format.
//!
//! Game Maker Studio uses a pseudo IFF-like format.
//!
//! It doesn't actually conform to the IFF spec, so it doesn't make sense
//! to use a generic IFF library.
//!
//! A couple assumptions are made about the format.
//!
//! - The root chunk is always a FORM chunk
//!
//! - The chunks are the following in the following order
//!   (optional chunks are marked with parentheses):
//!
//!    1. GEN8
//!    2. OPTN
//!    3. EXTN
//!    4. SOND
//!    5. (AGRP)
//!    6. SPRT
//!    7. BGND
//!    8. PATH
//!    9. SCPT
//!   10. SHDR
//!   11. FONT
//!   12. TMLN
//!   13. OBJT
//!   14. ROOM
//!   15. DAFL
//!   16. TPAG
//!   17. CODE
//!   18. VARI
//!   19. FUNC
//!   20. STRG
//!   21. TXTR
//!   22. AUDO
//!   23. (LANG)
//!   24. (GLOB)
//!
//! - Chunks are aligned on even byte offsets. Padding bytes are always zero.
//!
//! - You can rely on the fact that chunks always have sizes (indicated by their
//!   IFF chunk size property) that land you on even alignment when reading,
//!   so you don't have to manually adjust alignment.
//!
//! - You can't rely on any of the chunks (other than the root FORM) having a constant size,
//!   that is, having the same size in every game. Therefore, unknown trailing data should be
//!   read, and collected into a buffer that can be written back when serializing.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::error::Error;
use std::io::{self, SeekFrom, Read};
use {GameData, GameDataWrite};

pub fn read_from<R: Read>(reader: &mut R) -> Result<GameData, Box<Error>> {
    read_form_chunk(reader)?;
    Ok(GameData {
        gen8: read_opt_chunk(reader, b"GEN8")?.ok_or("missing GEN8 chunk")?,
        optn: read_opt_chunk(reader, b"OPTN")?.ok_or("missing OPTN chunk")?,
        extn: read_opt_chunk(reader, b"EXTN")?.ok_or("missing EXTN chunk")?,
        sond: read_opt_chunk(reader, b"SOND")?.ok_or("missing SOND chunk")?,
        agrp: read_opt_chunk(reader, b"AGRP")?,
        sprt: read_opt_chunk(reader, b"SPRT")?.ok_or("missing SPRT chunk")?,
        bgnd: read_opt_chunk(reader, b"BGND")?.ok_or("missing BGND chunk")?,
        path: read_opt_chunk(reader, b"PATH")?.ok_or("missing PATH chunk")?,
        scpt: read_opt_chunk(reader, b"SCPT")?.ok_or("missing SCPT chunk")?,
        shdr: read_opt_chunk(reader, b"SHDR")?.ok_or("missing SHDR chunk")?,
        font: read_opt_chunk(reader, b"FONT")?.ok_or("missing FONT chunk")?,
        tmln: read_opt_chunk(reader, b"TMLN")?.ok_or("missing TMLN chunk")?,
        objt: read_opt_chunk(reader, b"OBJT")?.ok_or("missing OBJT chunk")?,
        room: read_opt_chunk(reader, b"ROOM")?.ok_or("missing ROOM chunk")?,
        dafl: read_opt_chunk(reader, b"DAFL")?.ok_or("missing DAFL chunk")?,
        tpag: read_opt_chunk(reader, b"TPAG")?.ok_or("missing TPAG chunk")?,
        code: read_opt_chunk(reader, b"CODE")?.ok_or("missing CODE chunk")?,
        vari: read_opt_chunk(reader, b"VARI")?.ok_or("missing VARI chunk")?,
        func: read_opt_chunk(reader, b"FUNC")?.ok_or("missing FUNC chunk")?,
        strg: read_opt_chunk(reader, b"STRG")?.ok_or("missing STRG chunk")?,
        txtr: read_opt_chunk(reader, b"TXTR")?.ok_or("missing TXTR chunk")?,
        audo: read_opt_chunk(reader, b"AUDO")?.ok_or("missing AUDO chunk")?,
        lang: read_opt_chunk(reader, b"LANG")?,
        glob: read_opt_chunk(reader, b"GLOB")?,
    })
}

pub fn write_to<W: GameDataWrite>(gdat: &GameData, writer: &mut W) -> io::Result<()> {
    writer.write_all(b"FORM")?;
    // Skip writing the FORM length, because we don't know it yet.
    let after_form_len = writer.seek(SeekFrom::Current(4))?;
    macro_rules! write {
        ($field:expr, $id:expr) => {
            writer.write_all($id)?;
            writer.write_i32::<LittleEndian>($field.len() as i32)?;
            writer.write_all(&$field)?;
        }
    }
    write!(gdat.gen8, b"GEN8");
    write!(gdat.optn, b"OPTN");
    write!(gdat.extn, b"EXTN");
    write!(gdat.sond, b"SOND");
    if let Some(ref data) = gdat.agrp {
        write!(data, b"AGRP");
    }
    write!(gdat.sprt, b"SPRT");
    write!(gdat.bgnd, b"BGND");
    write!(gdat.path, b"PATH");
    write!(gdat.scpt, b"SCPT");
    write!(gdat.shdr, b"SHDR");
    write!(gdat.font, b"FONT");
    write!(gdat.tmln, b"TMLN");
    write!(gdat.objt, b"OBJT");
    write!(gdat.room, b"ROOM");
    write!(gdat.dafl, b"DAFL");
    write!(gdat.tpag, b"TPAG");
    write!(gdat.code, b"CODE");
    write!(gdat.vari, b"VARI");
    write!(gdat.func, b"FUNC");
    write!(gdat.strg, b"STRG");
    write!(gdat.txtr, b"TXTR");
    write!(gdat.audo, b"AUDO");
    if let Some(ref data) = gdat.lang {
        write!(data, b"LANG");
    }
    if let Some(ref data) = gdat.glob {
        write!(data, b"GLOB");
    }
    let end = writer.seek(SeekFrom::Current(0))?;
    let form_len = end - after_form_len;
    // Finally write the form length
    writer.seek(SeekFrom::Start(after_form_len - 4))?;
    writer.write_i32::<LittleEndian>(form_len as i32)?;
    Ok(())
}

fn read_form_chunk<R: Read>(reader: &mut R) -> Result<(), Box<Error>> {
    let mut type_id = [0; 4];
    reader.read_exact(&mut type_id)?;
    let _len = reader.read_i32::<LittleEndian>();

    if &type_id[..] != b"FORM" {
        return Err(
            "Invalid data.win file. Must start with a FORM chunk.".into(),
        );
    }
    Ok(())
}

fn read_opt_chunk<R: Read>(
    reader: &mut R,
    expected_type: &'static [u8; 4],
) -> Result<Option<Box<[u8]>>, Box<Error>> {
    use std::io::ErrorKind;

    let mut type_id = [0; 4];
    if let Err(e) = reader.read_exact(&mut type_id) {
        match e.kind() {
            ErrorKind::UnexpectedEof => return Ok(None),
            _ => return Err(Box::new(e)),
        }
    }

    if type_id != *expected_type {
        // TODO: You can't just return None here, you already read the type id,
        // Which consumed the type id of the next item you're about to read.
        panic!("Optional chunks are not properly implemented.");
    }

    let size = reader.read_i32::<LittleEndian>()?;
    let mut data = vec![0; size as usize];
    reader.read_exact(&mut data[..])?;

    Ok(Some(data.into_boxed_slice()))
}
<|endoftext|>


<commit_before>//! lint on manually implemented checked conversions that could be transformed into `try_from`

use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::max_value() as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # use std::convert::TryFrom;
    /// # let foo = 1;
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr<'_>) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.kind;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if_chain! {
            if let Some(cv) = result;
            if let Some(to_type) = cv.to_type;

            then {
                let mut applicability = Applicability::MachineApplicable;
                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut
                                applicability);
                span_lint_and_sugg(
                    cx,
                    CHECKED_CONVERSIONS,
                    item.span,
                    "Checked cast can be simplified.",
                    "try",
                    format!("{}::try_from({}).is_ok()",
                            to_type,
                            snippet),
                    applicability
                );
            }
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr<'a>,
    to_type: Option<&'a str>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        transpose(self.to_type.as_ref(), other.to_type.as_ref()).map_or(true, |(l, r)| l == r)
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new(expr_to_cast: &'a Expr<'_>, from_type: &str, to_type: &'a str) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr<'_>) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    #[must_use]
    fn try_new(from: &str, to: &str) -> Option<Self> {
        if UINTS.contains(&from) {
            Some(Self::FromUnsigned)
        } else if SINTS.contains(&from) {
            if UINTS.contains(&to) {
                Some(Self::SignedToUnsigned)
            } else if SINTS.contains(&to) {
                Some(Self::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::max_value() as from_type)`
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, MAX_VALUE, INTS);

         then {
             Conversion::try_new(candidate, from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::min_value() as from_type)`
fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.kind;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::min_value() as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, MIN_VALUE, SINTS) {
        Conversion::try_new(candidate, from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str]) -> Option<(&'a str, &'a str)> {
    // `to_type::maxmin_value() as from_type`
    let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
        // to_type::maxmin_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind;
        if let TyKind::Path(ref from_type_path) = &from_type.kind;
        if let Some(from_sym) = int_ty_to_sym(from_type_path);

        then {
            Some((limit, from_sym))
        } else {
            None
        }
    };

    // `from_type::from(to_type::maxmin_value())`
    let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::maxmin_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.kind;
            // `to_type::maxmin_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.kind;
            if let Some(from_sym) = get_implementing_type(path, INTS, FROM);

            then {
                Some((limit, from_sym))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        if_chain! {
            if let ExprKind::Call(ref fun_name, _) = &limit.kind;
            // `to_type, maxmin_value`
            if let ExprKind::Path(ref path) = &fun_name.kind;
            // `to_type`
            if let Some(to_type) = get_implementing_type(path, types, func);

            then {
                Some((from_type, to_type))
            } else {
                None
            }
        }
    } else {
        None
    }
}

/// Gets the type which implements the called function
fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name.as_str() == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.kind;
        if let [int] = &*tp.segments;
        let name = &int.ident.name.as_str();

        then {
            candidates.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;
        let name = &ty.ident.name.as_str();

        then {
            INTS.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// (Option<T>, Option<U>) -> Option<(T, U)>
fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> {
    match (lhs, rhs) {
        (Some(l), Some(r)) => Some((l, r)),
        _ => None,
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

// Constants
const FROM: &str = "from";
const MAX_VALUE: &str = "max_value";
const MIN_VALUE: &str = "min_value";

const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"];
<commit_msg>Use int assoc consts in checked_conversions lint<commit_after>//! lint on manually implemented checked conversions that could be transformed into `try_from`

use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::MAX as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # use std::convert::TryFrom;
    /// # let foo = 1;
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr<'_>) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.kind;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if_chain! {
            if let Some(cv) = result;
            if let Some(to_type) = cv.to_type;

            then {
                let mut applicability = Applicability::MachineApplicable;
                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut
                                applicability);
                span_lint_and_sugg(
                    cx,
                    CHECKED_CONVERSIONS,
                    item.span,
                    "Checked cast can be simplified.",
                    "try",
                    format!("{}::try_from({}).is_ok()",
                            to_type,
                            snippet),
                    applicability
                );
            }
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr<'a>,
    to_type: Option<&'a str>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        transpose(self.to_type.as_ref(), other.to_type.as_ref()).map_or(true, |(l, r)| l == r)
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new(expr_to_cast: &'a Expr<'_>, from_type: &str, to_type: &'a str) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr<'_>) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    #[must_use]
    fn try_new(from: &str, to: &str) -> Option<Self> {
        if UINTS.contains(&from) {
            Some(Self::FromUnsigned)
        } else if SINTS.contains(&from) {
            if UINTS.contains(&to) {
                Some(Self::SignedToUnsigned)
            } else if SINTS.contains(&to) {
                Some(Self::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::MAX as from_type)`
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, MAX_VALUE, INTS);

         then {
             Conversion::try_new(candidate, from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::MIN as from_type)`
fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.kind;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::MIN as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, MIN_VALUE, SINTS) {
        Conversion::try_new(candidate, from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str]) -> Option<(&'a str, &'a str)> {
    // `to_type::maxmin_value() as from_type`
    let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
        // to_type::maxmin_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind;
        if let TyKind::Path(ref from_type_path) = &from_type.kind;
        if let Some(from_sym) = int_ty_to_sym(from_type_path);

        then {
            Some((limit, from_sym))
        } else {
            None
        }
    };

    // `from_type::from(to_type::maxmin_value())`
    let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::maxmin_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.kind;
            // `to_type::maxmin_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.kind;
            if let Some(from_sym) = get_implementing_type(path, INTS, FROM);

            then {
                Some((limit, from_sym))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        if_chain! {
            if let ExprKind::Call(ref fun_name, _) = &limit.kind;
            // `to_type, maxmin_value`
            if let ExprKind::Path(ref path) = &fun_name.kind;
            // `to_type`
            if let Some(to_type) = get_implementing_type(path, types, func);

            then {
                Some((from_type, to_type))
            } else {
                None
            }
        }
    } else {
        None
    }
}

/// Gets the type which implements the called function
fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name.as_str() == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.kind;
        if let [int] = &*tp.segments;
        let name = &int.ident.name.as_str();

        then {
            candidates.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;
        let name = &ty.ident.name.as_str();

        then {
            INTS.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// (Option<T>, Option<U>) -> Option<(T, U)>
fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> {
    match (lhs, rhs) {
        (Some(l), Some(r)) => Some((l, r)),
        _ => None,
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

// Constants
const FROM: &str = "from";
const MAX_VALUE: &str = "max_value";
const MIN_VALUE: &str = "min_value";

const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"];
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

extern crate ndarray;

use ndarray::Array;
use ndarray::{arr1, arr2};

#[test]
fn identity()
{
    let e = ndarray::linalg::eye::<f32>(4);
    let e2 = e.mat_mul(&e);
    assert_eq!(e2, e);

    let e = ndarray::linalg::eye::<f32>(2);
    let ans =
        arr2(&[[3.16227770, 0.00000000],
               [4.42718887, 0.63245525]]);

    assert!(ans.allclose(&ans.mat_mul(&e), 0.000001));
}

#[test]
fn chol()
{
    let _ = arr2(&[[1., 2.], [3., 4.]]); // not pos. def.
    let a = arr2(&[[10., 14.], [14., 20.]]); // aT a is pos def

    let chol = ndarray::linalg::cholesky(a);
    let ans =
        arr2(&[[3.16227770, 0.00000000],
               [4.42718887, 0.63245525]]);

    assert!(ans.allclose(&chol, 0.001));

    // Compute bT b for a pos def matrix
    let b = Array::linspace(0f32, 8., 9).reshape((3, 3));
    let mut bt = b.clone();
    bt.swap_axes(0, 1);
    let bpd = bt.mat_mul(&b);
    println!("bpd=\n{:?}", bpd);
    let chol = ndarray::linalg::cholesky(bpd);
    println!("chol=\n{:.8?}", chol);

    let ans =
        arr2(&[[6.70820379, 0.00000000, 0.00000000],
               [8.04984474, 1.09544373, 0.00000000],
               [9.39148617, 2.19088745, 0.00000000]]);
    assert!(ans.allclose(&chol, 0.001));

    let a =
        arr2(&[[ 0.05201001,  0.22982409,  0.1014132 ],
               [ 0.22982409,  1.105822  ,  0.37946544],
               [ 0.1014132 ,  0.37946544,  1.16199134]]);
    let chol = ndarray::linalg::cholesky(a);

    let ans =
        arr2(&[[ 0.22805704,  0.        ,  0.        ],
               [ 1.00774829,  0.30044197,  0.        ],
               [ 0.44468348, -0.2285419 ,  0.95499557]]);
    assert!(ans.allclose(&chol, 0.001));
}

#[test]
fn subst()
{
    let lll =
        arr2(&[[ 0.22805704,  0.        ,  0.        ],
               [ 1.00774829,  0.30044197,  0.        ],
               [ 0.44468348, -0.2285419 ,  0.95499557]]);
    let ans = arr1::<f32>(&[4.384868, -8.050947, -0.827078]);

    assert!(ans.allclose(&ndarray::linalg::subst_fw(&lll, &arr1(&[1., 2., 3.])),
                         0.001));
}

#[test]
fn lst_squares()
{
    let xs =
        arr2(&[[ 2.,  3.],
               [-2., -1.],
               [ 1.,  5.],
               [-1.,  2.]]);
    let b = arr1(&[1., -1., 2., 1.]);
    let x_lstsq = ndarray::linalg::least_squares(&xs, &b);
    let ans = arr1(&[0.070632, 0.390335]);
    assert!(x_lstsq.allclose(&ans, 0.001));
}
<commit_msg>Add test for bigger matrix multiply<commit_after>#![allow(non_snake_case)]

extern crate ndarray;

use ndarray::Array;
use ndarray::{arr1, arr2};

#[test]
fn identity()
{
    let e = ndarray::linalg::eye::<f32>(4);
    let e2 = e.mat_mul(&e);
    assert_eq!(e2, e);

    let e = ndarray::linalg::eye::<f32>(2);
    let ans =
        arr2(&[[3.16227770, 0.00000000],
               [4.42718887, 0.63245525]]);

    assert!(ans.allclose(&ans.mat_mul(&e), 0.000001));
}

#[test]
fn chol()
{
    let _ = arr2(&[[1., 2.], [3., 4.]]); // not pos. def.
    let a = arr2(&[[10., 14.], [14., 20.]]); // aT a is pos def

    let chol = ndarray::linalg::cholesky(a);
    let ans =
        arr2(&[[3.16227770, 0.00000000],
               [4.42718887, 0.63245525]]);

    assert!(ans.allclose(&chol, 0.001));

    // Compute bT b for a pos def matrix
    let b = Array::linspace(0f32, 8., 9).reshape((3, 3));
    let mut bt = b.clone();
    bt.swap_axes(0, 1);
    let bpd = bt.mat_mul(&b);
    println!("bpd=\n{:?}", bpd);
    let chol = ndarray::linalg::cholesky(bpd);
    println!("chol=\n{:.8?}", chol);

    let ans =
        arr2(&[[6.70820379, 0.00000000, 0.00000000],
               [8.04984474, 1.09544373, 0.00000000],
               [9.39148617, 2.19088745, 0.00000000]]);
    assert!(ans.allclose(&chol, 0.001));

    let a =
        arr2(&[[ 0.05201001,  0.22982409,  0.1014132 ],
               [ 0.22982409,  1.105822  ,  0.37946544],
               [ 0.1014132 ,  0.37946544,  1.16199134]]);
    let chol = ndarray::linalg::cholesky(a);

    let ans =
        arr2(&[[ 0.22805704,  0.        ,  0.        ],
               [ 1.00774829,  0.30044197,  0.        ],
               [ 0.44468348, -0.2285419 ,  0.95499557]]);
    assert!(ans.allclose(&chol, 0.001));
}

#[test]
fn subst()
{
    let lll =
        arr2(&[[ 0.22805704,  0.        ,  0.        ],
               [ 1.00774829,  0.30044197,  0.        ],
               [ 0.44468348, -0.2285419 ,  0.95499557]]);
    let ans = arr1::<f32>(&[4.384868, -8.050947, -0.827078]);

    assert!(ans.allclose(&ndarray::linalg::subst_fw(&lll, &arr1(&[1., 2., 3.])),
                         0.001));
}

#[test]
fn lst_squares()
{
    let xs =
        arr2(&[[ 2.,  3.],
               [-2., -1.],
               [ 1.,  5.],
               [-1.,  2.]]);
    let b = arr1(&[1., -1., 2., 1.]);
    let x_lstsq = ndarray::linalg::least_squares(&xs, &b);
    let ans = arr1(&[0.070632, 0.390335]);
    assert!(x_lstsq.allclose(&ans, 0.001));
}

#[test]
fn mat_mul() {
    // smoke test, a big matrix multiplication of uneven size
    let (n, m) = (45, 33);
    let mut a = Array::linspace(0., ((n * m) - 1) as f32, n as usize * m as usize ).reshape((n, m));
    let b = ndarray::linalg::eye(m);
    assert_eq!(a.mat_mul(&b), a);
    let c = ndarray::linalg::eye(n);
    assert_eq!(c.mat_mul(&a), a);
}
<|endoftext|>


<commit_before><commit_msg>tracing: Simplify `log_filter` variable<commit_after><|endoftext|>


<commit_before><commit_msg>pr: fix locking of stdout<commit_after><|endoftext|>