<commit_before>use itertools::Itertools;
use regex::Regex;
use reqwest;
use rust_htslib::bcf;
use rust_htslib::bcf::Read;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::str;

#[derive(Serialize, Deserialize, Debug)]
struct Dgidb {
    #[serde(rename = "matchedTerms")]
    matched_terms: Vec<MatchedTerm>,
}

#[derive(Serialize, Deserialize, Debug)]
struct MatchedTerm {
    #[serde(rename = "geneName")]
    gene_name: String,
    interactions: Vec<Interaction>,
}

#[derive(Serialize, Deserialize, Debug)]
struct Interaction {
    #[serde(rename = "drugName")]
    drug_name: String,
    #[serde(rename = "interactionTypes")]
    interaction_types: Vec<String>,
}

pub fn annotate_dgidb(
    vcf_path: &str,
    api_path: String,
    field_name: &str,
) -> Result<(), Box<dyn Error>> {
    let gene_drug_interactions = request_interaction_drugs(vcf_path, api_path)?;
    modify_vcf_entries(vcf_path, gene_drug_interactions, field_name)
}

fn request_interaction_drugs(
    vcf_path: &str,
    mut api_path: String,
) -> Result<HashMap<String, Vec<(String, Vec<String>)>>, Box<dyn Error>> {
    let mut genes = collect_genes(vcf_path)?;
    api_path.push_str(genes.drain().join(",").as_str());
    let res: Dgidb = reqwest::get(&api_path)?.json()?;

    let mut gene_drug_interactions: HashMap<String, Vec<(String, Vec<String>)>> = HashMap::new();
    for term in res.matched_terms {
        if !term.interactions.is_empty() {
            gene_drug_interactions.insert(
                term.gene_name,
                term.interactions
                    .iter()
                    .map(|interaction| {
                        (
                            interaction.drug_name.clone(),
                            interaction.interaction_types.clone(),
                        )
                    })
                    .collect(),
            );
        }
    }
    Ok(gene_drug_interactions)
}

//TODO Remove split by ',' when updating to latest htslib release
fn collect_genes(vcf_path: &str) -> Result<HashSet<String>, Box<dyn Error>> {
    let mut total_genes = HashSet::new();
    let mut reader = bcf::Reader::from_path(vcf_path)?;
    //let all_genes = HashSet::new();
    for result in reader.records() {
        let mut rec = result?;
        let genes_opt = extract_genes(&mut rec)?;
        match genes_opt {
            Some(genes) => {
                for gene in genes {
                    total_genes.insert(gene);
                }
            }
            None => {}
        }
    }
    Ok(total_genes)
}

//TODO Remove split by ',' when updating to latest htslib release
fn extract_genes<'a>(
    rec: &'a mut bcf::Record,
) -> Result<Option<impl Iterator<Item = String> + 'a>, Box<dyn Error>> {
    let annotation = rec.info("ANN".as_bytes()).string()?;
    match annotation {
        Some(transcripts) => Ok(Some(transcripts[0].split(|c| *c == b',').map(
            |transcript| {
                str::from_utf8(transcript.split(|c| *c == b'|').nth(3).unwrap())
                    .unwrap()
                    .to_owned()
            },
        ))),
        None => Ok(None),
    }
}

fn modify_vcf_entries(
    vcf_path: &str,
    gene_drug_interactions: HashMap<String, Vec<(String, Vec<String>)>>,
    field_name: &str,
) -> Result<(), Box<dyn Error>> {
    let mut reader = bcf::Reader::from_path(vcf_path)?;
    let mut header = bcf::header::Header::from_template(reader.header());
    header.push_record(format!("##INFO=<ID={},Number=.,Type=String,Description=\"Combination of gene, drug, interaction types extracted from dgiDB. Each combination is pipe-seperated annotated as GENE|DRUG|TYPE\">", field_name).as_bytes());
    let mut writer = bcf::Writer::from_stdout(&header, true, true)?;

    for result in reader.records() {
        let mut rec = result?;
        writer.translate(&mut rec);
        let genes = extract_genes(&mut rec)?.map(|genes| genes.collect_vec());;
        if let Some(mut genes) = genes {
            genes.dedup();
            let field_entries = build_dgidb_field(&gene_drug_interactions, genes)?;
            let field_entries: Vec<&[u8]> = field_entries.iter().map(|v| v.as_slice()).collect();
            rec.push_info_string(field_name.as_bytes(), &field_entries[..])?;
        }
        writer.write(&rec)?;
    }
    Ok(())
}

fn build_dgidb_field(
    gene_drug_interactions: &HashMap<String, Vec<(String, Vec<String>)>>,
    genes: Vec<String>,
) -> Result<Vec<Vec<u8>>, Box<dyn Error>> {
    let mut field_entries: Vec<Vec<u8>> = Vec::new();
    let re = Regex::new(r"\s\(\w+\)").unwrap();
    for gene in genes.iter() {
        match gene_drug_interactions.get(gene) {
            Some(drug_interactions) => {
                drug_interactions
                    .iter()
                    .for_each(|(drug, interaction_types)| {
                        if !interaction_types.is_empty() {
                            interaction_types.iter().for_each(|interaction_type| {
                                field_entries.push(
                                    format!(
                                        "{g}|{d}|{t}",
                                        g = gene,
                                        d = re.replace(drug, ""),
                                        t = interaction_type
                                    )
                                    .as_bytes()
                                    .to_vec(),
                                )
                            })
                        } else {
                            field_entries.push(
                                format!("{g}|{d}|.", g = gene, d = re.replace(drug, ""))
                                    .as_bytes()
                                    .to_vec(),
                            )
                        }
                    });
            }
            None => field_entries.push(format!("{g}|.|.", g = gene).as_bytes().to_vec()),
        }
    }
    Ok(field_entries)
}
<commit_msg>Removed comments<commit_after>use itertools::Itertools;
use regex::Regex;
use reqwest;
use rust_htslib::bcf;
use rust_htslib::bcf::Read;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::str;

#[derive(Serialize, Deserialize, Debug)]
struct Dgidb {
    #[serde(rename = "matchedTerms")]
    matched_terms: Vec<MatchedTerm>,
}

#[derive(Serialize, Deserialize, Debug)]
struct MatchedTerm {
    #[serde(rename = "geneName")]
    gene_name: String,
    interactions: Vec<Interaction>,
}

#[derive(Serialize, Deserialize, Debug)]
struct Interaction {
    #[serde(rename = "drugName")]
    drug_name: String,
    #[serde(rename = "interactionTypes")]
    interaction_types: Vec<String>,
}

pub fn annotate_dgidb(
    vcf_path: &str,
    api_path: String,
    field_name: &str,
) -> Result<(), Box<dyn Error>> {
    let gene_drug_interactions = request_interaction_drugs(vcf_path, api_path)?;
    modify_vcf_entries(vcf_path, gene_drug_interactions, field_name)
}

fn request_interaction_drugs(
    vcf_path: &str,
    mut api_path: String,
) -> Result<HashMap<String, Vec<(String, Vec<String>)>>, Box<dyn Error>> {
    let mut genes = collect_genes(vcf_path)?;
    api_path.push_str(genes.drain().join(",").as_str());
    let res: Dgidb = reqwest::get(&api_path)?.json()?;

    let mut gene_drug_interactions: HashMap<String, Vec<(String, Vec<String>)>> = HashMap::new();
    for term in res.matched_terms {
        if !term.interactions.is_empty() {
            gene_drug_interactions.insert(
                term.gene_name,
                term.interactions
                    .iter()
                    .map(|interaction| {
                        (
                            interaction.drug_name.clone(),
                            interaction.interaction_types.clone(),
                        )
                    })
                    .collect(),
            );
        }
    }
    Ok(gene_drug_interactions)
}

fn collect_genes(vcf_path: &str) -> Result<HashSet<String>, Box<dyn Error>> {
    let mut total_genes = HashSet::new();
    let mut reader = bcf::Reader::from_path(vcf_path)?;
    for result in reader.records() {
        let mut rec = result?;
        let genes_opt = extract_genes(&mut rec)?;
        match genes_opt {
            Some(genes) => {
                for gene in genes {
                    total_genes.insert(gene);
                }
            }
            None => {}
        }
    }
    Ok(total_genes)
}

