<commit_before>// spell-checker:ignore (vars) charf cninetyninehexfloatf decf floatf intf scif strf Cninety

//! handles creating printed output for numeric substitutions

// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety

use std::env;
use std::vec::Vec;

use super::format_field::{FieldType, FormatField};
use super::formatter::{Base, FormatPrimitive, Formatter, InitialPrefix};
use super::formatters::cninetyninehexfloatf::CninetyNineHexFloatf;
use super::formatters::decf::Decf;
use super::formatters::floatf::Floatf;
use super::formatters::intf::Intf;
use super::formatters::scif::Scif;

use crate::cli;

pub fn warn_expected_numeric(pf_arg: &str) {
    // important: keep println here not print
    cli::err_msg(&format!("{}: expected a numeric value", pf_arg));
}

// when character constant arguments have excess characters
// issue a warning when POSIXLY_CORRECT is not set
fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
    match env::var("POSIXLY_CORRECT") {
        Ok(_) => {}
        Err(e) => {
            if let env::VarError::NotPresent = e {
                cli::err_msg(&format!(
                    "warning: {:?}: character(s) following character \
                     constant have been ignored",
                    &*remaining_bytes
                ));
            }
        }
    }
}

// this function looks at the first few
// characters of an argument and returns a value if we can learn
// a value from that (e.g. no argument? return 0, char constant? ret value)
fn get_provided(str_in_opt: Option<&String>) -> Option<u8> {
    const C_S_QUOTE: u8 = 39;
    const C_D_QUOTE: u8 = 34;
    match str_in_opt {
        Some(str_in) => {
            let mut byte_it = str_in.bytes();
            if let Some(ch) = byte_it.next() {
                match ch {
                    C_S_QUOTE | C_D_QUOTE => {
                        Some(match byte_it.next() {
                            Some(second_byte) => {
                                let mut ignored: Vec<u8> = Vec::new();
                                for cont in byte_it {
                                    ignored.push(cont);
                                }
                                if !ignored.is_empty() {
                                    warn_char_constant_ign(ignored);
                                }
                                second_byte as u8
                            }
                            // no byte after quote
                            None => {
                                let so_far = (ch as u8 as char).to_string();
                                warn_expected_numeric(&so_far);
                                0_u8
                            }
                        })
                    }
                    // first byte is not quote
                    _ => None, // no first byte
                }
            } else {
                Some(0_u8)
            }
        }
        None => Some(0),
    }
}

// takes a string and returns
// a sign,
// a base,
// and an offset for index after all
//  initial spacing, sign, base prefix, and leading zeroes
fn get_initial_prefix(str_in: &str, field_type: &FieldType) -> InitialPrefix {
    let mut str_it = str_in.chars();
    let mut ret = InitialPrefix {
        radix_in: Base::Ten,
        sign: 1,
        offset: 0,
    };
    let mut top_char = str_it.next();
    // skip spaces and ensure top_char is the first non-space char
    // (or None if none exists)
    while let Some(' ') = top_char {
        ret.offset += 1;
        top_char = str_it.next();
    }
    // parse sign
    match top_char {
        Some('+') => {
            ret.offset += 1;
            top_char = str_it.next();
        }
        Some('-') => {
            ret.sign = -1;
            ret.offset += 1;
            top_char = str_it.next();
        }
        _ => {}
    }
    // we want to exit with offset being
    // the index of the first non-zero
    // digit before the decimal point or
    // if there is none, the zero before the
    // decimal point, or, if there is none,
    // the decimal point.

    // while we are determining the offset
    // we will ensure as a convention
    // the offset is always on the first character
    // that we are yet unsure if it is the
    // final offset. If the zero could be before
    // a decimal point we don't move past the zero.
    let mut is_hex = false;
    if Some('0') == top_char {
        if let Some(base) = str_it.next() {
            // lead zeroes can only exist in
            // octal and hex base
            let mut do_clean_lead_zeroes = false;
            match base {
                'x' | 'X' => {
                    is_hex = true;
                    ret.offset += 2;
                    ret.radix_in = Base::Hex;
                    do_clean_lead_zeroes = true;
                }
                e @ '0'..='9' => {
                    ret.offset += 1;
                    if let FieldType::Intf = *field_type {
                        ret.radix_in = Base::Octal;
                    }
                    if e == '0' {
                        do_clean_lead_zeroes = true;
                    }
                }
                _ => {}
            }
            if do_clean_lead_zeroes {
                let mut first = true;
                for ch_zero in str_it {
                    // see notes on offset above:
                    // this is why the offset for octal and decimal numbers
                    // that reach this branch is 1 even though
                    // they have already eaten the characters '00'
                    // this is also why when hex encounters its
                    // first zero it does not move its offset
                    // forward because it does not know for sure
                    // that it's current offset (of that zero)
                    // is not the final offset,
                    // whereas at that point octal knows its
                    // current offset is not the final offset.
                    match ch_zero {
                        '0' => {
                            if !(is_hex && first) {
                                ret.offset += 1;
                            }
                        }
                        // if decimal, keep last zero if one exists
                        // (it's possible for last zero to
                        // not exist at this branch if we're in hex input)
                        '.' => break,
                        // other digit, etc.
                        _ => {
                            if !(is_hex && first) {
                                ret.offset += 1;
                            }
                            break;
                        }
                    }
                    if first {
                        first = false;
                    }
                }
            }
        }
    }
    ret
}

// this is the function a Sub's print will delegate to
// if it is a numeric field, passing the field details
// and an iterator to the argument
pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<String> {
    let field_char = field.field_char;

    // num format mainly operates by further delegating to one of
    // several Formatter structs depending on the field
    // see formatter.rs for more details

    // to do switch to static dispatch
    let formatter: Box<dyn Formatter> = match *field.field_type {
        FieldType::Intf => Box::new(Intf::new()),
        FieldType::Floatf => Box::new(Floatf::new()),
        FieldType::CninetyNineHexFloatf => Box::new(CninetyNineHexFloatf::new()),
        FieldType::Scif => Box::new(Scif::new()),
        FieldType::Decf => Box::new(Decf::new()),
        _ => {
            panic!("asked to do num format with non-num field type");
        }
    };
    let prim_opt=
        // if we can get an assumed value from looking at the first
        // few characters, use that value to create the FormatPrimitive
        if let Some(provided_num) = get_provided(in_str_opt) {
            let mut tmp : FormatPrimitive = Default::default();
            match field_char {
                'u' | 'i' | 'd' => {
                    tmp.pre_decimal = Some(
                        format!("{}", provided_num));
                },
                'x' | 'X' => {
                    tmp.pre_decimal = Some(
                        format!("{:x}", provided_num));
                },
                'o' => {
                    tmp.pre_decimal = Some(
                        format!("{:o}", provided_num));
                },
                'e' | 'E' | 'g' | 'G' => {
                    let as_str = format!("{}", provided_num);
                    let initial_prefix = get_initial_prefix(
                        &as_str,
                        &field.field_type
                    );
                    tmp=formatter.get_primitive(field, &initial_prefix, &as_str)
                        .expect("err during default provided num");
                },
                _ => {
                    tmp.pre_decimal = Some(
                        format!("{}", provided_num));
                    tmp.post_decimal = Some(String::from("0"));
                }
            }
            Some(tmp)
        } else {
            // otherwise we'll interpret the argument as a number
            // using the appropriate Formatter
            let in_str = in_str_opt.expect(
                "please send the devs this message:
                \n get_provided is failing to ret as Some(0) on no str ");
            // first get information about the beginning of the
            // numeric argument that would be useful for
            // any formatter (int or float)
            let initial_prefix = get_initial_prefix(
                in_str,
                &field.field_type
            );
            // then get the FormatPrimitive from the Formatter
            formatter.get_primitive(field, &initial_prefix, in_str)
        };
    // if we have a formatPrimitive, print its results
    // according to the field-char appropriate Formatter
    prim_opt.map(|prim| formatter.primitive_to_str(&prim, field.clone()))
}
<commit_msg>refactor/printf ~ fix `cargo clippy` complaint (clippy::needless_borrow)<commit_after>// spell-checker:ignore (vars) charf cninetyninehexfloatf decf floatf intf scif strf Cninety

//! handles creating printed output for numeric substitutions

// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety

use std::env;
use std::vec::Vec;

use super::format_field::{FieldType, FormatField};
use super::formatter::{Base, FormatPrimitive, Formatter, InitialPrefix};
use super::formatters::cninetyninehexfloatf::CninetyNineHexFloatf;
use super::formatters::decf::Decf;
use super::formatters::floatf::Floatf;
use super::formatters::intf::Intf;
use super::formatters::scif::Scif;

use crate::cli;

pub fn warn_expected_numeric(pf_arg: &str) {
    // important: keep println here not print
    cli::err_msg(&format!("{}: expected a numeric value", pf_arg));
}

// when character constant arguments have excess characters
// issue a warning when POSIXLY_CORRECT is not set
fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
    match env::var("POSIXLY_CORRECT") {
        Ok(_) => {}
        Err(e) => {
            if let env::VarError::NotPresent = e {
                cli::err_msg(&format!(
                    "warning: {:?}: character(s) following character \
                     constant have been ignored",
                    &*remaining_bytes
                ));
            }
        }
    }
}

