<commit_before>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
use std::ops::Bound;
use tikv_util::keybuilder::KeyBuilder;

#[derive(Clone)]
pub struct ReadOptions {
    fill_cache: bool,
}

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

    #[inline]
    pub fn fill_cache(&self) -> bool {
        self.fill_cache
    }

    #[inline]
    pub fn set_fill_cache(&mut self, v: bool) {
        self.fill_cache = v;
    }
}

impl Default for ReadOptions {
    fn default() -> ReadOptions {
        ReadOptions { fill_cache: false }
    }
}

#[derive(Clone)]
pub struct WriteOptions {
    sync: bool,
}

impl WriteOptions {
    pub fn new() -> WriteOptions {
        WriteOptions { sync: false }
    }

    pub fn set_sync(&mut self, sync: bool) {
        self.sync = sync;
    }

    pub fn sync(&self) -> bool {
        self.sync
    }
}

impl Default for WriteOptions {
    fn default() -> WriteOptions {
        WriteOptions { sync: false }
    }
}

#[derive(Clone, PartialEq)]
pub enum SeekMode {
    TotalOrder,
    Prefix,
}

#[derive(Clone)]
pub struct IterOptions {
    lower_bound: Option<KeyBuilder>,
    upper_bound: Option<KeyBuilder>,
    prefix_same_as_start: bool,
    fill_cache: bool,
    // hint for we will only scan data with commit ts >= hint_min_ts
    hint_min_ts: Option<u64>,
    // hint for we will only scan data with commit ts <= hint_max_ts
    hint_max_ts: Option<u64>,
    // only supported when Titan enabled, otherwise it doesn't take effect.
    key_only: bool,
    seek_mode: SeekMode,
}

impl IterOptions {
    pub fn new(
        lower_bound: Option<KeyBuilder>,
        upper_bound: Option<KeyBuilder>,
        fill_cache: bool,
    ) -> IterOptions {
        IterOptions {
            lower_bound,
            upper_bound,
            prefix_same_as_start: false,
            fill_cache,
            hint_min_ts: None,
            hint_max_ts: None,
            key_only: false,
            seek_mode: SeekMode::TotalOrder,
        }
    }

    #[inline]
    pub fn use_prefix_seek(mut self) -> IterOptions {
        self.seek_mode = SeekMode::Prefix;
        self
    }

    #[inline]
    pub fn total_order_seek_used(&self) -> bool {
        self.seek_mode == SeekMode::TotalOrder
    }

    #[inline]
    pub fn fill_cache(&self) -> bool {
        self.fill_cache
    }

    #[inline]
    pub fn set_fill_cache(&mut self, v: bool) {
        self.fill_cache = v;
    }

    #[inline]
    pub fn set_hint_min_ts(&mut self, bound_ts: Bound<u64>) {
        match bound_ts {
            Bound::Included(ts) => self.hint_min_ts = Some(ts),
            Bound::Excluded(ts) => self.hint_min_ts = Some(ts + 1),
            Bound::Unbounded => self.hint_min_ts = None,
        }
    }

    #[inline]
    pub fn hint_min_ts(&self) -> Option<u64> {
        self.hint_min_ts
    }

    #[inline]
    pub fn hint_max_ts(&self) -> Option<u64> {
        self.hint_max_ts
    }

    #[inline]
    pub fn set_hint_max_ts(&mut self, bound_ts: Bound<u64>) {
        match bound_ts {
            Bound::Included(ts) => self.hint_max_ts = Some(ts),
            Bound::Excluded(ts) => self.hint_max_ts = Some(ts - 1),
            Bound::Unbounded => self.hint_max_ts = None,
        }
    }

    #[inline]
    pub fn key_only(&self) -> bool {
        self.key_only
    }

    #[inline]
    pub fn set_key_only(&mut self, v: bool) {
        self.key_only = v;
    }

    #[inline]
    pub fn lower_bound(&self) -> Option<&[u8]> {
        self.lower_bound.as_ref().map(|v| v.as_slice())
    }

    #[inline]
    pub fn set_lower_bound(&mut self, bound: &[u8], reserved_prefix_len: usize) {
        let builder = KeyBuilder::from_slice(bound, reserved_prefix_len, 0);
        self.lower_bound = Some(builder);
    }

    pub fn set_vec_lower_bound(&mut self, bound: Vec<u8>) {
        self.lower_bound = Some(KeyBuilder::from_vec(bound, 0, 0));
    }

    pub fn set_lower_bound_prefix(&mut self, prefix: &[u8]) {
        if let Some(ref mut builder) = self.lower_bound {
            builder.set_prefix(prefix);
        }
    }

    #[inline]
    pub fn upper_bound(&self) -> Option<&[u8]> {
        self.upper_bound.as_ref().map(|v| v.as_slice())
    }

    #[inline]
    pub fn set_upper_bound(&mut self, bound: &[u8], reserved_prefix_len: usize) {
        let builder = KeyBuilder::from_slice(bound, reserved_prefix_len, 0);
        self.upper_bound = Some(builder);
    }

    pub fn set_vec_upper_bound(&mut self, bound: Vec<u8>) {
        self.upper_bound = Some(KeyBuilder::from_vec(bound, 0, 0));
    }

    pub fn set_upper_bound_prefix(&mut self, prefix: &[u8]) {
        if let Some(ref mut builder) = self.upper_bound {
            builder.set_prefix(prefix);
        }
    }

    #[inline]
    pub fn build_bounds(self) -> (Option<Vec<u8>>, Option<Vec<u8>>) {
        let lower = self.lower_bound.map(KeyBuilder::build);
        let upper = self.upper_bound.map(KeyBuilder::build);
        (lower, upper)
    }

    #[inline]
    pub fn prefix_same_as_start(&self) -> bool {
        self.prefix_same_as_start
    }

    #[inline]
    pub fn set_prefix_same_as_start(mut self, enable: bool) -> IterOptions {
        self.prefix_same_as_start = enable;
        self
    }
}

impl Default for IterOptions {
    fn default() -> IterOptions {
        IterOptions {
            lower_bound: None,
            upper_bound: None,
            prefix_same_as_start: false,
            fill_cache: true,
            hint_min_ts: None,
            hint_max_ts: None,
            key_only: false,
            seek_mode: SeekMode::TotalOrder,
        }
    }
}

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

    #[test]
    fn test_hint_ts() {
        let mut ops = IterOptions::default();
        assert_eq!(ops.hint_min_ts(), None);
        assert_eq!(ops.hint_max_ts(), None);

        ops.set_hint_min_ts(Bound::Included(1));
        ops.set_hint_max_ts(Bound::Included(10));
        assert_eq!(ops.hint_min_ts(), Some(1));
        assert_eq!(ops.hint_max_ts(), Some(10));

        ops.set_hint_min_ts(Bound::Excluded(1));
        ops.set_hint_max_ts(Bound::Excluded(10));
        assert_eq!(ops.hint_min_ts(), Some(2));
        assert_eq!(ops.hint_max_ts(), Some(9));
    }
}
<commit_msg>engine_traits: fix default value for fill cache (#8392)<commit_after>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
use std::ops::Bound;
use tikv_util::keybuilder::KeyBuilder;

#[derive(Clone)]
pub struct ReadOptions {
    fill_cache: bool,
}

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

    #[inline]
    pub fn fill_cache(&self) -> bool {
        self.fill_cache
    }

    #[inline]
    pub fn set_fill_cache(&mut self, v: bool) {
        self.fill_cache = v;
    }
}

impl Default for ReadOptions {
    fn default() -> ReadOptions {
        ReadOptions { fill_cache: true }
    }
}

#[derive(Clone)]
pub struct WriteOptions {
    sync: bool,
}

impl WriteOptions {
    pub fn new() -> WriteOptions {
        WriteOptions { sync: false }
    }

    pub fn set_sync(&mut self, sync: bool) {
        self.sync = sync;
    }

    pub fn sync(&self) -> bool {
        self.sync
    }
}

impl Default for WriteOptions {
    fn default() -> WriteOptions {
        WriteOptions { sync: false }
    }
}

#[derive(Clone, PartialEq)]
pub enum SeekMode {
    TotalOrder,
    Prefix,
}

#[derive(Clone)]
pub struct IterOptions {
    lower_bound: Option<KeyBuilder>,
    upper_bound: Option<KeyBuilder>,
    prefix_same_as_start: bool,
    fill_cache: bool,
    // hint for we will only scan data with commit ts >= hint_min_ts
    hint_min_ts: Option<u64>,
    // hint for we will only scan data with commit ts <= hint_max_ts
    hint_max_ts: Option<u64>,
    // only supported when Titan enabled, otherwise it doesn't take effect.
    key_only: bool,
    seek_mode: SeekMode,
}

impl IterOptions {
    pub fn new(
        lower_bound: Option<KeyBuilder>,
        upper_bound: Option<KeyBuilder>,
        fill_cache: bool,
    ) -> IterOptions {
        IterOptions {
            lower_bound,
            upper_bound,
            prefix_same_as_start: false,
            fill_cache,
            hint_min_ts: None,
            hint_max_ts: None,
            key_only: false,
            seek_mode: SeekMode::TotalOrder,
        }
    }

    #[inline]
    pub fn use_prefix_seek(mut self) -> IterOptions {
        self.seek_mode = SeekMode::Prefix;
        self
    }

    #[inline]
    pub fn total_order_seek_used(&self) -> bool {
        self.seek_mode == SeekMode::TotalOrder
    }

    #[inline]
    pub fn fill_cache(&self) -> bool {
        self.fill_cache
    }

    #[inline]
    pub fn set_fill_cache(&mut self, v: bool) {
        self.fill_cache = v;
    }

    #[inline]
    pub fn set_hint_min_ts(&mut self, bound_ts: Bound<u64>) {
        match bound_ts {
            Bound::Included(ts) => self.hint_min_ts = Some(ts),
            Bound::Excluded(ts) => self.hint_min_ts = Some(ts + 1),
            Bound::Unbounded => self.hint_min_ts = None,
        }
    }

    #[inline]
    pub fn hint_min_ts(&self) -> Option<u64> {
        self.hint_min_ts
    }

    #[inline]
    pub fn hint_max_ts(&self) -> Option<u64> {
        self.hint_max_ts
    }

    #[inline]
    pub fn set_hint_max_ts(&mut self, bound_ts: Bound<u64>) {
        match bound_ts {
            Bound::Included(ts) => self.hint_max_ts = Some(ts),
            Bound::Excluded(ts) => self.hint_max_ts = Some(ts - 1),
            Bound::Unbounded => self.hint_max_ts = None,
        }
    }

    #[inline]
    pub fn key_only(&self) -> bool {
        self.key_only
    }

    #[inline]
    pub fn set_key_only(&mut self, v: bool) {
        self.key_only = v;
    }

    #[inline]
    pub fn lower_bound(&self) -> Option<&[u8]> {
        self.lower_bound.as_ref().map(|v| v.as_slice())
    }

    #[inline]
    pub fn set_lower_bound(&mut self, bound: &[u8], reserved_prefix_len: usize) {
        let builder = KeyBuilder::from_slice(bound, reserved_prefix_len, 0);
        self.lower_bound = Some(builder);
    }

    pub fn set_vec_lower_bound(&mut self, bound: Vec<u8>) {
        self.lower_bound = Some(KeyBuilder::from_vec(bound, 0, 0));
    }

    pub fn set_lower_bound_prefix(&mut self, prefix: &[u8]) {
        if let Some(ref mut builder) = self.lower_bound {
            builder.set_prefix(prefix);
        }
    }

    #[inline]
    pub fn upper_bound(&self) -> Option<&[u8]> {
        self.upper_bound.as_ref().map(|v| v.as_slice())
    }

    #[inline]
    pub fn set_upper_bound(&mut self, bound: &[u8], reserved_prefix_len: usize) {
        let builder = KeyBuilder::from_slice(bound, reserved_prefix_len, 0);
        self.upper_bound = Some(builder);
    }

    pub fn set_vec_upper_bound(&mut self, bound: Vec<u8>) {
        self.upper_bound = Some(KeyBuilder::from_vec(bound, 0, 0));
    }