//TODO Remove split by ',' when updating to latest htslib release
fn extract_genes<'a>(
    rec: &'a mut bcf::Record,
) -> Result<Option<impl Iterator<Item = String> + 'a>, Box<dyn Error>> {
    let annotation = rec.info("ANN".as_bytes()).string()?;
    match annotation {
        Some(transcripts) => Ok(Some(transcripts[0].split(|c| *c == b',').map(
            |transcript| {
                str::from_utf8(transcript.split(|c| *c == b'|').nth(3).unwrap())
                    .unwrap()
                    .to_owned()
            },
        ))),
        None => Ok(None),
    }
}

fn modify_vcf_entries(
    vcf_path: &str,
    gene_drug_interactions: HashMap<String, Vec<(String, Vec<String>)>>,
    field_name: &str,
) -> Result<(), Box<dyn Error>> {
    let mut reader = bcf::Reader::from_path(vcf_path)?;
    let mut header = bcf::header::Header::from_template(reader.header());
    header.push_record(format!("##INFO=<ID={},Number=.,Type=String,Description=\"Combination of gene, drug, interaction types extracted from dgiDB. Each combination is pipe-seperated annotated as GENE|DRUG|TYPE\">", field_name).as_bytes());
    let mut writer = bcf::Writer::from_stdout(&header, true, true)?;

    for result in reader.records() {
        let mut rec = result?;
        writer.translate(&mut rec);
        let genes = extract_genes(&mut rec)?.map(|genes| genes.collect_vec());;
        if let Some(mut genes) = genes {
            genes.dedup();
            let field_entries = build_dgidb_field(&gene_drug_interactions, genes)?;
            let field_entries: Vec<&[u8]> = field_entries.iter().map(|v| v.as_slice()).collect();
            rec.push_info_string(field_name.as_bytes(), &field_entries[..])?;
        }
        writer.write(&rec)?;
    }
    Ok(())
}