// this function looks at the first few
// characters of an argument and returns a value if we can learn
// a value from that (e.g. no argument? return 0, char constant? ret value)
fn get_provided(str_in_opt: Option<&String>) -> Option<u8> {
    const C_S_QUOTE: u8 = 39;
    const C_D_QUOTE: u8 = 34;
    match str_in_opt {
        Some(str_in) => {
            let mut byte_it = str_in.bytes();
            if let Some(ch) = byte_it.next() {
                match ch {
                    C_S_QUOTE | C_D_QUOTE => {
                        Some(match byte_it.next() {
                            Some(second_byte) => {
                                let mut ignored: Vec<u8> = Vec::new();
                                for cont in byte_it {
                                    ignored.push(cont);
                                }
                                if !ignored.is_empty() {
                                    warn_char_constant_ign(ignored);
                                }
                                second_byte as u8
                            }
                            // no byte after quote
                            None => {
                                let so_far = (ch as u8 as char).to_string();
                                warn_expected_numeric(&so_far);
                                0_u8
                            }
                        })
                    }
                    // first byte is not quote
                    _ => None, // no first byte
                }
            } else {
                Some(0_u8)
            }
        }
        None => Some(0),
    }
}

// takes a string and returns
// a sign,
// a base,
// and an offset for index after all
//  initial spacing, sign, base prefix, and leading zeroes
fn get_initial_prefix(str_in: &str, field_type: &FieldType) -> InitialPrefix {
    let mut str_it = str_in.chars();
    let mut ret = InitialPrefix {
        radix_in: Base::Ten,
        sign: 1,
        offset: 0,
    };
    let mut top_char = str_it.next();
    // skip spaces and ensure top_char is the first non-space char
    // (or None if none exists)
    while let Some(' ') = top_char {
        ret.offset += 1;
        top_char = str_it.next();
    }
    // parse sign
    match top_char {
        Some('+') => {
            ret.offset += 1;
            top_char = str_it.next();
        }
        Some('-') => {
            ret.sign = -1;
            ret.offset += 1;
            top_char = str_it.next();
        }
        _ => {}
    }
    // we want to exit with offset being
    // the index of the first non-zero
    // digit before the decimal point or
    // if there is none, the zero before the
    // decimal point, or, if there is none,
    // the decimal point.

    // while we are determining the offset
    // we will ensure as a convention
    // the offset is always on the first character
    // that we are yet unsure if it is the
    // final offset. If the zero could be before
    // a decimal point we don't move past the zero.
    let mut is_hex = false;
    if Some('0') == top_char {
        if let Some(base) = str_it.next() {
            // lead zeroes can only exist in
            // octal and hex base
            let mut do_clean_lead_zeroes = false;
            match base {
                'x' | 'X' => {
                    is_hex = true;
                    ret.offset += 2;
                    ret.radix_in = Base::Hex;
                    do_clean_lead_zeroes = true;
                }
                e @ '0'..='9' => {
                    ret.offset += 1;
                    if let FieldType::Intf = *field_type {
                        ret.radix_in = Base::Octal;
                    }
                    if e == '0' {
                        do_clean_lead_zeroes = true;
                    }
                }
                _ => {}
            }
            if do_clean_lead_zeroes {
                let mut first = true;
                for ch_zero in str_it {
                    // see notes on offset above:
                    // this is why the offset for octal and decimal numbers
                    // that reach this branch is 1 even though
                    // they have already eaten the characters '00'
                    // this is also why when hex encounters its
                    // first zero it does not move its offset
                    // forward because it does not know for sure
                    // that it's current offset (of that zero)
                    // is not the final offset,
                    // whereas at that point octal knows its
                    // current offset is not the final offset.
                    match ch_zero {
                        '0' => {
                            if !(is_hex && first) {
                                ret.offset += 1;
                            }
                        }
                        // if decimal, keep last zero if one exists
                        // (it's possible for last zero to
                        // not exist at this branch if we're in hex input)
                        '.' => break,
                        // other digit, etc.
                        _ => {
                            if !(is_hex && first) {
                                ret.offset += 1;
                            }
                            break;
                        }
                    }
                    if first {
                        first = false;
                    }
                }
            }
        }
    }
    ret
}

// this is the function a Sub's print will delegate to
// if it is a numeric field, passing the field details
// and an iterator to the argument
pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<String> {
    let field_char = field.field_char;

    // num format mainly operates by further delegating to one of
    // several Formatter structs depending on the field
    // see formatter.rs for more details

    // to do switch to static dispatch
    let formatter: Box<dyn Formatter> = match *field.field_type {
        FieldType::Intf => Box::new(Intf::new()),
        FieldType::Floatf => Box::new(Floatf::new()),
        FieldType::CninetyNineHexFloatf => Box::new(CninetyNineHexFloatf::new()),
        FieldType::Scif => Box::new(Scif::new()),
        FieldType::Decf => Box::new(Decf::new()),
        _ => {
            panic!("asked to do num format with non-num field type");
        }
    };
    let prim_opt=
        // if we can get an assumed value from looking at the first
        // few characters, use that value to create the FormatPrimitive
        if let Some(provided_num) = get_provided(in_str_opt) {
            let mut tmp : FormatPrimitive = Default::default();
            match field_char {
                'u' | 'i' | 'd' => {
                    tmp.pre_decimal = Some(
                        format!("{}", provided_num));
                },
                'x' | 'X' => {
                    tmp.pre_decimal = Some(
                        format!("{:x}", provided_num));
                },
                'o' => {
                    tmp.pre_decimal = Some(
                        format!("{:o}", provided_num));
                },
                'e' | 'E' | 'g' | 'G' => {
                    let as_str = format!("{}", provided_num);
                    let initial_prefix = get_initial_prefix(
                        &as_str,
                        &field.field_type
                    );
                    tmp=formatter.get_primitive(field, &initial_prefix, &as_str)
                        .expect("err during default provided num");
                },
                _ => {
                    tmp.pre_decimal = Some(
                        format!("{}", provided_num));
                    tmp.post_decimal = Some(String::from("0"));
                }
            }
            Some(tmp)
        } else {
            // otherwise we'll interpret the argument as a number
            // using the appropriate Formatter
            let in_str = in_str_opt.expect(
                "please send the devs this message:
                \n get_provided is failing to ret as Some(0) on no str ");
            // first get information about the beginning of the
            // numeric argument that would be useful for
            // any formatter (int or float)
            let initial_prefix = get_initial_prefix(
                in_str,
                field.field_type
            );
            // then get the FormatPrimitive from the Formatter
            formatter.get_primitive(field, &initial_prefix, in_str)
        };
    // if we have a formatPrimitive, print its results
    // according to the field-char appropriate Formatter
    prim_opt.map(|prim| formatter.primitive_to_str(&prim, field.clone()))
}
<|endoftext|>


<commit_before>extern crate getopts;
use std::io::Write;

pub struct HelpText<'a> {
    pub name : &'a str,
    pub version : &'a str,
    pub syntax : &'a str,
    pub summary : &'a str,
    pub long_help : &'a str,
    pub display_usage : bool
}

pub struct CoreOptions<'a> {
    options : getopts::Options,
    help_text : HelpText<'a>
}