    pub fn set_upper_bound_prefix(&mut self, prefix: &[u8]) {
        if let Some(ref mut builder) = self.upper_bound {
            builder.set_prefix(prefix);
        }
    }

    #[inline]
    pub fn build_bounds(self) -> (Option<Vec<u8>>, Option<Vec<u8>>) {
        let lower = self.lower_bound.map(KeyBuilder::build);
        let upper = self.upper_bound.map(KeyBuilder::build);
        (lower, upper)
    }

    #[inline]
    pub fn prefix_same_as_start(&self) -> bool {
        self.prefix_same_as_start
    }

    #[inline]
    pub fn set_prefix_same_as_start(mut self, enable: bool) -> IterOptions {
        self.prefix_same_as_start = enable;
        self
    }
}

impl Default for IterOptions {
    fn default() -> IterOptions {
        IterOptions {
            lower_bound: None,
            upper_bound: None,
            prefix_same_as_start: false,
            fill_cache: true,
            hint_min_ts: None,
            hint_max_ts: None,
            key_only: false,
            seek_mode: SeekMode::TotalOrder,
        }
    }
}

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

    #[test]
    fn test_hint_ts() {
        let mut ops = IterOptions::default();
        assert_eq!(ops.hint_min_ts(), None);
        assert_eq!(ops.hint_max_ts(), None);

        ops.set_hint_min_ts(Bound::Included(1));
        ops.set_hint_max_ts(Bound::Included(10));
        assert_eq!(ops.hint_min_ts(), Some(1));
        assert_eq!(ops.hint_max_ts(), Some(10));

        ops.set_hint_min_ts(Bound::Excluded(1));
        ops.set_hint_max_ts(Bound::Excluded(10));
        assert_eq!(ops.hint_min_ts(), Some(2));
        assert_eq!(ops.hint_max_ts(), Some(9));
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro, generators, box_syntax)]
#![allow(non_camel_case_types, non_snake_case)]

extern crate arc_reactor;
use arc_reactor::native_tls::{Pkcs12, TlsAcceptor};
use arc_reactor::{prelude::*, ArcReactor, Router};

fn main() {
	// build the tls acceptor.
	let der = include_bytes!("identity.p12");
	let cert = Pkcs12::from_der(der, "mypass").unwrap();
	let tls_cx = TlsAcceptor::builder(cert).unwrap().build().unwrap();

	ArcReactor::new()
		.port(3000) // port to listen on
		.routes(getMainRoutes())
		.tls(tls_cx) // set the tls acceptor on the arc reactor
		.threads(3)
		.initiate()
		.unwrap()
}

fn getMainRoutes() -> Router {
	// Setup and maps routes to Services.
	return Router::new()
		.get("/", RequestHandler)
}

#[service]
fn RequestHandler(_request: Request, mut res: Response) {
	res.set_body("hello world");

	Ok(res)
}<commit_msg>updated documentation<commit_after>#![feature(proc_macro, generators, box_syntax)]
#![allow(non_camel_case_types, non_snake_case)]

extern crate arc_reactor;
use arc_reactor::native_tls::{Pkcs12, TlsAcceptor};
use arc_reactor::{prelude::*, ArcReactor, Router};

fn main() {
	// build the tls acceptor.
	let der = include_bytes!("identity.p12");
	let cert = Pkcs12::from_der(der, "mypass").unwrap();
	let tls_cx = TlsAcceptor::builder(cert).unwrap().build().unwrap();

	ArcReactor::new()
		.port(3000) // port to listen on
		.routes(getMainRoutes())
		.tls(tls_cx) // set the tls acceptor on the arc reactor
		.threads(3)
		.initiate()
		.unwrap()
	// now visit https://localhost:3000 in your browser.
}

fn getMainRoutes() -> Router {
	// Setup and maps routes to Services.
	Router::new()
		.get("/", RequestHandler)
}

#[service]
fn RequestHandler(_request: Request, mut res: Response) {
	res.set_body("hello world");

	Ok(res)
}
<|endoftext|>


<commit_before>extern crate tempfile;

use std::collections::BTreeMap;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Write;
use std::ffi::OsStr;
use std::fs::File;
use std::process::Command;
use self::tempfile::NamedTempFileOptions;

pub enum Strand {
    Plus,
    Minus,
    Both
}

fn write_chrom_info(filename: &str, chroms: &Vec<String>, chrom_sizes: &Vec<u32>) -> Result<(), Error> {
    let mut f = try!(File::create(filename));

    for index in 0..chroms.len() {
        try!(write!(f, "{}\t{}\n", chroms[index], chrom_sizes[index]));
    }

    Ok(())
}

fn write_wiggle(filename: &str, chroms: &Vec<String>, counts: &Vec<BTreeMap<u32, (f64, f64)>>, strand: Strand) -> Result<(), Error> {
    // open new file
    let mut f = try!(File::create(filename));

    // write data
    for i in 0..chroms.len() {
        let chrom : &str = &chroms[i];

        try!(write!(f, "variableStep chrom={}\n", chrom));

        for (pos, value) in counts[i].iter() {
            let pos = pos + 1; // shift position by one since wiggleFiles are use 1 based positions

            match strand {
                Strand::Plus => if value.0 > 0f64 { try!(write!(f, "{}\t{}\n", pos, value.0)) },
                Strand::Minus => if value.1 > 0f64 { try!(write!(f, "{}\t{}\n", pos, -value.1)) },
                Strand::Both => try!(write!(f, "{}\t{}\n", pos, value.0 + value.1)),
            }
        }
    }
    Ok(())
}

pub fn write_bigwig(filename: &OsStr, chroms: &Vec<String>, chrom_sizes: &Vec<u32>, counts: &Vec<BTreeMap<u32, (f64, f64)>>, strand: Strand) -> Result<(),Error> {
    // create temporary chromInfo file
    let chrominfo_tmpfile = NamedTempFileOptions::new()
                        .prefix("chromInfo")
                        .suffix(".tmp")
                        .rand_bytes(5)
                        .create()
                        .unwrap();
    let chrominfo_name = chrominfo_tmpfile.path()
                        .file_name().unwrap()
                        .to_str().unwrap();
    try!(write_chrom_info(chrominfo_name, chroms, chrom_sizes));

    // create temporary wiggle file
    let wiggle_tmpfile = NamedTempFileOptions::new()
                        .prefix("wiggle")
                        .suffix(".tmp")
                        .rand_bytes(5)
                        .create()
                        .unwrap();
    let wiggle_name = wiggle_tmpfile.path()
                      .file_name().unwrap()
                      .to_str().unwrap();
    try!(write_wiggle(wiggle_name, chroms, counts, strand));

    // run wigToBigWig
    let status = Command::new("wigToBigWig")
        .arg("-keepAllChromosomes")
        .arg("-clip")
        .arg(wiggle_name)
        .arg(chrominfo_name)
        .arg(filename)
        .status().unwrap_or_else(|e| {
            panic!("failed to execute wigToBigWig: {}", e)
    });

    // NOTE: Temporary files are deleted when their variables (wiggle_tmpfile and chrominfo_tmpfile) go out of scope
    //
    if !status.success() {
        return Err(Error::new(ErrorKind::Other, format!("An error occurred running: wigToBigWig -keepAllChromosomes {:?} {:?} {:?}", filename, wiggle_name, chrominfo_name)));
    }

    Ok(())
}
<commit_msg>Force release (delete) of temporary files<commit_after>extern crate tempfile;

use std::collections::BTreeMap;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Write;
use std::ffi::OsStr;
use std::fs::File;
use std::process::Command;
use self::tempfile::NamedTempFileOptions;

pub enum Strand {
    Plus,
    Minus,
    Both
}

fn write_chrom_info(filename: &str, chroms: &Vec<String>, chrom_sizes: &Vec<u32>) -> Result<(), Error> {
    let mut f = try!(File::create(filename));

    for index in 0..chroms.len() {
        try!(write!(f, "{}\t{}\n", chroms[index], chrom_sizes[index]));
    }

    Ok(())
}

fn write_wiggle(filename: &str, chroms: &Vec<String>, counts: &Vec<BTreeMap<u32, (f64, f64)>>, strand: Strand) -> Result<(), Error> {
    // open new file
    let mut f = try!(File::create(filename));

    // write data
    for i in 0..chroms.len() {
        let chrom : &str = &chroms[i];

        try!(write!(f, "variableStep chrom={}\n", chrom));

        for (pos, value) in counts[i].iter() {
            let pos = pos + 1; // shift position by one since wiggleFiles are use 1 based positions

            match strand {
                Strand::Plus => if value.0 > 0f64 { try!(write!(f, "{}\t{}\n", pos, value.0)) },
                Strand::Minus => if value.1 > 0f64 { try!(write!(f, "{}\t{}\n", pos, -value.1)) },
                Strand::Both => try!(write!(f, "{}\t{}\n", pos, value.0 + value.1)),
            }
        }
    }
    Ok(())
}

pub fn write_bigwig(filename: &OsStr, chroms: &Vec<String>, chrom_sizes: &Vec<u32>, counts: &Vec<BTreeMap<u32, (f64, f64)>>, strand: Strand) -> Result<(),Error> {
    // create temporary chromInfo file
    let chrominfo_tmpfile = NamedTempFileOptions::new()
                        .prefix("chromInfo")
                        .suffix(".tmp")
                        .rand_bytes(5)
                        .create()
                        .unwrap();

    // create temporary wiggle file
    let wiggle_tmpfile = NamedTempFileOptions::new()
                        .prefix("wiggle")
                        .suffix(".tmp")
                        .rand_bytes(5)
                        .create()
                        .unwrap();

    { // block constrains lifetime of borrow on temporary file names
        // write to temporary files
        let chrominfo_name = chrominfo_tmpfile.path()
                            .file_name().unwrap()
                            .to_str().unwrap();
        try!(write_chrom_info(chrominfo_name, chroms, chrom_sizes));

        let wiggle_name = wiggle_tmpfile.path()
                        .file_name().unwrap()
                        .to_str().unwrap();
        try!(write_wiggle(wiggle_name, chroms, counts, strand));

        // run wigToBigWig
        let status = Command::new("wigToBigWig")
            .arg("-keepAllChromosomes")
            .arg("-clip")
            .arg(wiggle_name)
            .arg(chrominfo_name)
            .arg(filename)
            .status().unwrap_or_else(|e| {
                panic!("failed to execute wigToBigWig: {}", e)
        });

        //
        if !status.success() {
            return Err(Error::new(ErrorKind::Other, format!("An error occurred running: wigToBigWig -keepAllChromosomes {:?} {:?} {:?}", filename, wiggle_name, chrominfo_name)));
        }
    }

    // force release of temporary files
    wiggle_tmpfile.close().unwrap();
    chrominfo_tmpfile.close().unwrap();

    Ok(())
}
<|endoftext|>


<commit_before>use i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use i2cdev::linux::*;

use utils::*;

struct CompensationParams {
    t1: u16,
    t2: i16,
    t3: i16,
    h1: u8,
    h2: i16,
    h3: u8,
    h4: i16,
    h5: i16,
    h6: i8,
    p1: u16,
    p2: i16,
    p3: i16,
    p4: i16,
    p5: i16,
    p6: i16,
    p7: i16,
    p8: i16,
    p9: i16,
}

impl CompensationParams {
    pub fn new() -> CompensationParams {
        CompensationParams {
            t1: 0,
            t2: 0,
            t3: 0,
            h1: 0,
            h2: 0,
            h3: 0,
            h4: 0,
            h5: 0,
            h6: 0,
            p1: 0,
            p2: 0,
            p3: 0,
            p4: 0,
            p5: 0,
            p6: 0,
            p7: 0,
            p8: 0,
            p9: 0,
        }
    }