fn build_dgidb_field(
    gene_drug_interactions: &HashMap<String, Vec<(String, Vec<String>)>>,
    genes: Vec<String>,
) -> Result<Vec<Vec<u8>>, Box<dyn Error>> {
    let mut field_entries: Vec<Vec<u8>> = Vec::new();
    let re = Regex::new(r"\s\(\w+\)").unwrap();
    for gene in genes.iter() {
        match gene_drug_interactions.get(gene) {
            Some(drug_interactions) => {
                drug_interactions
                    .iter()
                    .for_each(|(drug, interaction_types)| {
                        if !interaction_types.is_empty() {
                            interaction_types.iter().for_each(|interaction_type| {
                                field_entries.push(
                                    format!(
                                        "{g}|{d}|{t}",
                                        g = gene,
                                        d = re.replace(drug, ""),
                                        t = interaction_type
                                    )
                                    .as_bytes()
                                    .to_vec(),
                                )
                            })
                        } else {
                            field_entries.push(
                                format!("{g}|{d}|.", g = gene, d = re.replace(drug, ""))
                                    .as_bytes()
                                    .to_vec(),
                            )
                        }
                    });
            }
            None => field_entries.push(format!("{g}|.|.", g = gene).as_bytes().to_vec()),
        }
    }
    Ok(field_entries)
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros for kernel-level logging

#[macro_export]
macro_rules! attempt {
    ($task:expr => dots: $dots:expr, $msg:expr ) => ({
            use $crate::status::Status;
            print!("{}{}", $dots, $msg);
            match $task {
               Ok(result) => {
                    $crate::CONSOLE.lock().okay();
                    info!("{} [ OKAY ]", $msg);
                    result
                }
              , Err(why) => {
                    $crate::CONSOLE.lock().fail();
                    panic!("{:?}", why);
              }
        }
    });
    ($task:expr => dots: $dots:expr, $($msg:tt)* ) => {
        attempt!($task => dots: $dots, format_args!($($msg)*))
    };

}
#[macro_export]
macro_rules! kinfo {
    ( dots: $dots:expr, target: $target:expr, "[ OKAY ]") => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            print!("{:<38}{:>40}", concat!($dots, $target));
            {
                use $crate::status::Status;
                $crate::CONSOLE.lock().okay();
            }
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, target: $target:expr, "[ FAIL ]") => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            print!("{:<38}{:>40}", concat!($dots, $target));
            {
                use $crate::status::Status;
                $crate::CONSOLE.lock().fail();
            }
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            print!("{}{}", $dots, format_args!($($args)*));
            info!( ($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            print!( $($args)* );
            info!( $($args)* );
        // }
    };
}
#[macro_export]
macro_rules! kinfoln {
    ( dots: $dots:expr, target: $target:expr, $status:expr ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            println!("{:<39}{:>40}", concat!($dots, $target), $status );
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            println!("{}{}", $dots, format_args!($($args)*));
            info!( $($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            println!( $($args)* );
            info!( $($args)* );
        // }
    };
}
<commit_msg>refac(vga::kinfo): expect that we wrote to the VGA buf successfully<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros for kernel-level logging

#[macro_export]
macro_rules! attempt {
    ($task:expr => dots: $dots:expr, $msg:expr ) => ({
            use $crate::status::Status;
            print!("{}{}", $dots, $msg);
            match $task {
               Ok(result) => {
                    $crate::CONSOLE.lock()
                        .okay()
                        .expect("Could not write to VGA buffer! Something's \
                                 really wrong!");
                    info!("{} [ OKAY ]", $msg);
                    result
                }
              , Err(why) => {
                    $crate::CONSOLE.lock()
                        .fail()
                        .expect("Could not write to VGA buffer! Something's \
                                 really wrong!");
                    panic!("{:?}", why);
              }
        }
    });
    ($task:expr => dots: $dots:expr, $($msg:tt)* ) => {
        attempt!($task => dots: $dots, format_args!($($msg)*))
    };

}
#[macro_export]
macro_rules! kinfo {
    ( dots: $dots:expr, target: $target:expr, "[ OKAY ]") => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            print!("{:<38}{:>40}", concat!($dots, $target));
            {
                use $crate::status::Status;
                $crate::CONSOLE.lock().okay()
                    .expect("Could not write to VGA buffer! Something's \
                             really wrong!");
            }
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, target: $target:expr, "[ FAIL ]") => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            print!("{:<38}{:>40}", concat!($dots, $target));
            {
                use $crate::status::Status;
                $crate::CONSOLE.lock().fail()
                    .expect("Could not write to VGA buffer! Something's \
                             really wrong!");
            }
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            print!("{}{}", $dots, format_args!($($args)*));
            info!( ($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            print!( $($args)* );
            info!( $($args)* );
        // }
    };
}
#[macro_export]
macro_rules! kinfoln {
    ( dots: $dots:expr, target: $target:expr, $status:expr ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            println!("{:<39}{:>40}", concat!($dots, $target), $status );
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            println!("{}{}", $dots, format_args!($($args)*));
            info!( $($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            println!( $($args)* );
            info!( $($args)* );
        // }
    };
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
use proc_macro::TokenStream;

extern crate syn;
use syn::*;

#[macro_use]
extern crate quote;

#[derive(Debug)]
enum BitFieldPosition {
    Single(u8),
    Range(std::ops::Range<u8>)
}

#[derive(Debug)]
struct BitField {
    position: BitFieldPosition,
    ident: Ident,
    ty: Ty
}

fn output_struct(name: &Ident, bitfields: &Vec<BitField>) -> quote::Tokens {

    let ends: Vec<u8> = bitfields.iter().map(|x| match &x.position {
        &BitFieldPosition::Single(x) => x,
        &BitFieldPosition::Range(ref range) => range.end
    }).collect();

    let max_ends = ends.iter().max().unwrap();

    let base_size: usize = (*max_ends as usize / 8) + 1;

    let mut impl_body = quote! {};

    for bitfield in bitfields {
        println!("iter field {} @{:?}", bitfield.ident, bitfield.position);

        let getter_str = format!("get_{}", bitfield.ident.as_ref());
        let getter: Ident = From::from(getter_str.as_str());

        let setter_str = format!("set_{}", bitfield.ident.as_ref());
        let setter: Ident = From::from(setter_str.as_str());

        let ty = &bitfield.ty;

        match &bitfield.position {
            &BitFieldPosition::Single(x) => {
                let mask: u8 = 1 << (x % 8);
                let nmask: u8 = !mask;

                let byteidx: usize = x as usize / 8;

                let shift = x % 8;

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: [u8;1] = [(self.0[#byteidx] & #mask) >> #shift];
                        return bitfield_register::FromBitfield::from_bitfield(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: [u8;1] = bitfield_register::IntoBitfield::into_bitfield(value);
                        self.0[#byteidx] &= #nmask;
                        self.0[#byteidx] |= (raw[0] & 1) << #shift;
                    }
                }
            },
            &BitFieldPosition::Range(ref range) => {
                let from = range.start;
                let to = range.end;

                let value_size: usize = (to - from) as usize / 8 + 1;
                // let value_bit_size = to - from + 1;

                let from_byte: usize = from as usize / 8;
                let to_byte: usize = to as usize / 8;

                let raw_size = to_byte - from_byte + 1;

                println!("value_byte_size:{}", value_size);
                println!("from_byte:{}, to_byte:{}", from_byte, to_byte);
                println!("raw_size:{}", raw_size);

                // let type_mask: u8 = (1 << type_bit_size) - 1;
                // let mask: u8 = type_mask << (from % 8);
                // let nmask: u8 = !mask;

                let bit_shift = from % 8;
                let bit_end = to % 8;

                let mut setter_body = quote! {
                    let value_array: [u8;#value_size] = bitfield_register::IntoBitfield::into_bitfield(value);
                    let mut raw: u8;
                };

                for i in 0..raw_size {

                    if i < value_size {
                        if bit_shift == 0 {
                            setter_body = quote! { #setter_body
                                 raw = value_array[#i];
                            }
                        } else {
                            setter_body = quote! { #setter_body
                                raw = value_array[#i] << #bit_shift;
                            }
                        }
                    } else {
                        setter_body = quote! { #setter_body
                            raw = 0;
                        }
                    }

                    if i != 0 {
                        let i_1 = i - 1;
                        if bit_shift != 0 {
                            setter_body = quote! { #setter_body
                                raw |= value_array[#i_1] >> (8 - #bit_shift);
                            }
                        }
                    }

                    let mask: u8 = if bit_end == 7 || i != raw_size - 1 {0xff}
                    else {(1 << (bit_end + 1)) - 1};

                    let i_from_byte = i + from_byte;

                    if mask != 0xff {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] &= !#mask;
                            self.0[#i_from_byte] |= raw & #mask;
                        };
                    } else {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] = raw;
                        };
                    }
                }

                let mut getter_body = quote! {
                    let mut value_array: [u8;#value_size] = [0;#value_size];
                };

                for i in 0..value_size {

                    let i_from_byte = i + from_byte;

                    let mask: u8 = if bit_end == 7 || i != raw_size - 1 {0xff}
                    else {(1 << (bit_end + 1)) - 1};

                    getter_body = quote! { #getter_body
                        value_array[#i] = self.0[#i_from_byte] >> #bit_shift;
                    };

                    if i < raw_size - 1 {
                        let i_from_byte = i + from_byte + 1;
                        if bit_shift != 0 {
                            getter_body = quote! { #getter_body
                                value_array[#i] |= self.0[#i_from_byte] << (8 - #bit_shift);
                            }
                        }
                    }

                    if mask != 0xff {
                        getter_body = quote! { #getter_body
                            value_array[#i] &= #mask;
                        };
                    }
                }

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        #getter_body
                        return bitfield_register::FromBitfield::from_bitfield(value_array);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        #setter_body
                    }
                }
            },
        }
    };

    return quote! {
        pub struct #name ([u8;#base_size]);
        impl Default for #name {
            fn default() -> Self {
                return #name ([0;#base_size]);
            }
        }
        impl #name {

            #impl_body
        }
        impl Clone for #name {
            fn clone(&self) -> Self {
                return #name (self.0.clone());
            }
        }
    }
}

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    #[derive(Debug)]
    let mut bitfields: Vec<BitField> = vec![];

    for field in &fields {
        let ty = field.clone().ty;

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        match attr_nest_item.clone() {
                            NestedMetaItem::MetaItem(MetaItem::NameValue(nv_ident, Lit::Int(nv_value, _))) => {
                                match nv_ident.as_ref() {
                                    "at" => (at = Some(nv_value as u8)),
                                    "from" => (from = Some(nv_value as u8)),
                                    "to" => (to = Some(nv_value as u8)),
                                    _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let position: BitFieldPosition = if from.is_some() && to.is_some() {
            BitFieldPosition::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitFieldPosition::Single(at.unwrap())
        };

        let ident = field.ident.clone().unwrap();

        bitfields.push(BitField {position: position, ident: ident, ty: ty});
    }

    let name = &ast.ident;

    return output_struct(name, &bitfields).parse().unwrap();
}
<commit_msg>Refactor macro implementation<commit_after>#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
use proc_macro::TokenStream;

extern crate syn;
use syn::*;

#[macro_use]
extern crate quote;
use quote::Tokens;

#[derive(Debug)]
enum BitFieldPosition {
    Single(u8),
    Range(std::ops::Range<u8>)
}

impl BitFieldPosition {
    pub fn len(&self) -> usize {
        match self {
            &BitFieldPosition::Single(_) => 1,
            &BitFieldPosition::Range(ref range) => (range.end - range.start) as usize
        }
    }

    pub fn byte_len(&self) -> usize {
        let len = self.len();
        if len % 8 == 0 { len / 8 } else { len / 8 + 1 }
    }
}

#[derive(Debug)]
struct BitField {
    position: BitFieldPosition,
    ident: Ident,
    ty: Ty
}

fn filled_byte(from:u8, to:u8) -> u8 {
    let mut res = 0;
    for i in from..to {
        res |= 1 << i;
    }
    return res;
}

fn emit_read_single_byte(from:Tokens, from_bit:usize, to_bit:usize) -> Tokens {
    assert!(to_bit - from_bit <= 8);

    let bit_len = (to_bit - from_bit) as u8;
    let from_byte = (from_bit / 8) as usize;
    let from_bit_mask = (from_bit % 8) as u8;

    if from_bit % 8 == 0 {
        let mask = filled_byte(from_bit_mask, from_bit_mask + bit_len);
        return quote! { #from[#from_byte] & #mask };
    } else {
        let second_byte = ((to_bit - 1) / 8) as usize;
        if second_byte == from_byte {
            let mask = filled_byte(from_bit_mask, from_bit_mask + bit_len);
            let offset = from_bit % 8;

            println!("emit_read_single_byte {} & {} >> {}", from_byte, mask, offset);

            return quote! {
                (#from[#from_byte] & #mask) >> #offset
            };
        } else {
            let first_byte_mask = filled_byte(from_bit_mask, 8);
            let first_byte_offset = from_bit % 8;

            let second_byte_mask = filled_byte(0, from_bit_mask);
            let second_byte_offset = 8 - first_byte_offset;

            println!("emit_read_single_byte {} & {} >> {} | {} & {} << {}", from_byte, first_byte_mask, first_byte_offset, second_byte, second_byte_mask, second_byte_offset);

            return quote! {
                ((#from[#from_byte] & #first_byte_mask) >> #first_byte_offset)
                | ((#from[#second_byte] & #second_byte_mask) << #second_byte_offset)
            };
        }
    }
}

fn output_struct(name: &Ident, bitfields: &Vec<BitField>) -> quote::Tokens {

    let ends: Vec<u8> = bitfields.iter().map(|x| match &x.position {
        &BitFieldPosition::Single(x) => x,
        &BitFieldPosition::Range(ref range) => range.end
    }).collect();

    let max_ends = ends.iter().max().unwrap();

    let base_size: usize = (*max_ends as usize / 8) + 1;

    let mut impl_body = quote! {};

    for bitfield in bitfields {
        println!("iter field {} @{:?}", bitfield.ident, bitfield.position);

        let getter_str = format!("get_{}", bitfield.ident.as_ref());
        let getter: Ident = From::from(getter_str.as_str());

        let setter_str = format!("set_{}", bitfield.ident.as_ref());
        let setter: Ident = From::from(setter_str.as_str());

        let ty = &bitfield.ty;

        match &bitfield.position {
            &BitFieldPosition::Single(x) => {
                let mask: u8 = 1 << (x % 8);
                let nmask: u8 = !mask;

                let byteidx: usize = x as usize / 8;

                let shift = x % 8;

                let getter_body = emit_read_single_byte(quote! { self.0 }, x as usize, (x+1) as usize);

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: [u8;1] = [#getter_body];
                        return bitfield_register::FromBitfield::from_bitfield(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: [u8;1] = bitfield_register::IntoBitfield::into_bitfield(value);
                        self.0[#byteidx] &= #nmask;
                        self.0[#byteidx] |= (raw[0] & 1) << #shift;
                    }
                }
            },
            &BitFieldPosition::Range(ref range) => {
                let from = range.start;
                let to = range.end;

                let value_byte_len = bitfield.position.byte_len();

                let from_byte: usize = from as usize / 8;
                let to_byte: usize = to as usize / 8;

                let raw_size = to_byte - from_byte + 1;

                println!("value_byte_len:{}", value_byte_len);
                println!("from_byte:{}, to_byte:{}", from_byte, to_byte);
                println!("raw_size:{}", raw_size);

                // let type_mask: u8 = (1 << type_bit_size) - 1;
                // let mask: u8 = type_mask << (from % 8);
                // let nmask: u8 = !mask;

                let bit_shift = from % 8;
                let bit_end = to % 8;

                let mut setter_body = quote! {
                    let value_array: [u8;#value_byte_len] = bitfield_register::IntoBitfield::into_bitfield(value);
                    let mut raw: u8;
                };

                for i in 0..raw_size {

                    if i < value_byte_len {
                        if bit_shift == 0 {
                            setter_body = quote! { #setter_body
                                 raw = value_array[#i];
                            }
                        } else {
                            setter_body = quote! { #setter_body
                                raw = value_array[#i] << #bit_shift;
                            }
                        }
                    } else {
                        setter_body = quote! { #setter_body
                            raw = 0;
                        }
                    }

                    if i != 0 {
                        let i_1 = i - 1;
                        if bit_shift != 0 {
                            setter_body = quote! { #setter_body
                                raw |= value_array[#i_1] >> (8 - #bit_shift);
                            }
                        }
                    }

                    let mask: u8 = if bit_end == 7 || i != raw_size - 1 {0xff}
                    else {(1 << (bit_end + 1)) - 1};

                    let i_from_byte = i + from_byte;

                    if mask != 0xff {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] &= !#mask;
                            self.0[#i_from_byte] |= raw & #mask;
                        };
                    } else {
                        setter_body = quote! { #setter_body
                            self.0[#i_from_byte] = raw;
                        };
                    }
                }

                let mut getter_body = quote! {
                    let mut value_array: [u8;#value_byte_len] = [0;#value_byte_len];
                };

                for i in 0..value_byte_len {
                    let from_bit_i = from + 8 * i as u8;
                    let to_bit_i = u8::min(from_bit_i + 8, to + 1);
                    let read_byte = emit_read_single_byte(quote! { self.0 }, from_bit_i as usize, to_bit_i as usize);
                    getter_body = quote! { #getter_body
                        value_array[#i] = #read_byte;
                    };
                }

                println!("getter body {}", getter_body);

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        #getter_body
                        return bitfield_register::FromBitfield::from_bitfield(value_array);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        #setter_body
                    }
                }
            },
        }
    };

    return quote! {
        pub struct #name ([u8;#base_size]);
        impl Default for #name {
            fn default() -> Self {
                return #name ([0;#base_size]);
            }
        }
        impl #name {

            #impl_body
        }
        impl Clone for #name {
            fn clone(&self) -> Self {
                return #name (self.0.clone());
            }
        }
    }
}

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    println!("{}", s);

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    #[derive(Debug)]
    let mut bitfields: Vec<BitField> = vec![];

    for field in &fields {
        let ty = field.clone().ty;

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        match attr_nest_item.clone() {
                            NestedMetaItem::MetaItem(MetaItem::NameValue(nv_ident, Lit::Int(nv_value, _))) => {
                                match nv_ident.as_ref() {
                                    "at" => (at = Some(nv_value as u8)),
                                    "from" => (from = Some(nv_value as u8)),
                                    "to" => (to = Some(nv_value as u8)),
                                    _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let position: BitFieldPosition = if from.is_some() && to.is_some() {
            BitFieldPosition::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitFieldPosition::Single(at.unwrap())
        };

        let ident = field.ident.clone().unwrap();

        bitfields.push(BitField {position: position, ident: ident, ty: ty});
    }

    let name = &ast.ident;

    return output_struct(name, &bitfields).parse().unwrap();
}

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

    #[test]
    fn position_test() {
        let pos = BitFieldPosition::Single(0);

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Single(1);

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Single(7);

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Single(8);

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Single(9);

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Single(15);

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Range((0..1));

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Range((0..5));

        assert_eq!(pos.len(), 5);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Range((0..8));

        assert_eq!(pos.len(), 8);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Range((0..9));

        assert_eq!(pos.len(), 9);
        assert_eq!(pos.byte_len(), 2);

        let pos = BitFieldPosition::Range((0..10));

        assert_eq!(pos.len(), 10);
        assert_eq!(pos.byte_len(), 2);

        let pos = BitFieldPosition::Range((0..15));

        assert_eq!(pos.len(), 15);
        assert_eq!(pos.byte_len(), 2);

        let pos = BitFieldPosition::Range((1..2));

        assert_eq!(pos.len(), 1);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Range((1..8));

        assert_eq!(pos.len(), 7);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Range((1..9));

        assert_eq!(pos.len(), 8);
        assert_eq!(pos.byte_len(), 1);

        let pos = BitFieldPosition::Range((1..10));

        assert_eq!(pos.len(), 9);
        assert_eq!(pos.byte_len(), 2);
    }

    #[test]
    fn emit_read_single_byte_test() {
        let from = quote!{arr};
        let res = emit_read_single_byte(from.clone(), 0, 8);
        assert_eq!(res, quote!{ #from[0usize] & 255u8 });

        let left_mask : u8 = 0b10000000;
        let from = quote!{arr};
        let res = emit_read_single_byte(from.clone(), 7, 8);
        assert_eq!(res, quote!{ (#from[0usize] & #left_mask) >> 7usize });

        let left_mask : u8 = 0b00011100;
        let from = quote!{arr};
        let res = emit_read_single_byte(from.clone(), 2, 5);
        assert_eq!(res, quote!{ (#from[0usize] & #left_mask) >> 2usize });

        let left_mask : u8 = 0b11111110;
        let right_mask : u8 = 0b00000001;
        let from = quote!{arr};
        let res = emit_read_single_byte(from.clone(), 9, 17);
        assert_eq!(res, quote!{ ((#from[1usize] & #left_mask) >> 1usize) | ((#from[2usize] & #right_mask) << 7usize) });
    }

    #[test]
    fn filled_byte_test() {
        assert_eq!(filled_byte(0,0), 0);
        assert_eq!(filled_byte(0,1), 0b1);
        assert_eq!(filled_byte(0,2), 0b11);

        assert_eq!(filled_byte(1,2), 0b10);
        assert_eq!(filled_byte(1,3), 0b110);

        assert_eq!(filled_byte(6,8), 0b11000000);
        assert_eq!(filled_byte(7,8), 0b10000000);

        assert_eq!(filled_byte(8,8), 0);
    }
}<|endoftext|>


<commit_before>/*
    TODO:
    1. Copy downloaded files to other places. (Completed)
    2. Verify the downloaded package.
    3. Make it support repos someday.
*/
crate hyper;
use self::hyper::client;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package downloading.", why),
    });
}

pub fn download_package(url: &str, output: &Path) {
    let client = Client::new();
    let response = custom_try!(client.get(url).send());
    let mut target = custom_try!(File::create(output));

    for byte in response.bytes() {
        target.write(&[byte.unwrap()]);
    }
}<commit_msg>Renamed function to match its actual usage<commit_after>/*
    TODO:
    1. Copy downloaded files to other places. (Completed)
    2. Verify the downloaded package.
    3. Make it support repos someday.
*/
crate hyper;
use self::hyper::client;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package downloading.", why),
    });
}

pub fn download_file(url: &str, output: &Path) {
    let client = Client::new();
    let response = custom_try!(client.get(url).send());
    let mut target = custom_try!(File::create(output));

    for byte in response.bytes() {
        target.write(&[byte.unwrap()]);
    }
}<|endoftext|>


<commit_before>use cargo_helper::CargoInfo;
use Bytes;
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar, Units};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;
use std::time::{Instant, Duration};
use write::{OutputFileWriter, OutputChunkWriter};

/// Constant to represent the length of the buffer to download
/// the remote content
const DOWNLOAD_BUFFER_BYTES: usize = 1024 * 64;

/// Constant to represent the refresh interval (in milliseconds)
/// for the CLI
const PROGRESS_UPDATE_INTERVAL_MILLIS: u64 = 500;

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

macro_rules! initbar {
    ($mp:ident,$mpb:ident,$length:expr,$index:expr) => {
        let mut $mp = $mpb.create_bar($length);
        $mp.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
        $mp.format("|#--|");
        $mp.show_tick = true;
        $mp.show_speed = true;
        $mp.show_percent = true;
        $mp.show_counter = false;
        $mp.show_time_left = true;
        $mp.set_units(Units::Bytes);
        $mp.message(&format!("Chunk {} ", $index));
    }
}

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, RangeBytes)> {

    get_chunk_length(chunk_index, content_length, global_chunk_length).map(|range| {
        let mut header = Headers::new();
        header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
        (header, RangeBytes(range.0, range.1 - range.0))
    })
}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    mut chunk_writer: OutputChunkWriter,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    let mut body = http_client.get_http_response_using_headers(url, http_header).unwrap();
    if !body.check_partialcontent_status() {
        return Err(Error::Status);
    }
    let mut bytes_buffer = [0; DOWNLOAD_BUFFER_BYTES];
    let mut sum_bytes = 0;

    let progress_update_interval = Duration::from_millis(PROGRESS_UPDATE_INTERVAL_MILLIS);
    let mut last_progress_bytes = 0;
    let mut last_progress_time = Instant::now() - progress_update_interval;

    while let Ok(n) = body.read(&mut bytes_buffer) {
        if n == 0 {
            return Ok(sum_bytes);
        }

        chunk_writer.write(sum_bytes, &bytes_buffer[0..n]);

        sum_bytes += n as u64;

        // Update the CLI
        if Instant::now().duration_since(last_progress_time) > progress_update_interval {
            last_progress_time = Instant::now();
            let progress_bytes_delta = sum_bytes - last_progress_bytes;
            last_progress_bytes = sum_bytes;
            mpb.add(progress_bytes_delta);
        }
    }
    mpb.add(sum_bytes - last_progress_bytes);
    return Ok(0u64);
}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server,
/// * a custom authorization to access and download the remote content.
pub fn download_chunks(cargo_info: CargoInfo,
                       mut out_file: OutputFileWriter,
                       nb_chunks: u64,
                       url: &str) {
    let (content_length, auth_header_factory) = (cargo_info.content_length, cargo_info.auth_header);

    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (mut http_header, RangeBytes(chunk_offset, chunk_length)) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        if let Some(auth_header_factory) = auth_header_factory.clone() {
            http_header.set(auth_header_factory.build_header());
        }

        // Initialize the progress bar for that chunk
        initbar!(mp, mpb, chunk_length, chunk_index);

        let chunk_writer = out_file.get_chunk_writer(chunk_offset);
        jobs.push(thread::spawn(move || match download_a_chunk(&hyper_client,
                                                       http_header,
                                                       chunk_writer,
                                                       &url_clone,
                                                       &mut mp) {
                                    Ok(bytes_written) => {
            mp.finish();
            if bytes_written == 0 {
                panic!("The downloaded chunk {} is empty", chunk_index);
            }
        }
                                    Err(error) => {
            mp.finish();
            panic!("Cannot download the chunk {}, due to error {}",
                   chunk_index,
                   error);
        }
                                }));
    }

    mpb.listen();

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::{get_header_from_index, RangeBytes};
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, RangeBytes(750, 247))),
                   get_header_from_index(3, 998, 250));
    }

}
<commit_msg>Change function definition to return a boolean - the boolean value is an indicator to know if the download is OK or not<commit_after>use cargo_helper::CargoInfo;
use Bytes;
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar, Units};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;
use std::time::{Instant, Duration};
use write::{OutputFileWriter, OutputChunkWriter};

/// Constant to represent the length of the buffer to download
/// the remote content
const DOWNLOAD_BUFFER_BYTES: usize = 1024 * 64;

/// Constant to represent the refresh interval (in milliseconds)
/// for the CLI
const PROGRESS_UPDATE_INTERVAL_MILLIS: u64 = 500;

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

macro_rules! initbar {
    ($mp:ident,$mpb:ident,$length:expr,$index:expr) => {
        let mut $mp = $mpb.create_bar($length);
        $mp.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
        $mp.format("|#--|");
        $mp.show_tick = true;
        $mp.show_speed = true;
        $mp.show_percent = true;
        $mp.show_counter = false;
        $mp.show_time_left = true;
        $mp.set_units(Units::Bytes);
        $mp.message(&format!("Chunk {} ", $index));
    }
}

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, RangeBytes)> {

    get_chunk_length(chunk_index, content_length, global_chunk_length).map(|range| {
        let mut header = Headers::new();
        header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
        (header, RangeBytes(range.0, range.1 - range.0))
    })
}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    mut chunk_writer: OutputChunkWriter,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    let mut body = http_client.get_http_response_using_headers(url, http_header).unwrap();
    if !body.check_partialcontent_status() {
        return Err(Error::Status);
    }
    let mut bytes_buffer = [0; DOWNLOAD_BUFFER_BYTES];
    let mut sum_bytes = 0;

    let progress_update_interval = Duration::from_millis(PROGRESS_UPDATE_INTERVAL_MILLIS);
    let mut last_progress_bytes = 0;
    let mut last_progress_time = Instant::now() - progress_update_interval;

    while let Ok(n) = body.read(&mut bytes_buffer) {
        if n == 0 {
            return Ok(sum_bytes);
        }

        chunk_writer.write(sum_bytes, &bytes_buffer[0..n]);

        sum_bytes += n as u64;

        // Update the CLI
        if Instant::now().duration_since(last_progress_time) > progress_update_interval {
            last_progress_time = Instant::now();
            let progress_bytes_delta = sum_bytes - last_progress_bytes;
            last_progress_bytes = sum_bytes;
            mpb.add(progress_bytes_delta);
        }
    }
    mpb.add(sum_bytes - last_progress_bytes);
    return Ok(0u64);
}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server,
/// * a custom authorization to access and download the remote content.
pub fn download_chunks(cargo_info: CargoInfo,
                       mut out_file: OutputFileWriter,
                       nb_chunks: u64,
                       url: &str)
                       -> bool {
    let (content_length, auth_header_factory) = (cargo_info.content_length, cargo_info.auth_header);

    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (mut http_header, RangeBytes(chunk_offset, chunk_length)) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        if let Some(auth_header_factory) = auth_header_factory.clone() {
            http_header.set(auth_header_factory.build_header());
        }

        // Initialize the progress bar for that chunk
        initbar!(mp, mpb, chunk_length, chunk_index);

        let chunk_writer = out_file.get_chunk_writer(chunk_offset);

        // In this work, we push a boolean value to know if the chunk is OK
        jobs.push(thread::spawn(move ||
            match download_a_chunk(&hyper_client, http_header, chunk_writer, &url_clone, &mut mp) {
                Ok(bytes_written) => {
                    mp.finish();
                    if bytes_written == 0 {
                        println!("The downloaded chunk {} is empty", chunk_index);
                    }
                    return true;
                }
                Err(error) => {
                    mp.finish();
                    println!("Cannot download the chunk {}, due to error {}", chunk_index, error);
                    return false;
                }
            }
        ));
    }

    mpb.listen();

    // Contain the result state for chunks
    let mut child_results : Vec<bool> = Vec::with_capacity(nb_chunks as usize);

    for child in jobs {
        match child.join() {
            Ok(b) => child_results.push(b),
            Err(_) => child_results.push(false),
        }
    }

    // Check if all chunks are ok
    return child_results.iter().all(|x| *x)
}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::{get_header_from_index, RangeBytes};
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, RangeBytes(750, 247))),
                   get_header_from_index(3, 998, 250));
    }

}
<|endoftext|>


<commit_before>use crate::bytes_deque::buf_vec_deque::BufVecDeque;
use crate::solicit::frame::FrameHeaderBuffer;
use bytes::Buf;
use bytes::Bytes;
use std::io::Cursor;
use std::io::IoSlice;
use std::mem;

enum Item {
    Vec(Cursor<Vec<u8>>),
    Bytes(Bytes),
    FrameHeaderBuffer(Cursor<FrameHeaderBuffer>),
}

impl Buf for Item {
    fn remaining(&self) -> usize {
        match self {
            Item::Vec(v) => v.remaining(),
            Item::Bytes(b) => b.remaining(),
            Item::FrameHeaderBuffer(c) => c.remaining(),
        }
    }

    fn bytes(&self) -> &[u8] {
        match self {
            Item::Vec(v) => v.bytes(),
            Item::Bytes(b) => b.bytes(),
            Item::FrameHeaderBuffer(c) => c.bytes(),
        }
    }

    fn advance(&mut self, cnt: usize) {
        match self {
            Item::Vec(v) => v.advance(cnt),
            Item::Bytes(b) => b.advance(cnt),
            Item::FrameHeaderBuffer(v) => v.advance(cnt),
        }
    }
}

#[derive(Default)]
pub struct WriteBuffer {
    deque: BufVecDeque<Item>,
}

impl Buf for WriteBuffer {
    /// Size of data in the buffer
    fn remaining(&self) -> usize {
        self.deque.remaining()
    }

    fn bytes(&self) -> &[u8] {
        self.deque.bytes()
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        self.deque.bytes_vectored(dst)
    }

    fn advance(&mut self, cnt: usize) {
        self.deque.advance(cnt)
    }
}

impl WriteBuffer {
    pub fn new() -> WriteBuffer {
        Default::default()
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        self.tail_vec().extend_from_slice(data);
    }

    pub fn extend_from_bytes(&mut self, data: Bytes) {
        if data.is_empty() {
            return;
        }
        self.deque.push_back(Item::Bytes(data));
    }

    pub fn extend_frame_header_buffer(&mut self, buffer: FrameHeaderBuffer) {
        self.deque
            .push_back(Item::FrameHeaderBuffer(Cursor::new(buffer)));
    }

    pub fn tail_vec(&mut self) -> WriteBufferTailVec {
        match self.deque.pop_back() {
            Some(Item::Vec(cursor)) => WriteBufferTailVec {
                write_buffer: self,
                position: cursor.position() as usize,
                data: cursor.into_inner(),
            },
            o => {
                if let Some(v) = o {
                    self.deque.push_back(v);
                }
                WriteBufferTailVec {
                    write_buffer: self,
                    data: Vec::new(),
                    position: 0,
                }
            }
        }
    }
}

impl Into<Vec<u8>> for WriteBuffer {
    fn into(mut self) -> Vec<u8> {
        let mut v = Vec::with_capacity(self.remaining());
        while self.has_remaining() {
            let bytes = self.bytes();
            v.extend_from_slice(bytes);
            self.advance(bytes.len());
        }
        v
    }
}

impl Into<Bytes> for WriteBuffer {
    fn into(self) -> Bytes {
        Bytes::from(Into::<Vec<u8>>::into(self))
    }
}

pub struct WriteBufferTailVec<'a> {
    write_buffer: &'a mut WriteBuffer,
    data: Vec<u8>,
    position: usize,
}

impl<'a> Drop for WriteBufferTailVec<'a> {
    fn drop(&mut self) {
        let mut cursor = Cursor::new(mem::take(&mut self.data));
        cursor.set_position(self.position as u64);
        self.write_buffer.deque.push_back(Item::Vec(cursor))
    }
}

impl<'a> WriteBufferTailVec<'a> {
    /// Size of data in the buffer
    pub fn remaining(&self) -> usize {
        debug_assert!(self.position <= self.data.len());
        self.data.len() - self.position
    }

    /// Pos is relative to "data"
    pub fn patch_buf(&mut self, pos: usize, data: &[u8]) {
        let patch_pos = self.position + pos;
        (&mut self.data[patch_pos..patch_pos + data.len()]).copy_from_slice(data);
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    pub fn compact(&mut self) {
        self.data.drain(..self.position);
        self.position = 0;
    }
}

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

    #[test]
    fn remaining() {
        let mut buf = WriteBuffer::new();
        buf.extend_from_slice(b"abcd");
        assert_eq!(4, buf.remaining());

        assert_eq!(b'a', buf.get_u8());
        assert_eq!(b'b', buf.get_u8());
        assert_eq!(2, buf.remaining());

        buf.extend_from_slice(b"ef");
        assert_eq!(b'c', buf.get_u8());
        assert_eq!(b'd', buf.get_u8());
        assert_eq!(b'e', buf.get_u8());
        assert_eq!(b'f', buf.get_u8());
        assert_eq!(0, buf.remaining());
    }
}
<commit_msg>Specialize bytes_vectored for WriteBuffer Item<commit_after>use crate::bytes_deque::buf_vec_deque::BufVecDeque;
use crate::solicit::frame::FrameHeaderBuffer;
use bytes::Buf;
use bytes::Bytes;
use std::io::Cursor;
use std::io::IoSlice;
use std::mem;

enum Item {
    Vec(Cursor<Vec<u8>>),
    Bytes(Bytes),
    FrameHeaderBuffer(Cursor<FrameHeaderBuffer>),
}

impl Buf for Item {
    fn remaining(&self) -> usize {
        match self {
            Item::Vec(v) => v.remaining(),
            Item::Bytes(b) => b.remaining(),
            Item::FrameHeaderBuffer(c) => c.remaining(),
        }
    }

    fn bytes(&self) -> &[u8] {
        match self {
            Item::Vec(v) => v.bytes(),
            Item::Bytes(b) => b.bytes(),
            Item::FrameHeaderBuffer(c) => c.bytes(),
        }
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        match self {
            Item::Vec(v) => v.bytes_vectored(dst),
            Item::Bytes(b) => b.bytes_vectored(dst),
            Item::FrameHeaderBuffer(c) => c.bytes_vectored(dst),
        }
    }

    fn advance(&mut self, cnt: usize) {
        match self {
            Item::Vec(v) => v.advance(cnt),
            Item::Bytes(b) => b.advance(cnt),
            Item::FrameHeaderBuffer(v) => v.advance(cnt),
        }
    }
}

#[derive(Default)]
pub struct WriteBuffer {
    deque: BufVecDeque<Item>,
}

impl Buf for WriteBuffer {
    /// Size of data in the buffer
    fn remaining(&self) -> usize {
        self.deque.remaining()
    }

    fn bytes(&self) -> &[u8] {
        self.deque.bytes()
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        self.deque.bytes_vectored(dst)
    }

    fn advance(&mut self, cnt: usize) {
        self.deque.advance(cnt)
    }
}

impl WriteBuffer {
    pub fn new() -> WriteBuffer {
        Default::default()
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        self.tail_vec().extend_from_slice(data);
    }

    pub fn extend_from_bytes(&mut self, data: Bytes) {
        if data.is_empty() {
            return;
        }
        self.deque.push_back(Item::Bytes(data));
    }

    pub fn extend_frame_header_buffer(&mut self, buffer: FrameHeaderBuffer) {
        self.deque
            .push_back(Item::FrameHeaderBuffer(Cursor::new(buffer)));
    }

    pub fn tail_vec(&mut self) -> WriteBufferTailVec {
        match self.deque.pop_back() {
            Some(Item::Vec(cursor)) => WriteBufferTailVec {
                write_buffer: self,
                position: cursor.position() as usize,
                data: cursor.into_inner(),
            },
            o => {
                if let Some(v) = o {
                    self.deque.push_back(v);
                }
                WriteBufferTailVec {
                    write_buffer: self,
                    data: Vec::new(),
                    position: 0,
                }
            }
        }
    }
}

impl Into<Vec<u8>> for WriteBuffer {
    fn into(mut self) -> Vec<u8> {
        let mut v = Vec::with_capacity(self.remaining());
        while self.has_remaining() {
            let bytes = self.bytes();
            v.extend_from_slice(bytes);
            self.advance(bytes.len());
        }
        v
    }
}

impl Into<Bytes> for WriteBuffer {
    fn into(self) -> Bytes {
        Bytes::from(Into::<Vec<u8>>::into(self))
    }
}

pub struct WriteBufferTailVec<'a> {
    write_buffer: &'a mut WriteBuffer,
    data: Vec<u8>,
    position: usize,
}

impl<'a> Drop for WriteBufferTailVec<'a> {
    fn drop(&mut self) {
        let mut cursor = Cursor::new(mem::take(&mut self.data));
        cursor.set_position(self.position as u64);
        self.write_buffer.deque.push_back(Item::Vec(cursor))
    }
}

impl<'a> WriteBufferTailVec<'a> {
    /// Size of data in the buffer
    pub fn remaining(&self) -> usize {
        debug_assert!(self.position <= self.data.len());
        self.data.len() - self.position
    }

    /// Pos is relative to "data"
    pub fn patch_buf(&mut self, pos: usize, data: &[u8]) {
        let patch_pos = self.position + pos;
        (&mut self.data[patch_pos..patch_pos + data.len()]).copy_from_slice(data);
    }

    pub fn extend_from_slice(&mut self, data: &[u8]) {
        // Could do something smarter
        self.reserve(data.len());
        self.data.extend_from_slice(data);
    }

    pub fn reserve(&mut self, additional: usize) {
        if self.remaining() >= additional {
            return;
        }
        self.compact();
        self.data.reserve(additional);
    }

    pub fn compact(&mut self) {
        self.data.drain(..self.position);
        self.position = 0;
    }
}

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

    #[test]
    fn remaining() {
        let mut buf = WriteBuffer::new();
        buf.extend_from_slice(b"abcd");
        assert_eq!(4, buf.remaining());

        assert_eq!(b'a', buf.get_u8());
        assert_eq!(b'b', buf.get_u8());
        assert_eq!(2, buf.remaining());

        buf.extend_from_slice(b"ef");
        assert_eq!(b'c', buf.get_u8());
        assert_eq!(b'd', buf.get_u8());
        assert_eq!(b'e', buf.get_u8());
        assert_eq!(b'f', buf.get_u8());
        assert_eq!(0, buf.remaining());
    }
}
<|endoftext|>


<commit_before>extern crate orbital;

extern crate system;

use orbital::Color;

use std::fs::File;
use std::io::{Read, Write};
use std::ops::Deref;
use std::sync::Arc;
use std::thread;

use system::error::Error;
use system::syscall::*;

use window::ConsoleWindow;

mod window;

macro_rules! readln {
    () => ({
        let mut buffer = String::new();
        match std::io::stdin().read_line(&mut buffer) {
            Ok(_) => Some(buffer),
            Err(_) => None
        }
    });
}

pub fn pipe() -> [usize; 2] {
    let mut fds = [0; 2];
    Error::demux(unsafe { sys_pipe2(fds.as_mut_ptr(), 0) }).unwrap();
    fds
}

fn main() {
    let to_shell_fds = pipe();
    let from_shell_fds = pipe();

    unsafe {
        if Error::demux(sys_clone(0)).unwrap() == 0 {
            // Close STDIO
            sys_close(2);
            sys_close(1);
            sys_close(0);

            // Create piped STDIO
            sys_dup(to_shell_fds[0]);
            sys_dup(from_shell_fds[1]);
            sys_dup(from_shell_fds[1]);

            // Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(to_shell_fds[1]);
            sys_close(from_shell_fds[0]);
            sys_close(from_shell_fds[1]);

            // Execute the shell
            let shell = "file:/apps/shell/main.bin\0";
            sys_execve(shell.as_ptr(), 0 as *const *const u8);
            panic!("Shell not found");
        } else {
            // Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(from_shell_fds[1]);
        }
    };

    let window = Arc::new(ConsoleWindow::new(0, 0, 576, 400, "Terminal"));

    let window_weak = Arc::downgrade(&window);
    thread::spawn(move || {
        let mut from_shell = unsafe { File::from_fd(from_shell_fds[0]).unwrap() };
        loop {
            let mut output = String::new();
            if let Ok(_) = from_shell.read_to_string(&mut output) {
                if let Some(window) = window_weak.upgrade() {
                    let window_ptr =
                        (window.deref() as *const Box<ConsoleWindow>) as *mut Box<ConsoleWindow>;
                    unsafe { &mut *window_ptr }.print(&output, Color::rgb(255, 255, 255));
                    unsafe { &mut *window_ptr }.sync();
                } else {
                    break;
                }
            } else {
                break;
            }
        }
    });

    {
        let mut to_shell = unsafe { File::from_fd(to_shell_fds[1]).unwrap() };
        let window_ptr = (window.deref() as *const Box<ConsoleWindow>) as *mut Box<ConsoleWindow>;
        while let Some(mut string) = unsafe { &mut *window_ptr }.read() {
            string.push('\n');
            if let Ok(_) = to_shell.write(&string.into_bytes()) {

            } else {
                break;
            }
        }
    }
}
<commit_msg>Fix terminal path<commit_after>extern crate orbital;

extern crate system;

use orbital::Color;

use std::fs::File;
use std::io::{Read, Write};
use std::ops::Deref;
use std::sync::Arc;
use std::thread;

use system::error::Error;
use system::syscall::*;

use window::ConsoleWindow;

mod window;

macro_rules! readln {
    () => ({
        let mut buffer = String::new();
        match std::io::stdin().read_line(&mut buffer) {
            Ok(_) => Some(buffer),
            Err(_) => None
        }
    });
}

pub fn pipe() -> [usize; 2] {
    let mut fds = [0; 2];
    Error::demux(unsafe { sys_pipe2(fds.as_mut_ptr(), 0) }).unwrap();
    fds
}

fn main() {
    let to_shell_fds = pipe();
    let from_shell_fds = pipe();

    unsafe {
        if Error::demux(sys_clone(0)).unwrap() == 0 {
            // Close STDIO
            sys_close(2);
            sys_close(1);
            sys_close(0);

            // Create piped STDIO
            sys_dup(to_shell_fds[0]);
            sys_dup(from_shell_fds[1]);
            sys_dup(from_shell_fds[1]);

            // Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(to_shell_fds[1]);
            sys_close(from_shell_fds[0]);
            sys_close(from_shell_fds[1]);

            // Execute the shell
            let shell = "ion\0";
            sys_execve(shell.as_ptr(), 0 as *const *const u8);
            panic!("Shell not found");
        } else {
            // Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(from_shell_fds[1]);
        }
    };

    let window = Arc::new(ConsoleWindow::new(0, 0, 576, 400, "Terminal"));

    let window_weak = Arc::downgrade(&window);
    thread::spawn(move || {
        let mut from_shell = unsafe { File::from_fd(from_shell_fds[0]).unwrap() };
        loop {
            let mut output = String::new();
            if let Ok(_) = from_shell.read_to_string(&mut output) {
                if let Some(window) = window_weak.upgrade() {
                    let window_ptr =
                        (window.deref() as *const Box<ConsoleWindow>) as *mut Box<ConsoleWindow>;
                    unsafe { &mut *window_ptr }.print(&output, Color::rgb(255, 255, 255));
                    unsafe { &mut *window_ptr }.sync();
                } else {
                    break;
                }
            } else {
                break;
            }
        }
    });

    {
        let mut to_shell = unsafe { File::from_fd(to_shell_fds[1]).unwrap() };
        let window_ptr = (window.deref() as *const Box<ConsoleWindow>) as *mut Box<ConsoleWindow>;
        while let Some(mut string) = unsafe { &mut *window_ptr }.read() {
            string.push('\n');
            if let Ok(_) = to_shell.write(&string.into_bytes()) {

            } else {
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Representations of C types and arrays thereof.

use std::{mem, ptr};
use libc;

use c;
use low;

type FfiType_      = *mut low::ffi_type;
type FfiTypeArray_ = *mut FfiType_;
type Owned<T>      = T;

#[derive(Debug)]
pub struct FfiType(FfiType_);

#[derive(Debug)]
pub struct FfiTypeArray(FfiTypeArray_);

/// Computes the length of a raw `FfiTypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: FfiTypeArray_) -> usize {
    let mut current = array;
    let mut count   = 0;
    while !(*current).is_null() {
        count += 1;
    }
    count
}

/// Creates an empty `FfiTypeArray_` with null terminator.
unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<FfiTypeArray_> {
    let array = libc::malloc((len + 1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;
    *array.offset(len as isize) = ptr::null::<low::ffi_type>() as FfiType_;
    array
}

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>)
    -> Owned<FfiTypeArray_>
{
    let size = elements.len();
    let new  = ffi_type_array_create_empty(size);
    for i in 0 .. size {
        *new.offset(i as isize) = elements[i].0;
    }

    for t in elements {
        mem::forget(t);
    }

    println!("ffi_type_array_create(...) = {:?}", new);

    new
}

/// Creates a struct type from a raw array of element types.
unsafe fn ffi_type_struct_create_raw(elements: FfiTypeArray_)
    -> Owned<FfiType_>
{
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as FfiType_;

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = c::ffi_type_enum::STRUCT as ::libc::c_ushort;
    (*new).elements  = elements;

    println!("ffi_type_struct_create_raw({:?}) = {:?}", elements, new);

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> Owned<FfiType_> {
    println!("ffi_type_array_create({:?})", elements);
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

/// Makes a copy of a type array.
unsafe fn ffi_type_array_clone(old: FfiTypeArray_) -> Owned<FfiTypeArray_> {
    let size = ffi_type_array_len(old);
    let new  = ffi_type_array_create_empty(size);

    for i in 0 .. size {
        *new.offset(i as isize) = ffi_type_clone(*old.offset(i as isize));
    }

    new
}

/// Makes a copy of a type.
unsafe fn ffi_type_clone(old: FfiType_) -> Owned<FfiType_> {
    if (*old).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys an array of FfiType_ and all of its elements.
unsafe fn ffi_type_array_destroy(victim: Owned<FfiTypeArray_>) {
    println!("ffi_type_array_destroy({:?})", victim);
    let mut current = victim;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(victim as *mut libc::c_void);
}

/// Destroys an FfiType_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(victim: Owned<FfiType_>) {
    println!("ffi_type_destroy({:?})", victim);
    if (*victim).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_array_destroy((*victim).elements);
        libc::free(victim as *mut libc::c_void);
    }
}

impl Drop for FfiType {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0) }
    }
}

impl Drop for FfiTypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.0) }
    }
}

impl FfiType {
    pub fn void() -> Self {
        FfiType(unsafe { &mut low::ffi_type_void })
    }

    pub fn uint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint8 })
    }

    pub fn sint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint8 })
    }

    pub fn uint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint16 })
    }

    pub fn sint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint16 })
    }

    pub fn uint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint32 })
    }

    pub fn sint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint32 })
    }

    pub fn uint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint64 })
    }

    pub fn sint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint64 })
    }

    pub fn float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_float })
    }

    pub fn double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_double })
    }

    pub fn pointer() -> Self {
        FfiType(unsafe { &mut low::ffi_type_pointer })
    }

    pub fn longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_longdouble })
    }

    pub fn complex_float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_float })
    }

    pub fn complex_double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_double })
    }

    pub fn complex_longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_longdouble })
    }

    pub fn structure(fields: Vec<FfiType>) -> Self {
        println!("FfiType::structure({:?})", fields);
        unsafe {
            FfiType(ffi_type_struct_create(fields))
        }
    }

    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        self.0
    }
}