impl<'a> CoreOptions<'a> {
    pub fn new(help_text: HelpText<'a>) -> Self {
        let mut ret = CoreOptions {
            options : getopts::Options::new(),
            help_text : help_text
        };
        ret.options
            .optflag("", "help", "print usage information")
            .optflag("", "version", "print name and version number");
        ret
    }
    pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optflagopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflag(short_name, long_name, desc);
        self
    }
    pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optopt(short_name, long_name, desc, hint);
        self
    }
    pub fn usage(&self, summary : &str) -> String {
        self.options.usage(summary)
    }
    pub fn parse(&mut self, args : Vec<String>) -> getopts::Matches {
        let matches = match self.options.parse(&args[1..]) {
            Ok(m) => { Some(m) },
            Err(f) => {
                pipe_write!(&mut ::std::io::stderr(), "{}: error: ", self.help_text.name);
                pipe_writeln!(&mut ::std::io::stderr(), "{}", f);
                ::std::process::exit(1);
            }
        }.unwrap();
        if matches.opt_present("help") {
            let usage_str = if self.help_text.display_usage {
                    format!("\n {}\n\n Reference\n",
                        self.options.usage(self.help_text.summary)
                    ).replace("Options:", " Options:")
                } else { String::new() };
            print!("
 {0} {1}

 {0} {2}
{3}{4}
", self.help_text.name, self.help_text.version, self.help_text.syntax, usage_str, self.help_text.long_help);
            exit!(0);
        } else if matches.opt_present("version") {
            println!("{} {}", self.help_text.name, self.help_text.version);
            exit!(0);
        }
        matches
    }
}

#[macro_export]
macro_rules! new_coreopts {
    ($syntax: expr, $summary: expr, $long_help: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: true
        })
    );
    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: $display_usage
        })
    );
}
<commit_msg>uucore: add support for optflagmulti and optmulti.<commit_after>extern crate getopts;
use std::io::Write;

pub struct HelpText<'a> {
    pub name : &'a str,
    pub version : &'a str,
    pub syntax : &'a str,
    pub summary : &'a str,
    pub long_help : &'a str,
    pub display_usage : bool
}

pub struct CoreOptions<'a> {
    options : getopts::Options,
    help_text : HelpText<'a>
}

impl<'a> CoreOptions<'a> {
    pub fn new(help_text: HelpText<'a>) -> Self {
        let mut ret = CoreOptions {
            options : getopts::Options::new(),
            help_text : help_text
        };
        ret.options
            .optflag("", "help", "print usage information")
            .optflag("", "version", "print name and version number");
        ret
    }
    pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optflagopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflag(short_name, long_name, desc);
        self
    }
    pub fn optflagmulti(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflagmulti(short_name, long_name, desc);
        self
    }
    pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optmulti(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optmulti(short_name, long_name, desc, hint);
        self
    }
    pub fn usage(&self, summary : &str) -> String {
        self.options.usage(summary)
    }
    pub fn parse(&mut self, args : Vec<String>) -> getopts::Matches {
        let matches = match self.options.parse(&args[1..]) {
            Ok(m) => { Some(m) },
            Err(f) => {
                pipe_write!(&mut ::std::io::stderr(), "{}: error: ", self.help_text.name);
                pipe_writeln!(&mut ::std::io::stderr(), "{}", f);
                ::std::process::exit(1);
            }
        }.unwrap();
        if matches.opt_present("help") {
            let usage_str = if self.help_text.display_usage {
                    format!("\n {}\n\n Reference\n",
                        self.options.usage(self.help_text.summary)
                    ).replace("Options:", " Options:")
                } else { String::new() };
            print!("
 {0} {1}

 {0} {2}
{3}{4}
", self.help_text.name, self.help_text.version, self.help_text.syntax, usage_str, self.help_text.long_help);
            exit!(0);
        } else if matches.opt_present("version") {
            println!("{} {}", self.help_text.name, self.help_text.version);
            exit!(0);
        }
        matches
    }
}

#[macro_export]
macro_rules! new_coreopts {
    ($syntax: expr, $summary: expr, $long_help: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: true
        })
    );
    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: $display_usage
        })
    );
}
<|endoftext|>


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

// Test that MIR borrowck and NLL analysis can handle constants of
// arbitrary types without ICEs.

// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass

const HI: &str = "hi";

fn main() {
    assert_eq!(HI, "hi");
}
<commit_msg>For some reason, on my linux box, using `-Zverbose` here is causing a linker failure.<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that MIR borrowck and NLL analysis can handle constants of
// arbitrary types without ICEs.

// compile-flags:-Zborrowck=mir
// compile-pass

const HI: &str = "hi";

fn main() {
    assert_eq!(HI, "hi");
}
<|endoftext|>


<commit_before>extern crate actix;
extern crate actix_web;
extern crate tokio_core;
extern crate reqwest;

use std::{net, thread};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use tokio_core::net::TcpListener;

use actix::*;
use actix_web::*;

#[test]
fn test_serve() {
    thread::spawn(|| {
        let sys = System::new("test");
        let srv = HttpServer::new(
            || vec![Application::new()
                    .resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk))]);
        srv.bind("127.0.0.1:58902").unwrap().start().unwrap();
        sys.run();
    });
    assert!(reqwest::get("http://localhost:58902/").unwrap().status().is_success());
}

#[test]
fn test_serve_incoming() {
    let loopback = net::Ipv4Addr::new(127, 0, 0, 1);
    let socket = net::SocketAddrV4::new(loopback, 0);
    let tcp = net::TcpListener::bind(socket).unwrap();
    let addr1 = tcp.local_addr().unwrap();
    let addr2 = tcp.local_addr().unwrap();

    thread::spawn(move || {
        let sys = System::new("test");

        let srv = HttpServer::new(
            || Application::new()
                .resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk)));
        let tcp = TcpListener::from_listener(tcp, &addr2, Arbiter::handle()).unwrap();
        srv.start_incoming::<_, ()>(tcp.incoming(), false).unwrap();
        sys.run();
    });

    assert!(reqwest::get(&format!("http://{}/", addr1))
            .unwrap().status().is_success());
}

struct MiddlewareTest {
    start: Arc<AtomicUsize>,
    response: Arc<AtomicUsize>,
    finish: Arc<AtomicUsize>,
}

impl<S> middlewares::Middleware<S> for MiddlewareTest {
    fn start(&self, _: &mut HttpRequest<S>) -> middlewares::Started {
        self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        middlewares::Started::Done
    }

    fn response(&self, _: &mut HttpRequest<S>, resp: HttpResponse) -> middlewares::Response {
        self.response.store(self.response.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        middlewares::Response::Done(resp)
    }

    fn finish(&self, _: &mut HttpRequest<S>, _: &HttpResponse) -> middlewares::Finished {
        self.finish.store(self.finish.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        middlewares::Finished::Done
    }
}

#[test]
fn test_middlewares() {
    let num1 = Arc::new(AtomicUsize::new(0));
    let num2 = Arc::new(AtomicUsize::new(0));
    let num3 = Arc::new(AtomicUsize::new(0));

    let act_num1 = Arc::clone(&num1);
    let act_num2 = Arc::clone(&num2);
    let act_num3 = Arc::clone(&num3);

    thread::spawn(move || {
        let sys = System::new("test");

        HttpServer::new(
            move || vec![Application::new()
                         .middleware(MiddlewareTest{start: Arc::clone(&act_num1),
                                                    response: Arc::clone(&act_num2),
                                                    finish: Arc::clone(&act_num3)})
                         .resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk))])
            .bind("127.0.0.1:58904").unwrap()
            .start().unwrap();
        sys.run();
    });

    assert!(reqwest::get("http://localhost:58904/").unwrap().status().is_success());
    assert_eq!(num1.load(Ordering::Relaxed), 1);
    assert_eq!(num2.load(Ordering::Relaxed), 1);
    assert_eq!(num3.load(Ordering::Relaxed), 1);
}
<commit_msg>update tests<commit_after>extern crate actix;
extern crate actix_web;
extern crate tokio_core;
extern crate reqwest;

use std::{net, thread};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use tokio_core::net::TcpListener;

use actix::*;
use actix_web::*;

#[test]
fn test_serve() {
    thread::spawn(|| {
        let sys = System::new("test");
        let srv = HttpServer::new(
            || vec![Application::new()
                    .resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk))]);
        srv.bind("127.0.0.1:58902").unwrap().start().unwrap();
        sys.run();
    });
    assert!(reqwest::get("http://localhost:58902/").unwrap().status().is_success());
}

#[test]
fn test_serve_incoming() {
    let loopback = net::Ipv4Addr::new(127, 0, 0, 1);
    let socket = net::SocketAddrV4::new(loopback, 0);
    let tcp = net::TcpListener::bind(socket).unwrap();
    let addr1 = tcp.local_addr().unwrap();
    let addr2 = tcp.local_addr().unwrap();

    thread::spawn(move || {
        let sys = System::new("test");

        let srv = HttpServer::new(
            || Application::new()
                .resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk)));
        let tcp = TcpListener::from_listener(tcp, &addr2, Arbiter::handle()).unwrap();
        srv.start_incoming(tcp.incoming(), false).unwrap();
        sys.run();
    });

    assert!(reqwest::get(&format!("http://{}/", addr1))
            .unwrap().status().is_success());
}