    pub fn load(&mut self, dev: &mut LinuxI2CDevice) -> Result<(), LinuxI2CError> {
        self.t1 = read_unsigned_short(dev, 0x88)?;
        self.t2 = read_signed_short(dev, 0x8A)?;
        self.t3 = read_signed_short(dev, 0x8C)?;
        self.h1 = dev.smbus_read_byte_data(0xA1)?;
        self.h2 = read_signed_short(dev, 0xE1)?;
        self.h3 = dev.smbus_read_byte_data(0xE3)?;
        let e4 = dev.smbus_read_byte_data(0xE4)? as i16;
        let e5 = dev.smbus_read_byte_data(0xE5)?;
        let e6 = dev.smbus_read_byte_data(0xE6)? as i16;
        self.h4 = (e4 << 4) + ((e5 & 0x0F) as i16);
        self.h5 = (e6 << 4) + (((e5 & 0xF0) >> 4) as i16);
        self.h6 = dev.smbus_read_byte_data(0xE7)? as i8;
        self.p1 = read_unsigned_short(dev, 0x8E)?;
        self.p2 = read_signed_short(dev, 0x90)?;
        self.p3 = read_signed_short(dev, 0x92)?;
        self.p4 = read_signed_short(dev, 0x94)?;
        self.p5 = read_signed_short(dev, 0x96)?;
        self.p6 = read_signed_short(dev, 0x98)?;
        self.p7 = read_signed_short(dev, 0x9A)?;
        self.p8 = read_signed_short(dev, 0x9C)?;
        self.p9 = read_signed_short(dev, 0x9E)?;
        Ok(())
    }

    pub fn fine_resolution_temp(&self, uncomp_t: u32) -> i32 {
        let t1 = self.t1 as f64;

        let x1 = ((uncomp_t as f64) / 16384.0 - t1 / 1024.0) * (self.t2 as f64);
        let x2_ = (uncomp_t as f64) / 131072.0 - t1 / 8192.0;
        let x2 = (x2_ * x2_) * (self.t3 as f64);
        (x1 + x2) as i32
    }

    pub fn compensated_temp(&self, uncomp_t: u32) -> f64 {
        const MAX: f64 = 85.0;
        const MIN: f64 = -40.0;

        let tf = ((self.fine_resolution_temp(uncomp_t) * 5 + 128) >> 8) as f64;
        (tf / 100.0).max(MIN).min(MAX)
    }

    pub fn compensated_humidity(&self, uncomp_h: u32, uncomp_t: u32) -> f64 {
        const MAX: f64 = 100.0;
        const MIN: f64 = 0.0;

        let t_fine = self.fine_resolution_temp(uncomp_t);
        let x1 = (t_fine as f64) - 76800.0;
        let x2 = ((self.h4 as f64) * 64.0) + ((self.h5 as f64) / 16384.0) * x1;
        let x3 = (uncomp_h as f64) - x2;
        let x4 = (self.h2 as f64) / 65536.0;
        let x5 = 1.0 + ((self.h3 as f64) / 67108864.0 * x1);
        let x6 = 1.0 + ((self.h6 as f64) / 67108864.0) * x1 * x5;
        let x7 = x3 * x4 * (x5 * x6);
        let humidity = x7 * (1.0 - (self.h1 as f64) * x7 / 524288.0);

        humidity.max(MIN).min(MAX)
    }

    pub fn compensated_pressure(&self, uncomp_p: u32, uncomp_t: u32) -> f64 {
        const MAX: f64 = 110000.0;
        const MIN: f64 = 30000.0;

        let t_fine = self.fine_resolution_temp(uncomp_t) as f64;
        let mut x1 = t_fine / 2.0 - 64000.0;
        let mut x2 = x1 * x1 * (self.p6 as f64) / 32768.0;
        x2 = x2 + x1 * (self.p5 as f64) * 2.0;
        x2 = x2 / 4.0 + (self.p4 as f64) * 65536.0;
        let x3 = (self.p3 as f64) * x1 * x1 / 524288.0;
        x1 = (x3 + (self.p2 as f64) * x1) / 524288.0;
        x1 = (1.0 + x1 / 32768.0) * (self.p1 as f64);

        // To avoid zero-division error.
        if x1 == 0.0 {
            return MIN;
        }

        let mut pressure = 1048576.0 - (uncomp_p as f64);
        pressure = (pressure - (x2 / 4096.0)) * 6250.0 / x1;
        x1 = (self.p9 as f64) * pressure * pressure / 2147483648.0;
        x2 = pressure * (self.p8 as f64) / 32768.0;
        pressure = pressure + (x1 + x2 + (self.p7 as f64)) / 16.0;

        pressure.min(MAX).max(MIN)
    }
}

#[derive(Clone)]
pub enum Mode {
    Sleep,
    Force,
    Normal,
}

impl Mode {
    fn to_raw(&self) -> u8 {
        match self {
            &Mode::Sleep => 0,
            &Mode::Force => 1,
            &Mode::Normal => 3,
        }
    }
}

pub enum Oversampling {
    No,
    X1,
    X2,
    X4,
    X8,
    X16,
}

impl Oversampling {
    fn to_raw(&self) -> u8 {
        match self {
            &Oversampling::No => 0,
            &Oversampling::X1 => 1,
            &Oversampling::X2 => 2,
            &Oversampling::X4 => 3,
            &Oversampling::X8 => 4,
            &Oversampling::X16 => 5,
        }
    }
}

pub enum StandbyTime {
    Ms1,
    Ms62_5,
    Ms125,
    Ms250,
    Ms500,
    Ms1000,
    Ms10,
    Ms20,
}

impl StandbyTime {
    fn to_raw(&self) -> u8 {
        match self {
            &StandbyTime::Ms1 => 0,
            &StandbyTime::Ms62_5 => 1,
            &StandbyTime::Ms125 => 2,
            &StandbyTime::Ms250 => 3,
            &StandbyTime::Ms500 => 4,
            &StandbyTime::Ms1000 => 5,
            &StandbyTime::Ms10 => 6,
            &StandbyTime::Ms20 => 7,
        }
    }
}

pub enum IIRFilterCoeff {
    OFF,
    X2,
    X4,
    X8,
    X16,
}

impl IIRFilterCoeff {
    fn to_raw(&self) -> u8 {
        match self {
            &IIRFilterCoeff::OFF => 0,
            &IIRFilterCoeff::X2 => 1,
            &IIRFilterCoeff::X4 => 2,
            &IIRFilterCoeff::X8 => 3,
            &IIRFilterCoeff::X16 => 4,
        }
    }
}

pub struct Config {
    pub mode: Mode,
    pub oversampling_temperature: Oversampling,
    pub oversampling_pressure: Oversampling,
    pub oversampling_humidity: Oversampling,
    pub standby_time: StandbyTime,
    pub filter_coeff: IIRFilterCoeff,
    pub spi3w_enabled: bool,
}

pub struct BME280 {
    device: LinuxI2CDevice,
    config: Config,
    params: CompensationParams,
}

impl BME280 {
    pub fn new(dev: LinuxI2CDevice, config: Config) -> Result<BME280, LinuxI2CError> {
        let params = CompensationParams::new();
        let mut bme280 = BME280 {
            device: dev,
            config: config,
            params: params,
        };
        bme280.params.load(&mut bme280.device)?;
        bme280.initialize()?;
        Ok(bme280)
    }

    fn initialize(&mut self) -> Result<(), LinuxI2CError> {
        let ctrl_hum_reg = self.config.oversampling_humidity.to_raw();
        let ctrl_meas_reg = (self.config.oversampling_temperature.to_raw() << 5) |
                            (self.config.oversampling_pressure.to_raw() << 2) |
                            self.config.mode.to_raw();
        let config_reg = (self.config.standby_time.to_raw() << 5) |
                         (self.config.filter_coeff.to_raw() << 2) |
                         (self.config.spi3w_enabled as u8);

        // ctrl_hum_reg has to be written before ctrl_meas_reg
        self.device.smbus_write_byte_data(0xF2, ctrl_hum_reg)?;
        self.device.smbus_write_byte_data(0xF4, ctrl_meas_reg)?;
        self.device.smbus_write_byte_data(0xF5, config_reg)
    }

    pub fn raw_pressure(&mut self) -> Result<u32, LinuxI2CError> {
        let v = self.device.smbus_read_i2c_block_data(0xF7, 3)?;
        let p0 = v[0] as u32;
        let p1 = v[1] as u32;
        let p2 = v[2] as u32;
        Ok((p0 << 12) + (p1 << 4) + (p2 >> 4))
    }

    pub fn raw_temperature(&mut self) -> Result<u32, LinuxI2CError> {
        let v = self.device.smbus_read_i2c_block_data(0xFA, 3)?;
        let t0 = v[0] as u32;
        let t1 = v[1] as u32;
        let t2 = v[2] as u32;
        Ok((t0 << 12) + (t1 << 4) + (t2 >> 4))
    }

    pub fn raw_humidity(&mut self) -> Result<u32, LinuxI2CError> {
        let v = self.device.smbus_read_i2c_block_data(0xFD, 2)?;
        let h1 = v[0] as u32;
        let h2 = v[1] as u32;
        Ok((h1 << 8) + h2)
    }

    pub fn temperature(&mut self) -> Result<f64, LinuxI2CError> {
        let raw_value = self.raw_temperature()?;
        Ok(self.params.compensated_temp(raw_value))
    }

    pub fn humidity(&mut self) -> Result<f64, LinuxI2CError> {
        let raw_t = self.raw_temperature()?;
        let raw_h = self.raw_humidity()?;
        Ok(self.params.compensated_humidity(raw_h, raw_t))
    }

    pub fn pressure(&mut self) -> Result<f64, LinuxI2CError> {
        let raw_t = self.raw_temperature()?;
        let raw_p = self.raw_pressure()?;
        Ok(self.params.compensated_pressure(raw_p, raw_t))
    }
}
<commit_msg>Implement bme280.soft_reset().<commit_after>use std::{thread, time};

use i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use i2cdev::linux::*;

use utils::*;

struct CompensationParams {
    t1: u16,
    t2: i16,
    t3: i16,
    h1: u8,
    h2: i16,
    h3: u8,
    h4: i16,
    h5: i16,
    h6: i8,
    p1: u16,
    p2: i16,
    p3: i16,
    p4: i16,
    p5: i16,
    p6: i16,
    p7: i16,
    p8: i16,
    p9: i16,
}

impl CompensationParams {
    pub fn new() -> CompensationParams {
        CompensationParams {
            t1: 0,
            t2: 0,
            t3: 0,
            h1: 0,
            h2: 0,
            h3: 0,
            h4: 0,
            h5: 0,
            h6: 0,
            p1: 0,
            p2: 0,
            p3: 0,
            p4: 0,
            p5: 0,
            p6: 0,
            p7: 0,
            p8: 0,
            p9: 0,
        }
    }

    pub fn load(&mut self, dev: &mut LinuxI2CDevice) -> Result<(), LinuxI2CError> {
        self.t1 = read_unsigned_short(dev, 0x88)?;
        self.t2 = read_signed_short(dev, 0x8A)?;
        self.t3 = read_signed_short(dev, 0x8C)?;
        self.h1 = dev.smbus_read_byte_data(0xA1)?;
        self.h2 = read_signed_short(dev, 0xE1)?;
        self.h3 = dev.smbus_read_byte_data(0xE3)?;
        let e4 = dev.smbus_read_byte_data(0xE4)? as i16;
        let e5 = dev.smbus_read_byte_data(0xE5)?;
        let e6 = dev.smbus_read_byte_data(0xE6)? as i16;
        self.h4 = (e4 << 4) + ((e5 & 0x0F) as i16);
        self.h5 = (e6 << 4) + (((e5 & 0xF0) >> 4) as i16);
        self.h6 = dev.smbus_read_byte_data(0xE7)? as i8;
        self.p1 = read_unsigned_short(dev, 0x8E)?;
        self.p2 = read_signed_short(dev, 0x90)?;
        self.p3 = read_signed_short(dev, 0x92)?;
        self.p4 = read_signed_short(dev, 0x94)?;
        self.p5 = read_signed_short(dev, 0x96)?;
        self.p6 = read_signed_short(dev, 0x98)?;
        self.p7 = read_signed_short(dev, 0x9A)?;
        self.p8 = read_signed_short(dev, 0x9C)?;
        self.p9 = read_signed_short(dev, 0x9E)?;
        Ok(())
    }

    pub fn fine_resolution_temp(&self, uncomp_t: u32) -> i32 {
        let t1 = self.t1 as f64;

        let x1 = ((uncomp_t as f64) / 16384.0 - t1 / 1024.0) * (self.t2 as f64);
        let x2_ = (uncomp_t as f64) / 131072.0 - t1 / 8192.0;
        let x2 = (x2_ * x2_) * (self.t3 as f64);
        (x1 + x2) as i32
    }