impl FfiTypeArray {
    pub fn new(elements: Vec<FfiType>) -> Self {
        unsafe { FfiTypeArray(ffi_type_array_create(elements)) }
    }

    pub fn len(&self) -> usize {
        unsafe { ffi_type_array_len(self.0) }
    }

    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        self.0
    }
}

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

    #[test]
    fn create_uint64() {
        FfiType::uint64();
    }

    #[test]
    fn create_struct() {
        FfiType::structure(vec![FfiType::sint64(),
                                FfiType::sint64(),
                                FfiType::uint64()]);
    }

}
<commit_msg>added Clone for FfiType(Array)<commit_after>//! Representations of C types and arrays thereof.

use std::{mem, ptr};
use libc;

use c;
use low;

type FfiType_      = *mut low::ffi_type;
type FfiTypeArray_ = *mut FfiType_;
type Owned<T>      = T;

#[derive(Debug)]
pub struct FfiType(FfiType_);

#[derive(Debug)]
pub struct FfiTypeArray(FfiTypeArray_);

/// Computes the length of a raw `FfiTypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: FfiTypeArray_) -> usize {
    let mut current = array;
    let mut count   = 0;
    while !(*current).is_null() {
        count += 1;
    }
    count
}

/// Creates an empty `FfiTypeArray_` with null terminator.
unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<FfiTypeArray_> {
    let array = libc::malloc((len + 1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;
    *array.offset(len as isize) = ptr::null::<low::ffi_type>() as FfiType_;
    array
}

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>)
    -> Owned<FfiTypeArray_>
{
    let size = elements.len();
    let new  = ffi_type_array_create_empty(size);
    for i in 0 .. size {
        *new.offset(i as isize) = elements[i].0;
    }

    for t in elements {
        mem::forget(t);
    }

    println!("ffi_type_array_create(...) = {:?}", new);

    new
}

/// Creates a struct type from a raw array of element types.
unsafe fn ffi_type_struct_create_raw(elements: FfiTypeArray_)
    -> Owned<FfiType_>
{
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as FfiType_;

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = c::ffi_type_enum::STRUCT as ::libc::c_ushort;
    (*new).elements  = elements;

    println!("ffi_type_struct_create_raw({:?}) = {:?}", elements, new);

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> Owned<FfiType_> {
    println!("ffi_type_array_create({:?})", elements);
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

/// Makes a copy of a type array.
unsafe fn ffi_type_array_clone(old: FfiTypeArray_) -> Owned<FfiTypeArray_> {
    let size = ffi_type_array_len(old);
    let new  = ffi_type_array_create_empty(size);

    for i in 0 .. size {
        *new.offset(i as isize) = ffi_type_clone(*old.offset(i as isize));
    }

    new
}

/// Makes a copy of a type.
unsafe fn ffi_type_clone(old: FfiType_) -> Owned<FfiType_> {
    if (*old).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys an array of FfiType_ and all of its elements.
unsafe fn ffi_type_array_destroy(victim: Owned<FfiTypeArray_>) {
    println!("ffi_type_array_destroy({:?})", victim);
    let mut current = victim;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(victim as *mut libc::c_void);
}

/// Destroys an FfiType_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(victim: Owned<FfiType_>) {
    println!("ffi_type_destroy({:?})", victim);
    if (*victim).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_array_destroy((*victim).elements);
        libc::free(victim as *mut libc::c_void);
    }
}

impl Drop for FfiType {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0) }
    }
}