struct MiddlewareTest {
    start: Arc<AtomicUsize>,
    response: Arc<AtomicUsize>,
    finish: Arc<AtomicUsize>,
}

impl<S> middlewares::Middleware<S> for MiddlewareTest {
    fn start(&self, _: &mut HttpRequest<S>) -> middlewares::Started {
        self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        middlewares::Started::Done
    }

    fn response(&self, _: &mut HttpRequest<S>, resp: HttpResponse) -> middlewares::Response {
        self.response.store(self.response.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        middlewares::Response::Done(resp)
    }

    fn finish(&self, _: &mut HttpRequest<S>, _: &HttpResponse) -> middlewares::Finished {
        self.finish.store(self.finish.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        middlewares::Finished::Done
    }
}

#[test]
fn test_middlewares() {
    let num1 = Arc::new(AtomicUsize::new(0));
    let num2 = Arc::new(AtomicUsize::new(0));
    let num3 = Arc::new(AtomicUsize::new(0));

    let act_num1 = Arc::clone(&num1);
    let act_num2 = Arc::clone(&num2);
    let act_num3 = Arc::clone(&num3);

    thread::spawn(move || {
        let sys = System::new("test");

        HttpServer::new(
            move || vec![Application::new()
                         .middleware(MiddlewareTest{start: Arc::clone(&act_num1),
                                                    response: Arc::clone(&act_num2),
                                                    finish: Arc::clone(&act_num3)})
                         .resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk))])
            .bind("127.0.0.1:58904").unwrap()
            .start().unwrap();
        sys.run();
    });