    pub fn compensated_temp(&self, uncomp_t: u32) -> f64 {
        const MAX: f64 = 85.0;
        const MIN: f64 = -40.0;

        let tf = ((self.fine_resolution_temp(uncomp_t) * 5 + 128) >> 8) as f64;
        (tf / 100.0).max(MIN).min(MAX)
    }

    pub fn compensated_humidity(&self, uncomp_h: u32, uncomp_t: u32) -> f64 {
        const MAX: f64 = 100.0;
        const MIN: f64 = 0.0;

        let t_fine = self.fine_resolution_temp(uncomp_t);
        let x1 = (t_fine as f64) - 76800.0;
        let x2 = ((self.h4 as f64) * 64.0) + ((self.h5 as f64) / 16384.0) * x1;
        let x3 = (uncomp_h as f64) - x2;
        let x4 = (self.h2 as f64) / 65536.0;
        let x5 = 1.0 + ((self.h3 as f64) / 67108864.0 * x1);
        let x6 = 1.0 + ((self.h6 as f64) / 67108864.0) * x1 * x5;
        let x7 = x3 * x4 * (x5 * x6);
        let humidity = x7 * (1.0 - (self.h1 as f64) * x7 / 524288.0);

        humidity.max(MIN).min(MAX)
    }

    pub fn compensated_pressure(&self, uncomp_p: u32, uncomp_t: u32) -> f64 {
        const MAX: f64 = 110000.0;
        const MIN: f64 = 30000.0;

        let t_fine = self.fine_resolution_temp(uncomp_t) as f64;
        let mut x1 = t_fine / 2.0 - 64000.0;
        let mut x2 = x1 * x1 * (self.p6 as f64) / 32768.0;
        x2 = x2 + x1 * (self.p5 as f64) * 2.0;
        x2 = x2 / 4.0 + (self.p4 as f64) * 65536.0;
        let x3 = (self.p3 as f64) * x1 * x1 / 524288.0;
        x1 = (x3 + (self.p2 as f64) * x1) / 524288.0;
        x1 = (1.0 + x1 / 32768.0) * (self.p1 as f64);

        // To avoid zero-division error.
        if x1 == 0.0 {
            return MIN;
        }

        let mut pressure = 1048576.0 - (uncomp_p as f64);
        pressure = (pressure - (x2 / 4096.0)) * 6250.0 / x1;
        x1 = (self.p9 as f64) * pressure * pressure / 2147483648.0;
        x2 = pressure * (self.p8 as f64) / 32768.0;
        pressure = pressure + (x1 + x2 + (self.p7 as f64)) / 16.0;

        pressure.min(MAX).max(MIN)
    }
}

#[derive(Clone)]
pub enum Mode {
    Sleep,
    Force,
    Normal,
}

impl Mode {
    fn to_raw(&self) -> u8 {
        match self {
            &Mode::Sleep => 0,
            &Mode::Force => 1,
            &Mode::Normal => 3,
        }
    }
}

pub enum Oversampling {
    No,
    X1,
    X2,
    X4,
    X8,
    X16,
}

impl Oversampling {
    fn to_raw(&self) -> u8 {
        match self {
            &Oversampling::No => 0,
            &Oversampling::X1 => 1,
            &Oversampling::X2 => 2,
            &Oversampling::X4 => 3,
            &Oversampling::X8 => 4,
            &Oversampling::X16 => 5,
        }
    }
}

pub enum StandbyTime {
    Ms1,
    Ms62_5,
    Ms125,
    Ms250,
    Ms500,
    Ms1000,
    Ms10,
    Ms20,
}

impl StandbyTime {
    fn to_raw(&self) -> u8 {
        match self {
            &StandbyTime::Ms1 => 0,
            &StandbyTime::Ms62_5 => 1,
            &StandbyTime::Ms125 => 2,
            &StandbyTime::Ms250 => 3,
            &StandbyTime::Ms500 => 4,
            &StandbyTime::Ms1000 => 5,
            &StandbyTime::Ms10 => 6,
            &StandbyTime::Ms20 => 7,
        }
    }
}

pub enum IIRFilterCoeff {
    OFF,
    X2,
    X4,
    X8,
    X16,
}

impl IIRFilterCoeff {
    fn to_raw(&self) -> u8 {
        match self {
            &IIRFilterCoeff::OFF => 0,
            &IIRFilterCoeff::X2 => 1,
            &IIRFilterCoeff::X4 => 2,
            &IIRFilterCoeff::X8 => 3,
            &IIRFilterCoeff::X16 => 4,
        }
    }
}

pub struct Config {
    pub mode: Mode,
    pub oversampling_temperature: Oversampling,
    pub oversampling_pressure: Oversampling,
    pub oversampling_humidity: Oversampling,
    pub standby_time: StandbyTime,
    pub filter_coeff: IIRFilterCoeff,
    pub spi3w_enabled: bool,
}

pub struct BME280 {
    device: LinuxI2CDevice,
    config: Config,
    params: CompensationParams,
}

impl BME280 {
    pub fn new(dev: LinuxI2CDevice, config: Config) -> Result<BME280, LinuxI2CError> {
        let params = CompensationParams::new();
        let mut bme280 = BME280 {
            device: dev,
            config: config,
            params: params,
        };
        bme280.soft_reset()?;
        bme280.params.load(&mut bme280.device)?;
        bme280.initialize()?;
        Ok(bme280)
    }

    fn initialize(&mut self) -> Result<(), LinuxI2CError> {
        let ctrl_hum_reg = self.config.oversampling_humidity.to_raw();
        let ctrl_meas_reg = (self.config.oversampling_temperature.to_raw() << 5) |
                            (self.config.oversampling_pressure.to_raw() << 2) |
                            self.config.mode.to_raw();
        let config_reg = (self.config.standby_time.to_raw() << 5) |
                         (self.config.filter_coeff.to_raw() << 2) |
                         (self.config.spi3w_enabled as u8);

        // ctrl_hum_reg has to be written before ctrl_meas_reg
        self.device.smbus_write_byte_data(0xF2, ctrl_hum_reg)?;
        self.device.smbus_write_byte_data(0xF4, ctrl_meas_reg)?;
        self.device.smbus_write_byte_data(0xF5, config_reg)
    }

    pub fn soft_reset(&mut self) -> Result<(), LinuxI2CError> {
        const SOFT_RESET_CMD: u8 = 0xB6;
        self.device.smbus_write_byte_data(0xE0, SOFT_RESET_CMD)?;
        // Startup time is 2ms as per the data sheet.
        thread::sleep(time::Duration::from_millis(2));
        Ok(())
    }

    pub fn raw_pressure(&mut self) -> Result<u32, LinuxI2CError> {
        let v = self.device.smbus_read_i2c_block_data(0xF7, 3)?;
        let p0 = v[0] as u32;
        let p1 = v[1] as u32;
        let p2 = v[2] as u32;
        Ok((p0 << 12) + (p1 << 4) + (p2 >> 4))
    }

    pub fn raw_temperature(&mut self) -> Result<u32, LinuxI2CError> {
        let v = self.device.smbus_read_i2c_block_data(0xFA, 3)?;
        let t0 = v[0] as u32;
        let t1 = v[1] as u32;
        let t2 = v[2] as u32;
        Ok((t0 << 12) + (t1 << 4) + (t2 >> 4))
    }

    pub fn raw_humidity(&mut self) -> Result<u32, LinuxI2CError> {
        let v = self.device.smbus_read_i2c_block_data(0xFD, 2)?;
        let h1 = v[0] as u32;
        let h2 = v[1] as u32;
        Ok((h1 << 8) + h2)
    }

    pub fn temperature(&mut self) -> Result<f64, LinuxI2CError> {
        let raw_value = self.raw_temperature()?;
        Ok(self.params.compensated_temp(raw_value))
    }

    pub fn humidity(&mut self) -> Result<f64, LinuxI2CError> {
        let raw_t = self.raw_temperature()?;
        let raw_h = self.raw_humidity()?;
        Ok(self.params.compensated_humidity(raw_h, raw_t))
    }