impl Drop for FfiTypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.0) }
    }
}

impl Clone for FfiType {
    fn clone(&self) -> Self {
        unsafe { FfiType(ffi_type_clone(self.0)) }
    }
}

impl Clone for FfiTypeArray {
    fn clone(&self) -> Self {
        unsafe { FfiTypeArray(ffi_type_array_clone(self.0)) }
    }
}

impl FfiType {
    pub fn void() -> Self {
        FfiType(unsafe { &mut low::ffi_type_void })
    }

    pub fn uint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint8 })
    }

    pub fn sint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint8 })
    }

    pub fn uint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint16 })
    }

    pub fn sint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint16 })
    }

    pub fn uint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint32 })
    }

    pub fn sint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint32 })
    }

    pub fn uint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint64 })
    }

    pub fn sint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint64 })
    }

    pub fn float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_float })
    }

    pub fn double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_double })
    }

    pub fn pointer() -> Self {
        FfiType(unsafe { &mut low::ffi_type_pointer })
    }

    pub fn longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_longdouble })
    }

    pub fn complex_float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_float })
    }

    pub fn complex_double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_double })
    }

    pub fn complex_longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_longdouble })
    }

    pub fn structure(fields: Vec<FfiType>) -> Self {
        println!("FfiType::structure({:?})", fields);
        unsafe {
            FfiType(ffi_type_struct_create(fields))
        }
    }

    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        self.0
    }
}

impl FfiTypeArray {
    pub fn new(elements: Vec<FfiType>) -> Self {
        unsafe { FfiTypeArray(ffi_type_array_create(elements)) }
    }

    pub fn len(&self) -> usize {
        unsafe { ffi_type_array_len(self.0) }
    }

    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        self.0
    }
}

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

    #[test]
    fn create_uint64() {
        FfiType::uint64();
    }

    #[test]
    fn create_struct() {
        FfiType::structure(vec![FfiType::sint64(),
                                FfiType::sint64(),
                                FfiType::uint64()]);
    }

}
<|endoftext|>