    assert!(reqwest::get("http://localhost:58904/").unwrap().status().is_success());
    assert_eq!(num1.load(Ordering::Relaxed), 1);
    assert_eq!(num2.load(Ordering::Relaxed), 1);
    assert_eq!(num3.load(Ordering::Relaxed), 1);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate rustc_perf;
extern crate serde_json;
extern crate iron_test;
extern crate serde;
extern crate iron;

use std::fs::File;
use std::io::{Write, Read};
use std::path::Path;

use iron::prelude::*;
use iron::status::Status;
use iron::{Headers, headers};
use iron::response::ResponseBody;
use serde_json::Value;
use serde::Serialize;

use rustc_perf::server::{self, GroupBy};
use rustc_perf::load::{Kind, InputData};
use rustc_perf::date::{OptionalDate, Date};
use rustc_perf::api::{data, tabular, days, stats};

lazy_static! {
    static ref CHAIN: Chain = server::chain(InputData::from_fs("tests/data").unwrap());
}

fn request(path: &str) -> Response {
    iron_test::request::get(&format!("http://perf.rust-lang.org/{}", path),
                            Headers::new(),
                            &*CHAIN).unwrap()
}

fn post_request<T: Serialize>(path: &str,
                                          body: T)
                                          -> Response {
    iron_test::request::post(&format!("http://perf.rust-lang.org/{}", path),
                             Headers::new(),
                             &serde_json::to_string(&body).unwrap(),
                             &*CHAIN).unwrap()
}

fn response_body(response: Response) -> Value {
    if let Some(mut body) = response.body {
        let mut buf = Vec::new();
        body.write_body(&mut ResponseBody::new(&mut buf)).unwrap();
        let s = String::from_utf8(buf).unwrap();
        serde_json::from_str(&s).unwrap()
    } else {
        Value::Null
    }
}

fn round_trip_value(v: &Value) -> Value {
    let s = pretty_json(v);
    serde_json::from_str(&s).unwrap()
}

fn from_file<P: AsRef<Path>>(path: P) -> Value {
    let mut file = File::open(path).unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    serde_json::from_str(&s).unwrap()
}

#[allow(dead_code)]
fn to_file<P: AsRef<Path>>(path: P, value: &Value) {
    let mut file = File::create(path).unwrap();
    file.write_all(pretty_json(&value).as_bytes()).unwrap();
}

fn pretty_json(value: &Value) -> String {
    serde_json::to_string_pretty(&value).unwrap()
}

fn check_response(response: Response, expected_file: &str) {
    assert_eq!(response.status, Some(Status::Ok));
    assert_eq!(response.headers.get(),
               Some(&headers::AccessControlAllowOrigin::Any));
    assert_eq!(response.headers.get(),
               Some(&headers::ContentType("application/json".parse().unwrap())));

    // The deserialized value from wire.
    // If new values are to be recorded to the files, this is the value that
    // should be recorded.
    // This has undergone: server serialize -> tests deserialize
    let raw_received_value = response_body(response);

    // Uncomment this line to refresh the expected results.
    // to_file(expected_file, &raw_received_value);

    // The deserialized value from the file.
    // This has undergone:
    //     server serialize -> tests deserialize ->
    //     to_file serialize (pretty) -> tests deserialize
    let expected_value = from_file(expected_file);

    // This value has now undergone the same amount of round trips through
    // Serde as the one in the file.
    let received_value = round_trip_value(&raw_received_value);

    if received_value != expected_value {
        // Note: This value's float fields should not be used for direct
        // comparison with the expected results, due to the loss of precision in Serde
        println!("{}", serde_json::to_string(&raw_received_value).unwrap());
        panic!("Compared {} body with server result, results not equal.", expected_file);
    }
}

#[test]
fn summary() {
    let response = request("/summary");
    check_response(response, "tests/expected_results/summary.json");
}

// This test breaks on Travis for unknown reasons for the time being, so
// set it to ignored.
#[test]
#[ignore]
fn info() {
    let response = request("/info");
    check_response(response, "tests/expected_results/info.json");
}

#[test]
fn data_crate_benchmarks() {
    let response = post_request("/data",
                                data::Request {
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    group_by: GroupBy::Crate,
                                    kind: Kind::Benchmarks,
                                    phases: vec!["total".into()],
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                });
    check_response(response, "tests/expected_results/data_crate_benchmarks.json");
}

#[test]
fn data_crate_rustc_total() {
    let response = post_request("/data",
                                data::Request {
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    group_by: GroupBy::Crate,
                                    kind: Kind::Rustc,
                                    phases: vec!["total".into()],
                                    crates: vec!["total".into()],
                                });
    check_response(response, "tests/expected_results/data_crate_rustc_total.json");
}

#[test]
fn tabular_rustc() {
    let response = post_request("/get_tabular",
                                tabular::Request {
                                    kind: Kind::Rustc,
                                    date: OptionalDate::CouldNotParse("".into()),
                                });
    check_response(response, "tests/expected_results/tabular_rustc.json");
}

#[test]
fn tabular_benchmarks() {
    let response = post_request("/get_tabular",
                                tabular::Request {
                                    kind: Kind::Benchmarks,
                                    date: OptionalDate::CouldNotParse("".into()),
                                });
    check_response(response, "tests/expected_results/tabular_benchmarks.json");
}

fn ymd_date(year: i32, month: u32, day: u32) -> OptionalDate {
    OptionalDate::Date(Date::ymd_hms(year, month, day, 0, 0, 0))
}

#[test]
fn days_benchmarks() {
    let response = post_request("/get",
                                days::Request {
                                    kind: Kind::Benchmarks,
                                    date_a: ymd_date(2016, 02, 21),
                                    date_b: ymd_date(2016, 03, 22),
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                    phases: vec!["total".into()],
                                    group_by: GroupBy::Crate,
                                });
    check_response(response, "tests/expected_results/days_benchmarks.json");
}

#[test]
fn days_rustc() {
    let response = post_request("/get",
                                days::Request {
                                    kind: Kind::Rustc,
                                    date_a: ymd_date(2016, 02, 21),
                                    date_b: ymd_date(2016, 03, 22),
                                    crates: vec!["total".into()],
                                    phases: vec!["total".into()],
                                    group_by: GroupBy::Crate,
                                });
    check_response(response, "tests/expected_results/days_rustc.json");
}

#[test]
fn stats_benchmarks() {
    let response = post_request("/stats",
                                stats::Request {
                                    kind: Kind::Benchmarks,
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                    phases: vec!["total".into()],
                                });
    check_response(response, "tests/expected_results/stats_benchmarks.json");
}

#[test]
fn stats_rustc() {
    let response = post_request("/stats",
                                stats::Request {
                                    kind: Kind::Rustc,
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    crates: vec!["total".into()],
                                    phases: vec!["total".into()],
                                });
    check_response(response, "tests/expected_results/stats_rustc.json");
}
<commit_msg>De-ignore info integration test<commit_after>#[macro_use]
extern crate lazy_static;
extern crate rustc_perf;
extern crate serde_json;
extern crate iron_test;
extern crate serde;
extern crate iron;

use std::fs::File;
use std::io::{Write, Read};
use std::path::Path;

use iron::prelude::*;
use iron::status::Status;
use iron::{Headers, headers};
use iron::response::ResponseBody;
use serde_json::Value;
use serde::Serialize;

use rustc_perf::server::{self, GroupBy};
use rustc_perf::load::{Kind, InputData};
use rustc_perf::date::{OptionalDate, Date};
use rustc_perf::api::{data, tabular, days, stats};

lazy_static! {
    static ref CHAIN: Chain = server::chain(InputData::from_fs("tests/data").unwrap());
}

fn request(path: &str) -> Response {
    iron_test::request::get(&format!("http://perf.rust-lang.org/{}", path),
                            Headers::new(),
                            &*CHAIN).unwrap()
}

fn post_request<T: Serialize>(path: &str,
                                          body: T)
                                          -> Response {
    iron_test::request::post(&format!("http://perf.rust-lang.org/{}", path),
                             Headers::new(),
                             &serde_json::to_string(&body).unwrap(),
                             &*CHAIN).unwrap()
}

fn response_body(response: Response) -> Value {
    if let Some(mut body) = response.body {
        let mut buf = Vec::new();
        body.write_body(&mut ResponseBody::new(&mut buf)).unwrap();
        let s = String::from_utf8(buf).unwrap();
        serde_json::from_str(&s).unwrap()
    } else {
        Value::Null
    }
}

fn round_trip_value(v: &Value) -> Value {
    let s = pretty_json(v);
    serde_json::from_str(&s).unwrap()
}

fn from_file<P: AsRef<Path>>(path: P) -> Value {
    let mut file = File::open(path).unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    serde_json::from_str(&s).unwrap()
}

#[allow(dead_code)]
fn to_file<P: AsRef<Path>>(path: P, value: &Value) {
    let mut file = File::create(path).unwrap();
    file.write_all(pretty_json(&value).as_bytes()).unwrap();
}

fn pretty_json(value: &Value) -> String {
    serde_json::to_string_pretty(&value).unwrap()
}

fn check_response(response: Response, expected_file: &str) {
    assert_eq!(response.status, Some(Status::Ok));
    assert_eq!(response.headers.get(),
               Some(&headers::AccessControlAllowOrigin::Any));
    assert_eq!(response.headers.get(),
               Some(&headers::ContentType("application/json".parse().unwrap())));

    // The deserialized value from wire.
    // If new values are to be recorded to the files, this is the value that
    // should be recorded.
    // This has undergone: server serialize -> tests deserialize
    let raw_received_value = response_body(response);

    // Uncomment this line to refresh the expected results.
    // to_file(expected_file, &raw_received_value);

    // The deserialized value from the file.
    // This has undergone:
    //     server serialize -> tests deserialize ->
    //     to_file serialize (pretty) -> tests deserialize
    let expected_value = from_file(expected_file);

    // This value has now undergone the same amount of round trips through
    // Serde as the one in the file.
    let received_value = round_trip_value(&raw_received_value);

    if received_value != expected_value {
        // Note: This value's float fields should not be used for direct
        // comparison with the expected results, due to the loss of precision in Serde
        println!("{}", serde_json::to_string(&raw_received_value).unwrap());
        panic!("Compared {} body with server result, results not equal.", expected_file);
    }
}

#[test]
fn summary() {
    let response = request("/summary");
    check_response(response, "tests/expected_results/summary.json");
}

#[test]
fn info() {
    let response = request("/info");
    check_response(response, "tests/expected_results/info.json");
}

#[test]
fn data_crate_benchmarks() {
    let response = post_request("/data",
                                data::Request {
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    group_by: GroupBy::Crate,
                                    kind: Kind::Benchmarks,
                                    phases: vec!["total".into()],
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                });
    check_response(response, "tests/expected_results/data_crate_benchmarks.json");
}

#[test]
fn data_crate_rustc_total() {
    let response = post_request("/data",
                                data::Request {
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    group_by: GroupBy::Crate,
                                    kind: Kind::Rustc,
                                    phases: vec!["total".into()],
                                    crates: vec!["total".into()],
                                });
    check_response(response, "tests/expected_results/data_crate_rustc_total.json");
}

#[test]
fn tabular_rustc() {
    let response = post_request("/get_tabular",
                                tabular::Request {
                                    kind: Kind::Rustc,
                                    date: OptionalDate::CouldNotParse("".into()),
                                });
    check_response(response, "tests/expected_results/tabular_rustc.json");
}

#[test]
fn tabular_benchmarks() {
    let response = post_request("/get_tabular",
                                tabular::Request {
                                    kind: Kind::Benchmarks,
                                    date: OptionalDate::CouldNotParse("".into()),
                                });
    check_response(response, "tests/expected_results/tabular_benchmarks.json");
}

fn ymd_date(year: i32, month: u32, day: u32) -> OptionalDate {
    OptionalDate::Date(Date::ymd_hms(year, month, day, 0, 0, 0))
}

#[test]
fn days_benchmarks() {
    let response = post_request("/get",
                                days::Request {
                                    kind: Kind::Benchmarks,
                                    date_a: ymd_date(2016, 02, 21),
                                    date_b: ymd_date(2016, 03, 22),
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                    phases: vec!["total".into()],
                                    group_by: GroupBy::Crate,
                                });
    check_response(response, "tests/expected_results/days_benchmarks.json");
}

#[test]
fn days_rustc() {
    let response = post_request("/get",
                                days::Request {
                                    kind: Kind::Rustc,
                                    date_a: ymd_date(2016, 02, 21),
                                    date_b: ymd_date(2016, 03, 22),
                                    crates: vec!["total".into()],
                                    phases: vec!["total".into()],
                                    group_by: GroupBy::Crate,
                                });
    check_response(response, "tests/expected_results/days_rustc.json");
}

#[test]
fn stats_benchmarks() {
    let response = post_request("/stats",
                                stats::Request {
                                    kind: Kind::Benchmarks,
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                    phases: vec!["total".into()],
                                });
    check_response(response, "tests/expected_results/stats_benchmarks.json");
}

#[test]
fn stats_rustc() {
    let response = post_request("/stats",
                                stats::Request {
                                    kind: Kind::Rustc,
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    crates: vec!["total".into()],
                                    phases: vec!["total".into()],
                                });
    check_response(response, "tests/expected_results/stats_rustc.json");
}
<|endoftext|>


<commit_before>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    if rev_list_output.status.success() {
        let rev_list_output_cow = String::from_utf8_lossy(&rev_list_output.stdout).to_string();

        for (i, commit_hash) in rev_list_output_cow.split("\n").enumerate() {
            println!("i: {i}");
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if checkout_output.status.success() {
                    println!(
                        "checkout stdout: {}",
                        String::from_utf8_lossy(&checkout_output.stdout)
                    );
                } else {
                    println!(
                        "checkout stderr: {}",
                        String::from_utf8_lossy(&checkout_output.stderr)
                    );

                    process::exit(1);
                }

                println!("git show --no-patch --format='%s'");

                let show_s_output = Command::new("git")
                    .arg("show")
                    .arg("--no-patch")
                    .arg("--format='%s'")
                    .output()
                    .expect("show failed");

                if show_s_output.status.success() {
                    println!(
                        "show stdout: {}",
                        String::from_utf8_lossy(&show_s_output.stdout)
                    );
                } else {
                    println!(
                        "show stderr: {}",
                        String::from_utf8_lossy(&show_s_output.stderr)
                    );

                    process::exit(1);
                }

                println!("git show --no-patch --format='%b'");

                let show_b_output = Command::new("git")
                    .arg("show")
                    .arg("--no-patch")
                    .arg("--format='%b'")
                    .output()
                    .expect("show failed");

                if show_b_output.status.success() {
                    println!(
                        "show stdout: {}",
                        String::from_utf8_lossy(&show_b_output.stdout)
                    );
                } else {
                    println!(
                        "show stderr: {}",
                        String::from_utf8_lossy(&show_b_output.stderr)
                    );

                    process::exit(1);
                }

                let mut path = env::current_dir().expect("getting current directory failed");
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                  Ok(_) => {},
                  Err(_) => {
                      continue;
                  }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if test_output.status.success() {
                    println!(
                        "test stdout: {}",
                        String::from_utf8_lossy(&test_output.stdout)
                    );
                } else {
                    println!(
                        "test stderr: {}",
                        String::from_utf8_lossy(&test_output.stderr)
                    );

                    process::exit(1);
                }
            }
        }