    pub fn pressure(&mut self) -> Result<f64, LinuxI2CError> {
        let raw_t = self.raw_temperature()?;
        let raw_p = self.raw_pressure()?;
        Ok(self.params.compensated_pressure(raw_p, raw_t))
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use maplit::hashset;
use std::{
    collections::{HashMap, HashSet},
    io::{BufRead, BufReader},
    path::{Path, PathBuf},
    process::Command,
};

use crate::{
    files::*,
    internal::{CargoManifest, Scope},
};

#[derive(Debug)]
pub struct ModifiedContent {
    /// List of modified files.
    pub files: Option<Vec<String>>,
}

impl ModifiedContent {
    pub fn contains(&self, file_name: &str) -> bool {
        self.files.is_none()
            || self
                .files
                .as_ref()
                .unwrap()
                .contains(&file_name.to_string())
    }
}

/// Get all the files that have been modified in the given `scope`. If the scope is `Scope::All`
/// returns `None` as the list of files in `ModifiedContent`. For `Scope::Commits` and
/// `Scope::DiffToMain` the returned files include tracked files with unstaged changes, but do
/// not include new files that are not tracked (i.e., not added to git yet). For
/// `Scope::Commits(N)`, a positive number of commits must be given. In case of zero or
/// a negative number, only the last commit will be considered for finding the modified files.
pub fn modified_files(scope: &Scope) -> ModifiedContent {
    let args = match scope {
        Scope::All => None,
        Scope::Commits(commits) => Some(format!("HEAD~{}", std::cmp::max(1, *commits))),
        // TODO(#2491): Use `--merge-base` when we have a newer version of Git in the docker image.
        Scope::DiffToMain => Some("main".to_owned()),
    };

    let files = args.map(|args| {
        let vec = Command::new("git")
            .args(spread!["diff".to_owned(), "--name-only".to_owned(), args,])
            .output()
            .expect("could not get modified files")
            .stdout;

        // Extract the file names from the git output
        String::from_utf8(vec)
            .expect("could not convert to string")
            .split('\n')
            .map(|s| format!("./{}", s))
            .collect()
    });
    ModifiedContent { files }
}

/// Returns the list of paths to `Cargo.toml` files for all crates that include at least one of the
/// given modified files.
pub fn directly_modified_crates(files: &ModifiedContent) -> ModifiedContent {
    let files = files.files.as_ref().map(|modified_files| {
        let mut crates = hashset![];
        for str_path in modified_files {
            if let Some(crate_path) = find_crate_toml_file(str_path.clone()) {
                crates.insert(crate_path);
            }
        }
        crates.iter().cloned().collect()
    });
    ModifiedContent { files }
}

fn find_crate_toml_file(str_path: String) -> Option<String> {
    if str_path.ends_with("Cargo.toml") {
        return Some(str_path);
    } else if str_path.ends_with(".rs") || str_path.ends_with(".lock") {
        let mut path = PathBuf::from(&str_path);
        while path.parent().is_some() {
            path.pop();
            let crate_path = path.join("Cargo.toml");
            let crate_path = crate_path.as_path();
            if crate_path.exists() {
                return Some(crate_path.to_str().unwrap().to_string());
            }
        }
    }
    None
}

/// Returns the list of paths to all `.proto` files affected by the given list of modified files.
fn affected_protos(files: &ModifiedContent) -> Vec<String> {
    files
        .files
        .as_ref()
        .map(|modified_files| {
            let mut affected_protos: Vec<String> = modified_files
                .iter()
                .filter(|p| p.ends_with(".proto"))
                .cloned()
                .collect();

            if !affected_protos.is_empty() {
                let all_protos = source_files()
                    .map(to_string)
                    .map(|s| s.replace("./", ""))
                    .filter(|p| p.ends_with(".proto"));

                for proto in all_protos {
                    add_affected_protos(proto, &mut affected_protos);
                }
            }

            affected_protos
        })
        .unwrap_or_else(Vec::new)
}

/// Adds `proto_path` to the list of `affected_protos` if `proto_path` or any of its imported protos
/// imports any of the proto files in `affected_protos`.
fn add_affected_protos(proto_path: String, affected_protos: &mut Vec<String>) {
    if affected_protos.contains(&proto_path) {
        return;
    }

    let imported_proto_files = imported_proto_files(proto_path.clone());
    for imported_proto_file in imported_proto_files {
        if !affected_protos.contains(&imported_proto_file) {
            add_affected_protos(imported_proto_file.clone(), affected_protos);
        }

        if affected_protos.contains(&imported_proto_file) {
            affected_protos.push(proto_path);
            return;
        }
    }
}

/// Returns paths to all `.proto` files that `proto_file_path` imports.
fn imported_proto_files(proto_file_path: String) -> Vec<String> {
    let mut imported_protos = vec![];
    if let Ok(file) = std::fs::File::open(proto_file_path) {
        let lines = BufReader::new(file).lines();
        let re = regex::Regex::new(r#"import "(.*)";"#).unwrap();

        // Scan the lines in the file line by line to find all the imports.
        for line in lines {
            let line = line.expect("could not read line");
            if let Some(imported) = re.captures(&line).map(|c| c[1].to_string()) {
                imported_protos.push(imported);
            }
        }
    }

    imported_protos
}

/// Path to the `Cargo.toml` files for all crates that are either directly modified or have a
/// dependency to a modified crate.
pub fn all_affected_crates(scope: &Scope) -> ModifiedContent {
    crates_affected_by_files(&modified_files(scope))
}

fn crates_affected_by_files(files: &ModifiedContent) -> ModifiedContent {
    let modified_crates = directly_modified_crates(files);
    let files = modified_crates.files.map(|modified_files| {
        let crate_manifest_files = crate_manifest_files();
        // A map of `Cargo.toml` files visited by the algorithm. If the value associated with a
        // key is `true`, the crate is affected by the changes and should be included in the
        // result.
        let mut affected_crates: HashMap<String, bool> = modified_files
            .into_iter()
            .map(|path| (path, true))
            .collect();

        crates_affected_by_protos(&affected_protos(files))
            .iter()
            .fold(&mut affected_crates, |affected_crates, toml_path| {
                affected_crates.insert(toml_path.clone(), true);
                affected_crates
            });

        for crate_path in crate_manifest_files {
            add_affected_crates(crate_path, &mut affected_crates);
        }

        // Return `Cargo.toml` files of the crates that are affected by the changes
        affected_crates
            .iter()
            .filter(|(_key, value)| **value)
            .map(|(key, _value)| key.clone())
            .collect()
    });

    ModifiedContent { files }
}

/// Returns the paths to `Cargo.toml` files of crates affected by the changed proto files.
fn crates_affected_by_protos(affected_protos: &[String]) -> HashSet<String> {
    source_files()
        .filter(|path| to_string(path.clone()).ends_with("build.rs"))
        .filter(|path| {
            for proto in affected_protos {
                if file_contains(path, &proto.replace("./", "")) {
                    return true;
                }
            }
            false
        })
        .map(to_string)
        .map(|build_path| find_crate_toml_file(build_path).unwrap())
        .collect()
}

/// Checks if `crate_toml_path` has a direct or indirect dependency to any of the affected crates in
/// `affected_crates_toml_path`. If so, adds `crate_toml_path` and any of its affected dependencies
/// to `affected_crates_toml_path`.
///
/// Keys in `affected_crates_toml_path` are paths to visited `Cargo.toml` files. If the value
/// associated with a key is `true`, then the corresponding crate is affected by the changes.
fn add_affected_crates(
    crate_toml_path: PathBuf,
    affected_crates_toml_path: &mut HashMap<String, bool>,
) {
    // Return immediately, if the `crate_toml_path` is already visited.
    if affected_crates_toml_path.contains_key(&to_string(crate_toml_path.clone())) {
        return;
    }
    affected_crates_toml_path.insert(to_string(crate_toml_path.clone()), false);
    let deps = get_local_dependencies(&crate_toml_path);
    for dep in deps {
        // If the dependency is not visited, visit it and its dependencies
        if !affected_crates_toml_path.contains_key(&dep) {
            let dep_path = PathBuf::from(dep.clone());
            add_affected_crates(dep_path.clone(), affected_crates_toml_path)
        }
        if *affected_crates_toml_path.get(&dep).unwrap_or(&false) {
            affected_crates_toml_path.insert(to_string(crate_toml_path), true);
            return;
        }
    }
}

/// Returns paths to `Cargo.toml` files of local crates (crates belonging to the Oak repo) that the
/// given crate has a dependency to. Converts the relative dependency paths in `Cargo.toml` into
/// paths relative to the repo's root.
fn get_local_dependencies(toml_path: &Path) -> Vec<String> {
    let cargo_manifest: CargoManifest =
        toml::from_str(&read_file(toml_path)).unwrap_or_else(|err| {
            panic!(
                "could not parse crate manifest file {:?}: {}",
                toml_path, err
            )
        });

    let mut dependency_toml_paths = vec![];
    cargo_manifest
        .all_dependencies_with_toml_path()
        .iter()
        .fold(&mut dependency_toml_paths, |paths, dep_path_str| {
            let dep_path = PathBuf::from(dep_path_str);
            let dep_path = dep_path.as_path();
            let mut canonical_dep_toml_path = toml_path.to_path_buf();
            canonical_dep_toml_path.pop();
            // Change the path to be relative to the repo's root.
            for dir in dep_path.components() {
                if dir == std::path::Component::ParentDir {
                    canonical_dep_toml_path.pop();
                } else {
                    canonical_dep_toml_path.push(dir);
                }
            }
            paths.push(to_string(canonical_dep_toml_path));
            paths
        });

    dependency_toml_paths
}
<commit_msg>Always run all CI steps if a Dockerfile is changed (#2558)<commit_after>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use maplit::hashset;
use std::{
    collections::{HashMap, HashSet},
    io::{BufRead, BufReader},
    path::{Path, PathBuf},
    process::Command,
};

use crate::{
    files::*,
    internal::{CargoManifest, Scope},
};

#[derive(Debug)]
pub struct ModifiedContent {
    /// List of modified files.
    pub files: Option<Vec<String>>,
}

impl ModifiedContent {
    pub fn contains(&self, file_name: &str) -> bool {
        self.files.is_none()
            || self
                .files
                .as_ref()
                .unwrap()
                .contains(&file_name.to_string())
    }
}

/// Get all the files that have been modified in the given `scope`. If the scope is `Scope::All`
/// returns `None` as the list of files in `ModifiedContent`. For `Scope::Commits` and
/// `Scope::DiffToMain` the returned files include tracked files with unstaged changes, but do
/// not include new files that are not tracked (i.e., not added to git yet). For
/// `Scope::Commits(N)`, a positive number of commits must be given. In case of zero or
/// a negative number, only the last commit will be considered for finding the modified files.
pub fn modified_files(scope: &Scope) -> ModifiedContent {
    let args = match scope {
        Scope::All => None,
        Scope::Commits(commits) => Some(format!("HEAD~{}", std::cmp::max(1, *commits))),
        // TODO(#2491): Use `--merge-base` when we have a newer version of Git in the docker image.
        Scope::DiffToMain => Some("main".to_owned()),
    };

    let files: Option<Vec<String>> = args.map(|args| {
        let vec = Command::new("git")
            .args(spread!["diff".to_owned(), "--name-only".to_owned(), args,])
            .output()
            .expect("could not get modified files")
            .stdout;

        // Extract the file names from the git output
        String::from_utf8(vec)
            .expect("could not convert to string")
            .split('\n')
            .map(|s| format!("./{}", s))
            .collect()
    });

    // If something is changed in a Dockerfile, we'd want to run all CI steps, so set `files` to
    // `None` in `ModifiedContent`.
    if let Some(ref paths) = files {
        if paths.iter().any(|path| path.contains("Dockerfile")) {
            return ModifiedContent { files: None };
        }
    }

    ModifiedContent { files }
}

/// Returns the list of paths to `Cargo.toml` files for all crates that include at least one of the
/// given modified files.
pub fn directly_modified_crates(files: &ModifiedContent) -> ModifiedContent {
    let files = files.files.as_ref().map(|modified_files| {
        let mut crates = hashset![];
        for str_path in modified_files {
            if let Some(crate_path) = find_crate_toml_file(str_path.clone()) {
                crates.insert(crate_path);
            }
        }
        crates.iter().cloned().collect()
    });
    ModifiedContent { files }
}

fn find_crate_toml_file(str_path: String) -> Option<String> {
    if str_path.ends_with("Cargo.toml") {
        return Some(str_path);
    } else if str_path.ends_with(".rs") || str_path.ends_with(".lock") {
        let mut path = PathBuf::from(&str_path);
        while path.parent().is_some() {
            path.pop();
            let crate_path = path.join("Cargo.toml");
            let crate_path = crate_path.as_path();
            if crate_path.exists() {
                return Some(crate_path.to_str().unwrap().to_string());
            }
        }
    }
    None
}

/// Returns the list of paths to all `.proto` files affected by the given list of modified files.
fn affected_protos(files: &ModifiedContent) -> Vec<String> {
    files
        .files
        .as_ref()
        .map(|modified_files| {
            let mut affected_protos: Vec<String> = modified_files
                .iter()
                .filter(|p| p.ends_with(".proto"))
                .cloned()
                .collect();

            if !affected_protos.is_empty() {
                let all_protos = source_files()
                    .map(to_string)
                    .map(|s| s.replace("./", ""))
                    .filter(|p| p.ends_with(".proto"));

                for proto in all_protos {
                    add_affected_protos(proto, &mut affected_protos);
                }
            }

            affected_protos
        })
        .unwrap_or_else(Vec::new)
}

/// Adds `proto_path` to the list of `affected_protos` if `proto_path` or any of its imported protos
/// imports any of the proto files in `affected_protos`.
fn add_affected_protos(proto_path: String, affected_protos: &mut Vec<String>) {
    if affected_protos.contains(&proto_path) {
        return;
    }

    let imported_proto_files = imported_proto_files(proto_path.clone());
    for imported_proto_file in imported_proto_files {
        if !affected_protos.contains(&imported_proto_file) {
            add_affected_protos(imported_proto_file.clone(), affected_protos);
        }

        if affected_protos.contains(&imported_proto_file) {
            affected_protos.push(proto_path);
            return;
        }
    }
}

/// Returns paths to all `.proto` files that `proto_file_path` imports.
fn imported_proto_files(proto_file_path: String) -> Vec<String> {
    let mut imported_protos = vec![];
    if let Ok(file) = std::fs::File::open(proto_file_path) {
        let lines = BufReader::new(file).lines();
        let re = regex::Regex::new(r#"import "(.*)";"#).unwrap();

        // Scan the lines in the file line by line to find all the imports.
        for line in lines {
            let line = line.expect("could not read line");
            if let Some(imported) = re.captures(&line).map(|c| c[1].to_string()) {
                imported_protos.push(imported);
            }
        }
    }

    imported_protos
}

/// Path to the `Cargo.toml` files for all crates that are either directly modified or have a
/// dependency to a modified crate.
pub fn all_affected_crates(scope: &Scope) -> ModifiedContent {
    crates_affected_by_files(&modified_files(scope))
}

fn crates_affected_by_files(files: &ModifiedContent) -> ModifiedContent {
    let modified_crates = directly_modified_crates(files);
    let files = modified_crates.files.map(|modified_files| {
        let crate_manifest_files = crate_manifest_files();
        // A map of `Cargo.toml` files visited by the algorithm. If the value associated with a
        // key is `true`, the crate is affected by the changes and should be included in the
        // result.
        let mut affected_crates: HashMap<String, bool> = modified_files
            .into_iter()
            .map(|path| (path, true))
            .collect();

        crates_affected_by_protos(&affected_protos(files))
            .iter()
            .fold(&mut affected_crates, |affected_crates, toml_path| {
                affected_crates.insert(toml_path.clone(), true);
                affected_crates
            });

        for crate_path in crate_manifest_files {
            add_affected_crates(crate_path, &mut affected_crates);
        }

        // Return `Cargo.toml` files of the crates that are affected by the changes
        affected_crates
            .iter()
            .filter(|(_key, value)| **value)
            .map(|(key, _value)| key.clone())
            .collect()
    });

    ModifiedContent { files }
}

/// Returns the paths to `Cargo.toml` files of crates affected by the changed proto files.
fn crates_affected_by_protos(affected_protos: &[String]) -> HashSet<String> {
    source_files()
        .filter(|path| to_string(path.clone()).ends_with("build.rs"))
        .filter(|path| {
            for proto in affected_protos {
                if file_contains(path, &proto.replace("./", "")) {
                    return true;
                }
            }
            false
        })
        .map(to_string)
        .map(|build_path| find_crate_toml_file(build_path).unwrap())
        .collect()
}

/// Checks if `crate_toml_path` has a direct or indirect dependency to any of the affected crates in
/// `affected_crates_toml_path`. If so, adds `crate_toml_path` and any of its affected dependencies
/// to `affected_crates_toml_path`.
///
/// Keys in `affected_crates_toml_path` are paths to visited `Cargo.toml` files. If the value
/// associated with a key is `true`, then the corresponding crate is affected by the changes.
fn add_affected_crates(
    crate_toml_path: PathBuf,
    affected_crates_toml_path: &mut HashMap<String, bool>,
) {
    // Return immediately, if the `crate_toml_path` is already visited.
    if affected_crates_toml_path.contains_key(&to_string(crate_toml_path.clone())) {
        return;
    }
    affected_crates_toml_path.insert(to_string(crate_toml_path.clone()), false);
    let deps = get_local_dependencies(&crate_toml_path);
    for dep in deps {
        // If the dependency is not visited, visit it and its dependencies
        if !affected_crates_toml_path.contains_key(&dep) {
            let dep_path = PathBuf::from(dep.clone());
            add_affected_crates(dep_path.clone(), affected_crates_toml_path)
        }
        if *affected_crates_toml_path.get(&dep).unwrap_or(&false) {
            affected_crates_toml_path.insert(to_string(crate_toml_path), true);
            return;
        }
    }
}

/// Returns paths to `Cargo.toml` files of local crates (crates belonging to the Oak repo) that the
/// given crate has a dependency to. Converts the relative dependency paths in `Cargo.toml` into
/// paths relative to the repo's root.
fn get_local_dependencies(toml_path: &Path) -> Vec<String> {
    let cargo_manifest: CargoManifest =
        toml::from_str(&read_file(toml_path)).unwrap_or_else(|err| {
            panic!(
                "could not parse crate manifest file {:?}: {}",
                toml_path, err
            )
        });

    let mut dependency_toml_paths = vec![];
    cargo_manifest
        .all_dependencies_with_toml_path()
        .iter()
        .fold(&mut dependency_toml_paths, |paths, dep_path_str| {
            let dep_path = PathBuf::from(dep_path_str);
            let dep_path = dep_path.as_path();
            let mut canonical_dep_toml_path = toml_path.to_path_buf();
            canonical_dep_toml_path.pop();
            // Change the path to be relative to the repo's root.
            for dir in dep_path.components() {
                if dir == std::path::Component::ParentDir {
                    canonical_dep_toml_path.pop();
                } else {
                    canonical_dep_toml_path.push(dir);
                }
            }
            paths.push(to_string(canonical_dep_toml_path));
            paths
        });

    dependency_toml_paths
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use std::fmt;

mod cards;
use cards::shuffled_deck;
mod display_cards;

fn main ()
{
    let all_cards = *shuffled_deck();

    for card in all_cards.iter()
    {
        if card.id < 51
        {
            print!("{}{} ", card.color, card.rank);
        }
        else
        {
            println!("{}{}", card.color, card.rank);
        }
    }
}
<commit_msg>Remove unused import from main.<commit_after>/*
 * Copyright (c) 2017 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

mod cards;
use cards::shuffled_deck;
mod display_cards;

fn main ()
{
    let all_cards = *shuffled_deck();

    for card in all_cards.iter()
    {
        if card.id < 51
        {
            print!("{}{} ", card.color, card.rank);
        }
        else
        {
            println!("{}{}", card.color, card.rank);
        }
    }
}
<|endoftext|>


<commit_before>//! Prints the elapsed time every 1 second and quits on Ctrl+C.

#[macro_use]
extern crate crossbeam_channel;
extern crate signal_hook;

use std::io;
use std::thread;
use std::time::{Duration, Instant};

use crossbeam_channel::{tick, unbounded, Receiver};
use signal_hook::iterator::Signals;
use signal_hook::SIGINT;

// Creates a channel that gets a message every time `SIGINT` is signalled.
fn sigint_notifier() -> io::Result<Receiver<()>> {
    let (s, r) = unbounded();
    let signals = Signals::new(&[SIGINT])?;

    thread::spawn(move || {
        for _ in signals.forever() {
            if s.send(()).is_err() {
                break;
            }
        }
    });

    Ok(r)
}

// Prints the elapsed time.
fn show(dur: Duration) {
    println!(
        "Elapsed: {}.{:03} sec",
        dur.as_secs(),
        dur.subsec_nanos() / 1_000_000
    );
}

fn main() {
    let start = Instant::now();
    let update = tick(Duration::from_secs(1));
    let ctrl_c = sigint_notifier().unwrap();

    loop {
        select! {
            recv(update) -> _ => {
                show(start.elapsed());
            }
            recv(ctrl_c) -> _ => {
                println!();
                println!("Goodbye!");
                show(start.elapsed());
                break;
            }
        }
    }
}
<commit_msg>Use a bounded channel for signals<commit_after>//! Prints the elapsed time every 1 second and quits on Ctrl+C.

#[macro_use]
extern crate crossbeam_channel;
extern crate signal_hook;

use std::io;
use std::thread;
use std::time::{Duration, Instant};

use crossbeam_channel::{bounded, tick, Receiver};
use signal_hook::iterator::Signals;
use signal_hook::SIGINT;

// Creates a channel that gets a message every time `SIGINT` is signalled.
fn sigint_notifier() -> io::Result<Receiver<()>> {
    let (s, r) = bounded(100);
    let signals = Signals::new(&[SIGINT])?;

    thread::spawn(move || {
        for _ in signals.forever() {
            if s.send(()).is_err() {
                break;
            }
        }
    });

    Ok(r)
}

// Prints the elapsed time.
fn show(dur: Duration) {
    println!(
        "Elapsed: {}.{:03} sec",
        dur.as_secs(),
        dur.subsec_nanos() / 1_000_000
    );
}

fn main() {
    let start = Instant::now();
    let update = tick(Duration::from_secs(1));
    let ctrl_c = sigint_notifier().unwrap();

    loop {
        select! {
            recv(update) -> _ => {
                show(start.elapsed());
            }
            recv(ctrl_c) -> _ => {
                println!();
                println!("Goodbye!");
                show(start.elapsed());
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>use error::{Result, Error};

use std::cell::RefCell;
use std::rc::Rc;
use std::net::SocketAddr;
use std::collections::HashMap;
use std::io;

use futures::stream::Stream;
use futures::Sink;
use futures::Future;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;
use tokio_io::AsyncRead;

use mqtt3::{Packet, Connack, ConnectReturnCode};

use codec::MqttCodec;
use client::Client;

pub struct Broker {
    clients: Rc<RefCell<HashMap<SocketAddr, Client>>>,
}

impl Broker {
    pub fn new() -> Self {
        Broker { clients: Rc::new(RefCell::new(HashMap::new())) }
    }

    pub fn start(&mut self) -> Result<()> {
        let mut core = Core::new().unwrap();
        let handle = core.handle();
        let address = "0.0.0.0:1883".parse().unwrap();
        let listener = TcpListener::bind(&address, &core.handle()).unwrap();

        let welcomes = listener.incoming().and_then(|(socket, addr)| {
            let framed = socket.framed(MqttCodec);

            let handshake = framed.into_future()
                                  .map_err(|(err, _)| err)
                                  .and_then(|(packet, framed)|{
                                      if let Some(Packet::Connect(c)) = packet {
                                          println!("{:?}", c);
                                          Ok(framed)
                                      } else {
                                        Err(io::Error::new(io::ErrorKind::Other, "invalid handshake"))
                                      }
                                  });
            handshake
        });

        let server = welcomes.for_each(|framed| {

            let (sender, receiver) = framed.split();

            let connack = Packet::Connack(Connack{session_present: false, code: ConnectReturnCode::Accepted});
            let sender = sender.send(connack).wait();

            let rx_future = receiver.for_each(|msg| {
                println!("{:?}", msg);
                Ok(())
            }).then(|_| Ok(()));

            handle.spawn(rx_future);
            Ok(())
        });

        core.run(server)?;
        Ok(())
    }

    pub fn add(&self, addr: SocketAddr, client: Client) {
        self.clients.borrow_mut().insert(addr, client);
    }

    pub fn remove(&self, addr: &SocketAddr) -> Option<Client> {
        self.clients.borrow_mut().remove(addr)
    }
}
<commit_msg>add some comments to understand futures<commit_after>use error::{Result, Error};

use std::cell::RefCell;
use std::rc::Rc;
use std::net::SocketAddr;
use std::collections::HashMap;
use std::io;

use futures::stream::Stream;
use futures::Sink;
use futures::Future;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;
use tokio_io::AsyncRead;

use mqtt3::{Packet, Connack, ConnectReturnCode};

use codec::MqttCodec;
use client::Client;

pub struct Broker {
    clients: Rc<RefCell<HashMap<SocketAddr, Client>>>,
}

impl Broker {
    pub fn new() -> Self {
        Broker { clients: Rc::new(RefCell::new(HashMap::new())) }
    }

    pub fn start(&mut self) -> Result<()> {
        let mut core = Core::new().unwrap();
        let handle = core.handle();
        let address = "0.0.0.0:1883".parse().unwrap();
        let listener = TcpListener::bind(&address, &core.handle()).unwrap();

        let welcomes = listener.incoming().and_then(|(socket, addr)| {
            let framed = socket.framed(MqttCodec);

            // and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
            // where F: FnOnce(Self::Item) -> B,
            //       B: IntoFuture<Error=Self::Error>, // Error of value returned by 'F' and Error of Self should match
            //       Self: Sized

            // => If Self resolves to Ok(_), Execute 'F' with '_'

            // AndThen<Self, B, F> => F: FnOnce(Self::Item) -> B, B: IntoFuture<Error=Self::Error>, Self: Sized

            /// handshake = AndThen<
            ///                MapErr< Stream<Framed>, closure>, --> Self
            ///                Result<Framed, io::Error>,        --> B (Should be an IntoFuture whose error = Self's error)
            ///                closure >                         --> F (Should be which returns 'B')

            /// Creates a 'Self' from stream, whose error match to that of and_then's closure
            let handshake = framed.into_future().map_err(|(err, _)| err).and_then(|(packet,framed)| {
                if let Some(Packet::Connect(c)) = packet {
                    println!("{:?}", c);
                    Ok(framed)
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "invalid handshake"))
                }
            });

            handshake
        });

        let server = welcomes.for_each(|framed| {

            let (sender, receiver) = framed.split();

            let connack = Packet::Connack(Connack {
                                              session_present: false,
                                              code: ConnectReturnCode::Accepted,
                                          });
            let sender = sender.send(connack).wait();

            let rx_future = receiver
                .for_each(|msg| {
                              println!("{:?}", msg);
                              Ok(())
                          })
                .then(|_| Ok(()));

            handle.spawn(rx_future);
            Ok(())
        });

        core.run(server)?;
        Ok(())
    }

    pub fn add(&self, addr: SocketAddr, client: Client) {
        self.clients.borrow_mut().insert(addr, client);
    }

    pub fn remove(&self, addr: &SocketAddr) -> Option<Client> {
        self.clients.borrow_mut().remove(addr)
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::io::{self, Read, BufRead};

pub struct BufReader<R> {
    inner: R,
    buf: Vec<u8>,
    pos: usize,
    cap: usize,
}

const INIT_BUFFER_SIZE: usize = 4096;
const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;

impl<R: Read> BufReader<R> {
    #[inline]
    pub fn new(rdr: R) -> BufReader<R> {
        BufReader::with_capacity(rdr, INIT_BUFFER_SIZE)
    }

    #[inline]
    pub fn with_capacity(rdr: R, cap: usize) -> BufReader<R> {
        BufReader {
            inner: rdr,
            buf: vec![0; cap],
            pos: 0,
            cap: 0,
        }
    }

    #[inline]
    pub fn get_ref(&self) -> &R { &self.inner }

    #[inline]
    pub fn get_mut(&mut self) -> &mut R { &mut self.inner }

    #[inline]
    pub fn get_buf(&self) -> &[u8] {
        if self.pos < self.cap {
            trace!("get_buf [u8; {}][{}..{}]", self.buf.len(), self.pos, self.cap);
            &self.buf[self.pos..self.cap]
        } else {
            trace!("get_buf []");
            &[]
        }
    }

    #[inline]
    pub fn into_inner(self) -> R { self.inner }

    #[inline]
    pub fn read_into_buf(&mut self) -> io::Result<usize> {
        self.maybe_reserve();
        let v = &mut self.buf;
        trace!("read_into_buf buf[{}..{}]", self.cap, v.len());
        if self.cap < v.capacity() {
            let nread = try!(self.inner.read(&mut v[self.cap..]));
            self.cap += nread;
            Ok(nread)
        } else {
            trace!("read_into_buf at full capacity");
            Ok(0)
        }
    }

    #[inline]
    fn maybe_reserve(&mut self) {
        let cap = self.buf.capacity();
        if self.cap == cap && cap < MAX_BUFFER_SIZE {
            self.buf.reserve(cmp::min(cap * 4, MAX_BUFFER_SIZE) - cap);
            let new = self.buf.capacity() - self.buf.len();
            trace!("reserved {}", new);
            unsafe { grow_zerofill(&mut self.buf, new) }
        }
    }
}

#[inline]
unsafe fn grow_zerofill(buf: &mut Vec<u8>, additional: usize) {
    use std::ptr;
    let len = buf.len();
    buf.set_len(len + additional);
    ptr::write_bytes(buf.as_mut_ptr().offset(len as isize), 0, buf.len());
}

impl<R: Read> Read for BufReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.cap == self.pos && buf.len() >= self.buf.len() {
            return self.inner.read(buf);
        }
        let nread = {
           let mut rem = try!(self.fill_buf());
           try!(rem.read(buf))
        };
        self.consume(nread);
        Ok(nread)
    }
}

impl<R: Read> BufRead for BufReader<R> {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        if self.pos == self.cap {
            self.cap = try!(self.inner.read(&mut self.buf));
            self.pos = 0;
        }
        Ok(&self.buf[self.pos..self.cap])
    }

    #[inline]
    fn consume(&mut self, amt: usize) {
        self.pos = cmp::min(self.pos + amt, self.cap);
        if self.pos == self.cap {
            self.pos = 0;
            self.cap = 0;
        }
    }
}

#[cfg(test)]
mod tests {

    use std::io::{self, Read, BufRead};
    use super::BufReader;

    struct SlowRead(u8);

    impl Read for SlowRead {
        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
            let state = self.0;
            self.0 += 1;
            (&match state % 3 {
                0 => b"foo",
                1 => b"bar",
                _ => b"baz",
            }[..]).read(buf)
        }
    }

    #[test]
    fn test_consume_and_get_buf() {
        let mut rdr = BufReader::new(SlowRead(0));
        rdr.read_into_buf().unwrap();
        rdr.consume(1);
        assert_eq!(rdr.get_buf(), b"oo");
        rdr.read_into_buf().unwrap();
        rdr.read_into_buf().unwrap();
        assert_eq!(rdr.get_buf(), b"oobarbaz");
        rdr.consume(5);
        assert_eq!(rdr.get_buf(), b"baz");
        rdr.consume(3);
        assert_eq!(rdr.get_buf(), b"");
        assert_eq!(rdr.pos, 0);
        assert_eq!(rdr.cap, 0);
    }

    #[test]
    fn test_resize() {
        let raw = b"hello world";
        let mut rdr = BufReader::with_capacity(&raw[..], 5);
        rdr.read_into_buf().unwrap();
        assert_eq!(rdr.get_buf(), b"hello");
        rdr.read_into_buf().unwrap();
        assert_eq!(rdr.get_buf(), b"hello world");
    }
}
<commit_msg> fix(buffer): prevent possible buffer overflow in `grow_zerofill`<commit_after>use std::cmp;
use std::io::{self, Read, BufRead};

pub struct BufReader<R> {
    inner: R,
    buf: Vec<u8>,
    pos: usize,
    cap: usize,
}

const INIT_BUFFER_SIZE: usize = 4096;
const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;

impl<R: Read> BufReader<R> {
    #[inline]
    pub fn new(rdr: R) -> BufReader<R> {
        BufReader::with_capacity(rdr, INIT_BUFFER_SIZE)
    }

    #[inline]
    pub fn with_capacity(rdr: R, cap: usize) -> BufReader<R> {
        BufReader {
            inner: rdr,
            buf: vec![0; cap],
            pos: 0,
            cap: 0,
        }
    }

    #[inline]
    pub fn get_ref(&self) -> &R { &self.inner }

    #[inline]
    pub fn get_mut(&mut self) -> &mut R { &mut self.inner }

    #[inline]
    pub fn get_buf(&self) -> &[u8] {
        if self.pos < self.cap {
            trace!("get_buf [u8; {}][{}..{}]", self.buf.len(), self.pos, self.cap);
            &self.buf[self.pos..self.cap]
        } else {
            trace!("get_buf []");
            &[]
        }
    }

    #[inline]
    pub fn into_inner(self) -> R { self.inner }

    #[inline]
    pub fn read_into_buf(&mut self) -> io::Result<usize> {
        self.maybe_reserve();
        let v = &mut self.buf;
        trace!("read_into_buf buf[{}..{}]", self.cap, v.len());
        if self.cap < v.capacity() {
            let nread = try!(self.inner.read(&mut v[self.cap..]));
            self.cap += nread;
            Ok(nread)
        } else {
            trace!("read_into_buf at full capacity");
            Ok(0)
        }
    }

    #[inline]
    fn maybe_reserve(&mut self) {
        let cap = self.buf.capacity();
        if self.cap == cap && cap < MAX_BUFFER_SIZE {
            self.buf.reserve(cmp::min(cap * 4, MAX_BUFFER_SIZE) - cap);
            let new = self.buf.capacity() - self.buf.len();
            trace!("reserved {}", new);
            unsafe { grow_zerofill(&mut self.buf, new) }
        }
    }
}

#[inline]
unsafe fn grow_zerofill(buf: &mut Vec<u8>, additional: usize) {
    use std::ptr;
    let len = buf.len();
    buf.set_len(len + additional);
    ptr::write_bytes(buf.as_mut_ptr().offset(len as isize), 0, additional);
}

impl<R: Read> Read for BufReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.cap == self.pos && buf.len() >= self.buf.len() {
            return self.inner.read(buf);
        }
        let nread = {
           let mut rem = try!(self.fill_buf());
           try!(rem.read(buf))
        };
        self.consume(nread);
        Ok(nread)
    }
}

impl<R: Read> BufRead for BufReader<R> {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        if self.pos == self.cap {
            self.cap = try!(self.inner.read(&mut self.buf));
            self.pos = 0;
        }
        Ok(&self.buf[self.pos..self.cap])
    }

    #[inline]
    fn consume(&mut self, amt: usize) {
        self.pos = cmp::min(self.pos + amt, self.cap);
        if self.pos == self.cap {
            self.pos = 0;
            self.cap = 0;
        }
    }
}

#[cfg(test)]
mod tests {

    use std::io::{self, Read, BufRead};
    use super::BufReader;

    struct SlowRead(u8);

    impl Read for SlowRead {
        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
            let state = self.0;
            self.0 += 1;
            (&match state % 3 {
                0 => b"foo",
                1 => b"bar",
                _ => b"baz",
            }[..]).read(buf)
        }
    }

    #[test]
    fn test_consume_and_get_buf() {
        let mut rdr = BufReader::new(SlowRead(0));
        rdr.read_into_buf().unwrap();
        rdr.consume(1);
        assert_eq!(rdr.get_buf(), b"oo");
        rdr.read_into_buf().unwrap();
        rdr.read_into_buf().unwrap();
        assert_eq!(rdr.get_buf(), b"oobarbaz");
        rdr.consume(5);
        assert_eq!(rdr.get_buf(), b"baz");
        rdr.consume(3);
        assert_eq!(rdr.get_buf(), b"");
        assert_eq!(rdr.pos, 0);
        assert_eq!(rdr.cap, 0);
    }

    #[test]
    fn test_resize() {
        let raw = b"hello world";
        let mut rdr = BufReader::with_capacity(&raw[..], 5);
        rdr.read_into_buf().unwrap();
        assert_eq!(rdr.get_buf(), b"hello");
        rdr.read_into_buf().unwrap();
        assert_eq!(rdr.get_buf(), b"hello world");
    }
}
<|endoftext|>


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

extern crate cc;
extern crate glsl_to_cxx;
extern crate webrender_build;

use std::collections::HashSet;
use std::fmt::Write;
use webrender_build::shader::{ShaderFeatureFlags, get_shader_features};

// Shader key is in "name feature,feature" format.
// File name needs to be formatted as "name_feature_feature".
fn shader_file(shader_key: &str) -> String {
    shader_key.replace(' ', "_").replace(',', "_")
}

fn write_load_shader(shader_keys: &[String]) {
    let mut load_shader = String::new();
    for s in shader_keys {
        let _ = write!(load_shader, "#include \"{}.h\"\n", shader_file(s));
    }
    load_shader.push_str("ProgramLoader load_shader(const char* name) {\n");
    for s in shader_keys {
        let _ = write!(load_shader, "  if (!strcmp(name, \"{}\")) {{ return {}_program::loader; }}\n",
                       s, shader_file(s));
    }
    load_shader.push_str("  return nullptr;\n}\n");
    std::fs::write(std::env::var("OUT_DIR").unwrap() + "/load_shader.h", load_shader).unwrap();
}

fn process_imports(shader_dir: &str, shader: &str, included: &mut HashSet<String>, output: &mut String) {
    if !included.insert(shader.into()) {
        return;
    }
    println!("cargo:rerun-if-changed={}/{}.glsl", shader_dir, shader);
    let source = std::fs::read_to_string(format!("{}/{}.glsl", shader_dir, shader)).unwrap();
    for line in source.lines() {
        if line.starts_with("#include ") {
            let imports = line["#include ".len() ..].split(',');
            for import in imports {
                process_imports(shader_dir, import, included, output);
            }
        } else if line.starts_with("#version ") || line.starts_with("#extension ") {
            // ignore
        } else {
            output.push_str(line);
            output.push('\n');
        }
    }
}

fn translate_shader(shader_key: &str, shader_dir: &str) {
    let mut imported = String::from("#define SWGL 1\n#define __VERSION__ 150\n");
    let _ = write!(imported, "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
                   webrender_build::MAX_VERTEX_TEXTURE_WIDTH);

    let (basename, features) =
        shader_key.split_at(shader_key.find(' ').unwrap_or(shader_key.len()));
    if !features.is_empty() {
        for feature in features.trim().split(',') {
            let _ = write!(imported, "#define WR_FEATURE_{}\n", feature);
        }
    }

    process_imports(shader_dir, basename, &mut HashSet::new(), &mut imported);

    let shader = shader_file(shader_key);

    let out_dir = std::env::var("OUT_DIR").unwrap();
    let imp_name = format!("{}/{}.c", out_dir, shader);
    std::fs::write(&imp_name, imported).unwrap();

    let mut build = cc::Build::new();
    build.no_default_flags(true);
    if let Ok(tool) = build.try_get_compiler() {
        if tool.is_like_msvc() {
            build.flag("/EP");
            if tool.path().to_str().map_or(false, |p| p.contains("clang")) {
                build.flag("/clang:-undef");
            } else {
                build.flag("/u");
            }
        } else {
            build.flag("-xc").flag("-P").flag("-undef");
        }
    }
    // Use SWGLPP target to avoid pulling CFLAGS/CXXFLAGS.
    build.target("SWGLPP");
    build.file(&imp_name);
    let vs = build.clone()
        .define("WR_VERTEX_SHADER", Some("1"))
        .expand();
    let fs = build.clone()
        .define("WR_FRAGMENT_SHADER", Some("1"))
        .expand();
    let vs_name = format!("{}/{}.vert", out_dir, shader);
    let fs_name = format!("{}/{}.frag", out_dir, shader);
    std::fs::write(&vs_name, vs).unwrap();
    std::fs::write(&fs_name, fs).unwrap();

    let args = vec![
        "glsl_to_cxx".to_string(),
        vs_name,
        fs_name,
    ];
    let result = glsl_to_cxx::translate(&mut args.into_iter());
    std::fs::write(format!("{}/{}.h", out_dir, shader), result).unwrap();
}

fn main() {
    let shader_dir = match std::env::var("MOZ_SRC") {
        Ok(dir) => dir + "/gfx/wr/webrender/res",
        Err(_) => std::env::var("CARGO_MANIFEST_DIR").unwrap() + "/../webrender/res",
    };

    let shader_flags =
        ShaderFeatureFlags::GL |
        ShaderFeatureFlags::DUAL_SOURCE_BLENDING |
        ShaderFeatureFlags::ADVANCED_BLEND_EQUATION |
        ShaderFeatureFlags::DEBUG;
    let mut shaders: Vec<String> = Vec::new();
    for (name, features) in get_shader_features(shader_flags) {
        shaders.extend(features.iter().map(|f| {
            if f.is_empty() { name.to_owned() } else { format!("{} {}", name, f) }
        }));
    }

    shaders.sort();

    // We need to ensure that the C preprocessor does not pull compiler flags from
    // the host or target environment. Set up a SWGLPP target with empty flags to
    // work around this.
    if let Ok(target) = std::env::var("TARGET") {
        if let Ok(cc) = std::env::var(format!("CC_{}", target))
                        .or(std::env::var(format!("CC_{}", target.replace("-", "_")))) {
            std::env::set_var("CC_SWGLPP", cc);
        }
    }
    std::env::set_var("CFLAGS_SWGLPP", "");

    for shader in &shaders {
        translate_shader(shader, &shader_dir);
    }

    write_load_shader(&shaders);

    println!("cargo:rerun-if-changed=src/blend.h");
    println!("cargo:rerun-if-changed=src/composite.h");
    println!("cargo:rerun-if-changed=src/gl_defs.h");
    println!("cargo:rerun-if-changed=src/glsl.h");
    println!("cargo:rerun-if-changed=src/program.h");
    println!("cargo:rerun-if-changed=src/rasterize.h");
    println!("cargo:rerun-if-changed=src/swgl_ext.h");
    println!("cargo:rerun-if-changed=src/texture.h");
    println!("cargo:rerun-if-changed=src/vector_type.h");
    println!("cargo:rerun-if-changed=src/gl.cc");
    let mut build = cc::Build::new();
    build.cpp(true);

    if let Ok(tool) = build.try_get_compiler() {
        if tool.is_like_msvc() {
            build.flag("/std:c++17")
                 .flag("/EHs-")
                 .flag("/GR-")
                 .flag("/UMOZILLA_CONFIG_H");
        } else {
            build.flag("-std=c++17")
                 .flag("-fno-exceptions")
                 .flag("-fno-rtti")
                 .flag("-fno-math-errno")
                 .flag("-UMOZILLA_CONFIG_H");
        }
        // SWGL relies heavily on inlining for performance so override -Oz with -O2
        if tool.args().contains(&"-Oz".into()) {
            build.flag("-O2");
        }

        // Most GLSL compilers assume something like fast-math so we turn it on.
        // However, reciprocal division makes it so 1/1 = 0.999994 which can produce a lot of fuzz
        // in reftests and the use of reciprocal instructions usually involves a refinement step
        // which bloats our already bloated code. Further, our shader code is sufficiently parallel
        // that we're more likely to be throughput bound vs latency bound. Having fewer
        // instructions makes things easier on the processor and in places where it matters we can
        // probably explicitly use reciprocal instructions and avoid the refinement step.
        if tool.is_like_msvc() {
            build.flag("/fp:fast")
                 .flag("-Xclang")
                 .flag("-mrecip=none");
        } else {
            build.flag("-ffast-math")
                 .flag("-mrecip=none");
        }
    }

    build.file("src/gl.cc")
        .define("_GLIBCXX_USE_CXX11_ABI", Some("0"))
        .include(shader_dir)
        .include("src")
        .include(std::env::var("OUT_DIR").unwrap())
        .compile("gl_cc");
}
<commit_msg>Bug 1702189. Don't use -ffast-math on gcc. r=lsalzman<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cc;
extern crate glsl_to_cxx;
extern crate webrender_build;

use std::collections::HashSet;
use std::fmt::Write;
use webrender_build::shader::{ShaderFeatureFlags, get_shader_features};

// Shader key is in "name feature,feature" format.
// File name needs to be formatted as "name_feature_feature".
fn shader_file(shader_key: &str) -> String {
    shader_key.replace(' ', "_").replace(',', "_")
}

fn write_load_shader(shader_keys: &[String]) {
    let mut load_shader = String::new();
    for s in shader_keys {
        let _ = write!(load_shader, "#include \"{}.h\"\n", shader_file(s));
    }
    load_shader.push_str("ProgramLoader load_shader(const char* name) {\n");
    for s in shader_keys {
        let _ = write!(load_shader, "  if (!strcmp(name, \"{}\")) {{ return {}_program::loader; }}\n",
                       s, shader_file(s));
    }
    load_shader.push_str("  return nullptr;\n}\n");
    std::fs::write(std::env::var("OUT_DIR").unwrap() + "/load_shader.h", load_shader).unwrap();
}

fn process_imports(shader_dir: &str, shader: &str, included: &mut HashSet<String>, output: &mut String) {
    if !included.insert(shader.into()) {
        return;
    }
    println!("cargo:rerun-if-changed={}/{}.glsl", shader_dir, shader);
    let source = std::fs::read_to_string(format!("{}/{}.glsl", shader_dir, shader)).unwrap();
    for line in source.lines() {
        if line.starts_with("#include ") {
            let imports = line["#include ".len() ..].split(',');
            for import in imports {
                process_imports(shader_dir, import, included, output);
            }
        } else if line.starts_with("#version ") || line.starts_with("#extension ") {
            // ignore
        } else {
            output.push_str(line);
            output.push('\n');
        }
    }
}

fn translate_shader(shader_key: &str, shader_dir: &str) {
    let mut imported = String::from("#define SWGL 1\n#define __VERSION__ 150\n");
    let _ = write!(imported, "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
                   webrender_build::MAX_VERTEX_TEXTURE_WIDTH);

    let (basename, features) =
        shader_key.split_at(shader_key.find(' ').unwrap_or(shader_key.len()));
    if !features.is_empty() {
        for feature in features.trim().split(',') {
            let _ = write!(imported, "#define WR_FEATURE_{}\n", feature);
        }
    }

    process_imports(shader_dir, basename, &mut HashSet::new(), &mut imported);

    let shader = shader_file(shader_key);

    let out_dir = std::env::var("OUT_DIR").unwrap();
    let imp_name = format!("{}/{}.c", out_dir, shader);
    std::fs::write(&imp_name, imported).unwrap();

    let mut build = cc::Build::new();
    build.no_default_flags(true);
    if let Ok(tool) = build.try_get_compiler() {
        if tool.is_like_msvc() {
            build.flag("/EP");
            if tool.path().to_str().map_or(false, |p| p.contains("clang")) {
                build.flag("/clang:-undef");
            } else {
                build.flag("/u");
            }
        } else {
            build.flag("-xc").flag("-P").flag("-undef");
        }
    }
    // Use SWGLPP target to avoid pulling CFLAGS/CXXFLAGS.
    build.target("SWGLPP");
    build.file(&imp_name);
    let vs = build.clone()
        .define("WR_VERTEX_SHADER", Some("1"))
        .expand();
    let fs = build.clone()
        .define("WR_FRAGMENT_SHADER", Some("1"))
        .expand();
    let vs_name = format!("{}/{}.vert", out_dir, shader);
    let fs_name = format!("{}/{}.frag", out_dir, shader);
    std::fs::write(&vs_name, vs).unwrap();
    std::fs::write(&fs_name, fs).unwrap();

    let args = vec![
        "glsl_to_cxx".to_string(),
        vs_name,
        fs_name,
    ];
    let result = glsl_to_cxx::translate(&mut args.into_iter());
    std::fs::write(format!("{}/{}.h", out_dir, shader), result).unwrap();
}

fn main() {
    let shader_dir = match std::env::var("MOZ_SRC") {
        Ok(dir) => dir + "/gfx/wr/webrender/res",
        Err(_) => std::env::var("CARGO_MANIFEST_DIR").unwrap() + "/../webrender/res",
    };

    let shader_flags =
        ShaderFeatureFlags::GL |
        ShaderFeatureFlags::DUAL_SOURCE_BLENDING |
        ShaderFeatureFlags::ADVANCED_BLEND_EQUATION |
        ShaderFeatureFlags::DEBUG;
    let mut shaders: Vec<String> = Vec::new();
    for (name, features) in get_shader_features(shader_flags) {
        shaders.extend(features.iter().map(|f| {
            if f.is_empty() { name.to_owned() } else { format!("{} {}", name, f) }
        }));
    }

    shaders.sort();

    // We need to ensure that the C preprocessor does not pull compiler flags from
    // the host or target environment. Set up a SWGLPP target with empty flags to
    // work around this.
    if let Ok(target) = std::env::var("TARGET") {
        if let Ok(cc) = std::env::var(format!("CC_{}", target))
                        .or(std::env::var(format!("CC_{}", target.replace("-", "_")))) {
            std::env::set_var("CC_SWGLPP", cc);
        }
    }
    std::env::set_var("CFLAGS_SWGLPP", "");

    for shader in &shaders {
        translate_shader(shader, &shader_dir);
    }

    write_load_shader(&shaders);

    println!("cargo:rerun-if-changed=src/blend.h");
    println!("cargo:rerun-if-changed=src/composite.h");
    println!("cargo:rerun-if-changed=src/gl_defs.h");
    println!("cargo:rerun-if-changed=src/glsl.h");
    println!("cargo:rerun-if-changed=src/program.h");
    println!("cargo:rerun-if-changed=src/rasterize.h");
    println!("cargo:rerun-if-changed=src/swgl_ext.h");
    println!("cargo:rerun-if-changed=src/texture.h");
    println!("cargo:rerun-if-changed=src/vector_type.h");
    println!("cargo:rerun-if-changed=src/gl.cc");
    let mut build = cc::Build::new();
    build.cpp(true);

    if let Ok(tool) = build.try_get_compiler() {
        if tool.is_like_msvc() {
            build.flag("/std:c++17")
                 .flag("/EHs-")
                 .flag("/GR-")
                 .flag("/UMOZILLA_CONFIG_H");
        } else {
            build.flag("-std=c++17")
                 .flag("-fno-exceptions")
                 .flag("-fno-rtti")
                 .flag("-fno-math-errno")
                 .flag("-UMOZILLA_CONFIG_H");
        }
        // SWGL relies heavily on inlining for performance so override -Oz with -O2
        if tool.args().contains(&"-Oz".into()) {
            build.flag("-O2");
        }

        // Most GLSL compilers assume something like fast-math so we turn it on.
        // However, reciprocal division makes it so 1/1 = 0.999994 which can produce a lot of fuzz
        // in reftests and the use of reciprocal instructions usually involves a refinement step
        // which bloats our already bloated code. Further, our shader code is sufficiently parallel
        // that we're more likely to be throughput bound vs latency bound. Having fewer
        // instructions makes things easier on the processor and in places where it matters we can
        // probably explicitly use reciprocal instructions and avoid the refinement step.
        if tool.is_like_msvc() {
            build.flag("/fp:fast")
                 .flag("-Xclang")
                 .flag("-mrecip=none");
        } else if tool.is_like_clang() {
            // gcc only supports -mrecip=none on some targets so to keep
            // things simple we don't use -ffast-math with gcc at all
            build.flag("-ffast-math")
                 .flag("-mrecip=none");
        }
    }

    build.file("src/gl.cc")
        .define("_GLIBCXX_USE_CXX11_ABI", Some("0"))
        .include(shader_dir)
        .include("src")
        .include(std::env::var("OUT_DIR").unwrap())
        .compile("gl_cc");
}
<|endoftext|>