<commit_before>// Copyright (C) 2019, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::ffi;
use std::ptr;
use std::slice;

use libc::c_char;
use libc::c_int;
use libc::c_void;
use libc::size_t;
use libc::ssize_t;

use crate::*;

#[no_mangle]
pub extern fn quiche_h3_config_new(
    num_placeholders: u64, max_header_list_size: u64,
    qpack_max_table_capacity: u64, qpack_blocked_streams: u64,
) -> *mut h3::Config {
    match h3::Config::new(
        num_placeholders,
        max_header_list_size,
        qpack_max_table_capacity,
        qpack_blocked_streams,
    ) {
        Ok(c) => Box::into_raw(Box::new(c)),

        Err(_) => ptr::null_mut(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_config_free(config: *mut h3::Config) {
    unsafe { Box::from_raw(config) };
}

#[no_mangle]
pub extern fn quiche_h3_conn_new_with_transport(
    quic_conn: &mut Connection, config: &mut h3::Config,
) -> *mut h3::Connection {
    match h3::Connection::with_transport(quic_conn, config) {
        Ok(c) => Box::into_raw(Box::new(c)),

        Err(_) => ptr::null_mut(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_conn_poll(
    conn: &mut h3::Connection, quic_conn: &mut Connection,
    ev: *mut *const h3::Event,
) -> i64 {
    match conn.poll(quic_conn) {
        Ok((stream_id, v)) => {
            unsafe {
                *ev = Box::into_raw(Box::new(v));
            }

            stream_id as i64
        },

        Err(e) => e.to_c() as i64,
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_type(ev: &h3::Event) -> u32 {
    match ev {
        h3::Event::Headers { .. } => 0,

        h3::Event::Data { .. } => 1,
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_for_each_header(
    ev: &h3::Event,
    cb: fn(
        name: *const u8,
        name_len: size_t,
        value: *const u8,
        value_len: size_t,
        argp: *mut c_void,
    ),
    argp: *mut c_void,
) {
    match ev {
        h3::Event::Headers(headers) =>
            for h in headers {
                cb(
                    h.name().as_ptr(),
                    h.name().len(),
                    h.value().as_ptr(),
                    h.value().len(),
                    argp,
                );
            },

        h3::Event::Data { .. } => unreachable!(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_data(
    ev: &h3::Event, out: *mut *const u8,
) -> size_t {
    match ev {
        h3::Event::Headers { .. } => unreachable!(),

        h3::Event::Data(data) => {
            unsafe {
                *out = (&data).as_ptr();
            }

            data.len()
        },
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_free(ev: *mut h3::Event) {
    unsafe { Box::from_raw(ev) };
}

#[repr(C)]
pub struct FFIHeader {
    name: *mut c_char,
    value: *mut c_char,
}

#[no_mangle]
pub extern fn quiche_h3_send_request(
    conn: &mut h3::Connection, quic_conn: &mut Connection,
    headers: *const FFIHeader, headers_len: size_t, fin: bool,
) -> i64 {
    let headers = unsafe { slice::from_raw_parts(headers, headers_len) };

    let mut req_headers = Vec::new();

    for h in headers {
        req_headers.push(unsafe {
            let name = match ffi::CStr::from_ptr(h.name).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            let value = match ffi::CStr::from_ptr(h.value).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            h3::Header::new(name, value)
        });
    }

    match conn.send_request(quic_conn, &req_headers, fin) {
        Ok(v) => v as i64,

        Err(e) => e.to_c() as i64,
    }
}

#[no_mangle]
pub extern fn quiche_h3_send_response(
    conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
    headers: *const FFIHeader, headers_len: size_t, fin: bool,
) -> c_int {
    let headers = unsafe { slice::from_raw_parts(headers, headers_len) };

    let mut resp_headers = Vec::new();

    for h in headers {
        resp_headers.push(unsafe {
            let name = match ffi::CStr::from_ptr(h.name).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            let value = match ffi::CStr::from_ptr(h.value).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            h3::Header::new(name, value)
        });
    }

    match conn.send_response(quic_conn, stream_id, &resp_headers, fin) {
        Ok(_) => 0,

        Err(e) => e.to_c() as c_int,
    }
}

#[no_mangle]
pub extern fn quiche_h3_send_body(
    conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
    body: *const u8, body_len: size_t, fin: bool,
) -> ssize_t {
    if body_len > <ssize_t>::max_value() as usize {
        panic!("The provided buffer is too large");
    }

    let body = unsafe { slice::from_raw_parts(body, body_len) };

    match conn.send_body(quic_conn, stream_id, body, fin) {
        Ok(v) => v as ssize_t,

        Err(e) => e.to_c(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_conn_free(conn: *mut h3::Connection) {
    unsafe { Box::from_raw(conn) };
}
<commit_msg>h3/ffi: rename FFIHeader -> Header<commit_after>// Copyright (C) 2019, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::ffi;
use std::ptr;
use std::slice;

use libc::c_char;
use libc::c_int;
use libc::c_void;
use libc::size_t;
use libc::ssize_t;

use crate::*;

#[no_mangle]
pub extern fn quiche_h3_config_new(
    num_placeholders: u64, max_header_list_size: u64,
    qpack_max_table_capacity: u64, qpack_blocked_streams: u64,
) -> *mut h3::Config {
    match h3::Config::new(
        num_placeholders,
        max_header_list_size,
        qpack_max_table_capacity,
        qpack_blocked_streams,
    ) {
        Ok(c) => Box::into_raw(Box::new(c)),

        Err(_) => ptr::null_mut(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_config_free(config: *mut h3::Config) {
    unsafe { Box::from_raw(config) };
}

#[no_mangle]
pub extern fn quiche_h3_conn_new_with_transport(
    quic_conn: &mut Connection, config: &mut h3::Config,
) -> *mut h3::Connection {
    match h3::Connection::with_transport(quic_conn, config) {
        Ok(c) => Box::into_raw(Box::new(c)),

        Err(_) => ptr::null_mut(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_conn_poll(
    conn: &mut h3::Connection, quic_conn: &mut Connection,
    ev: *mut *const h3::Event,
) -> i64 {
    match conn.poll(quic_conn) {
        Ok((stream_id, v)) => {
            unsafe {
                *ev = Box::into_raw(Box::new(v));
            }

            stream_id as i64
        },

        Err(e) => e.to_c() as i64,
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_type(ev: &h3::Event) -> u32 {
    match ev {
        h3::Event::Headers { .. } => 0,

        h3::Event::Data { .. } => 1,
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_for_each_header(
    ev: &h3::Event,
    cb: fn(
        name: *const u8,
        name_len: size_t,
        value: *const u8,
        value_len: size_t,
        argp: *mut c_void,
    ),
    argp: *mut c_void,
) {
    match ev {
        h3::Event::Headers(headers) =>
            for h in headers {
                cb(
                    h.name().as_ptr(),
                    h.name().len(),
                    h.value().as_ptr(),
                    h.value().len(),
                    argp,
                );
            },

        h3::Event::Data { .. } => unreachable!(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_data(
    ev: &h3::Event, out: *mut *const u8,
) -> size_t {
    match ev {
        h3::Event::Headers { .. } => unreachable!(),

        h3::Event::Data(data) => {
            unsafe {
                *out = (&data).as_ptr();
            }

            data.len()
        },
    }
}

#[no_mangle]
pub extern fn quiche_h3_event_free(ev: *mut h3::Event) {
    unsafe { Box::from_raw(ev) };
}

#[repr(C)]
pub struct Header {
    name: *mut c_char,
    value: *mut c_char,
}

#[no_mangle]
pub extern fn quiche_h3_send_request(
    conn: &mut h3::Connection, quic_conn: &mut Connection,
    headers: *const Header, headers_len: size_t, fin: bool,
) -> i64 {
    let headers = unsafe { slice::from_raw_parts(headers, headers_len) };

    let mut req_headers = Vec::new();

    for h in headers {
        req_headers.push(unsafe {
            let name = match ffi::CStr::from_ptr(h.name).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            let value = match ffi::CStr::from_ptr(h.value).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            h3::Header::new(name, value)
        });
    }

    match conn.send_request(quic_conn, &req_headers, fin) {
        Ok(v) => v as i64,

        Err(e) => e.to_c() as i64,
    }
}

#[no_mangle]
pub extern fn quiche_h3_send_response(
    conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
    headers: *const Header, headers_len: size_t, fin: bool,
) -> c_int {
    let headers = unsafe { slice::from_raw_parts(headers, headers_len) };

    let mut resp_headers = Vec::new();

    for h in headers {
        resp_headers.push(unsafe {
            let name = match ffi::CStr::from_ptr(h.name).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            let value = match ffi::CStr::from_ptr(h.value).to_str() {
                Ok(v) => v,

                Err(_) => return -1,
            };

            h3::Header::new(name, value)
        });
    }

    match conn.send_response(quic_conn, stream_id, &resp_headers, fin) {
        Ok(_) => 0,

        Err(e) => e.to_c() as c_int,
    }
}

#[no_mangle]
pub extern fn quiche_h3_send_body(
    conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
    body: *const u8, body_len: size_t, fin: bool,
) -> ssize_t {
    if body_len > <ssize_t>::max_value() as usize {
        panic!("The provided buffer is too large");
    }

    let body = unsafe { slice::from_raw_parts(body, body_len) };

    match conn.send_body(quic_conn, stream_id, body, fin) {
        Ok(v) => v as ssize_t,

        Err(e) => e.to_c(),
    }
}

#[no_mangle]
pub extern fn quiche_h3_conn_free(conn: *mut h3::Connection) {
    unsafe { Box::from_raw(conn) };
}
<|endoftext|>


<commit_before>use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::value_part::ValuePart;
use std::collections::HashMap;
use std::borrow::Cow;

pub struct VariableMapper<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
}

impl<'vm, I> VariableMapper<'vm, I> {
    pub fn new(tokenizer: I) -> VariableMapper<'vm, I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }

    fn replace_children_in_scope<'b>(&self, children: Vec<Event<'b>>, mut local_variables: HashMap<String, ValuePart<'b>>) -> Vec<Event<'b>> {
        children.into_iter().filter_map(|c|
            match c {
                Event::Variable(SassVariable { name, value }) => {
                    let val = owned_evaluated_value(value, &local_variables);
                    local_variables.insert((*name).to_string(), val);
                    None
                },
                Event::Property(name, value) => {
                    Some(Event::Property(
                        name,
                        // TODO: Is it ok that property values are strings or should they
                        // be value parts ...?
                        Evaluator::new_from_string(
                            &value
                        ).evaluate(&local_variables).to_string().into()
                    ))
                },
                Event::ChildRule(rule) => {
                    Some(Event::ChildRule(SassRule {
                        children: self.replace_children_in_scope(
                            rule.children, local_variables.clone()
                        ), ..rule
                    }))
                },
                other => Some(other)
            }
        ).collect::<Vec<_>>()
    }
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> ValuePart<'a> {

    match value {
        Cow::Borrowed(v) => {
            Evaluator::new_from_string(&v).evaluate(variables)
        },
        Cow::Owned(v) => {
            Evaluator::new_from_string(&v).evaluate(variables).into_owned()
        },
    }
}

impl<'a, I> Iterator for VariableMapper<'a, I>
    where I: Iterator<Item = TopLevelEvent<'a>>
{
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        match self.tokenizer.next() {
            Some(TopLevelEvent::Variable(SassVariable { name, value })) => {
                let val = owned_evaluated_value(value, &self.variables);
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(TopLevelEvent::Rule(sass_rule)) => {
                Some(TopLevelEvent::Rule(SassRule {
                    children: self.replace_children_in_scope(
                        sass_rule.children, self.variables.clone()
                    ), ..sass_rule
                }))
            },
            other => other,
        }
    }
}
<commit_msg>Results of variables should be treated as computed<commit_after>use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use std::collections::HashMap;
use std::borrow::Cow;

pub struct VariableMapper<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
}

impl<'vm, I> VariableMapper<'vm, I> {
    pub fn new(tokenizer: I) -> VariableMapper<'vm, I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }

    fn replace_children_in_scope<'b>(&self, children: Vec<Event<'b>>, mut local_variables: HashMap<String, ValuePart<'b>>) -> Vec<Event<'b>> {
        children.into_iter().filter_map(|c|
            match c {
                Event::Variable(SassVariable { name, value }) => {
                    let val = owned_evaluated_value(value, &local_variables);
                    local_variables.insert((*name).to_string(), val);
                    None
                },
                Event::Property(name, value) => {
                    Some(Event::Property(
                        name,
                        // TODO: Is it ok that property values are strings or should they
                        // be value parts ...?
                        Evaluator::new_from_string(
                            &value
                        ).evaluate(&local_variables).to_string().into()
                    ))
                },
                Event::ChildRule(rule) => {
                    Some(Event::ChildRule(SassRule {
                        children: self.replace_children_in_scope(
                            rule.children, local_variables.clone()
                        ), ..rule
                    }))
                },
                other => Some(other)
            }
        ).collect::<Vec<_>>()
    }
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> ValuePart<'a> {

    let value_part = match value {
        Cow::Borrowed(v) => {
            Evaluator::new_from_string(&v).evaluate(variables)
        },
        Cow::Owned(v) => {
            Evaluator::new_from_string(&v).evaluate(variables).into_owned()
        },
    };
    match value_part {
        ValuePart::Number(nv) => ValuePart::Number(NumberValue { computed: true, ..nv }),
        other => other,
    }
}

impl<'a, I> Iterator for VariableMapper<'a, I>
    where I: Iterator<Item = TopLevelEvent<'a>>
{
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        match self.tokenizer.next() {
            Some(TopLevelEvent::Variable(SassVariable { name, value })) => {
                let val = owned_evaluated_value(value, &self.variables);
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(TopLevelEvent::Rule(sass_rule)) => {
                Some(TopLevelEvent::Rule(SassRule {
                    children: self.replace_children_in_scope(
                        sass_rule.children, self.variables.clone()
                    ), ..sass_rule
                }))
            },
            other => other,
        }
    }
}
<|endoftext|>


<commit_before>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Default for Vector2f {
    fn default() -> Vector2f {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }
}

impl Vector<Vector2f, f32> for Vector2f {
    fn add(&mut self, v: &Vector2f) -> &mut Self {
        self.x += v.x;
        self.y += v.y;
        self
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        unimplemented!()
    }

    fn length_squared(&self) -> f32 {
        unimplemented!()
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        unimplemented!()
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn negate(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn normalize(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn zero(&mut self) -> &mut Self {
        unimplemented!()
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn new(x: f32, y: f32) -> Self {
        Vector2f {
            x: x,
            y: y,
        }
    }

    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector2;
    use super::Vector2f;

    #[test]
    fn test_new() {
        let a = Vector2f::new(1f32, 2f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector2f::default();
        let b = Vector2f::new(1f32, 2f32);

        a.add(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);

        assert_eq!(b.x, 1f32);
        assert_eq!(b.y, 2f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::default();

        a.add_into(&b, &mut c);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 1f32);

        assert_eq!(b.x, 1f32);
        assert_eq!(b.y, 2f32);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 3f32);
    }
}
<commit_msg>add distance and distance squared impls.<commit_after>use super::Vector;
use super::Vector2;

pub struct Vector2f {
    pub x: f32,
    pub y: f32,
}

impl Default for Vector2f {
    fn default() -> Vector2f {
        Vector2f {
            x: 0f32,
            y: 0f32,
        }
    }
}

impl Vector<Vector2f, f32> for Vector2f {
    fn add(&mut self, v: &Vector2f) -> &mut Self {
        self.x += v.x;
        self.y += v.y;
        self
    }

    fn add_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        dest.x = self.x + v.x;
        dest.y = self.y + v.y;
    }

    fn angle(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn angle_cos(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn distance(&self, v: &Vector2f) -> f32 {
        self.distance_squared(v).sqrt()
    }

    fn distance_squared(&self, v: &Vector2f) -> f32 {
        let dx = self.x - v.x;
        let dy = self.y - v.y;
        (dx * dx) + (dy * dy)
    }

    fn dot(&self, v: &Vector2f) -> f32 {
        unimplemented!()
    }

    fn fma_scalar(&mut self, a: f32, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_scalar_into(&self, a: f32, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn fma_vector(&mut self, a: &Vector2f, b: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn fma_vector_into(&self, a: &Vector2f, b: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn length(&self) -> f32 {
        unimplemented!()
    }

    fn length_squared(&self) -> f32 {
        unimplemented!()
    }

    fn lerp(&mut self, other: &Vector2f, t: f32) -> &mut Self {
        unimplemented!()
    }

    fn lerp_into(&self, other: &Vector2f, t: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_scalar(&mut self, s: f32) -> &mut Self {
        unimplemented!()
    }

    fn mul_scalar_into(&self, s: f32, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn mul_vector(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn mul_vector_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn negate(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn negate_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn normalize(&mut self) -> &mut Self {
        unimplemented!()
    }

    fn normalize_into(&self, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn set(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub(&mut self, v: &Vector2f) -> &mut Self {
        unimplemented!()
    }

    fn sub_into(&self, v: &Vector2f, dest: &mut Vector2f) {
        unimplemented!()
    }

    fn zero(&mut self) -> &mut Self {
        unimplemented!()
    }
}

impl Vector2<Vector2f, f32> for Vector2f {
    fn new(x: f32, y: f32) -> Self {
        Vector2f {
            x: x,
            y: y,
        }
    }

    fn add_components(&mut self, x: f32, y: f32) -> &mut Self {
        unimplemented!()
    }

    fn add_components_into(&self, x: f32, y: f32, dest: &mut Vector2f) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vector;
    use super::super::Vector2;
    use super::Vector2f;

    #[test]
    fn test_new() {
        let a = Vector2f::new(1f32, 2f32);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add() {
        let mut a = Vector2f::default();
        let b = Vector2f::new(1f32, 2f32);

        a.add(&b);

        assert_eq!(a.x, 1f32);
        assert_eq!(a.y, 2f32);
    }

    #[test]
    fn test_add_into() {
        let a = Vector2f::new(1f32, 1f32);
        let b = Vector2f::new(1f32, 2f32);
        let mut c = Vector2f::default();

        a.add_into(&b, &mut c);

        assert_eq!(c.x, 2f32);
        assert_eq!(c.y, 3f32);
    }

    #[test]
    fn test_distance() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance = 2f32;
        let distance = a.distance(&b);

        assert_eq!(target_distance, distance);
    }

    #[test]
    fn test_distance_squared() {
        let a = Vector2f::new(2f32, 1f32);
        let b = Vector2f::new(0f32, 1f32);

        let target_distance_sq = 4f32; //distance is 2
        let distance_sq = a.distance_squared(&b);

        assert_eq!(target_distance_sq, distance_sq);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::from_str::FromStr;
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use std::slice::Items;

use super::utils::MultiIter;

/// Trait for converting from RFC822 Header values into
/// Rust types.
pub trait FromHeader {
    /// Parse the `value` of the header.
    ///
    /// Returns None if the value failed to be parsed
    fn from_header(value: String) -> Option<Self>;
}

impl FromHeader for String {
    fn from_header(value: String) -> Option<String> {
        Some(value)
    }
}

/// Represents an RFC 822 Header
#[deriving(PartialEq, Eq, Clone, Hash)]
pub struct Header {
    /// The name of this header
    pub name: String,
    value: String,
}

impl Header {
    /// Creates a new Header for the given `name` and `value`
    pub fn new(name: String, value: String) -> Header {
        Header {
            name: name,
            value: value,
        }
    }

    /// Get the value represented by this header, as parsed
    /// into whichever type `T`
    pub fn get_value<T: FromHeader>(&self) -> Option<T> {
        FromHeader::from_header(self.value.clone())
    }
}

impl fmt::Show for Header {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut lines = self.value.as_slice().split('\n');
        // Take the first line as the start of the formatted value
        let mut formatted_value = lines.next().unwrap().to_string();
        for line in lines {
            // Add the separator between lines
            // RFC 822 uses linear whitespace (tabs or spaces) to indicate
            // a continuation of a header value over a newline
            formatted_value.push_str("\r\n\t");
            formatted_value.push_str(line);
        }

        write!(fmt, "{}: {}", self.name, formatted_value)
    }
}

impl FromStr for Header {
    fn from_str(s: &str) -> Option<Header> {
        // Split the header on the first semicolon
        let mut parts = s.splitn(2, ':');
        let before = parts.next();
        let after = parts.next();

        match (before, after) {
            // If either value is None, then this isn't a header
            (None, None) | (_, None) | (None, _) => None,
            (Some(ref name), Some(ref value)) => {
                Some(Header::new(
                    name.trim().to_string(),
                    value.trim().to_string()
                ))
            }
        }
    }
}

/// A collection of Headers
pub struct HeaderMap {
    headers: HashMap<String, Vec<Header>>,
}

impl HeaderMap {
    pub fn new() -> HeaderMap {
        HeaderMap {
            headers: HashMap::new()
        }
    }

    /// Adds a header to the collection
    pub fn insert(&mut self, header: Header) {
        // If the header hashmap already has this header, use that list.
        // Otherwise, make a new one.
        let header_list = match self.headers.entry(header.name.clone()) {
            Vacant(entry) => entry.set(Vec::new()),
            Occupied(entry) => entry.into_mut(),
        };
        // ... and add the new header to it
        header_list.push(header);
    }

    /// Get an Iterator over the collection of headers.
    pub fn iter(&self) -> MultiIter<&Header, Items<Header>> {
        let mut iters = Vec::new();
        for header_list in self.headers.values() {
            iters.push(header_list.iter());
        }
        MultiIter::new(iters)
    }
}

impl fmt::Show for HeaderMap {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.headers)
    }
}

impl Collection for HeaderMap {
    fn len(&self) -> uint {
        self.iter().count()
    }
}

impl Map<String, Vec<Header>> for HeaderMap {
    fn find(&self, key: &String) -> Option<&Vec<Header>> {
        self.headers.find(key)
    }
}

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

    static SAMPLE_HEADERS: [&'static str, ..4] = [
        "Test: Value",
        "Test : Value 2",
        "Test-2: Value 3",
        "Test-Multiline: Foo\nBar",
    ];

    #[test]
    fn test_header_to_string() {
        let header = Header::new("Test".to_string(), "Value".to_string());
        assert_eq!(header.to_string(), "Test: Value".to_string());
    }

    #[test]
    fn test_multiline_header_to_string() {
        let header = Header::new("Test".to_string(), "Value\nOver lines".to_string());
        assert_eq!(header.to_string(), "Test: Value\r\n\tOver lines".to_string());
    }

    #[test]
    fn test_string_get_value() {
        let header = Header::new("Test".to_string(), "Value".to_string());
        let string_value: String = header.get_value().unwrap();
        assert_eq!(string_value, "Value".to_string());
    }

    #[test]
    fn test_parse_header() {
        let vals = ["Test: Value", "Test : Value"];
        for &val in vals.iter() {
            let header: Header = from_str(val).unwrap();
            assert_eq!(header.name, "Test".to_string());
            assert_eq!(header.value, "Value".to_string());
        }
    }

    #[test]
    fn test_parse_header_roundtrip() {
        let header: Header = from_str("Test: Value").unwrap();
        let header_string = header.to_string();
        assert_eq!(header_string, "Test: Value".to_string());
    }

    #[test]
    fn test_header_map_len() {
        let mut headers = HeaderMap::new();
        for (i, &val) in SAMPLE_HEADERS.iter().enumerate() {
            let header: Header = from_str(val).unwrap();
            headers.insert(header);
            assert_eq!(headers.len(), i + 1);
        }
    }

    #[test]
    fn test_header_map_iter() {
        let mut headers = HeaderMap::new();
        let mut expected_headers = HashSet::new();
        for &val in SAMPLE_HEADERS.iter() {
            let header: Header = from_str(val).unwrap();
            headers.insert(header.clone());
            expected_headers.insert(header);
        }

        let mut count = 0u;
        // Ensure all the headers returned are expected
        for header in headers.iter() {
            assert!(expected_headers.contains(header));
            count += 1;
        }
        // And that there is the right number of them
        assert_eq!(count, expected_headers.len());
    }
}
<commit_msg>Add correct to_string impl for HeaderMap<commit_after>use std::fmt;
use std::from_str::FromStr;
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use std::slice::Items;

use super::utils::MultiIter;

/// Trait for converting from RFC822 Header values into
/// Rust types.
pub trait FromHeader {
    /// Parse the `value` of the header.
    ///
    /// Returns None if the value failed to be parsed
    fn from_header(value: String) -> Option<Self>;
}

impl FromHeader for String {
    fn from_header(value: String) -> Option<String> {
        Some(value)
    }
}

/// Represents an RFC 822 Header
#[deriving(PartialEq, Eq, Clone, Hash)]
pub struct Header {
    /// The name of this header
    pub name: String,
    value: String,
}

impl Header {
    /// Creates a new Header for the given `name` and `value`
    pub fn new(name: String, value: String) -> Header {
        Header {
            name: name,
            value: value,
        }
    }

    /// Get the value represented by this header, as parsed
    /// into whichever type `T`
    pub fn get_value<T: FromHeader>(&self) -> Option<T> {
        FromHeader::from_header(self.value.clone())
    }
}

impl fmt::Show for Header {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut lines = self.value.as_slice().split('\n');
        // Take the first line as the start of the formatted value
        let mut formatted_value = lines.next().unwrap().to_string();
        for line in lines {
            // Add the separator between lines
            // RFC 822 uses linear whitespace (tabs or spaces) to indicate
            // a continuation of a header value over a newline
            formatted_value.push_str("\r\n\t");
            formatted_value.push_str(line);
        }

        write!(fmt, "{}: {}", self.name, formatted_value)
    }
}

impl FromStr for Header {
    fn from_str(s: &str) -> Option<Header> {
        // Split the header on the first semicolon
        let mut parts = s.splitn(2, ':');
        let before = parts.next();
        let after = parts.next();

        match (before, after) {
            // If either value is None, then this isn't a header
            (None, None) | (_, None) | (None, _) => None,
            (Some(ref name), Some(ref value)) => {
                Some(Header::new(
                    name.trim().to_string(),
                    value.trim().to_string()
                ))
            }
        }
    }
}

/// A collection of Headers
pub struct HeaderMap {
    headers: HashMap<String, Vec<Header>>,
}

impl HeaderMap {
    pub fn new() -> HeaderMap {
        HeaderMap {
            headers: HashMap::new()
        }
    }

    /// Adds a header to the collection
    pub fn insert(&mut self, header: Header) {
        // If the header hashmap already has this header, use that list.
        // Otherwise, make a new one.
        let header_list = match self.headers.entry(header.name.clone()) {
            Vacant(entry) => entry.set(Vec::new()),
            Occupied(entry) => entry.into_mut(),
        };
        // ... and add the new header to it
        header_list.push(header);
    }

    /// Get an Iterator over the collection of headers.
    pub fn iter(&self) -> MultiIter<&Header, Items<Header>> {
        let mut iters = Vec::new();
        for header_list in self.headers.values() {
            iters.push(header_list.iter());
        }
        MultiIter::new(iters)
    }
}

impl fmt::Show for HeaderMap {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        for header in self.iter() {
            match write!(fmt, "{}\r\n", header) {
                Err(e) => return Err(e),
                _ => {}
            }
        }
        Ok(())
    }
}

impl Collection for HeaderMap {
    fn len(&self) -> uint {
        self.iter().count()
    }
}

impl Map<String, Vec<Header>> for HeaderMap {
    fn find(&self, key: &String) -> Option<&Vec<Header>> {
        self.headers.find(key)
    }
}

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

    static SAMPLE_HEADERS: [&'static str, ..4] = [
        "Test: Value",
        "Test : Value 2",
        "Test-2: Value 3",
        "Test-Multiline: Foo\nBar",
    ];

    #[test]
    fn test_header_to_string() {
        let header = Header::new("Test".to_string(), "Value".to_string());
        assert_eq!(header.to_string(), "Test: Value".to_string());
    }

    #[test]
    fn test_multiline_header_to_string() {
        let header = Header::new("Test".to_string(), "Value\nOver lines".to_string());
        assert_eq!(header.to_string(), "Test: Value\r\n\tOver lines".to_string());
    }

    #[test]
    fn test_string_get_value() {
        let header = Header::new("Test".to_string(), "Value".to_string());
        let string_value: String = header.get_value().unwrap();
        assert_eq!(string_value, "Value".to_string());
    }

    #[test]
    fn test_parse_header() {
        let vals = ["Test: Value", "Test : Value"];
        for &val in vals.iter() {
            let header: Header = from_str(val).unwrap();
            assert_eq!(header.name, "Test".to_string());
            assert_eq!(header.value, "Value".to_string());
        }
    }

    #[test]
    fn test_parse_header_roundtrip() {
        let header: Header = from_str("Test: Value").unwrap();
        let header_string = header.to_string();
        assert_eq!(header_string, "Test: Value".to_string());
    }

    #[test]
    fn test_header_map_len() {
        let mut headers = HeaderMap::new();
        for (i, &val) in SAMPLE_HEADERS.iter().enumerate() {
            let header: Header = from_str(val).unwrap();
            headers.insert(header);
            assert_eq!(headers.len(), i + 1);
        }
    }

    #[test]
    fn test_header_map_iter() {
        let mut headers = HeaderMap::new();
        let mut expected_headers = HashSet::new();
        for &val in SAMPLE_HEADERS.iter() {
            let header: Header = from_str(val).unwrap();
            headers.insert(header.clone());
            expected_headers.insert(header);
        }

        let mut count = 0u;
        // Ensure all the headers returned are expected
        for header in headers.iter() {
            assert!(expected_headers.contains(header));
            count += 1;
        }
        // And that there is the right number of them
        assert_eq!(count, expected_headers.len());
    }

    #[test]
    fn test_header_map_string() {
        let mut headers = HeaderMap::new();
        for &val in SAMPLE_HEADERS.iter() {
            let header: Header = from_str(val).unwrap();
            headers.insert(header.clone());
        }
        let result = headers.to_string();
        let slice = result.as_slice();
        println!("{}", result);
        assert!(slice.contains("Test: Value\r\n"));
        assert!(slice.contains("Test: Value 2\r\n"));
        assert!(slice.contains("Test-2: Value 3\r\n"));
        assert!(slice.contains("Test-Multiline: Foo\r\n\tBar"));
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016-2017 Ivan Dejanovic
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::io::stdin;
use std::collections::HashMap;
use std::mem::transmute;

use common::INSTRUCTIONS;

// Bit Masks
const INST_MASK: u64 = 0xFF;
const REG_MASK: u64 = 0xF;
const FULL_REG_MASK: u64 = 0x1F;

//Rotation values
const INST_ROTATION: u32 = 8;
const OPERAND_ONE_ROTATION: u32 = 12;
const OPERANT_TWO_ROTATION: u32 = 15;
const FULL_REG_ROTATION: u32 = 13;

// Opcodes
const HALT: u64 = 0x00;
const IN_N: u64 = 0x01;
const OUT_N: u64 = 0x02;
const IN_S: u64 = 0x03;
const OUT_S: u64 = 0x04;
const ADD: u64 = 0x05;
const SUB: u64 = 0x06;
const MUL: u64 = 0x07;
const DIV: u64 = 0x08;
const CON: u64 = 0x09;
const PUSH: u64 = 0x0A;
const POP: u64 = 0x0B;
const LD: u64 = 0x0C;
const ST: u64 = 0x0D;
const JMP: u64 = 0x0E;
const JGR: u64 = 0x0F;
const JGE: u64 = 0x10;
const JEQ: u64 = 0x11;
const JNE: u64 = 0x12;
const JLE: u64 = 0x13;
const JLS: u64 = 0x14;

const REG_NUM: usize = 8;
const INS_MEM_CAP: usize = 50000;

pub struct Vm {
    ip: usize,
    sp: usize,
    acc: u64,
    reg: [u64; REG_NUM],
    ins_mem: [u64; INS_MEM_CAP],
}

impl Vm {
    pub fn new() -> Box<Vm> {
        Box::new(Vm {
                     ip: 0,
                     sp: 0,
                     acc: 0,
                     reg: [0; REG_NUM],
                     ins_mem: [0; INS_MEM_CAP],
                 })
    }

    pub fn load_code(&mut self, code: Vec<String>) {
        println!("{}", code.len());

        let mut opcode_map: HashMap<&'static str, u64> = HashMap::new();

        opcode_map.insert(INSTRUCTIONS.halt, HALT);
        opcode_map.insert(INSTRUCTIONS.in_n, IN_N);
        opcode_map.insert(INSTRUCTIONS.out_n, OUT_N);
        opcode_map.insert(INSTRUCTIONS.in_s, IN_S);
        opcode_map.insert(INSTRUCTIONS.out_s, OUT_S);
        opcode_map.insert(INSTRUCTIONS.add, ADD);
        opcode_map.insert(INSTRUCTIONS.sub, SUB);
        opcode_map.insert(INSTRUCTIONS.mul, MUL);
        opcode_map.insert(INSTRUCTIONS.div, DIV);
        opcode_map.insert(INSTRUCTIONS.con, CON);
        opcode_map.insert(INSTRUCTIONS.push, PUSH);
        opcode_map.insert(INSTRUCTIONS.pop, POP);
        opcode_map.insert(INSTRUCTIONS.ld, LD);
        opcode_map.insert(INSTRUCTIONS.st, ST);
        opcode_map.insert(INSTRUCTIONS.jmp, JMP);
        opcode_map.insert(INSTRUCTIONS.jgr, JGR);
        opcode_map.insert(INSTRUCTIONS.jge, JGE);
        opcode_map.insert(INSTRUCTIONS.jeq, JEQ);
        opcode_map.insert(INSTRUCTIONS.jne, JNE);
        opcode_map.insert(INSTRUCTIONS.jle, JLE);
        opcode_map.insert(INSTRUCTIONS.jls, JLS);

        for instruction in code {
            println!("{}", instruction);
        }
    }

    pub fn execute(&mut self) {
        loop {
            let inst = self.ins_mem[self.ip];
            let opcode = inst.rotate_left(INST_ROTATION) & INST_MASK;

            match opcode {
                HALT => break,
                IN_N => self.process_in_n(),
                OUT_N => self.process_out_n(),
                IN_S => self.process_in_s(),
                OUT_S => self.process_out_s(),
                ADD => self.process_add(),
                SUB => self.process_sub(),
                MUL => self.process_mul(),
                DIV => self.process_div(),
                CON => self.process_con(),
                PUSH => self.process_push(),
                POP => self.process_pop(),
                LD => self.process_ld(),
                ST => self.process_st(),
                JMP => self.process_jmp(),
                JGR => self.process_jgr(),
                JGE => self.process_jge(),
                JEQ => self.process_jeq(),
                JNE => self.process_jne(),
                JLE => self.process_jle(),
                JLS => self.process_jls(),
                _ => {
                    println!("Unknow instruction. Aborting.");
                    break;
                }

            }

            if self.has_errors() {
                self.throw_exception();
                break;
            }
        }
    }

    fn process_in_n(&mut self) {
        let mut input_text = String::new();
        stdin()
            .read_line(&mut input_text)
            .expect("failed to read from stdin");

        let trimmed = input_text.trim();
        match trimmed.parse::<f64>() {
            Ok(i) => {
                self.acc = unsafe { transmute::<f64, u64>(i) };
                self.ip = self.ip + 1;
            }
            Err(..) => self.set_io_error_flag(),
        };
    }

    fn process_out_n(&mut self) {
        let output = unsafe { transmute::<u64, f64>(self.acc) };
        println!("{}", output);
        self.ip = self.ip + 1;
    }

    fn process_in_s(&mut self) {}

    fn process_out_s(&mut self) {}

    fn process_add(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 + operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_sub(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 - operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_mul(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 * operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_div(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 / operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_con(&mut self) {}

    fn process_push(&mut self) {
        let reg_index = self.get_register_index();

        // register push
        if reg_index <= 7 {
            let value = self.reg[reg_index];

            // ip push
        } else if reg_index == 8 {
            // sp push
        } else if reg_index == 9 {
            // acc push
        } else if reg_index == 10 {
            // error
        } else {

        }
    }

    fn process_pop(&mut self) {
        let reg_index = self.get_register_index();
    }

    fn process_ld(&mut self) {
        let reg_index = self.get_register_index();
    }

    fn process_st(&mut self) {
        let reg_index = self.get_register_index();
    }

    fn process_jmp(&mut self) {}

    fn process_jgr(&mut self) {}

    fn process_jge(&mut self) {}

    fn process_jeq(&mut self) {}

    fn process_jne(&mut self) {}

    fn process_jle(&mut self) {}

    fn process_jls(&mut self) {}

    fn set_io_error_flag(&mut self) {
        println!("IO error flag set!")
    }

    fn has_errors(&mut self) -> bool {
        false
    }

    fn throw_exception(&mut self) {
        println!("Exception thrown!")
    }

    fn get_operand(&mut self, rotation: u32) -> f64 {
        let inst = self.ins_mem[self.ip];
        let operand_reg = (inst.rotate_left(rotation) & REG_MASK) as usize;

        unsafe { transmute::<u64, f64>(self.reg[operand_reg]) }
    }

    fn get_register_index(&mut self) -> usize {
        let inst = self.ins_mem[self.ip];
        let reg_index = (inst.rotate_left(FULL_REG_ROTATION) & FULL_REG_MASK) as usize;

        reg_index
    }
}
<commit_msg>Implemented pop in push vm operations.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016-2017 Ivan Dejanovic
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::io::stdin;
use std::collections::HashMap;
use std::mem::transmute;

use common::INSTRUCTIONS;

// Bit Masks
const INST_MASK: u64 = 0xFF;
const REG_MASK: u64 = 0xF;
const FULL_REG_MASK: u64 = 0x1F;

//Rotation values
const INST_ROTATION: u32 = 8;
const OPERAND_ONE_ROTATION: u32 = 12;
const OPERANT_TWO_ROTATION: u32 = 15;
const FULL_REG_ROTATION: u32 = 13;

//Register index
const IP_INDEX: usize = 8;
const SP_INDEX: usize = 9;
const ACC_INDEX: usize = 10;

// Opcodes
const HALT: u64 = 0x00;
const IN_N: u64 = 0x01;
const OUT_N: u64 = 0x02;
const IN_S: u64 = 0x03;
const OUT_S: u64 = 0x04;
const ADD: u64 = 0x05;
const SUB: u64 = 0x06;
const MUL: u64 = 0x07;
const DIV: u64 = 0x08;
const CON: u64 = 0x09;
const PUSH: u64 = 0x0A;
const POP: u64 = 0x0B;
const LD: u64 = 0x0C;
const ST: u64 = 0x0D;
const JMP: u64 = 0x0E;
const JGR: u64 = 0x0F;
const JGE: u64 = 0x10;
const JEQ: u64 = 0x11;
const JNE: u64 = 0x12;
const JLE: u64 = 0x13;
const JLS: u64 = 0x14;

const REG_NUM: usize = 8;
const MEM_CAP: usize = 50000;
const VAR_MEM_TOP: usize = 50000;
const VAR_MEM_BOTTOM: usize = 40001;
const STACK_MEM_TOP: usize = 40000;
const STACK_MEM_BOTTOM: usize = 30001;

pub struct Vm {
    ip: usize,
    sp: usize,
    acc: u64,
    reg: [u64; REG_NUM],
    mem: [u64; MEM_CAP],
}

impl Vm {
    pub fn new() -> Box<Vm> {
        Box::new(Vm {
            ip: 0,
            sp: STACK_MEM_TOP,
            acc: 0,
            reg: [0; REG_NUM],
            mem: [0; MEM_CAP],
        })
    }

    pub fn load_code(&mut self, code: Vec<String>) {
        println!("{}", code.len());

        let mut opcode_map: HashMap<&'static str, u64> = HashMap::new();

        opcode_map.insert(INSTRUCTIONS.halt, HALT);
        opcode_map.insert(INSTRUCTIONS.in_n, IN_N);
        opcode_map.insert(INSTRUCTIONS.out_n, OUT_N);
        opcode_map.insert(INSTRUCTIONS.in_s, IN_S);
        opcode_map.insert(INSTRUCTIONS.out_s, OUT_S);
        opcode_map.insert(INSTRUCTIONS.add, ADD);
        opcode_map.insert(INSTRUCTIONS.sub, SUB);
        opcode_map.insert(INSTRUCTIONS.mul, MUL);
        opcode_map.insert(INSTRUCTIONS.div, DIV);
        opcode_map.insert(INSTRUCTIONS.con, CON);
        opcode_map.insert(INSTRUCTIONS.push, PUSH);
        opcode_map.insert(INSTRUCTIONS.pop, POP);
        opcode_map.insert(INSTRUCTIONS.ld, LD);
        opcode_map.insert(INSTRUCTIONS.st, ST);
        opcode_map.insert(INSTRUCTIONS.jmp, JMP);
        opcode_map.insert(INSTRUCTIONS.jgr, JGR);
        opcode_map.insert(INSTRUCTIONS.jge, JGE);
        opcode_map.insert(INSTRUCTIONS.jeq, JEQ);
        opcode_map.insert(INSTRUCTIONS.jne, JNE);
        opcode_map.insert(INSTRUCTIONS.jle, JLE);
        opcode_map.insert(INSTRUCTIONS.jls, JLS);

        for instruction in code {
            println!("{}", instruction);
        }
    }

    pub fn execute(&mut self) {
        loop {
            let inst = self.mem[self.ip];
            let opcode = inst.rotate_left(INST_ROTATION) & INST_MASK;

            match opcode {
                HALT => break,
                IN_N => self.process_in_n(),
                OUT_N => self.process_out_n(),
                IN_S => self.process_in_s(),
                OUT_S => self.process_out_s(),
                ADD => self.process_add(),
                SUB => self.process_sub(),
                MUL => self.process_mul(),
                DIV => self.process_div(),
                CON => self.process_con(),
                PUSH => self.process_push(),
                POP => self.process_pop(),
                LD => self.process_ld(),
                ST => self.process_st(),
                JMP => self.process_jmp(),
                JGR => self.process_jgr(),
                JGE => self.process_jge(),
                JEQ => self.process_jeq(),
                JNE => self.process_jne(),
                JLE => self.process_jle(),
                JLS => self.process_jls(),
                _ => {
                    println!("Unknow instruction. Aborting.");
                    break;
                }

            }

            if self.has_errors() {
                self.throw_exception();
                break;
            }
        }
    }

    fn process_in_n(&mut self) {
        let mut input_text = String::new();
        stdin().read_line(&mut input_text).expect(
            "failed to read from stdin",
        );

        let trimmed = input_text.trim();
        match trimmed.parse::<f64>() {
            Ok(i) => {
                self.acc = unsafe { transmute::<f64, u64>(i) };
                self.ip = self.ip + 1;
            }
            Err(..) => self.set_io_error_flag(),
        };
    }

    fn process_out_n(&mut self) {
        let output = unsafe { transmute::<u64, f64>(self.acc) };
        println!("{}", output);
        self.ip = self.ip + 1;
    }

    fn process_in_s(&mut self) {}

    fn process_out_s(&mut self) {}

    fn process_add(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 + operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_sub(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 - operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_mul(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 * operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_div(&mut self) {
        let operand1 = self.get_operand(OPERAND_ONE_ROTATION);
        let operand2 = self.get_operand(OPERANT_TWO_ROTATION);

        let result = operand1 / operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_con(&mut self) {}

    fn process_push(&mut self) {
        //check if stack is full
        if self.sp <= STACK_MEM_BOTTOM {
            self.set_mem_error_flag("Push attempt on full stack.");
            return;
        }

        let reg_index = self.get_register_index();
        let mut value: u64;

        // register push
        if reg_index < REG_NUM {
            value = self.reg[reg_index];
        // ip push
        } else if reg_index == IP_INDEX {
            value = self.ip as u64;
        // sp push
        } else if reg_index == SP_INDEX {
            value = self.sp as u64;
        // acc push
        } else if reg_index == ACC_INDEX {
            value = self.acc;
        // error
        } else {
            self.set_mem_error_flag("Push attempt on unknown register.");
            return;
        }

        self.mem[self.sp] = value;
        self.sp = self.sp - 1;
    }

    fn process_pop(&mut self) {
        //check if stack is empty
        if self.sp > STACK_MEM_TOP {
            self.set_mem_error_flag("Pop attempt on empty stack.");
            return;
        }

        let reg_index = self.get_register_index();
        let value = self.mem[self.sp];
        self.sp = self.sp + 1;

        // register pop
        if reg_index < REG_NUM {
            self.reg[reg_index] = value;
        // ip pop
        } else if reg_index == IP_INDEX {
            self.ip = value as usize;
        // sp pop
        } else if reg_index == SP_INDEX {
            self.sp = value as usize;
        // acc pop
        } else if reg_index == ACC_INDEX {
            self.acc = value;
        // error
        } else {
            self.set_mem_error_flag("Pop attempt on unknown register.");
            return;
        }
    }

    fn process_ld(&mut self) {
        let reg_index = self.get_register_index();
    }

    fn process_st(&mut self) {
        let reg_index = self.get_register_index();
    }

    fn process_jmp(&mut self) {}

    fn process_jgr(&mut self) {}

    fn process_jge(&mut self) {}

    fn process_jeq(&mut self) {}

    fn process_jne(&mut self) {}

    fn process_jle(&mut self) {}

    fn process_jls(&mut self) {}

    fn set_io_error_flag(&mut self) {
        println!("IO error flag set!")
    }

    fn set_mem_error_flag(&mut self, error: &'static str) {
        println!("{}", error)
    }

    fn has_errors(&mut self) -> bool {
        false
    }

    fn throw_exception(&mut self) {
        println!("Exception thrown!")
    }

    fn get_operand(&mut self, rotation: u32) -> f64 {
        let inst = self.mem[self.ip];
        let operand_reg = (inst.rotate_left(rotation) & REG_MASK) as usize;

        unsafe { transmute::<u64, f64>(self.reg[operand_reg]) }
    }

    fn get_register_index(&mut self) -> usize {
        let inst = self.mem[self.ip];
        let reg_index = (inst.rotate_left(FULL_REG_ROTATION) & FULL_REG_MASK) as usize;

        reg_index
    }
}
<|endoftext|>


<commit_before>// Tests that we correctly handle the instantiated
// inference variable being completely unconstrained.
//
// check-pass
#![feature(type_alias_impl_trait)]

type Foo = impl Copy;

enum Wrapper<T> {
    First(T),
    Second
}

fn _make_iter() -> Foo {
    true
}

fn _produce() -> Wrapper<Foo> {
    Wrapper::Second
}

fn main() {}
<commit_msg>Add explanation of unconstrained opaque type<commit_after>// Tests that we correctly handle the instantiated
// inference variable being completely unconstrained.
//
// check-pass
#![feature(type_alias_impl_trait)]

type Foo = impl Copy;

enum Wrapper<T> {
    First(T),
    Second
}

// This method constrains `Foo` to be `bool`
fn constrained_foo() -> Foo {
    true
}

// This method does not constrain `Foo`.
// Per RFC 2071, function bodies may either
// fully constrain an opaque type, or place no
// constraints on it.
fn unconstrained_foo() -> Wrapper<Foo> {
    Wrapper::Second
}

fn main() {}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

extern crate lambda_calculus as lambda;

use test::Bencher;
use lambda::parser::*;
use lambda::parser::Token::*;
use lambda::parser::Expression::*;

#[bench]
fn tokenizing_debruijn(b: &mut Bencher) {
    let blc_debruijn = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))\
        (1(2(λ12))(λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";

    b.iter(|| { let _ = tokenize_dbr(&blc_debruijn); } );
}

#[bench]
fn tokenizing_classic(b: &mut Bencher) {
    let blc_classic = "(λa.a a) (λa.λb.λc.c (λd.λe.λf.λg.e (λh.d (f (λi.h (g (λj.λk.i (λl.l k j)))\
     (f (λj.g (λk.i k (j k)))))) (h (g (λi.i h)) (λi.f (λj.g (λk.j (k h))) e)))) (a a) b)\
     (λa.a ((λb.b b) (λb.b b)))";

    b.iter(|| { convert_classic_tokens(&tokenize_cla(&blc_classic).unwrap()); } );
}

#[bench]
fn creating_ast(b: &mut Bencher) {
    let blc_tokens = vec![Lparen, Lambda, Number(1), Number(1), Rparen, Lparen, Lambda, Lambda,
        Lambda, Number(1), Lparen, Lambda, Lambda, Lambda, Lambda, Number(3), Lparen, Lambda,
        Number(5), Lparen, Number(3), Lparen, Lambda, Number(2), Lparen, Number(3), Lparen, Lambda,
        Lambda, Number(3), Lparen, Lambda, Number(1), Number(2), Number(3), Rparen, Rparen, Rparen,
        Lparen, Number(4), Lparen, Lambda, Number(4), Lparen, Lambda, Number(3), Number(1), Lparen,
        Number(2), Number(1), Rparen, Rparen, Rparen, Rparen, Rparen, Rparen, Lparen, Number(1),
        Lparen, Number(2), Lparen, Lambda, Number(1), Number(2), Rparen, Rparen, Lparen, Lambda,
        Number(4), Lparen, Lambda, Number(4), Lparen, Lambda, Number(2), Lparen, Number(1),
        Number(4), Rparen, Rparen, Rparen, Number(5), Rparen, Rparen, Rparen, Rparen, Lparen,
        Number(3), Number(3), Rparen, Number(2), Rparen, Lparen, Lambda, Number(1), Lparen, Lparen,
        Lambda, Number(1), Number(1), Rparen, Lparen, Lambda, Number(1), Number(1), Rparen, Rparen,
        Rparen];

    b.iter(|| { let _ = get_ast(&blc_tokens); } );
}

#[bench]
fn interpreting_ast(b: &mut Bencher) {
    let blc_ast = vec![Sequence(vec![Abstraction, Variable(1), Variable(1)]), Sequence(vec![Abstraction,
        Abstraction, Abstraction, Variable(1), Sequence(vec![Abstraction, Abstraction, Abstraction,
        Abstraction, Variable(3), Sequence(vec![Abstraction, Variable(5), Sequence(vec![Variable(3),
        Sequence(vec![Abstraction, Variable(2), Sequence(vec![Variable(3), Sequence(vec![Abstraction,
        Abstraction, Variable(3), Sequence(vec![Abstraction, Variable(1), Variable(2), Variable(3)])])]),
        Sequence(vec![Variable(4), Sequence(vec![Abstraction, Variable(4), Sequence(vec![Abstraction,
        Variable(3), Variable(1), Sequence(vec![Variable(2), Variable(1)])])])])])]),
        Sequence(vec![Variable(1), Sequence(vec![Variable(2), Sequence(vec![Abstraction, Variable(1),
        Variable(2)])]), Sequence(vec![Abstraction, Variable(4), Sequence(vec![Abstraction, Variable(4),
        Sequence(vec![Abstraction, Variable(2), Sequence(vec![Variable(1), Variable(4)])])]),
        Variable(5)])])])]), Sequence(vec![Variable(3), Variable(3)]), Variable(2)]),
        Sequence(vec![Abstraction, Variable(1), Sequence(vec![Sequence(vec![Abstraction, Variable(1),
        Variable(1)]), Sequence(vec![Abstraction, Variable(1), Variable(1)])])])];

    b.iter(|| { let _ = fold_exprs(&blc_ast); } );
}
<commit_msg>unify parser bench names<commit_after>#![feature(test)]
extern crate test;

extern crate lambda_calculus as lambda;

use test::Bencher;
use lambda::parser::*;
use lambda::parser::Token::*;
use lambda::parser::Expression::*;

#[bench]
fn parser_tokenizing_dbr(b: &mut Bencher) {
    let blc_debruijn = "(λ11)(λλλ1(λλλλ3(λ5(3(λ2(3(λλ3(λ123)))(4(λ4(λ31(21))))))\
        (1(2(λ12))(λ4(λ4(λ2(14)))5))))(33)2)(λ1((λ11)(λ11)))";

    b.iter(|| { let _ = tokenize_dbr(&blc_debruijn); } );
}

#[bench]
fn parser_tokenizing_cla(b: &mut Bencher) {
    let blc_classic = "(λa.a a) (λa.λb.λc.c (λd.λe.λf.λg.e (λh.d (f (λi.h (g (λj.λk.i (λl.l k j)))\
     (f (λj.g (λk.i k (j k)))))) (h (g (λi.i h)) (λi.f (λj.g (λk.j (k h))) e)))) (a a) b)\
     (λa.a ((λb.b b) (λb.b b)))";

    b.iter(|| { convert_classic_tokens(&tokenize_cla(&blc_classic).unwrap()); } );
}

#[bench]
fn parser_creating_ast(b: &mut Bencher) {
    let blc_tokens = vec![Lparen, Lambda, Number(1), Number(1), Rparen, Lparen, Lambda, Lambda,
        Lambda, Number(1), Lparen, Lambda, Lambda, Lambda, Lambda, Number(3), Lparen, Lambda,
        Number(5), Lparen, Number(3), Lparen, Lambda, Number(2), Lparen, Number(3), Lparen, Lambda,
        Lambda, Number(3), Lparen, Lambda, Number(1), Number(2), Number(3), Rparen, Rparen, Rparen,
        Lparen, Number(4), Lparen, Lambda, Number(4), Lparen, Lambda, Number(3), Number(1), Lparen,
        Number(2), Number(1), Rparen, Rparen, Rparen, Rparen, Rparen, Rparen, Lparen, Number(1),
        Lparen, Number(2), Lparen, Lambda, Number(1), Number(2), Rparen, Rparen, Lparen, Lambda,
        Number(4), Lparen, Lambda, Number(4), Lparen, Lambda, Number(2), Lparen, Number(1),
        Number(4), Rparen, Rparen, Rparen, Number(5), Rparen, Rparen, Rparen, Rparen, Lparen,
        Number(3), Number(3), Rparen, Number(2), Rparen, Lparen, Lambda, Number(1), Lparen, Lparen,
        Lambda, Number(1), Number(1), Rparen, Lparen, Lambda, Number(1), Number(1), Rparen, Rparen,
        Rparen];

    b.iter(|| { let _ = get_ast(&blc_tokens); } );
}

#[bench]
fn parser_interpreting_ast(b: &mut Bencher) {
    let blc_ast = vec![Sequence(vec![Abstraction, Variable(1), Variable(1)]), Sequence(vec![Abstraction,
        Abstraction, Abstraction, Variable(1), Sequence(vec![Abstraction, Abstraction, Abstraction,
        Abstraction, Variable(3), Sequence(vec![Abstraction, Variable(5), Sequence(vec![Variable(3),
        Sequence(vec![Abstraction, Variable(2), Sequence(vec![Variable(3), Sequence(vec![Abstraction,
        Abstraction, Variable(3), Sequence(vec![Abstraction, Variable(1), Variable(2), Variable(3)])])]),
        Sequence(vec![Variable(4), Sequence(vec![Abstraction, Variable(4), Sequence(vec![Abstraction,
        Variable(3), Variable(1), Sequence(vec![Variable(2), Variable(1)])])])])])]),
        Sequence(vec![Variable(1), Sequence(vec![Variable(2), Sequence(vec![Abstraction, Variable(1),
        Variable(2)])]), Sequence(vec![Abstraction, Variable(4), Sequence(vec![Abstraction, Variable(4),
        Sequence(vec![Abstraction, Variable(2), Sequence(vec![Variable(1), Variable(4)])])]),
        Variable(5)])])])]), Sequence(vec![Variable(3), Variable(3)]), Variable(2)]),
        Sequence(vec![Abstraction, Variable(1), Sequence(vec![Sequence(vec![Abstraction, Variable(1),
        Variable(1)]), Sequence(vec![Abstraction, Variable(1), Variable(1)])])])];

    b.iter(|| { let _ = fold_exprs(&blc_ast); } );
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
#[macro_use]
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::Target;
use std::any::Any;
use std::path::Path;

pub struct NoLlvmMetadataLoader;

impl MetadataLoader for NoLlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
        let buf =
            std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?;
        let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf);
        Ok(rustc_erase_owner!(buf.map_owner_box()))
    }

    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
        self.get_rlib_metadata(target, filename)
    }
}

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        Box::new(NoLlvmMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_symbol_mangling::provide(providers);

        providers.target_features_whitelist = |tcx, _cnum| {
            tcx.arena.alloc(Default::default()) // Just a dummy
        };
        providers.is_reachable_non_generic = |_tcx, _defid| true;
        providers.exported_symbols = |_tcx, _crate| &[];
    }

    fn provide_extern(&self, providers: &mut Providers) {
        providers.is_reachable_non_generic = |_tcx, _defid| true;
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        _metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        use rustc_hir::def_id::LOCAL_CRATE;

        Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol)
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
        _dep_graph: &DepGraph,
    ) -> Result<Box<dyn Any>, ErrorReported> {
        let crate_name = ongoing_codegen
            .downcast::<Symbol>()
            .expect("in join_codegen: ongoing_codegen is not a Symbol");
        Ok(crate_name)
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: Box<dyn Any>,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name =
            codegen_results.downcast::<Symbol>().expect("in link: codegen_results is not a Symbol");
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<commit_msg>Fix fulldeps tests.<commit_after>#![feature(rustc_private)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
#[macro_use]
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::Target;
use std::any::Any;
use std::path::Path;

pub struct NoLlvmMetadataLoader;

impl MetadataLoader for NoLlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
        let buf =
            std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?;
        let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf);
        Ok(rustc_erase_owner!(buf.map_owner_box()))
    }

    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
        self.get_rlib_metadata(target, filename)
    }
}

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        Box::new(NoLlvmMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_symbol_mangling::provide(providers);

        providers.target_features_whitelist = |tcx, _cnum| {
            Default::default() // Just a dummy
        };
        providers.is_reachable_non_generic = |_tcx, _defid| true;
        providers.exported_symbols = |_tcx, _crate| &[];
    }

    fn provide_extern(&self, providers: &mut Providers) {
        providers.is_reachable_non_generic = |_tcx, _defid| true;
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        _metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        use rustc_hir::def_id::LOCAL_CRATE;

        Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol)
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
        _dep_graph: &DepGraph,
    ) -> Result<Box<dyn Any>, ErrorReported> {
        let crate_name = ongoing_codegen
            .downcast::<Symbol>()
            .expect("in join_codegen: ongoing_codegen is not a Symbol");
        Ok(crate_name)
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: Box<dyn Any>,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name =
            codegen_results.downcast::<Symbol>().expect("in link: codegen_results is not a Symbol");
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<|endoftext|>


<commit_before>use anyhow::Result;
use clap::Parser;
use regex::Regex;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::PathBuf;
use std::time::Instant;

use polars::frame::DataFrame;
use polars::prelude::*;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
    /// List of input files. Ideally with headers
    #[clap(short, long, multiple_values(true))]
    input: Vec<PathBuf>,

    /// An output file
    #[clap(short, long)]
    output: String,

    /// The column to select. If files have no headers, use "column_N"
    #[clap(short, long, multiple_values(true))]
    select: Vec<String>,

    /// The size of chunks to process at once
    #[clap(short, long, default_value_t = 100)]
    chunksize: usize,
}

fn load_data(path: &PathBuf, delim: u8) -> Result<DataFrame> {
    let mut df: DataFrame = CsvReader::from_path(path)?
        .has_header(true)
        .with_delimiter(delim)
        .with_null_values(Some(NullValues::AllColumns("NA".to_string())))
        .infer_schema(None)
        .finish()
        .unwrap();

    // hstack the experiment name (derived from the filename) into the DataFrame
    let iter_exp =
        vec![path.file_name().unwrap().to_str().unwrap().split('-').collect::<Vec<&str>>()[0..=2]
            .join("-")]
        .into_iter();
    let exp_col: Series = Series::new(
        "experiment",
        iter_exp.flat_map(|n| std::iter::repeat(n).take(df.height())).collect::<Vec<String>>(),
    );
    // exp_col.rename("experiment");
    df.hstack_mut(&[exp_col]).unwrap();

    Ok(df)
}

fn baseline_get_median_gt_zero(str_val: &Series) -> Series {
    let lists = str_val.utf8().unwrap().into_iter().map(|x| {
        x.unwrap().split(',').into_iter().map(|y| y.parse::<f64>().unwrap()).collect::<Vec<f64>>()
    });

    let medians: Vec<bool> =
        lists.into_iter().map(|x| Series::from_iter(x).median().unwrap() > 0.0).collect();
    Series::from_iter(medians)
}

fn filter_input(input: &mut DataFrame, baseline: bool) -> DataFrame {
    if baseline {
        filter_baseline(input)
    } else {
        filter_differential(input)
    }
}

fn filter_baseline(input: &mut DataFrame) -> DataFrame {
    // This is a baseline experiment.
    // Find columns starting with lower case g, then apply the function to convert to
    // medain and select greater than zero
    let mut meas = Vec::<String>::new();

    for col in input.get_column_names_owned() {
        if col.starts_with('g') {
            input.apply(&col, baseline_get_median_gt_zero).unwrap();
            meas.push(col);
        }
    }
    println!("{:?}", meas);
    // Selection should now have all the gN column names in it
    input
        .clone()
        .lazy()
        .filter(any_exprs(meas.into_iter().map(|x| col(&x)).collect::<Vec<Expr>>()))
        .collect()
        .unwrap()
}

fn filter_differential(input: &DataFrame) -> DataFrame {
    // find the p value and log fold columns
    let pv_regex = Regex::new(r".*p-value.*").unwrap();
    let log_fold_regex = Regex::new(r".*log2.*").unwrap();
    let mut exprs: Vec<Expr> = Vec::new();
    let mut pv: Expr;
    let mut lf: Expr;
    for column in input.get_column_names_owned() {
        if pv_regex.is_match(&column) {
            pv = col(&column).is_not_null();
            exprs.push(pv);
        } else if log_fold_regex.is_match(&column) {
            lf = col(&column).neq(lit(0));
            exprs.push(lf);
        }
    }

    input.clone().lazy().filter(all_exprs(exprs)).collect().unwrap()
}

fn load_chunk(
    paths: &mut Vec<PathBuf>,
    select: &mut Vec<String>,
) -> Result<DataFrame, anyhow::Error> {
    /*
    Work with the chunks of input to reduce them into a single dataframe of the genes we want from
    that particular set of experiments. Should return a single dataframe
    */
    let mut output: Option<DataFrame> = None;
    while let Some(infile) = paths.pop() {
        // Load the input Csv
        let mut input: DataFrame = if infile.extension().unwrap() == "tsv" {
            load_data(&infile, b'\t')
        } else {
            load_data(&infile, b',')
        }
        .unwrap_or_else(|error| match error.downcast_ref::<PolarsError>() {
            Some(PolarsError::Io(_string)) => panic!("Input file does not exist! {:?}", infile),
            _ => panic!("An error occurred! {:?}", error),
        });

        // Rename columns to remove . in the names. Now also remove spaces
        let mut new_cols = Vec::new();
        let mut c: u8 = 0;
        for nm in input.get_column_names().iter() {
            let mut new_name = nm.replace('.', "").replace(' ', "");
            if new_cols.contains(&new_name) {
                c += 1;
                new_name += &c.to_string(); // Hopefully avoid duplicate names
            }
            new_cols.push(new_name);
        }

        if new_cols != input.get_column_names() {
            input.set_column_names(&new_cols).unwrap_or_else(|error| {
                panic!("Failed to set column names for some reason {:?}", error);
            });
        }

        // Need to detect which type of experiment it is - differential or baseline
        let type_re = Regex::new(r"tpms").unwrap();
        let filtered = filter_input(&mut input, type_re.is_match(infile.to_str().unwrap()));
        // Drop everything from the input except the genes
        let genes: DataFrame = filtered.select(select.iter()).unwrap_or_else(|error| match error {
            PolarsError::NotFound(_string) => {
                panic!(
                    "{:?} was not found in the header, does the file have a header?\n{:?}",
                    select,
                    input.get_column_names()
                );
            },
            _ => panic!("Error selecting column from input: {:?}", error),
        });

        output = match output {
            None => {
                let output_df = genes.clone();
                Some(output_df)
            },
            Some(mut output_df) => {
                // genes =/= output, so we are handling a new file
                output_df.extend(&genes).unwrap_or_else(|error| {
                    panic!("Failed to extend the output dataframe. {:?}", error)
                });
                output_df =
                    output_df.unique(None, UniqueKeepStrategy::First).unwrap_or_else(|error| {
                        panic!("Failed to parse selected column for uniqueness. {:?}", error)
                    });
                Some(output_df)
            },
        }
    }
    Ok(output.unwrap())
}

fn get_taxid(paths: &mut Vec<PathBuf>, lookup_table: &mut HashMap<String, String>) {
    let tax_regex = Regex::new(r".*Taxon_([0-9]{4,})").unwrap();

    while let Some(path) = paths.pop() {
        let exp_name =
            path.file_name().unwrap().to_str().unwrap().split('-').collect::<Vec<&str>>()[0..=2]
                .join("-")
                .replace(".condensed", "");

        let file = File::open(path).unwrap();
        let lines = io::BufReader::new(file).lines();
        for line in lines {
            match line {
                Ok(line) => {
                    let captures = tax_regex.captures(line.as_str());
                    match captures {
                        Some(caps) => {
                            let taxid = caps.get(1).map_or("", |m| m.as_str());
                            lookup_table.insert(exp_name, taxid.to_string());
                            break;
                        },
                        None => {},
                    };
                },
                Err(_idc) => {},
            }
        }
    }
}

fn main() {
    let timer = Instant::now();

    let mut args = Args::parse();

    // Always select the experiment
    args.select.push("experiment".to_string());

    // separate expression data from taxa data
    let mut taxa_files: Vec<PathBuf> = Vec::new();
    let mut expr_files: Vec<PathBuf> = Vec::new();

    let re = Regex::new(r"sdrf.tsv").unwrap();

    for infile in args.input {
        if re.is_match(infile.to_str().unwrap()) {
            // File is experiment setup data, parse for taxa
            taxa_files.push(infile);
        } else {
            // Should only be expression data, parse for genes
            expr_files.push(infile);
        }
    }

    println!("{} taxa files to parse", taxa_files.len());
    println!("{} expression files to parse", expr_files.len());

    let n_files = expr_files.len();

    let mut dataframes: Vec<DataFrame> = Vec::new();

    let chunked_input: Vec<Vec<PathBuf>> =
        expr_files.chunks(args.chunksize).map(|x| x.to_vec()).collect();
    // Read everything into a big vector
    let mut n_chunks = 0;
    for mut files_chunk in chunked_input {
        dataframes.push(
            load_chunk(&mut files_chunk, &mut args.select)
                .unwrap_or_else(|_error| panic!("Something wrong in one of the reads, aborting")),
        );
        n_chunks += 1;
        println!("Done {} files", n_chunks * args.chunksize);
    }

    let mut output: DataFrame = dataframes[0].clone();

    for item in dataframes.iter() {
        output.extend(item).unwrap_or_else(|error| {
            panic!("Unable to extend the DataFrame! Out of memory? {:?}", error)
        });
        output.unique(None, UniqueKeepStrategy::First).unwrap();
    }

    // Now parse the experiment files to get taxa
    let chunked_taxa: Vec<Vec<PathBuf>> =
        taxa_files.chunks(args.chunksize).map(|x| x.to_vec()).collect();

    let mut lookup_table: HashMap<String, String> = HashMap::new();

    for mut tax_chunk in chunked_taxa {
        get_taxid(&mut tax_chunk, &mut lookup_table);
    }

    // Now we have the experiment - taxid lookup_table, we just need to add the column to the output df

    let expt_col = output.select(["experiment"]).unwrap();
    let mut tax_ids: Vec<String> = Vec::with_capacity(expt_col.height());
    for ex in expt_col.iter() {
        let mut warn_flag: bool = true;
        let uhy = ex.utf8().unwrap();
        for (idx, x) in uhy.into_iter().enumerate() {
            if lookup_table.contains_key(x.unwrap()) {
                tax_ids.insert(idx, lookup_table.get(x.unwrap()).unwrap().to_string());
            } else {
                tax_ids.insert(idx, String::new());
                if warn_flag {
                    println!("Experiment {} does not name a taxon", x.unwrap());
                    warn_flag = false;
                }
            }
        }
    }

    output.hstack_mut(&[Series::new("taxid", tax_ids.into_iter())]).unwrap();

    let out_stream: File = File::create(args.output).unwrap();
    CsvWriter::new(out_stream)
        .has_header(true)
        .finish(&mut output)
        .unwrap_or_else(|error| panic!("Something wrong writing file: {:?}", error));

    println!("Processed {} in {} seconds", n_files, timer.elapsed().as_secs());
}
<commit_msg>Remove some verbosity from parser<commit_after>use anyhow::Result;
use clap::Parser;
use regex::Regex;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::PathBuf;
use std::time::Instant;

use polars::frame::DataFrame;
use polars::prelude::*;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
    /// List of input files. Ideally with headers
    #[clap(short, long, multiple_values(true))]
    input: Vec<PathBuf>,

    /// An output file
    #[clap(short, long)]
    output: String,

    /// The column to select. If files have no headers, use "column_N"
    #[clap(short, long, multiple_values(true))]
    select: Vec<String>,

    /// The size of chunks to process at once
    #[clap(short, long, default_value_t = 100)]
    chunksize: usize,
}

fn load_data(path: &PathBuf, delim: u8) -> Result<DataFrame> {
    let mut df: DataFrame = CsvReader::from_path(path)?
        .has_header(true)
        .with_delimiter(delim)
        .with_null_values(Some(NullValues::AllColumns("NA".to_string())))
        .infer_schema(None)
        .finish()
        .unwrap();

    // hstack the experiment name (derived from the filename) into the DataFrame
    let iter_exp =
        vec![path.file_name().unwrap().to_str().unwrap().split('-').collect::<Vec<&str>>()[0..=2]
            .join("-")]
        .into_iter();
    let exp_col: Series = Series::new(
        "experiment",
        iter_exp.flat_map(|n| std::iter::repeat(n).take(df.height())).collect::<Vec<String>>(),
    );
    // exp_col.rename("experiment");
    df.hstack_mut(&[exp_col]).unwrap();

    Ok(df)
}

fn baseline_get_median_gt_zero(str_val: &Series) -> Series {
    let lists = str_val.utf8().unwrap().into_iter().map(|x| {
        x.unwrap().split(',').into_iter().map(|y| y.parse::<f64>().unwrap()).collect::<Vec<f64>>()
    });

    let medians: Vec<bool> =
        lists.into_iter().map(|x| Series::from_iter(x).median().unwrap() > 0.0).collect();
    Series::from_iter(medians)
}

fn filter_input(input: &mut DataFrame, baseline: bool) -> DataFrame {
    if baseline {
        filter_baseline(input)
    } else {
        filter_differential(input)
    }
}

fn filter_baseline(input: &mut DataFrame) -> DataFrame {
    // This is a baseline experiment.
    // Find columns starting with lower case g, then apply the function to convert to
    // medain and select greater than zero
    let mut meas = Vec::<String>::new();

    for col in input.get_column_names_owned() {
        if col.starts_with('g') {
            input.apply(&col, baseline_get_median_gt_zero).unwrap();
            meas.push(col);
        }
    }
    // Selection should now have all the gN column names in it
    input
        .clone()
        .lazy()
        .filter(any_exprs(meas.into_iter().map(|x| col(&x)).collect::<Vec<Expr>>()))
        .collect()
        .unwrap()
}

fn filter_differential(input: &DataFrame) -> DataFrame {
    // find the p value and log fold columns
    let pv_regex = Regex::new(r".*p-value.*").unwrap();
    let log_fold_regex = Regex::new(r".*log2.*").unwrap();
    let mut exprs: Vec<Expr> = Vec::new();
    let mut pv: Expr;
    let mut lf: Expr;
    for column in input.get_column_names_owned() {
        if pv_regex.is_match(&column) {
            pv = col(&column).is_not_null();
            exprs.push(pv);
        } else if log_fold_regex.is_match(&column) {
            lf = col(&column).neq(lit(0));
            exprs.push(lf);
        }
    }

    input.clone().lazy().filter(all_exprs(exprs)).collect().unwrap()
}

fn load_chunk(
    paths: &mut Vec<PathBuf>,
    select: &mut Vec<String>,
) -> Result<DataFrame, anyhow::Error> {
    /*
    Work with the chunks of input to reduce them into a single dataframe of the genes we want from
    that particular set of experiments. Should return a single dataframe
    */
    let mut output: Option<DataFrame> = None;
    while let Some(infile) = paths.pop() {
        // Load the input Csv
        let mut input: DataFrame = if infile.extension().unwrap() == "tsv" {
            load_data(&infile, b'\t')
        } else {
            load_data(&infile, b',')
        }
        .unwrap_or_else(|error| match error.downcast_ref::<PolarsError>() {
            Some(PolarsError::Io(_string)) => panic!("Input file does not exist! {:?}", infile),
            _ => panic!("An error occurred! {:?}", error),
        });

        // Rename columns to remove . in the names. Now also remove spaces
        let mut new_cols = Vec::new();
        let mut c: u8 = 0;
        for nm in input.get_column_names().iter() {
            let mut new_name = nm.replace('.', "").replace(' ', "");
            if new_cols.contains(&new_name) {
                c += 1;
                new_name += &c.to_string(); // Hopefully avoid duplicate names
            }
            new_cols.push(new_name);
        }

        if new_cols != input.get_column_names() {
            input.set_column_names(&new_cols).unwrap_or_else(|error| {
                panic!("Failed to set column names for some reason {:?}", error);
            });
        }

        // Need to detect which type of experiment it is - differential or baseline
        let type_re = Regex::new(r"tpms").unwrap();
        let filtered = filter_input(&mut input, type_re.is_match(infile.to_str().unwrap()));
        // Drop everything from the input except the genes
        let genes: DataFrame = filtered.select(select.iter()).unwrap_or_else(|error| match error {
            PolarsError::NotFound(_string) => {
                panic!(
                    "{:?} was not found in the header, does the file have a header?\n{:?}",
                    select,
                    input.get_column_names()
                );
            },
            _ => panic!("Error selecting column from input: {:?}", error),
        });

        output = match output {
            None => {
                let output_df = genes.clone();
                Some(output_df)
            },
            Some(mut output_df) => {
                // genes =/= output, so we are handling a new file
                output_df.extend(&genes).unwrap_or_else(|error| {
                    panic!("Failed to extend the output dataframe. {:?}", error)
                });
                output_df =
                    output_df.unique(None, UniqueKeepStrategy::First).unwrap_or_else(|error| {
                        panic!("Failed to parse selected column for uniqueness. {:?}", error)
                    });
                Some(output_df)
            },
        }
    }
    Ok(output.unwrap())
}

fn get_taxid(paths: &mut Vec<PathBuf>, lookup_table: &mut HashMap<String, String>) {
    let tax_regex = Regex::new(r".*Taxon_([0-9]{4,})").unwrap();

    while let Some(path) = paths.pop() {
        let exp_name =
            path.file_name().unwrap().to_str().unwrap().split('-').collect::<Vec<&str>>()[0..=2]
                .join("-")
                .replace(".condensed", "");

        let file = File::open(path).unwrap();
        let lines = io::BufReader::new(file).lines();
        for line in lines {
            match line {
                Ok(line) => {
                    let captures = tax_regex.captures(line.as_str());
                    match captures {
                        Some(caps) => {
                            let taxid = caps.get(1).map_or("", |m| m.as_str());
                            lookup_table.insert(exp_name, taxid.to_string());
                            break;
                        },
                        None => {},
                    };
                },
                Err(_idc) => {},
            }
        }
    }
}

fn main() {
    let timer = Instant::now();

    let mut args = Args::parse();

    // Always select the experiment
    args.select.push("experiment".to_string());

    // separate expression data from taxa data
    let mut taxa_files: Vec<PathBuf> = Vec::new();
    let mut expr_files: Vec<PathBuf> = Vec::new();

    let re = Regex::new(r"sdrf.tsv").unwrap();

    for infile in args.input {
        if re.is_match(infile.to_str().unwrap()) {
            // File is experiment setup data, parse for taxa
            taxa_files.push(infile);
        } else {
            // Should only be expression data, parse for genes
            expr_files.push(infile);
        }
    }

    println!("{} taxa files to parse", taxa_files.len());
    println!("{} expression files to parse", expr_files.len());

    let n_files = expr_files.len();

    let mut dataframes: Vec<DataFrame> = Vec::new();

    let chunked_input: Vec<Vec<PathBuf>> =
        expr_files.chunks(args.chunksize).map(|x| x.to_vec()).collect();
    // Read everything into a big vector
    let mut n_chunks = 0;
    for mut files_chunk in chunked_input {
        dataframes.push(
            load_chunk(&mut files_chunk, &mut args.select)
                .unwrap_or_else(|_error| panic!("Something wrong in one of the reads, aborting")),
        );
        n_chunks += 1;
        println!("Done {} files", n_chunks * args.chunksize);
    }

    let mut output: DataFrame = dataframes[0].clone();

    for item in dataframes.iter() {
        output.extend(item).unwrap_or_else(|error| {
            panic!("Unable to extend the DataFrame! Out of memory? {:?}", error)
        });
        output.unique(None, UniqueKeepStrategy::First).unwrap();
    }

    // Now parse the experiment files to get taxa
    let chunked_taxa: Vec<Vec<PathBuf>> =
        taxa_files.chunks(args.chunksize).map(|x| x.to_vec()).collect();

    let mut lookup_table: HashMap<String, String> = HashMap::new();

    for mut tax_chunk in chunked_taxa {
        get_taxid(&mut tax_chunk, &mut lookup_table);
    }

    // Now we have the experiment - taxid lookup_table, we just need to add the column to the output df

    let expt_col = output.select(["experiment"]).unwrap();
    let mut tax_ids: Vec<String> = Vec::with_capacity(expt_col.height());
    for ex in expt_col.iter() {
        let mut warn_flag: bool = true;
        let uhy = ex.utf8().unwrap();
        for (idx, x) in uhy.into_iter().enumerate() {
            if lookup_table.contains_key(x.unwrap()) {
                tax_ids.insert(idx, lookup_table.get(x.unwrap()).unwrap().to_string());
            } else {
                tax_ids.insert(idx, String::new());
                if warn_flag {
                    println!("Experiment {} does not name a taxon", x.unwrap());
                    warn_flag = false;
                }
            }
        }
    }

    output.hstack_mut(&[Series::new("taxid", tax_ids.into_iter())]).unwrap();

    let out_stream: File = File::create(args.output).unwrap();
    CsvWriter::new(out_stream)
        .has_header(true)
        .finish(&mut output)
        .unwrap_or_else(|error| panic!("Something wrong writing file: {:?}", error));

    println!("Processed {} in {} seconds", n_files, timer.elapsed().as_secs());
}
<|endoftext|>