        println!(
            "rev-list stdout: {}",
            String::from_utf8_lossy(&rev_list_output.stdout)
        );
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8_lossy(&rev_list_output.stderr)
        );

        process::exit(1);
    }
}
<commit_msg>getting whole diff of each commit<commit_after>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let git_rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    if git_rev_list_output.status.success() {
        let git_rev_list_output_cow =
            String::from_utf8_lossy(&git_rev_list_output.stdout).to_string();

        for (i, commit_hash) in git_rev_list_output_cow.split("\n").enumerate() {
            println!("i: {i}");
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let git_checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if git_checkout_output.status.success() {
                    println!(
                        "git checkout stdout: {}",
                        String::from_utf8(git_checkout_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git checkout stderr: {}",
                        String::from_utf8(git_checkout_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("git show");

                let git_show_output = Command::new("git")
                    .arg("show")
                    .output()
                    .expect("show failed");

                if git_show_output.status.success() {
                    println!(
                        "git show stdout: {}",
                        String::from_utf8(git_show_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git show stderr: {}",
                        String::from_utf8(git_show_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                let mut path = env::current_dir().expect("getting current directory failed");
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                    Ok(_) => {}
                    Err(_) => {
                        continue;
                    }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let cargo_test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if cargo_test_output.status.success() {
                    println!(
                        "cargo test stdout: {}",
                        String::from_utf8(cargo_test_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "cargo test stderr: {}",
                        String::from_utf8(cargo_test_output.stderr).unwrap()
                    );

                    process::exit(1);
                }
            }
        }

        println!(
            "rev-list stdout: {}",
            String::from_utf8(git_rev_list_output.stdout).unwrap()
        );
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8(git_rev_list_output.stderr).unwrap()
        );

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Implementation of the EDID specification provided by software.
//! EDID spec: https://glenwing.github.io/docs/VESA-EEDID-A2.pdf

use std::fmt;
use std::fmt::Debug;

use super::protocol::GpuResponse::*;
use super::protocol::VirtioGpuResult;

const EDID_DATA_LENGTH: usize = 128;
const DEFAULT_HORIZONTAL_BLANKING: u16 = 560;
const DEFAULT_VERTICAL_BLANKING: u16 = 50;
const DEFAULT_HORIZONTAL_FRONT_PORCH: u16 = 64;
const DEFAULT_VERTICAL_FRONT_PORCH: u16 = 1;
const DEFAULT_HORIZONTAL_SYNC_PULSE: u16 = 192;
const DEFAULT_VERTICAL_SYNC_PULSE: u16 = 3;

/// This class is used to create the Extended Display Identification Data (EDID), which will be
/// exposed to the guest system.
///
/// We ignore most of the spec, the point here being for us to provide enough for graphics to work
/// and to allow us to configure the resolution and refresh rate (via the preferred timing mode
/// pixel clock).
///
/// The EDID spec defines a number of methods to provide mode information, but in priority order the
/// "detailed" timing information is first, so we provide a single block of detailed timing
/// information and no other form of timing information.
#[repr(C)]
pub struct EdidBytes {
    bytes: [u8; EDID_DATA_LENGTH],
}

impl EdidBytes {
    pub fn len(&self) -> usize {
        self.bytes.len()
    }

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

impl Debug for EdidBytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.bytes[..].fmt(f)
    }
}

impl PartialEq for EdidBytes {
    fn eq(&self, other: &EdidBytes) -> bool {
        self.bytes[..] == other.bytes[..]
    }
}

#[derive(Copy, Clone)]
pub struct Resolution {
    width: u32,
    height: u32,
}

impl Resolution {
    fn new(width: u32, height: u32) -> Resolution {
        Resolution { width, height }
    }

    fn get_aspect_ratio(&self) -> (u32, u32) {
        let divisor = gcd(self.width, self.height);
        (self.width / divisor, self.height / divisor)
    }
}

fn gcd(x: u32, y: u32) -> u32 {
    match y {
        0 => x,
        _ => gcd(y, x % y),
    }
}

#[derive(Copy, Clone)]
pub struct DisplayInfo {
    resolution: Resolution,
    refresh_rate: u32,
    horizontal_blanking: u16,
    vertical_blanking: u16,
    horizontal_front: u16,
    vertical_front: u16,
    horizontal_sync: u16,
    vertical_sync: u16,
}

impl DisplayInfo {
    /// Only width, height and refresh rate are required for the graphics stack to work, so instead
    /// of pulling actual numbers from the system, we just use some typical values to populate other
    /// fields for now.
    pub fn new(width: u32, height: u32, refresh_rate: u32) -> Self {
        Self {
            resolution: Resolution::new(width, height),
            refresh_rate,
            horizontal_blanking: DEFAULT_HORIZONTAL_BLANKING,
            vertical_blanking: DEFAULT_VERTICAL_BLANKING,
            horizontal_front: DEFAULT_HORIZONTAL_FRONT_PORCH,
            vertical_front: DEFAULT_VERTICAL_FRONT_PORCH,
            horizontal_sync: DEFAULT_HORIZONTAL_SYNC_PULSE,
            vertical_sync: DEFAULT_VERTICAL_SYNC_PULSE,
        }
    }

    pub fn width(&self) -> u32 {
        self.resolution.width
    }

    pub fn height(&self) -> u32 {
        self.resolution.height
    }
}

impl EdidBytes {
    /// Creates a virtual EDID block.
    pub fn new(info: &DisplayInfo) -> VirtioGpuResult {
        let mut edid: [u8; EDID_DATA_LENGTH] = [0; EDID_DATA_LENGTH];

        populate_header(&mut edid);
        populate_edid_version(&mut edid);
        populate_detailed_timings(&mut edid, info);
        populate_standard_timings(&mut edid)?;

        calculate_checksum(&mut edid);

        Ok(OkEdid(Self { bytes: edid }))
    }
}

fn populate_detailed_timings(edid: &mut [u8], info: &DisplayInfo) {
    // Eventually we probably want to grab the display's underlying supported resolutions.
    let detailed_resolutions = [
        info.resolution,
        Resolution::new(1920, 1080),
        Resolution::new(1366, 768),
        Resolution::new(2560, 1600),
    ];

    let mut info: DisplayInfo = *info;
    for (block, resolution) in detailed_resolutions.iter().enumerate() {
        info.resolution = *resolution;
        populate_detailed_timing(edid, &info, block)
    }
}

fn populate_detailed_timing(edid: &mut [u8], info: &DisplayInfo, block: usize) {
    const DETAILED_TIMING_BLOCK_SIZE: usize = 18;
    let block_offset: usize = 54 + (DETAILED_TIMING_BLOCK_SIZE * block);

    // Detailed timings
    //
    // 18 Byte Descriptors - 72 Bytes
    // The 72 bytes in this section are divided into four data fields. Each of the four data fields
    // are 18 bytes in length. These 18 byte data fields shall contain either detailed timing data
    // as described in Section 3.10.2 or other types of data as described in Section 3.10.3. The
    // addresses and the contents of the four 18 byte descriptors are shown in Table 3.20.
    //
    // We leave the bottom 6 bytes of this block purposefully empty.
    let horizontal_blanking_lsb: u8 = (info.horizontal_blanking & 0xFF) as u8;
    let horizontal_blanking_msb: u8 = ((info.horizontal_blanking >> 8) & 0x0F) as u8;

    let vertical_blanking_lsb: u8 = (info.vertical_blanking & 0xFF) as u8;
    let vertical_blanking_msb: u8 = ((info.vertical_blanking >> 8) & 0x0F) as u8;

    // The pixel clock is what controls the refresh timing information.
    //
    // The formula for getting refresh rate out of this value is:
    //   refresh_rate = clk * 10000 / (htotal * vtotal)
    // Solving for clk:
    //   clk = (refresh_rate * htotal * votal) / 10000
    //
    // where:
    //   clk - The setting here
    //   vtotal - Total lines
    //   htotal - Total pixels per line
    //
    // Value here is pixel clock + 10,000, in 10khz steps.
    //
    // Pseudocode of kernel logic for vrefresh:
    //    vtotal := mode->vtotal;
    //    calc_val := (clock * 1000) / htotal
    //    refresh := (calc_val + vtotal / 2) / vtotal
    //    if flags & INTERLACE: refresh *= 2
    //    if flags & DBLSCAN: refresh /= 2
    //    if vscan > 1: refresh /= vscan
    //
    let htotal = info.width() + (info.horizontal_blanking as u32);
    let vtotal = info.height() + (info.vertical_blanking as u32);
    let mut clock: u16 = ((info.refresh_rate * htotal * vtotal) / 10000) as u16;
    // Round to nearest 10khz.
    clock = ((clock + 5) / 10) * 10;
    edid[block_offset..block_offset + 2].copy_from_slice(&clock.to_le_bytes());

    let width_lsb: u8 = (info.width() & 0xFF) as u8;
    let width_msb: u8 = ((info.width() >> 8) & 0x0F) as u8;

    // Horizointal Addressable Video in pixels.
    edid[block_offset + 2] = width_lsb;
    // Horizontal blanking in pixels.
    edid[block_offset + 3] = horizontal_blanking_lsb;
    // Upper bits of the two above vals.
    edid[block_offset + 4] = horizontal_blanking_msb | (width_msb << 4) as u8;

    let vertical_active: u32 = info.height();
    let vertical_active_lsb: u8 = (vertical_active & 0xFF) as u8;
    let vertical_active_msb: u8 = ((vertical_active >> 8) & 0x0F) as u8;

    // Vertical addressable video in *lines*
    edid[block_offset + 5] = vertical_active_lsb;
    // Vertical blanking in lines
    edid[block_offset + 6] = vertical_blanking_lsb;
    // Sigbits of the above.
    edid[block_offset + 7] = vertical_blanking_msb | (vertical_active_msb << 4);

    let horizontal_front_lsb: u8 = (info.horizontal_front & 0xFF) as u8; // least sig 8 bits
    let horizontal_front_msb: u8 = ((info.horizontal_front >> 8) & 0x03) as u8; // most sig 2 bits
    let horizontal_sync_lsb: u8 = (info.horizontal_sync & 0xFF) as u8; // least sig 8 bits
    let horizontal_sync_msb: u8 = ((info.horizontal_sync >> 8) & 0x03) as u8; // most sig 2 bits

    let vertical_front_lsb: u8 = (info.vertical_front & 0x0F) as u8; // least sig 4 bits
    let vertical_front_msb: u8 = ((info.vertical_front >> 8) & 0x0F) as u8; // most sig 2 bits
    let vertical_sync_lsb: u8 = (info.vertical_sync & 0xFF) as u8; // least sig 4 bits
    let vertical_sync_msb: u8 = ((info.vertical_sync >> 8) & 0x0F) as u8; // most sig 2 bits

    // Horizontal front porch in pixels.
    edid[block_offset + 8] = horizontal_front_lsb;
    // Horizontal sync pulse width in pixels.
    edid[block_offset + 9] = horizontal_sync_lsb;
    // LSB of vertical front porch and sync pulse
    edid[block_offset + 10] = vertical_sync_lsb | (vertical_front_lsb << 4);
    // Upper 2 bits of these values.
    edid[block_offset + 11] = vertical_sync_msb
        | (vertical_front_msb << 2)
        | (horizontal_sync_msb << 4)
        | (horizontal_front_msb << 6);
}

// The EDID header. This is defined by the EDID spec.
fn populate_header(edid: &mut [u8]) {
    edid[0] = 0x00;
    edid[1] = 0xFF;
    edid[2] = 0xFF;
    edid[3] = 0xFF;
    edid[4] = 0xFF;
    edid[5] = 0xFF;
    edid[6] = 0xFF;
    edid[7] = 0x00;
}

// The standard timings are 8 timing modes with a lower priority (and different data format)
// than the 4 detailed timing modes.
fn populate_standard_timings(edid: &mut [u8]) -> VirtioGpuResult {
    let resolutions = [
        Resolution::new(1440, 900),
        Resolution::new(1600, 900),
        Resolution::new(800, 600),
        Resolution::new(1680, 1050),
        Resolution::new(1856, 1392),
        Resolution::new(1280, 1024),
        Resolution::new(1400, 1050),
        Resolution::new(1920, 1200),
    ];

    // Index 0 is horizontal pixels / 8 - 31
    // Index 1 is a combination of the refresh_rate - 60 (so we are setting to 0, for now) and two
    // bits for the aspect ratio.
    for (index, r) in resolutions.iter().enumerate() {
        edid[0x26 + (index * 2)] = (r.width / 8 - 31) as u8;
        let ar_bits = match r.get_aspect_ratio() {
            (8, 5) => 0x0,
            (4, 3) => 0x1,
            (5, 4) => 0x2,
            (16, 9) => 0x3,
            (x, y) => return Err(ErrEdid(format!("Unsupported aspect ratio: {} {}", x, y))),
        };
        edid[0x27 + (index * 2)] = ar_bits;
    }
    Ok(OkNoData)
}

// Per the EDID spec, needs to be 1 and 4.
fn populate_edid_version(edid: &mut [u8]) {
    edid[18] = 1;
    edid[19] = 4;
}

fn calculate_checksum(edid: &mut [u8]) {
    let mut checksum: u8 = 0;
    for byte in edid.iter().take(EDID_DATA_LENGTH - 1) {
        checksum = checksum.wrapping_add(*byte);
    }

    if checksum != 0 {
        checksum = 255 - checksum + 1;
    }

    edid[127] = checksum;
}
<commit_msg>gpu: populate more EDID info<commit_after>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Implementation of the EDID specification provided by software.
//! EDID spec: https://glenwing.github.io/docs/VESA-EEDID-A2.pdf

use std::fmt;
use std::fmt::Debug;

use super::protocol::GpuResponse::*;
use super::protocol::VirtioGpuResult;

const EDID_DATA_LENGTH: usize = 128;
const DEFAULT_HORIZONTAL_BLANKING: u16 = 560;
const DEFAULT_VERTICAL_BLANKING: u16 = 50;
const DEFAULT_HORIZONTAL_FRONT_PORCH: u16 = 64;
const DEFAULT_VERTICAL_FRONT_PORCH: u16 = 1;
const DEFAULT_HORIZONTAL_SYNC_PULSE: u16 = 192;
const DEFAULT_VERTICAL_SYNC_PULSE: u16 = 3;

/// This class is used to create the Extended Display Identification Data (EDID), which will be
/// exposed to the guest system.
///
/// We ignore most of the spec, the point here being for us to provide enough for graphics to work
/// and to allow us to configure the resolution and refresh rate (via the preferred timing mode
/// pixel clock).
///
/// The EDID spec defines a number of methods to provide mode information, but in priority order the
/// "detailed" timing information is first, so we provide a single block of detailed timing
/// information and no other form of timing information.
#[repr(C)]
pub struct EdidBytes {
    bytes: [u8; EDID_DATA_LENGTH],
}

impl EdidBytes {
    pub fn len(&self) -> usize {
        self.bytes.len()
    }

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

impl Debug for EdidBytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.bytes[..].fmt(f)
    }
}

impl PartialEq for EdidBytes {
    fn eq(&self, other: &EdidBytes) -> bool {
        self.bytes[..] == other.bytes[..]
    }
}

#[derive(Copy, Clone)]
pub struct Resolution {
    width: u32,
    height: u32,
}

impl Resolution {
    fn new(width: u32, height: u32) -> Resolution {
        Resolution { width, height }
    }

    fn get_aspect_ratio(&self) -> (u32, u32) {
        let divisor = gcd(self.width, self.height);
        (self.width / divisor, self.height / divisor)
    }
}

fn gcd(x: u32, y: u32) -> u32 {
    match y {
        0 => x,
        _ => gcd(y, x % y),
    }
}

#[derive(Copy, Clone)]
pub struct DisplayInfo {
    resolution: Resolution,
    refresh_rate: u32,
    horizontal_blanking: u16,
    vertical_blanking: u16,
    horizontal_front: u16,
    vertical_front: u16,
    horizontal_sync: u16,
    vertical_sync: u16,
}

impl DisplayInfo {
    /// Only width, height and refresh rate are required for the graphics stack to work, so instead
    /// of pulling actual numbers from the system, we just use some typical values to populate other
    /// fields for now.
    pub fn new(width: u32, height: u32, refresh_rate: u32) -> Self {
        Self {
            resolution: Resolution::new(width, height),
            refresh_rate,
            horizontal_blanking: DEFAULT_HORIZONTAL_BLANKING,
            vertical_blanking: DEFAULT_VERTICAL_BLANKING,
            horizontal_front: DEFAULT_HORIZONTAL_FRONT_PORCH,
            vertical_front: DEFAULT_VERTICAL_FRONT_PORCH,
            horizontal_sync: DEFAULT_HORIZONTAL_SYNC_PULSE,
            vertical_sync: DEFAULT_VERTICAL_SYNC_PULSE,
        }
    }

    pub fn width(&self) -> u32 {
        self.resolution.width
    }

    pub fn height(&self) -> u32 {
        self.resolution.height
    }
}

impl EdidBytes {
    /// Creates a virtual EDID block.
    pub fn new(info: &DisplayInfo) -> VirtioGpuResult {
        let mut edid: [u8; EDID_DATA_LENGTH] = [0; EDID_DATA_LENGTH];

        populate_header(&mut edid);
        populate_edid_version(&mut edid);
        populate_standard_timings(&mut edid)?;

        // 4 available descriptor blocks
        let block0 = &mut edid[54..72];
        populate_detailed_timing(block0, info);

        let block1 = &mut edid[72..90];
        populate_display_name(block1);

        calculate_checksum(&mut edid);

        Ok(OkEdid(Self { bytes: edid }))
    }
}

fn populate_display_name(edid_block: &mut [u8]) {
    // Display Product Name String Descriptor Tag
    edid_block[0..5].clone_from_slice(&[0x00, 0x00, 0x00, 0xFC, 0x00]);
    edid_block[5..].clone_from_slice("CrosvmDisplay".as_bytes());
}

fn populate_detailed_timing(edid_block: &mut [u8], info: &DisplayInfo) {
    assert_eq!(edid_block.len(), 18);

    // Detailed timings
    //
    // 18 Byte Descriptors - 72 Bytes
    // The 72 bytes in this section are divided into four data fields. Each of the four data fields
    // are 18 bytes in length. These 18 byte data fields shall contain either detailed timing data
    // as described in Section 3.10.2 or other types of data as described in Section 3.10.3. The
    // addresses and the contents of the four 18 byte descriptors are shown in Table 3.20.
    //
    // We leave the bottom 6 bytes of this block purposefully empty.
    let horizontal_blanking_lsb: u8 = (info.horizontal_blanking & 0xFF) as u8;
    let horizontal_blanking_msb: u8 = ((info.horizontal_blanking >> 8) & 0x0F) as u8;

    let vertical_blanking_lsb: u8 = (info.vertical_blanking & 0xFF) as u8;
    let vertical_blanking_msb: u8 = ((info.vertical_blanking >> 8) & 0x0F) as u8;

    // The pixel clock is what controls the refresh timing information.
    //
    // The formula for getting refresh rate out of this value is:
    //   refresh_rate = clk * 10000 / (htotal * vtotal)
    // Solving for clk:
    //   clk = (refresh_rate * htotal * votal) / 10000
    //
    // where:
    //   clk - The setting here
    //   vtotal - Total lines
    //   htotal - Total pixels per line
    //
    // Value here is pixel clock + 10,000, in 10khz steps.
    //
    // Pseudocode of kernel logic for vrefresh:
    //    vtotal := mode->vtotal;
    //    calc_val := (clock * 1000) / htotal
    //    refresh := (calc_val + vtotal / 2) / vtotal
    //    if flags & INTERLACE: refresh *= 2
    //    if flags & DBLSCAN: refresh /= 2
    //    if vscan > 1: refresh /= vscan
    //
    let htotal = info.width() + (info.horizontal_blanking as u32);
    let vtotal = info.height() + (info.vertical_blanking as u32);
    let mut clock: u16 = ((info.refresh_rate * htotal * vtotal) / 10000) as u16;
    // Round to nearest 10khz.
    clock = ((clock + 5) / 10) * 10;
    edid_block[0..2].copy_from_slice(&clock.to_le_bytes());

    let width_lsb: u8 = (info.width() & 0xFF) as u8;
    let width_msb: u8 = ((info.width() >> 8) & 0x0F) as u8;

    // Horizointal Addressable Video in pixels.
    edid_block[2] = width_lsb;
    // Horizontal blanking in pixels.
    edid_block[3] = horizontal_blanking_lsb;
    // Upper bits of the two above vals.
    edid_block[4] = horizontal_blanking_msb | (width_msb << 4) as u8;

    let vertical_active: u32 = info.height();
    let vertical_active_lsb: u8 = (vertical_active & 0xFF) as u8;
    let vertical_active_msb: u8 = ((vertical_active >> 8) & 0x0F) as u8;

    // Vertical addressable video in *lines*
    edid_block[5] = vertical_active_lsb;
    // Vertical blanking in lines
    edid_block[6] = vertical_blanking_lsb;
    // Sigbits of the above.
    edid_block[7] = vertical_blanking_msb | (vertical_active_msb << 4);

    let horizontal_front_lsb: u8 = (info.horizontal_front & 0xFF) as u8; // least sig 8 bits
    let horizontal_front_msb: u8 = ((info.horizontal_front >> 8) & 0x03) as u8; // most sig 2 bits
    let horizontal_sync_lsb: u8 = (info.horizontal_sync & 0xFF) as u8; // least sig 8 bits
    let horizontal_sync_msb: u8 = ((info.horizontal_sync >> 8) & 0x03) as u8; // most sig 2 bits

    let vertical_front_lsb: u8 = (info.vertical_front & 0x0F) as u8; // least sig 4 bits
    let vertical_front_msb: u8 = ((info.vertical_front >> 8) & 0x0F) as u8; // most sig 2 bits
    let vertical_sync_lsb: u8 = (info.vertical_sync & 0xFF) as u8; // least sig 4 bits
    let vertical_sync_msb: u8 = ((info.vertical_sync >> 8) & 0x0F) as u8; // most sig 2 bits

    // Horizontal front porch in pixels.
    edid_block[8] = horizontal_front_lsb;
    // Horizontal sync pulse width in pixels.
    edid_block[9] = horizontal_sync_lsb;
    // LSB of vertical front porch and sync pulse
    edid_block[10] = vertical_sync_lsb | (vertical_front_lsb << 4);
    // Upper 2 bits of these values.
    edid_block[11] = vertical_sync_msb
        | (vertical_front_msb << 2)
        | (horizontal_sync_msb << 4)
        | (horizontal_front_msb << 6);
}

// The EDID header. This is defined by the EDID spec.
fn populate_header(edid: &mut [u8]) {
    edid[0] = 0x00;
    edid[1] = 0xFF;
    edid[2] = 0xFF;
    edid[3] = 0xFF;
    edid[4] = 0xFF;
    edid[5] = 0xFF;
    edid[6] = 0xFF;
    edid[7] = 0x00;

    let manufacturer_name: [char; 3] = ['G', 'G', 'L'];
    // 00001 -> A, 00010 -> B, etc
    let manufacturer_id: u16 = manufacturer_name
        .iter()
        .map(|c| (*c as u8 - b'A' + 1) & 0x1F)
        .fold(0u16, |res, lsb| (res << 5) | (lsb as u16));
    edid[8..10].copy_from_slice(&manufacturer_id.to_be_bytes());

    let manufacture_product_id: u16 = 1;
    edid[10..12].copy_from_slice(&manufacture_product_id.to_le_bytes());

    let serial_id: u32 = 1;
    edid[12..16].copy_from_slice(&serial_id.to_le_bytes());

    let manufacture_week: u8 = 8;
    edid[16] = manufacture_week;

    let manufacture_year: u32 = 2022;
    edid[17] = (manufacture_year - 1990u32) as u8;
}

// The standard timings are 8 timing modes with a lower priority (and different data format)
// than the 4 detailed timing modes.
fn populate_standard_timings(edid: &mut [u8]) -> VirtioGpuResult {
    let resolutions = [
        Resolution::new(1440, 900),
        Resolution::new(1600, 900),
        Resolution::new(800, 600),
        Resolution::new(1680, 1050),
        Resolution::new(1856, 1392),
        Resolution::new(1280, 1024),
        Resolution::new(1400, 1050),
        Resolution::new(1920, 1200),
    ];

    // Index 0 is horizontal pixels / 8 - 31
    // Index 1 is a combination of the refresh_rate - 60 (so we are setting to 0, for now) and two
    // bits for the aspect ratio.
    for (index, r) in resolutions.iter().enumerate() {
        edid[0x26 + (index * 2)] = (r.width / 8 - 31) as u8;
        let ar_bits = match r.get_aspect_ratio() {
            (8, 5) => 0x0,
            (4, 3) => 0x1,
            (5, 4) => 0x2,
            (16, 9) => 0x3,
            (x, y) => return Err(ErrEdid(format!("Unsupported aspect ratio: {} {}", x, y))),
        };
        edid[0x27 + (index * 2)] = ar_bits;
    }
    Ok(OkNoData)
}

// Per the EDID spec, needs to be 1 and 4.
fn populate_edid_version(edid: &mut [u8]) {
    edid[18] = 1;
    edid[19] = 4;
}

fn calculate_checksum(edid: &mut [u8]) {
    let mut checksum: u8 = 0;
    for byte in edid.iter().take(EDID_DATA_LENGTH - 1) {
        checksum = checksum.wrapping_add(*byte);
    }

    if checksum != 0 {
        checksum = 255 - checksum + 1;
    }

    edid[127] = checksum;
}
<|endoftext|>