<commit_before>#![crate_id = "zip"]
#![crate_type = "lib"]

#![desc="A simple rust library for reading and writing ZIP files"]
#![license="MIT"]

extern crate flate;

use std::io::{Reader, Writer, Seek, SeekSet, SeekEnd};
use std::io::{IoResult, IoError, InvalidInput};
use std::iter::range_inclusive;

mod crc32;
pub mod format;

#[deriving(Eq,Show)]
pub enum ZipError {
    IoError(IoError),
    NotAZipFile,
    CrcError,
    FileNotFoundInArchive
}

fn io_result_to_zip_result<T>(x: IoResult<T>) -> Result<T, ZipError> {
    match x {
        Ok(v) => Ok(v),
        Err(e) => Err(IoError(e)),
    }
}

#[deriving(Eq,Show,Clone)]
pub enum CompressionMethod {
    Store=0,
    Deflate=8,
    Unknown
}

fn u16_to_CompressionMethod(x: u16) -> CompressionMethod {
    let u = x as uint;
    if      u == (Store   as uint) { Store }
    else if u == (Deflate as uint) { Deflate }
    else                           { Unknown }
}

#[deriving(Clone)]
pub struct FileInfo {
    pub name:               String,
    pub compression_method: CompressionMethod,
    pub last_modified_time: (int, int, int), // (hour, minute, second)
    pub last_modified_date: (int, int, int), // (year, month, day)
    pub crc32:              u32,
    pub compressed_size:    u32,
    pub uncompressed_size:  u32,
    pub is_encrypted:       bool,

    pub local_file_header_offset: u32,
}

impl FileInfo {
    // fills a FileInfo struct with the file properties, for users of the external API to see
    pub fn from_cdh(h: &format::CentralDirectoryHeader) -> FileInfo {
        let method : CompressionMethod =
            if h.compression_method == 0 { Store }
            else if h.compression_method == 8 { Deflate }
            else { fail!() };
        FileInfo {
            name:               h.file_name.clone(),
            compression_method: method,
            last_modified_time: format::decode_msdos_time(h.last_modified_time),
            last_modified_date: format::decode_msdos_date(h.last_modified_date),
            crc32:              h.crc32,
            compressed_size:    h.compressed_size,
            uncompressed_size:  h.uncompressed_size,
            local_file_header_offset: h.relative_offset_of_local_header,
            is_encrypted:       h.is_encrypted(),
        }
    }
}

pub struct ZipReader<T> {
    reader: T,
    end_record: format::EndOfCentralDirectoryRecord,
}

pub struct ZipReaderIterator<'a, T> {
    zip_reader: &'a mut ZipReader<T>,
    current_entry: u16,
    current_offset: u64,
}

impl<'a, T:Reader+Seek> Iterator<FileInfo> for ZipReaderIterator<'a, T> {
    fn next(&mut self) -> Option<FileInfo> {
        if (self.current_entry < self.zip_reader.end_record.total_entry_count) {
            self.zip_reader.reader.seek(self.current_offset as i64, SeekSet);
            let h = format::CentralDirectoryHeader::read(&mut self.zip_reader.reader).unwrap();
            let info = FileInfo::from_cdh(&h);
            self.current_entry += 1;
            self.current_offset += h.total_size() as u64;
            Some(info)
        } else {
            None
        }
    }
}

impl<T:Reader+Seek> ZipReader<T> {
    pub fn new(reader: T) -> Result<ZipReader<T>, ZipError> {
        // find the End of Central Directory record, looking backwards from the end of the file
        let mut r = reader;
        try!(io_result_to_zip_result(r.seek(0, SeekEnd)));
        let file_size = try!(io_result_to_zip_result(r.tell()));
        let mut end_record_offset : Option<u64> = None;
        for i in range_inclusive(4, file_size) {
            let offset = file_size - i;
            try!(io_result_to_zip_result(r.seek(offset as i64, SeekSet)));

            let sig = try!(io_result_to_zip_result(r.read_le_u32()));

            // TODO: check for false positives here
            if (sig == format::EOCDR_SIGNATURE) {
                end_record_offset = Some(offset);
                break;
            }

        }

        match end_record_offset {
            Some(offset) => {
                r.seek(offset as i64, SeekSet);
                let e = format::EndOfCentralDirectoryRecord::read(&mut r).unwrap();
                Ok(ZipReader {reader: r, end_record: e})
            },
            None => Err(NotAZipFile)
        }
    }

    pub fn iter<'a>(&'a mut self) -> ZipReaderIterator<'a, T> {
        ZipReaderIterator {
            zip_reader: self,
            current_entry: 0,
            current_offset: self.end_record.central_directory_offset as u64
        }
    }

    pub fn infolist(&mut self) -> Vec<FileInfo> {
        let mut result = Vec::new();
        for info in self.iter() {
            result.push(info);
        }
        result
    }

    pub fn namelist(&mut self) -> Vec<String> {
        let mut result = Vec::new();
        for info in self.iter() {
            result.push(info.name.clone());
        }
        result
    }

    pub fn get_file_info(&mut self, name: &str) -> Result<FileInfo, ZipError> {
        for i in self.iter() {
            if name.equiv(&i.name) {
                return Ok(i);
            }
        }
        Err(FileNotFoundInArchive)
    }

    // TODO: Create a Reader for the cases when you don't want to decompress the whole file
    pub fn read(&mut self, f: &FileInfo) -> Result<Vec<u8>, ZipError> {
        self.reader.seek(f.local_file_header_offset as i64, SeekSet);
        let h = format::LocalFileHeader::read(&mut self.reader).unwrap();
        let file_offset = f.local_file_header_offset as i64 + h.total_size() as i64;

        let result =
            match u16_to_CompressionMethod(h.compression_method) {
                Store => self.read_stored_file(file_offset, h.uncompressed_size),
                Deflate => self.read_deflated_file(file_offset, h.compressed_size, h.uncompressed_size),
                _ => fail!()
            };
        let result = try!(io_result_to_zip_result(result));

        // Check the CRC32 of the result against the one stored in the header
        let crc = crc32::crc32(result.as_slice());

        if crc == h.crc32 { Ok(result) }
        else { Err(CrcError) }
    }

    fn read_stored_file(&mut self, pos: i64, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        self.reader.read_exact(uncompressed_size as uint)
    }

    fn read_deflated_file(&mut self, pos: i64, compressed_size: u32, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        let compressed_bytes = try!(self.reader.read_exact(compressed_size as uint));
        let uncompressed_bytes = match flate::inflate_bytes(compressed_bytes.as_slice()) {
            Some(bytes) => bytes,
            None => return Err(IoError { kind: InvalidInput, desc: "decompression failure", detail: None })
        };
        assert!(uncompressed_bytes.len() as u32 == uncompressed_size);
        // FIXME try not to copy the buffer, or switch to the incremental fashion
        Ok(Vec::from_slice(uncompressed_bytes.as_slice()))
    }

    // when we make read return a Reader, we will be able to loop here and copy
    // blocks of a fixed size from Reader to Writer
    pub fn extract<T:Writer>(&mut self, f: &FileInfo, writer: &mut T) -> Result<(), ZipError> {
        match self.read(f) {
            Ok(bytes) => {writer.write(bytes.as_slice()); Ok(())},
            Err(x) => Err(x)
        }
    }

}

<commit_msg>fixed some warnings.<commit_after>#![crate_id = "zip"]
#![crate_type = "lib"]

#![desc="A simple rust library for reading and writing ZIP files"]
#![license="MIT"]

extern crate flate;

use std::io::{Reader, Writer, Seek, SeekSet, SeekEnd};
use std::io::{IoResult, IoError, InvalidInput};
use std::iter::range_inclusive;

mod crc32;
pub mod format;

#[deriving(Eq,Show)]
pub enum ZipError {
    IoError(IoError),
    NotAZipFile,
    CrcError,
    FileNotFoundInArchive
}

fn io_result_to_zip_result<T>(x: IoResult<T>) -> Result<T, ZipError> {
    match x {
        Ok(v) => Ok(v),
        Err(e) => Err(IoError(e)),
    }
}

#[deriving(Eq,Show,Clone)]
pub enum CompressionMethod {
    Store=0,
    Deflate=8,
    Unknown
}

fn u16_to_CompressionMethod(x: u16) -> CompressionMethod {
    let u = x as uint;
    if      u == (Store   as uint) { Store }
    else if u == (Deflate as uint) { Deflate }
    else                           { Unknown }
}

#[deriving(Clone)]
pub struct FileInfo {
    pub name:               String,
    pub compression_method: CompressionMethod,
    pub last_modified_time: (int, int, int), // (hour, minute, second)
    pub last_modified_date: (int, int, int), // (year, month, day)
    pub crc32:              u32,
    pub compressed_size:    u32,
    pub uncompressed_size:  u32,
    pub is_encrypted:       bool,

    pub local_file_header_offset: u32,
}

impl FileInfo {
    // fills a FileInfo struct with the file properties, for users of the external API to see
    pub fn from_cdh(h: &format::CentralDirectoryHeader) -> FileInfo {
        let method : CompressionMethod =
            if h.compression_method == 0 { Store }
            else if h.compression_method == 8 { Deflate }
            else { fail!() };
        FileInfo {
            name:               h.file_name.clone(),
            compression_method: method,
            last_modified_time: format::decode_msdos_time(h.last_modified_time),
            last_modified_date: format::decode_msdos_date(h.last_modified_date),
            crc32:              h.crc32,
            compressed_size:    h.compressed_size,
            uncompressed_size:  h.uncompressed_size,
            local_file_header_offset: h.relative_offset_of_local_header,
            is_encrypted:       h.is_encrypted(),
        }
    }
}

pub struct ZipReader<T> {
    reader: T,
    end_record: format::EndOfCentralDirectoryRecord,
}

pub struct ZipReaderIterator<'a, T> {
    zip_reader: &'a mut ZipReader<T>,
    current_entry: u16,
    current_offset: u64,
}

impl<'a, T:Reader+Seek> Iterator<FileInfo> for ZipReaderIterator<'a, T> {
    fn next(&mut self) -> Option<FileInfo> {
        if self.current_entry < self.zip_reader.end_record.total_entry_count {
            self.zip_reader.reader.seek(self.current_offset as i64, SeekSet);
            let h = format::CentralDirectoryHeader::read(&mut self.zip_reader.reader).unwrap();
            let info = FileInfo::from_cdh(&h);
            self.current_entry += 1;
            self.current_offset += h.total_size() as u64;
            Some(info)
        } else {
            None
        }
    }
}

impl<T:Reader+Seek> ZipReader<T> {
    pub fn new(reader: T) -> Result<ZipReader<T>, ZipError> {
        // find the End of Central Directory record, looking backwards from the end of the file
        let mut r = reader;
        try!(io_result_to_zip_result(r.seek(0, SeekEnd)));
        let file_size = try!(io_result_to_zip_result(r.tell()));
        let mut end_record_offset : Option<u64> = None;
        for i in range_inclusive(4, file_size) {
            let offset = file_size - i;
            try!(io_result_to_zip_result(r.seek(offset as i64, SeekSet)));

            let sig = try!(io_result_to_zip_result(r.read_le_u32()));

            // TODO: check for false positives here
            if sig == format::EOCDR_SIGNATURE {
                end_record_offset = Some(offset);
                break;
            }

        }

        match end_record_offset {
            Some(offset) => {
                try!(io_result_to_zip_result(r.seek(offset as i64, SeekSet)));
                let e = format::EndOfCentralDirectoryRecord::read(&mut r).unwrap();
                Ok(ZipReader {reader: r, end_record: e})
            },
            None => Err(NotAZipFile)
        }
    }

    pub fn iter<'a>(&'a mut self) -> ZipReaderIterator<'a, T> {
        ZipReaderIterator {
            zip_reader: self,
            current_entry: 0,
            current_offset: self.end_record.central_directory_offset as u64
        }
    }

    pub fn infolist(&mut self) -> Vec<FileInfo> {
        let mut result = Vec::new();
        for info in self.iter() {
            result.push(info);
        }
        result
    }

    pub fn namelist(&mut self) -> Vec<String> {
        let mut result = Vec::new();
        for info in self.iter() {
            result.push(info.name.clone());
        }
        result
    }

    pub fn get_file_info(&mut self, name: &str) -> Result<FileInfo, ZipError> {
        for i in self.iter() {
            if name.equiv(&i.name) {
                return Ok(i);
            }
        }
        Err(FileNotFoundInArchive)
    }

    // TODO: Create a Reader for the cases when you don't want to decompress the whole file
    pub fn read(&mut self, f: &FileInfo) -> Result<Vec<u8>, ZipError> {
        try!(io_result_to_zip_result(self.reader.seek(f.local_file_header_offset as i64, SeekSet)));
        let h = format::LocalFileHeader::read(&mut self.reader).unwrap();
        let file_offset = f.local_file_header_offset as i64 + h.total_size() as i64;

        let result =
            match u16_to_CompressionMethod(h.compression_method) {
                Store => self.read_stored_file(file_offset, h.uncompressed_size),
                Deflate => self.read_deflated_file(file_offset, h.compressed_size, h.uncompressed_size),
                _ => fail!()
            };
        let result = try!(io_result_to_zip_result(result));

        // Check the CRC32 of the result against the one stored in the header
        let crc = crc32::crc32(result.as_slice());

        if crc == h.crc32 { Ok(result) }
        else { Err(CrcError) }
    }

    fn read_stored_file(&mut self, pos: i64, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        self.reader.read_exact(uncompressed_size as uint)
    }

    fn read_deflated_file(&mut self, pos: i64, compressed_size: u32, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        let compressed_bytes = try!(self.reader.read_exact(compressed_size as uint));
        let uncompressed_bytes = match flate::inflate_bytes(compressed_bytes.as_slice()) {
            Some(bytes) => bytes,
            None => return Err(IoError { kind: InvalidInput, desc: "decompression failure", detail: None })
        };
        assert!(uncompressed_bytes.len() as u32 == uncompressed_size);
        // FIXME try not to copy the buffer, or switch to the incremental fashion
        Ok(Vec::from_slice(uncompressed_bytes.as_slice()))
    }

    // when we make read return a Reader, we will be able to loop here and copy
    // blocks of a fixed size from Reader to Writer
    pub fn extract<T:Writer>(&mut self, f: &FileInfo, writer: &mut T) -> Result<(), ZipError> {
        match self.read(f) {
            Ok(bytes) => io_result_to_zip_result(writer.write(bytes.as_slice())),
            Err(x) => Err(x)
        }
    }

}

<|endoftext|>


<commit_before>// montecarlo.rs
// Some simple Monte-Carlo simulations in Rust
// Taken from: https://ggcarvalho.dev/posts/montecarlo
//
// vim: ft=rust sw=4 ts=4
//

extern crate rand;

//use rand::rngs::SmallRng::from_seed;
use rand::distributions::Uniform;
use rand::prelude::*;

/// Run a given number of simulations to estimate the value of Pi
pub fn simulate_pi(n: usize) -> f64 {
    // random generator
    let mut rng = SmallRng::seed_from_u64(1234);
    let unif = Uniform::new(0.0, 1.0);

    let mut count: usize = 0;
    for _ in (1..n).into_iter() {
        let x: f64 = 2.0 * rng.sample(unif) - 1.0;
        let y: f64 = 2.0 * rng.sample(unif) - 1.0;

        if x * x + y * y < 1.0 {
            count += 1;
        }
    }
    let pi_approx = 4.0 * (count as f64 / n as f64);

    pi_approx
}

// unit tests
#[cfg(test)]
mod test {
    extern crate float_cmp;
    use crate::montecarlo::simulate_pi;
    use float_cmp::approx_eq;

    #[test]
    fn test_sim_pi() {
        let pi_approx = simulate_pi(100_000);

        println!("pi_approx: {}", pi_approx);
        assert!(approx_eq!(
            f64,
            pi_approx,
            std::f64::consts::PI,
            epsilon = 0.001
        ));
    }
}
<commit_msg>simulate e by monte carlo<commit_after>// montecarlo.rs
// Some simple Monte-Carlo simulations in Rust
// Taken from: https://ggcarvalho.dev/posts/montecarlo
//
// vim: ft=rust sw=4 ts=4
//

extern crate rand;

//use rand::rngs::SmallRng::from_seed;
use rand::distributions::Uniform;
use rand::prelude::*;

/// Run a given number of simulations to estimate the value of Pi
pub fn simulate_pi(n: usize) -> f64 {
    // random generator
    let mut rng = SmallRng::seed_from_u64(1234);
    let unif = Uniform::new(0.0, 1.0);

    let mut count: usize = 0;
    for _ in (1..n).into_iter() {
        let x: f64 = 2.0 * rng.sample(unif) - 1.0;
        let y: f64 = 2.0 * rng.sample(unif) - 1.0;

        if x * x + y * y < 1.0 {
            count += 1;
        }
    }
    let pi_approx = 4.0 * (count as f64 / n as f64);

    pi_approx
}

/// Run a given number of simulations to estimate the value of e (2.71..)
pub fn simulate_e(n: usize) -> f64 {
    // random generator
    let mut rng = SmallRng::seed_from_u64(1234);
    let unif = Uniform::new(0.0, 1.0);

    let mut count: usize = 0;
    for _ in (1..n).into_iter() {
        let mut sum = 0f64;
        let mut sum_count: usize = 0;
        while sum < 1.0 {
            sum += rng.sample(unif);
            sum_count += 1;
        }
        count += sum_count;
    }
    let e_approx = count as f64 / n as f64;

    e_approx
}

// unit tests
#[cfg(test)]
mod test {
    extern crate float_cmp;
    use crate::montecarlo::{simulate_e, simulate_pi};
    use float_cmp::approx_eq;

    #[test]
    fn test_sim_pi() {
        let pi_approx = simulate_pi(100_000);

        assert!(approx_eq!(
            f64,
            pi_approx,
            std::f64::consts::PI,
            epsilon = 0.001
        ));
    }

    #[test]
    fn test_sim_e() {
        let e_approx = simulate_e(100_000);

        assert!(approx_eq!(
            f64,
            e_approx,
            std::f64::consts::E,
            epsilon = 0.001
        ));
    }
}
<|endoftext|>


<commit_before>extern crate mws;
use chrono::offset::TimeZone;
use chrono::{DateTime, NaiveDate, Utc};
use std::path::PathBuf;
use structopt::StructOpt;

use mws::client::Client;

mod env;

use self::env::Env;

#[derive(Debug, StructOpt)]
#[structopt(name = "mws-cli", about = "MWS CLI.")]
struct Opt {
  #[structopt(long = "env", parse(from_os_str))]
  env: Option<PathBuf>,
  #[structopt(subcommand)]
  cmd: Command,
}

#[derive(Debug, StructOpt)]
enum Command {
  ReportRequest {
    #[structopt(long = "report_type")]
    report_type: String,
    #[structopt(long = "start_date", parse(try_from_str))]
    start_date: Option<NaiveDate>,
    #[structopt(long = "end_date", parse(try_from_str))]
    end_date: Option<NaiveDate>,
    #[structopt(long = "report_options")]
    report_options: Option<String>,
    #[structopt(long = "marketplace")]
    marketplace_id_list: Option<Vec<String>>,
  },
  ReportListRequestByIds {
    #[structopt(long = "id")]
    ids: Vec<String>,
  },
  ReportListRequestByTypes {
    #[structopt(long = "type")]
    types: Vec<String>,
  },
  ReportGet {
    #[structopt(long = "id")]
    id: String,
    #[structopt(long = "out", parse(from_os_str))]
    out: PathBuf,
  },
  EncodingConvJp {
    #[structopt(long = "in", parse(from_os_str))]
    input: PathBuf,
    #[structopt(long = "out", parse(from_os_str))]
    out: PathBuf,
  },
  ProductGetLowestPricedOffersForSKU {
    #[structopt(long = "marketplace")]
    marketplace_id: String,
    #[structopt(long = "seller_sku")]
    seller_sku: String,
    #[structopt(long = "condition")]
    condition: String,
  },
  ProductGetMyPriceForASIN {
    #[structopt(long = "marketplace")]
    marketplace_id: String,
    #[structopt(long = "asin")]
    asins: Vec<String>,
    #[structopt(long = "condition")]
    condition: Option<String>,
  },
  SubmitFeed {
    #[structopt(long = "feed_type")]
    feed_type: String,
    #[structopt(long = "contant_file", parse(from_os_str))]
    content_file: PathBuf,
    #[structopt(long = "marketplace")]
    marketplace_id_list: Option<Vec<String>>,
    #[structopt(long = "content_type")]
    content_type: String,
  },
}

fn main() {
  let opt = Opt::from_args();

  let env_path = opt.env.unwrap_or_else(|| PathBuf::from(".env"));

  println!("env path: {:?}", env_path);
  ::dotenv::from_path(&env_path).ok();

  let env = Env::from_env();

  println!("seller id: {}", env.seller_id);
  println!("region id: {}", env.region_id);

  let client = get_client(&env);

  match opt.cmd {
    Command::ReportRequest {
      report_type,
      start_date,
      end_date,
      report_options,
      marketplace_id_list,
    } => {
      use mws::reports::*;
      let res = RequestReport(
        &client,
        RequestReportParameters {
          ReportType: report_type,
          StartDate: start_date.map(get_utc_datetime),
          EndDate: end_date.map(get_utc_datetime),
          ReportOptions: report_options,
          MarketplaceIdList: marketplace_id_list,
        },
      )
      .unwrap();
      println!("{:#?}", res)
    }
    Command::ReportListRequestByIds { ids } => {
      use mws::reports::*;
      let res = GetReportRequestList(
        &client,
        GetReportRequestListParameters {
          ReportRequestIdList: Some(ids),
          ..Default::default()
        },
      )
      .unwrap();

      println!("{:#?}", res)
    }
    Command::ReportListRequestByTypes { types } => {
      use mws::reports::*;
      let res = GetReportRequestList(
        &client,
        GetReportRequestListParameters {
          ReportTypeList: Some(types),
          ..Default::default()
        },
      )
      .unwrap();

      println!("{:#?}", res)
    }
    Command::ReportGet { id, out } => {
      use mws::reports::*;
      let mut out = std::fs::File::create(out).unwrap();
      GetReport(&client, id, &mut out).unwrap();
    }
    Command::EncodingConvJp { input, out } => {
      use encoding_rs::*;
      let bytes = std::fs::read(input).unwrap();
      let (cow, encoding_used, had_errors) = SHIFT_JIS.decode(&bytes);
      if had_errors {
        panic!("decode error.")
      }
      println!("encoding_used: {:?}", encoding_used);
      std::fs::write(out, cow.as_ref()).unwrap();
    }
    Command::ProductGetLowestPricedOffersForSKU {
      marketplace_id,
      seller_sku,
      condition,
    } => {
      use mws::products::*;
      let res = GetLowestPricedOffersForSKU(
        &client,
        GetLowestPricedOffersForSKUParameters {
          MarketplaceId: marketplace_id,
          SellerSKU: seller_sku,
          ItemCondition: ItemCondition::from(&condition as &str),
        },
      )
      .unwrap();
      println!("{:#?}", res)
    }
    Command::ProductGetMyPriceForASIN {
      marketplace_id,
      asins,
      condition,
    } => {
      use mws::products::*;
      let res = GetMyPriceForASIN(
        &client,
        GetMyPriceForASINParameters {
          MarketplaceId: marketplace_id,
          ASINList: asins,
          ItemCondition: condition.map(|v| ItemCondition::from(&v as &str)),
        },
      )
      .unwrap();
      println!("{:#?}", res)
    },
    Command::SubmitFeed {
      feed_type,
      content_file,
      marketplace_id_list,
      content_type
    } => {
      use mws::feeds::*;
      use std::io::Cursor;
      let content = std::fs::read(content_file).unwrap();
      let digest = md5::compute(&content);
      let b64 = base64::encode(&*digest);
      let res = SubmitFeed(
        &client,
        SubmitFeedParameters {
          FeedType: feed_type,
          MarketplaceIdList: marketplace_id_list,
          PurgeAndReplace: None,
        },
        Cursor::new(content),
        b64,
        content_type
      ).unwrap();
      println!("{:#?}", res)
    }
  }
}

fn get_client(env: &Env) -> Client {
  use mws::client::ClientOptions;
  use mws::constants;
  let region = constants::get_region(&env.region_id).expect("invalid region id");
  let opts = ClientOptions {
    endpoint: region.endpoint.to_string(),
    seller_id: env.seller_id.clone(),
    mws_auth_token: env.auth_token.clone(),
    aws_access_key_id: env.access_key_id.clone(),
    secret_key: env.secret_key.clone(),
  };
  Client::new(opts).unwrap()
}

fn get_utc_datetime(date: NaiveDate) -> DateTime<Utc> {
  Utc.from_utc_date(&date).and_hms(0, 0, 0)
}
<commit_msg>feat: cli list subscription<commit_after>extern crate mws;
use chrono::offset::TimeZone;
use chrono::{DateTime, NaiveDate, Utc};
use std::path::PathBuf;
use structopt::StructOpt;

use mws::client::Client;

mod env;

use self::env::Env;

#[derive(Debug, StructOpt)]
#[structopt(name = "mws-cli", about = "MWS CLI.")]
struct Opt {
  #[structopt(long = "env", parse(from_os_str))]
  env: Option<PathBuf>,
  #[structopt(subcommand)]
  cmd: Command,
}

#[derive(Debug, StructOpt)]
enum Command {
  ReportRequest {
    #[structopt(long = "report_type")]
    report_type: String,
    #[structopt(long = "start_date", parse(try_from_str))]
    start_date: Option<NaiveDate>,
    #[structopt(long = "end_date", parse(try_from_str))]
    end_date: Option<NaiveDate>,
    #[structopt(long = "report_options")]
    report_options: Option<String>,
    #[structopt(long = "marketplace")]
    marketplace_id_list: Option<Vec<String>>,
  },
  ReportListRequestByIds {
    #[structopt(long = "id")]
    ids: Vec<String>,
  },
  ReportListRequestByTypes {
    #[structopt(long = "type")]
    types: Vec<String>,
  },
  ReportGet {
    #[structopt(long = "id")]
    id: String,
    #[structopt(long = "out", parse(from_os_str))]
    out: PathBuf,
  },
  EncodingConvJp {
    #[structopt(long = "in", parse(from_os_str))]
    input: PathBuf,
    #[structopt(long = "out", parse(from_os_str))]
    out: PathBuf,
  },
  ProductGetLowestPricedOffersForSKU {
    #[structopt(long = "marketplace")]
    marketplace_id: String,
    #[structopt(long = "seller_sku")]
    seller_sku: String,
    #[structopt(long = "condition")]
    condition: String,
  },
  ProductGetMyPriceForASIN {
    #[structopt(long = "marketplace")]
    marketplace_id: String,
    #[structopt(long = "asin")]
    asins: Vec<String>,
    #[structopt(long = "condition")]
    condition: Option<String>,
  },
  SubmitFeed {
    #[structopt(long = "feed_type")]
    feed_type: String,
    #[structopt(long = "contant_file", parse(from_os_str))]
    content_file: PathBuf,
    #[structopt(long = "marketplace")]
    marketplace_id_list: Option<Vec<String>>,
    #[structopt(long = "content_type")]
    content_type: String,
  },
  ListSubscriptions {
    #[structopt(long = "marketplace")]
    marketplace_id: String,
  },
}

fn main() {
  let opt = Opt::from_args();

  let env_path = opt.env.unwrap_or_else(|| PathBuf::from(".env"));

  println!("env path: {:?}", env_path);
  ::dotenv::from_path(&env_path).ok();

  let env = Env::from_env();

  println!("seller id: {}", env.seller_id);
  println!("region id: {}", env.region_id);

  let client = get_client(&env);

  match opt.cmd {
    Command::ReportRequest {
      report_type,
      start_date,
      end_date,
      report_options,
      marketplace_id_list,
    } => {
      use mws::reports::*;
      let res = RequestReport(
        &client,
        RequestReportParameters {
          ReportType: report_type,
          StartDate: start_date.map(get_utc_datetime),
          EndDate: end_date.map(get_utc_datetime),
          ReportOptions: report_options,
          MarketplaceIdList: marketplace_id_list,
        },
      )
      .unwrap();
      println!("{:#?}", res)
    }
    Command::ReportListRequestByIds { ids } => {
      use mws::reports::*;
      let res = GetReportRequestList(
        &client,
        GetReportRequestListParameters {
          ReportRequestIdList: Some(ids),
          ..Default::default()
        },
      )
      .unwrap();

      println!("{:#?}", res)
    }
    Command::ReportListRequestByTypes { types } => {
      use mws::reports::*;
      let res = GetReportRequestList(
        &client,
        GetReportRequestListParameters {
          ReportTypeList: Some(types),
          ..Default::default()
        },
      )
      .unwrap();

      println!("{:#?}", res)
    }
    Command::ReportGet { id, out } => {
      use mws::reports::*;
      let mut out = std::fs::File::create(out).unwrap();
      GetReport(&client, id, &mut out).unwrap();
    }
    Command::EncodingConvJp { input, out } => {
      use encoding_rs::*;
      let bytes = std::fs::read(input).unwrap();
      let (cow, encoding_used, had_errors) = SHIFT_JIS.decode(&bytes);
      if had_errors {
        panic!("decode error.")
      }
      println!("encoding_used: {:?}", encoding_used);
      std::fs::write(out, cow.as_ref()).unwrap();
    }
    Command::ProductGetLowestPricedOffersForSKU {
      marketplace_id,
      seller_sku,
      condition,
    } => {
      use mws::products::*;
      let res = GetLowestPricedOffersForSKU(
        &client,
        GetLowestPricedOffersForSKUParameters {
          MarketplaceId: marketplace_id,
          SellerSKU: seller_sku,
          ItemCondition: ItemCondition::from(&condition as &str),
        },
      )
      .unwrap();
      println!("{:#?}", res)
    }
    Command::ProductGetMyPriceForASIN {
      marketplace_id,
      asins,
      condition,
    } => {
      use mws::products::*;
      let res = GetMyPriceForASIN(
        &client,
        GetMyPriceForASINParameters {
          MarketplaceId: marketplace_id,
          ASINList: asins,
          ItemCondition: condition.map(|v| ItemCondition::from(&v as &str)),
        },
      )
      .unwrap();
      println!("{:#?}", res)
    }
    Command::SubmitFeed {
      feed_type,
      content_file,
      marketplace_id_list,
      content_type,
    } => {
      use mws::feeds::*;
      use std::io::Cursor;
      let content = std::fs::read(content_file).unwrap();
      let digest = md5::compute(&content);
      let b64 = base64::encode(&*digest);
      let res = SubmitFeed(
        &client,
        SubmitFeedParameters {
          FeedType: feed_type,
          MarketplaceIdList: marketplace_id_list,
          PurgeAndReplace: None,
        },
        Cursor::new(content),
        b64,
        content_type,
      )
      .unwrap();
      println!("{:#?}", res)
    }
    Command::ListSubscriptions { marketplace_id } => {
      use mws::subscriptions::*;
      let res = ListSubscriptions(&client, marketplace_id).unwrap();
      println!("{:#?}", res)
    }
  }
}

fn get_client(env: &Env) -> Client {
  use mws::client::ClientOptions;
  use mws::constants;
  let region = constants::get_region(&env.region_id).expect("invalid region id");
  let opts = ClientOptions {
    endpoint: region.endpoint.to_string(),
    seller_id: env.seller_id.clone(),
    mws_auth_token: env.auth_token.clone(),
    aws_access_key_id: env.access_key_id.clone(),
    secret_key: env.secret_key.clone(),
  };
  Client::new(opts).unwrap()
}

fn get_utc_datetime(date: NaiveDate) -> DateTime<Utc> {
  Utc.from_utc_date(&date).and_hms(0, 0, 0)
}
<|endoftext|>


<commit_before>use RealNumber;
use super::super::{
	array_to_complex_mut,
	VoidResult, Buffer, Owner,
	NumberSpace, Domain,
	DspVec, Vector, ToSliceMut,
};

pub trait ReorganizeDataOps<S, T>
 	where T: RealNumber,
	      S: ToSliceMut<T> {
	/// Reverses the data inside the vector.
	///
	/// # Example
	///
	/// ```
    /// use basic_dsp_vector::vector_types2::*;
    /// let mut vector = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0).to_real_time_vec();
    /// vector.reverse();
    /// assert_eq!([8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0], vector[..]);
    /// ```
	fn reverse(&mut self);

	/// This function swaps both halves of the vector. This operation is also called FFT shift
	/// Use it after a `plain_fft` to get a spectrum which is centered at `0 Hz`.
	///
	/// # Example
	///
	/// ```
    /// use basic_dsp_vector::vector_types2::*;
    /// let mut vector = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0).to_real_time_vec();
	/// let mut buffer = SingleBuffer::new();
    /// vector.swap_halves(&mut buffer);
    /// assert_eq!([5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0], vector[..]);
    /// ```
	fn swap_halves<B>(&mut self, buffer: &mut B)
		where B: Buffer<S, T>;
}

/// An option which defines how a vector should be padded
#[derive(Copy)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
pub enum PaddingOption {
    /// Appends zeros to the end of the vector.
    End,
    /// Surrounds the vector with zeros at the beginning and at the end.
    Surround,

    /// Inserts zeros in the center of the vector
    Center,
}

pub trait InsertZerosOps {
	/// Appends zeros add the end of the vector until the vector has the size given in the points argument.
	/// If `points` smaller than the `self.len()` then this operation won't do anything.
	///
	/// Note: Each point is two floating point numbers if the vector is complex.
	/// Note2: Adding zeros to the signal changes its power. If this function is used to zero pad to a power
	/// of 2 in order to speed up FFT calculation then it might be necessary to multiply it with `len_after/len_before`\
	/// so that the spectrum shows the expected power. Of course this is depending on the application.
	/// # Example
	///
	/// ```
	/// use basic_dsp_vector::{PaddingOption, RealTimeVector32, ComplexTimeVector32, GenericVectorOps, DataVec, RealIndex, InterleavedIndex};
	/// let vector = RealTimeVector32::from_array(&[1.0, 2.0]);
	/// let result = vector.zero_pad(4, PaddingOption::End).expect("Ignoring error handling in examples");
	/// assert_eq!([1.0, 2.0, 0.0, 0.0], result.real(0..));
	/// let vector = ComplexTimeVector32::from_interleaved(&[1.0, 2.0]);
	/// let result = vector.zero_pad(2, PaddingOption::End).expect("Ignoring error handling in examples");
	/// assert_eq!([1.0, 2.0, 0.0, 0.0], result.interleaved(0..));
	/// ```
	fn zero_pad(&mut self, points: usize, option: PaddingOption);

	/// Interleaves zeros `factor - 1`times after every vector element, so that the resulting
	/// vector will have a length of `self.len() * factor`.
	///
	/// Note: Remember that each complex number consists of two floating points and interleaving
	/// will take that into account.
	///
	/// If factor is 0 (zero) then `self` will be returned.
	/// # Example
	///
	/// ```
	/// use basic_dsp_vector::{RealTimeVector32, ComplexTimeVector32, GenericVectorOps, DataVec, RealIndex, InterleavedIndex};
	/// let vector = RealTimeVector32::from_array(&[1.0, 2.0]);
	/// let result = vector.zero_interleave(2).expect("Ignoring error handling in examples");
	/// assert_eq!([1.0, 0.0, 2.0, 0.0], result.real(0..));
	/// let vector = ComplexTimeVector32::from_interleaved(&[1.0, 2.0, 3.0, 4.0]);
	/// let result = vector.zero_interleave(2).expect("Ignoring error handling in examples");
	/// assert_eq!([1.0, 2.0, 0.0, 0.0, 3.0, 4.0, 0.0, 0.0], result.interleaved(0..));
	/// ```
	fn zero_interleave(&mut self, factor: u32);
}

pub trait SplitOps {
	/// Splits the vector into several smaller vectors. `self.len()` must be dividable by
    /// `targets.len()` without a remainder and this condition must be true too `targets.len() > 0`.
    /// # Failures
    /// TransRes may report the following `ErrorReason` members:
    ///
    /// 1. `InvalidArgumentLength`: `self.points()` isn't dividable by `targets.len()`
    ///
    /// # Example
    ///
    /// ```
    /// use basic_dsp_vector::{RealTimeVector32, GenericVectorOps, DataVec, RealIndex};
    /// let a = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
    /// let merge = RealTimeVector32::from_array(&a);
    /// let mut split = &mut
    ///     [Box::new(RealTimeVector32::empty()),
    ///     Box::new(RealTimeVector32::empty())];
    /// merge.split_into(split).unwrap();
    /// assert_eq!([1.0, 3.0, 5.0, 7.0, 9.0], split[0].real(0..));
    /// ```
    fn split_into(&self, targets: &mut [Box<Self>]) -> VoidResult;
}

pub trait MergeOps {
    /// Merges several vectors into `self`. All vectors must have the same size and
    /// at least one vector must be provided.
    /// # Failures
    /// TransRes may report the following `ErrorReason` members:
    ///
    /// 1. `InvalidArgumentLength`: if `sources.len() == 0`
    ///
    /// # Example
    ///
    /// ```
    /// use basic_dsp_vector::{RealTimeVector32, GenericVectorOps, DataVec, RealIndex};
    /// let vector = RealTimeVector32::empty();
    /// let parts = &[
    ///     Box::new(RealTimeVector32::from_array(&[1.0, 2.0])),
    ///     Box::new(RealTimeVector32::from_array(&[1.0, 2.0]))];
    /// let merged = vector.merge(parts).expect("Ignoring error handling in examples");
    /// assert_eq!([1.0, 1.0, 2.0, 2.0], merged.real(0..));
    /// ```
    fn merge(&mut self, sources: &[Box<Self>]) -> VoidResult;
}

impl<S, T, N, D> ReorganizeDataOps<S, T> for DspVec<S, T, N, D>
    where S: ToSliceMut<T> + Owner,
          T: RealNumber,
          N: NumberSpace,
          D: Domain {
	fn reverse(&mut self) {
		if self.is_complex() {
			let len = self.points();
			let mut data = self.data.to_slice_mut();
			let mut data = array_to_complex_mut(&mut data[..]);
			for i in 0..len / 2 {
				let temp = data[i];
				data[i] = data[len - 1 - i];
				data[len - 1 - i] = temp;
			}
		} else {
			let len = self.len();
			let mut data = self.data.to_slice_mut();
			for i in 0..len / 2 {
				let temp = data[i];
				data[i] = data[len - 1 - i];
				data[len - 1 - i] = temp;
			}
		}

	}

	fn swap_halves<B>(&mut self, buffer: &mut B)
		where B: Buffer<S, T> {
		self.swap_halves_priv(buffer, true);
	}
}
<commit_msg>zero_pad and zero_interleave for vec2<commit_after>use std::mem;
use std::ptr;
use RealNumber;
use multicore_support::*;
use super::super::{
	array_to_complex_mut,
	VoidResult, Buffer, Owner,
	NumberSpace, Domain,
	DspVec, Vector, ToSliceMut,
};

pub trait ReorganizeDataOps<S, T>
 	where T: RealNumber,
	      S: ToSliceMut<T> {
	/// Reverses the data inside the vector.
	///
	/// # Example
	///
	/// ```
    /// use basic_dsp_vector::vector_types2::*;
    /// let mut vector = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0).to_real_time_vec();
    /// vector.reverse();
    /// assert_eq!([8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0], vector[..]);
    /// ```
	fn reverse(&mut self);

	/// This function swaps both halves of the vector. This operation is also called FFT shift
	/// Use it after a `plain_fft` to get a spectrum which is centered at `0 Hz`.
	///
	/// # Example
	///
	/// ```
    /// use basic_dsp_vector::vector_types2::*;
    /// let mut vector = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0).to_real_time_vec();
	/// let mut buffer = SingleBuffer::new();
    /// vector.swap_halves(&mut buffer);
    /// assert_eq!([5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0], vector[..]);
    /// ```
	fn swap_halves<B>(&mut self, buffer: &mut B)
		where B: Buffer<S, T>;
}

/// An option which defines how a vector should be padded
#[derive(Copy)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
pub enum PaddingOption {
    /// Appends zeros to the end of the vector.
    End,
    /// Surrounds the vector with zeros at the beginning and at the end.
    Surround,

    /// Inserts zeros in the center of the vector
    Center,
}

pub trait InsertZerosOps<S, T>
 	where T: RealNumber,
	      S: ToSliceMut<T> {
	/// Appends zeros add the end of the vector until the vector has the size given in the points argument.
	/// If `points` smaller than the `self.len()` then this operation won't do anything.
	///
	/// Note: Each point is two floating point numbers if the vector is complex.
	/// Note2: Adding zeros to the signal changes its power. If this function is used to zero pad to a power
	/// of 2 in order to speed up FFT calculation then it might be necessary to multiply it with `len_after/len_before`\
	/// so that the spectrum shows the expected power. Of course this is depending on the application.
	/// # Example
	///
	/// ```
    /// use basic_dsp_vector::vector_types2::*;
    /// let mut vector = vec!(1.0, 2.0).to_real_time_vec();
	/// let mut buffer = SingleBuffer::new();
    /// vector.zero_pad(&mut buffer, 4, PaddingOption::End);
    /// assert_eq!([1.0, 2.0, 0.0, 0.0], vector[..]);
	/// let mut vector = vec!(1.0, 2.0).to_complex_time_vec();
	/// let mut buffer = SingleBuffer::new();
    /// vector.zero_pad(&mut buffer, 2, PaddingOption::End);
    /// assert_eq!([1.0, 2.0, 0.0, 0.0], vector[..]);
    /// ```
	fn zero_pad<B>(&mut self, buffer: &mut B, points: usize, option: PaddingOption)
		where B: Buffer<S, T>;

	/// Interleaves zeros `factor - 1`times after every vector element, so that the resulting
	/// vector will have a length of `self.len() * factor`.
	///
	/// Note: Remember that each complex number consists of two floating points and interleaving
	/// will take that into account.
	///
	/// If factor is 0 (zero) then `self` will be returned.
	/// # Example
	///
	/// ```
    /// use basic_dsp_vector::vector_types2::*;
    /// let mut vector = vec!(1.0, 2.0).to_real_time_vec();
	/// let mut buffer = SingleBuffer::new();
    /// vector.zero_interleave(&mut buffer, 2);
    /// assert_eq!([1.0, 0.0, 2.0, 0.0], vector[..]);
	/// let mut vector = vec!(1.0, 2.0, 3.0, 4.0).to_complex_time_vec();
	/// let mut buffer = SingleBuffer::new();
    /// vector.zero_interleave(&mut buffer, 2);
    /// assert_eq!([1.0, 2.0, 0.0, 0.0, 3.0, 4.0, 0.0, 0.0], vector[..]);
    /// ```
	fn zero_interleave<B>(&mut self, buffer: &mut B, factor: u32)
		where B: Buffer<S, T>;
}

pub trait SplitOps {
	/// Splits the vector into several smaller vectors. `self.len()` must be dividable by
    /// `targets.len()` without a remainder and this condition must be true too `targets.len() > 0`.
    /// # Failures
    /// TransRes may report the following `ErrorReason` members:
    ///
    /// 1. `InvalidArgumentLength`: `self.points()` isn't dividable by `targets.len()`
    ///
    /// # Example
    ///
    /// ```
    /// use basic_dsp_vector::{RealTimeVector32, GenericVectorOps, DataVec, RealIndex};
    /// let a = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
    /// let merge = RealTimeVector32::from_array(&a);
    /// let mut split = &mut
    ///     [Box::new(RealTimeVector32::empty()),
    ///     Box::new(RealTimeVector32::empty())];
    /// merge.split_into(split).unwrap();
    /// assert_eq!([1.0, 3.0, 5.0, 7.0, 9.0], split[0].real(0..));
    /// ```
    fn split_into(&self, targets: &mut [Box<Self>]) -> VoidResult;
}

pub trait MergeOps {
    /// Merges several vectors into `self`. All vectors must have the same size and
    /// at least one vector must be provided.
    /// # Failures
    /// TransRes may report the following `ErrorReason` members:
    ///
    /// 1. `InvalidArgumentLength`: if `sources.len() == 0`
    ///
    /// # Example
    ///
    /// ```
    /// use basic_dsp_vector::{RealTimeVector32, GenericVectorOps, DataVec, RealIndex};
    /// let vector = RealTimeVector32::empty();
    /// let parts = &[
    ///     Box::new(RealTimeVector32::from_array(&[1.0, 2.0])),
    ///     Box::new(RealTimeVector32::from_array(&[1.0, 2.0]))];
    /// let merged = vector.merge(parts).expect("Ignoring error handling in examples");
    /// assert_eq!([1.0, 1.0, 2.0, 2.0], merged.real(0..));
    /// ```
    fn merge(&mut self, sources: &[Box<Self>]) -> VoidResult;
}

impl<S, T, N, D> ReorganizeDataOps<S, T> for DspVec<S, T, N, D>
    where S: ToSliceMut<T> + Owner,
          T: RealNumber,
          N: NumberSpace,
          D: Domain {
	fn reverse(&mut self) {
		if self.is_complex() {
			let len = self.points();
			let mut data = self.data.to_slice_mut();
			let mut data = array_to_complex_mut(&mut data[..]);
			for i in 0..len / 2 {
				let temp = data[i];
				data[i] = data[len - 1 - i];
				data[len - 1 - i] = temp;
			}
		} else {
			let len = self.len();
			let mut data = self.data.to_slice_mut();
			for i in 0..len / 2 {
				let temp = data[i];
				data[i] = data[len - 1 - i];
				data[len - 1 - i] = temp;
			}
		}

	}

	fn swap_halves<B>(&mut self, buffer: &mut B)
		where B: Buffer<S, T> {
		self.swap_halves_priv(buffer, true);
	}
}

macro_rules! zero_interleave {
    ($self_: ident, $buffer: ident, $step: ident, $tuple: expr) => {
        {
            if $step <= 1 {
                return;
            }

            let step = $step as usize;
            let old_len = $self_.len();
            let new_len = step * old_len;
            $self_.valid_len = new_len;
            let mut target = $buffer.get(new_len);
			{
				let mut target = target.to_slice_mut();
				let source = &$self_.data.to_slice();
                Chunk::from_src_to_dest(
                    Complexity::Small, &$self_.multicore_settings,
                    &source[0..old_len], $tuple,
                    &mut target[0..new_len], $tuple * step, (),
                    move|original, range, target, _arg| {
                         // Zero target
                        let ptr = &mut target[0] as *mut T;
                        unsafe {
                            ptr::write_bytes(ptr, 0, new_len);
                        }
                        let skip = step * $tuple;
                        let mut i = 0;
                        let mut j = range.start;
                        while i < target.len() {
                            let original_ptr = unsafe { original.get_unchecked(j) };
                            let target_ptr = unsafe { target.get_unchecked_mut(i) };
                            unsafe {
                                ptr::copy(original_ptr, target_ptr, $tuple);
                            }

                            j += $tuple;
                            i += skip;
                        }
            	});
			}

			mem::swap(&mut $self_.data, &mut target);
			$buffer.free(target);
        }
    }
}

impl<S, T, N, D> InsertZerosOps<S, T> for DspVec<S, T, N, D>
	where S: ToSliceMut<T> + Owner,
	  T: RealNumber,
	  N: NumberSpace,
	  D: Domain {
	fn zero_pad<B>(&mut self, buffer: &mut B, points: usize, option: PaddingOption)
		where B: Buffer<S, T> {
		let len_before = self.len();
		let is_complex = self.is_complex();
		let len = if is_complex { 2 * points } else { points };
		if len < len_before {
			return;
		}

		let mut target = buffer.get(len);
		{
			let data = self.data.to_slice();
			let target = target.to_slice_mut();
			self.valid_len = len;
			match option {
				PaddingOption::End => {
					// Zero target
					let src = &data[0] as *const T;
					let dest_start = &mut target[0] as *mut T;
					let dest_end = &mut target[len_before] as *mut T;
					unsafe {
						ptr::copy(src, dest_start, len_before);
						ptr::write_bytes(dest_end, 0, target.len() - len_before);
					}
				}
				PaddingOption::Surround => {
					let diff = (len - len_before) / if is_complex { 2 } else { 1 };
					let mut right = diff / 2;
					let mut left = diff - right;
					if is_complex {
						right *= 2;
						left *= 2;
					}

					unsafe {
						let src = &data[0] as *const T;
						let dest = &mut target[left] as *mut T;
						ptr::copy(src, dest, len_before);
						let dest = &mut target[len - right] as *mut T;
						ptr::write_bytes(dest, 0, right);
						let dest = &mut target[0] as *mut T;
						ptr::write_bytes(dest, 0, left);
					}
				}
				PaddingOption::Center => {
					let mut diff = (len - len_before) / if is_complex { 2 } else { 1 };
					let mut right = diff / 2;
					let mut left = diff - right;
					if is_complex {
						right *= 2;
						left *= 2;
						diff *= 2;
					}

					unsafe {
						let src = &data[left] as *const T;
						let dest = &mut target[len-right] as *mut T;
						ptr::copy(src, dest, right);
						let dest = &mut target[left] as *mut T;
						ptr::write_bytes(dest, 0, len - diff);
					}
				}
			}
		}

		mem::swap(&mut self.data, &mut target);
		buffer.free(target);
	}

	fn zero_interleave<B>(&mut self, buffer: &mut B, factor: u32)
		where B: Buffer<S, T> {
		if self.is_complex() {
			zero_interleave!(self, buffer, factor, 2)
		} else {
			zero_interleave!(self, buffer, factor, 1)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

macro_rules! impl_object_for_object_types {
    ( $( $objtype:ident ),* ) => {
        impl Info for Object {
            fn status(&self, download_dir: &std::path::Path) -> crate::object::Result<Status> {
                match *self {
                    $( Object::$objtype(ref o) => Ok(o.status(download_dir)?), )*
                }
            }

            fn filename(&self) -> &str {
                match *self {
                    $( Object::$objtype(ref o) => o.filename(), )*
                }
            }

            fn len(&self) -> u64 {
                match *self {
                    $( Object::$objtype(ref o) => o.len(), )*
                }
            }

            fn sha256sum(&self) -> &str {
                match *self {
                    $( Object::$objtype(ref o) => o.sha256sum(), )*
                }
            }

            fn required_install_size(&self) -> u64 {
                match *self {
                    $( Object::$objtype(ref o) => o.required_install_size(), )*
                }
            }
        }
    };
}

macro_rules! impl_object_info {
    ($objtype:ty) => {
        impl Info for $objtype {
            fn filename(&self) -> &str {
                &self.filename
            }

            fn len(&self) -> u64 {
                self.size
            }

            fn sha256sum(&self) -> &str {
                &self.sha256sum
            }

            fn required_install_size(&self) -> u64 {
                self.size
            }
        }
    };
}

macro_rules! impl_compressed_object_info {
    ($objtype:ty) => {
        impl Info for $objtype {
            fn filename(&self) -> &str {
                &self.filename
            }

            fn len(&self) -> u64 {
                self.size
            }

            fn sha256sum(&self) -> &str {
                &self.sha256sum
            }

            fn required_install_size(&self) -> u64 {
                self.required_uncompressed_size
            }
        }
    };
}

macro_rules! for_any_object {
    ($mode:ident, $alias:ident, $code:block) => {
        match $mode {
            Object::Copy($alias) => $code,
            Object::Flash($alias) => $code,
            Object::Imxkobs($alias) => $code,
            Object::Raw($alias) => $code,
            Object::Tarball($alias) => $code,
            Object::Test($alias) => $code,
            Object::Ubifs($alias) => $code,
        }
    };
}

// This wil execute the block only if the $rule is present, if so, the block
// must return a `R` that implements `Read` and `Seek`. If the
// `check_if_different` reports `Ok(true)` for `R` return is called.
macro_rules! handle_install_if_different {
    ($rule:expr, $sha256sum:expr, $handler:block) => {
        match $rule {
            Some(ref rule) => match $handler.and_then(|mut h| {
                crate::object::installer::check_if_different(&mut h, rule, $sha256sum)
            }) {
                Ok(true) => {
                    slog_scope::info!("Skipping installation due to install if different rule");
                    return Ok(());
                }
                Ok(false) => {
                    slog_scope::debug!("Install if different reported difference");
                }
                Err(e) => {
                    slog_scope::info!("Install if different reported error: {}", e);
                }
            },
            None => slog_scope::debug!("No install if different rule set, proceeding"),
        }
    };
}
<commit_msg>updatehub: Improve logging related to install if different checks<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

macro_rules! impl_object_for_object_types {
    ( $( $objtype:ident ),* ) => {
        impl Info for Object {
            fn status(&self, download_dir: &std::path::Path) -> crate::object::Result<Status> {
                match *self {
                    $( Object::$objtype(ref o) => Ok(o.status(download_dir)?), )*
                }
            }

            fn filename(&self) -> &str {
                match *self {
                    $( Object::$objtype(ref o) => o.filename(), )*
                }
            }

            fn len(&self) -> u64 {
                match *self {
                    $( Object::$objtype(ref o) => o.len(), )*
                }
            }

            fn sha256sum(&self) -> &str {
                match *self {
                    $( Object::$objtype(ref o) => o.sha256sum(), )*
                }
            }

            fn required_install_size(&self) -> u64 {
                match *self {
                    $( Object::$objtype(ref o) => o.required_install_size(), )*
                }
            }
        }
    };
}

macro_rules! impl_object_info {
    ($objtype:ty) => {
        impl Info for $objtype {
            fn filename(&self) -> &str {
                &self.filename
            }

            fn len(&self) -> u64 {
                self.size
            }

            fn sha256sum(&self) -> &str {
                &self.sha256sum
            }

            fn required_install_size(&self) -> u64 {
                self.size
            }
        }
    };
}

macro_rules! impl_compressed_object_info {
    ($objtype:ty) => {
        impl Info for $objtype {
            fn filename(&self) -> &str {
                &self.filename
            }

            fn len(&self) -> u64 {
                self.size
            }

            fn sha256sum(&self) -> &str {
                &self.sha256sum
            }

            fn required_install_size(&self) -> u64 {
                self.required_uncompressed_size
            }
        }
    };
}

macro_rules! for_any_object {
    ($mode:ident, $alias:ident, $code:block) => {
        match $mode {
            Object::Copy($alias) => $code,
            Object::Flash($alias) => $code,
            Object::Imxkobs($alias) => $code,
            Object::Raw($alias) => $code,
            Object::Tarball($alias) => $code,
            Object::Test($alias) => $code,
            Object::Ubifs($alias) => $code,
        }
    };
}

// This wil execute the block only if the $rule is present, if so, the block
// must return a `R` that implements `Read` and `Seek`. If the
// `check_if_different` reports `Ok(true)` for `R` return is called.
macro_rules! handle_install_if_different {
    ($rule:expr, $sha256sum:expr, $handler:block) => {
        match $rule {
            Some(ref rule) => match $handler.and_then(|mut h| {
                crate::object::installer::check_if_different(&mut h, rule, $sha256sum)
            }) {
                Ok(true) => {
                    slog_scope::info!(
                        "installation has been skipped (install if different): {}",
                        $rule.as_ref().unwrap()
                    );
                    return Ok(());
                }
                Ok(false) => {
                    slog_scope::debug!(
                        "installation will proceed (installation if different): {}",
                        $rule.as_ref().unwrap()
                    );
                }
                Err(e) => {
                    slog_scope::error!(
                        "install if different check ({}) check failed, error: {}",
                        $rule.as_ref().unwrap(),
                        e
                    );
                }
            },
            None => slog_scope::trace!("no install if different rule set, proceeding"),
        }
    };
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Modules/input_ps2/lib.rs
//! PS2 Keyboard/Mouse controller
#![feature(no_std,core,linkage)]
#![no_std]
#![feature(core_slice_ext)]
#![feature(const_fn)]	// needed for lazystatic_init

#[macro_use]
extern crate kernel;

extern crate gui;

use kernel::prelude::*;

// HACK: Requires USB to be active to ensure that emulation is off
module_define!{PS2, [DeviceManager, ACPI, GUI/*, USB*/], init}

#[derive(Debug)]
enum PS2Dev
{
	None,
	Unknown,
	Enumerating(EnumWaitState),
	Keyboard(keyboard::Dev),
	Mouse(mouse::Dev),
}
impl Default for PS2Dev { fn default() -> Self { PS2Dev::None } }

#[derive(Copy,Clone,Debug)]
enum EnumWaitState
{
	DSAck,
	IdentAck,
	IdentB1,
	IdentB2(u8),
}

mod i8042;

mod keyboard;
mod mouse;

fn init()
{
	// TODO: Support other controller types (e.g. the ARM PL050)
	i8042::init();
}

impl PS2Dev
{
	fn new_mouse(ty: mouse::Type) -> (Option<u8>, Option<PS2Dev>) {
		let (byte, dev) = mouse::Dev::new(ty);
		(byte, Some(PS2Dev::Mouse(dev)))
	}
	fn new_keyboard(ty: keyboard::Type) -> (Option<u8>, Option<PS2Dev>) {
		let (byte, dev) = keyboard::Dev::new(ty);
		(byte, Some(PS2Dev::Keyboard(dev)))
	}

	/// Handle a recieved byte, and optionally return a byte to be sent to the device
	pub fn recv_byte(&mut self, byte: u8) -> Option<u8> {
		log_trace!("PS2 Byte {:#x}", byte);
		let (rv, new_state): (Option<_>,Option<_>) = match *self
			{
			PS2Dev::None =>
				// TODO: Clean this section up, the OSDev.org wiki is a little hazy on the ordering
				if byte == 0xFA {
					(None, None)
				}
				else if byte == 0xAA {
					(Some(0xF5), Some(PS2Dev::Enumerating(EnumWaitState::DSAck)))
				}
				else {
					(None, None)
				},
			PS2Dev::Unknown => (None, None),
			PS2Dev::Enumerating(state) => match state
				{
				EnumWaitState::DSAck =>
					if byte == 0xFA {
						(Some(0xF2), Some(PS2Dev::Enumerating(EnumWaitState::IdentAck)))
					}
					else {
						(None, Some(PS2Dev::Unknown))
					},
				EnumWaitState::IdentAck =>
					if byte == 0xFA {
						(None, Some(PS2Dev::Enumerating(EnumWaitState::IdentB1)))
					}
					else {
						(None, Some(PS2Dev::Unknown))
					},
				EnumWaitState::IdentB1 =>
					match byte
					{
					0x00 => Self::new_mouse(mouse::Type::Std),
					0x03 => Self::new_mouse(mouse::Type::Scroll),
					0x04 => Self::new_mouse(mouse::Type::QuintBtn),
					0xAB => (None, Some(PS2Dev::Enumerating(EnumWaitState::IdentB2(byte)))),
					_ => {
						log_warning!("Unknown PS/2 device {:#02x}", byte);
						(None, Some(PS2Dev::Unknown))
						},
					},
				EnumWaitState::IdentB2(b1) =>
					match (b1,byte)
					{
					(0xAB, 0x83) => Self::new_keyboard(keyboard::Type::MF2),
					(0xAB, 0x41) => Self::new_keyboard(keyboard::Type::MF2Emul),
					(0xAB, 0xC1) => Self::new_keyboard(keyboard::Type::MF2Emul),
					_ => {
						log_warning!("Unknown PS/2 device {:#02x} {:#02x}", b1, byte);
						(None, Some(PS2Dev::Unknown))
						},
					},
				},
			PS2Dev::Keyboard(ref mut dev) => {
				(dev.recv_byte(byte), None)
				},
			PS2Dev::Mouse(ref mut dev) => {
				(dev.recv_byte(byte), None)
				},
			};

		if let Some(ns) = new_state
		{
			log_debug!("State transition {:?} to {:?}", *self, ns);
			*self = ns;
		}
		rv
	}
}

<commit_msg>Kernel (minor) - Remove core feature from ps2 driver (remove warning)<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Modules/input_ps2/lib.rs
//! PS2 Keyboard/Mouse controller
#![feature(no_std,linkage)]
#![no_std]
#![feature(core_slice_ext)]
#![feature(const_fn)]	// needed for lazystatic_init

#[macro_use]
extern crate kernel;

extern crate gui;

use kernel::prelude::*;

// HACK: Requires USB to be active to ensure that emulation is off
module_define!{PS2, [DeviceManager, ACPI, GUI/*, USB*/], init}

#[derive(Debug)]
enum PS2Dev
{
	None,
	Unknown,
	Enumerating(EnumWaitState),
	Keyboard(keyboard::Dev),
	Mouse(mouse::Dev),
}
impl Default for PS2Dev { fn default() -> Self { PS2Dev::None } }

#[derive(Copy,Clone,Debug)]
enum EnumWaitState
{
	DSAck,
	IdentAck,
	IdentB1,
	IdentB2(u8),
}

mod i8042;

mod keyboard;
mod mouse;

fn init()
{
	// TODO: Support other controller types (e.g. the ARM PL050)
	i8042::init();
}

impl PS2Dev
{
	fn new_mouse(ty: mouse::Type) -> (Option<u8>, Option<PS2Dev>) {
		let (byte, dev) = mouse::Dev::new(ty);
		(byte, Some(PS2Dev::Mouse(dev)))
	}
	fn new_keyboard(ty: keyboard::Type) -> (Option<u8>, Option<PS2Dev>) {
		let (byte, dev) = keyboard::Dev::new(ty);
		(byte, Some(PS2Dev::Keyboard(dev)))
	}

	/// Handle a recieved byte, and optionally return a byte to be sent to the device
	pub fn recv_byte(&mut self, byte: u8) -> Option<u8> {
		log_trace!("PS2 Byte {:#x}", byte);
		let (rv, new_state): (Option<_>,Option<_>) = match *self
			{
			PS2Dev::None =>
				// TODO: Clean this section up, the OSDev.org wiki is a little hazy on the ordering
				if byte == 0xFA {
					(None, None)
				}
				else if byte == 0xAA {
					(Some(0xF5), Some(PS2Dev::Enumerating(EnumWaitState::DSAck)))
				}
				else {
					(None, None)
				},
			PS2Dev::Unknown => (None, None),
			PS2Dev::Enumerating(state) => match state
				{
				EnumWaitState::DSAck =>
					if byte == 0xFA {
						(Some(0xF2), Some(PS2Dev::Enumerating(EnumWaitState::IdentAck)))
					}
					else {
						(None, Some(PS2Dev::Unknown))
					},
				EnumWaitState::IdentAck =>
					if byte == 0xFA {
						(None, Some(PS2Dev::Enumerating(EnumWaitState::IdentB1)))
					}
					else {
						(None, Some(PS2Dev::Unknown))
					},
				EnumWaitState::IdentB1 =>
					match byte
					{
					0x00 => Self::new_mouse(mouse::Type::Std),
					0x03 => Self::new_mouse(mouse::Type::Scroll),
					0x04 => Self::new_mouse(mouse::Type::QuintBtn),
					0xAB => (None, Some(PS2Dev::Enumerating(EnumWaitState::IdentB2(byte)))),
					_ => {
						log_warning!("Unknown PS/2 device {:#02x}", byte);
						(None, Some(PS2Dev::Unknown))
						},
					},
				EnumWaitState::IdentB2(b1) =>
					match (b1,byte)
					{
					(0xAB, 0x83) => Self::new_keyboard(keyboard::Type::MF2),
					(0xAB, 0x41) => Self::new_keyboard(keyboard::Type::MF2Emul),
					(0xAB, 0xC1) => Self::new_keyboard(keyboard::Type::MF2Emul),
					_ => {
						log_warning!("Unknown PS/2 device {:#02x} {:#02x}", b1, byte);
						(None, Some(PS2Dev::Unknown))
						},
					},
				},
			PS2Dev::Keyboard(ref mut dev) => {
				(dev.recv_byte(byte), None)
				},
			PS2Dev::Mouse(ref mut dev) => {
				(dev.recv_byte(byte), None)
				},
			};

		if let Some(ns) = new_state
		{
			log_debug!("State transition {:?} to {:?}", *self, ns);
			*self = ns;
		}
		rv
	}
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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 crate::known_types::KNOWN_TYPES;
use crate::types::{Namespace, TypeName};
use std::collections::HashMap;
use syn::{ItemStruct, Type};

#[derive(Clone)]
enum PodState {
    UnsafeToBePod(String),
    SafeToBePod,
    IsPod,
    IsAlias(TypeName),
}

#[derive(Clone)]
struct StructDetails {
    state: PodState,
    dependent_structs: Vec<TypeName>,
}

impl StructDetails {
    fn new(state: PodState) -> Self {
        StructDetails {
            state,
            dependent_structs: Vec::new(),
        }
    }
}

/// Type which is able to check whether it's safe to make a type
/// fully representable by cxx. For instance if it is a struct containing
/// a struct containing a std::string, the answer is no, because that
/// std::string contains a self-referential pointer.
/// It is possible that this is duplicative of the information stored
/// elsewhere in the `Api` list and could possibly be removed or simplified.
pub struct ByValueChecker {
    // Mapping from type name to whether it is safe to be POD
    results: HashMap<TypeName, StructDetails>,
}

impl ByValueChecker {
    pub fn new() -> Self {
        let mut results = HashMap::new();
        for (tn, by_value_safe) in KNOWN_TYPES.get_pod_safe_types() {
            let safety = if by_value_safe {
                PodState::IsPod
            } else {
                PodState::UnsafeToBePod(format!("type {} is not safe for POD", tn))
            };
            results.insert(tn, StructDetails::new(safety));
        }
        ByValueChecker { results }
    }

    pub fn ingest_blocklist<'a>(&mut self, blocklist: impl Iterator<Item = &'a String>) {
        for blocklisted in blocklist {
            let tn = TypeName::new_from_user_input(blocklisted);
            let safety = PodState::UnsafeToBePod(format!("type {} is on the blocklist", &tn));
            self.results.insert(tn, StructDetails::new(safety));
        }
    }

    pub fn ingest_struct(&mut self, def: &ItemStruct, ns: &Namespace) {
        // For this struct, work out whether it _could_ be safe as a POD.
        let tyname = TypeName::new(ns, &def.ident.to_string());
        let mut field_safety_problem = PodState::SafeToBePod;
        let fieldlist = Self::get_field_types(def);
        for ty_id in &fieldlist {
            match self.results.get(ty_id) {
                None => {
                    field_safety_problem = PodState::UnsafeToBePod(format!(
                        "Type {} could not be POD because its dependent type {} isn't known",
                        tyname, ty_id
                    ));
                    break;
                }
                Some(deets) => {
                    if let PodState::UnsafeToBePod(reason) = &deets.state {
                        let new_reason = format!("Type {} could not be POD because its dependent type {} isn't safe to be POD. Because: {}", tyname, ty_id, reason);
                        field_safety_problem = PodState::UnsafeToBePod(new_reason);
                        break;
                    }
                }
            }
        }
        let has_vtable = Self::has_vtable(def);
        if has_vtable {
            let reason = format!(
                "Type {} could not be POD because it has virtual functions.",
                tyname
            );
            field_safety_problem = PodState::UnsafeToBePod(reason);
        }
        let mut my_details = StructDetails::new(field_safety_problem);
        my_details.dependent_structs = fieldlist;
        self.results.insert(tyname, my_details);
    }

    pub fn ingest_pod_type(&mut self, tyname: TypeName) {
        self.results
            .insert(tyname, StructDetails::new(PodState::IsPod));
    }

    pub fn ingest_simple_typedef(&mut self, tyname: TypeName, target: TypeName) {
        self.results
            .insert(tyname, StructDetails::new(PodState::IsAlias(target)));
    }

    pub fn ingest_nonpod_type(&mut self, tyname: TypeName) {
        let new_reason = format!("Type {} is a typedef to a complex type", tyname);
        self.results.insert(
            tyname,
            StructDetails::new(PodState::UnsafeToBePod(new_reason)),
        );
    }

    pub fn satisfy_requests(&mut self, mut requests: Vec<TypeName>) -> Result<(), String> {
        while !requests.is_empty() {
            let ty_id = requests.remove(requests.len() - 1);
            let deets = self.results.get_mut(&ty_id);
            let mut alias_to_consider = None;
            match deets {
                None => {
                    return Err(format!(
                        "Unable to make {} POD because we never saw a struct definition",
                        ty_id
                    ))
                }
                Some(deets) => match &deets.state {
                    PodState::UnsafeToBePod(error_msg) => return Err(error_msg.clone()),
                    PodState::IsPod => {}
                    PodState::SafeToBePod => {
                        deets.state = PodState::IsPod;
                        requests.extend_from_slice(&deets.dependent_structs);
                    }
                    PodState::IsAlias(target_type) => {
                        alias_to_consider = Some(target_type.clone());
                    }
                },
            }
            // Do the following outside the match to avoid borrow checker violation.
            if let Some(alias) = alias_to_consider {
                match self.results.get(&alias) {
                    None => requests.extend_from_slice(&[alias, ty_id]), // try again after resolving alias target
                    Some(alias_target_deets) => {
                        self.results.get_mut(&ty_id).unwrap().state =
                            alias_target_deets.state.clone();
                    }
                }
            }
        }
        Ok(())
    }

    /// Return whether a given type is POD (i.e. can be represented by value in Rust) or not.
    /// Unless we've got a definite record that it _is_, we return false.
    /// Some types won't be in our `results` map. For example: (a) AutocxxConcrete types
    /// which we've synthesized; (b) types we couldn't parse but returned ignorable
    /// errors so that we could continue. Assume non-POD for all such cases.
    pub fn is_pod(&self, ty_id: &TypeName) -> bool {
        matches!(
            self.results.get(ty_id),
            Some(StructDetails {
                state: PodState::IsPod,
                dependent_structs: _,
            })
        )
    }

    fn get_field_types(def: &ItemStruct) -> Vec<TypeName> {
        let mut results = Vec::new();
        for f in &def.fields {
            let fty = &f.ty;
            if let Type::Path(p) = fty {
                results.push(TypeName::from_type_path(&p));
            }
            // TODO handle anything else which bindgen might spit out, e.g. arrays?
        }
        results
    }

    fn has_vtable(def: &ItemStruct) -> bool {
        for f in &def.fields {
            if f.ident.as_ref().map(|id| id == "vtable_").unwrap_or(false) {
                return true;
            }
        }
        false
    }
}

#[cfg(test)]
mod tests {
    use super::ByValueChecker;
    use crate::types::{Namespace, TypeName};
    use syn::{parse_quote, ItemStruct};

    #[test]
    fn test_primitive_by_itself() {
        let bvc = ByValueChecker::new();
        let t_id = TypeName::new_from_user_input("u32");
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_primitives() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Foo {
                a: i32,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        bvc.satisfy_requests(vec![t_id.clone()]).unwrap();
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_nested_primitives() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Foo {
                a: i32,
                b: i64,
            }
        };
        bvc.ingest_struct(&t, &Namespace::new());
        let t: ItemStruct = parse_quote! {
            struct Bar {
                a: Foo,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        bvc.satisfy_requests(vec![t_id.clone()]).unwrap();
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_with_up() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Bar {
                a: UniquePtr<CxxString>,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        bvc.satisfy_requests(vec![t_id.clone()]).unwrap();
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_with_cxxstring() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Bar {
                a: CxxString,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        assert!(bvc.satisfy_requests(vec![t_id]).is_err());
    }
}
<commit_msg>Fix ByValueChecker test.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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 crate::known_types::KNOWN_TYPES;
use crate::types::{Namespace, TypeName};
use std::collections::HashMap;
use syn::{ItemStruct, Type};

#[derive(Clone)]
enum PodState {
    UnsafeToBePod(String),
    SafeToBePod,
    IsPod,
    IsAlias(TypeName),
}

#[derive(Clone)]
struct StructDetails {
    state: PodState,
    dependent_structs: Vec<TypeName>,
}

impl StructDetails {
    fn new(state: PodState) -> Self {
        StructDetails {
            state,
            dependent_structs: Vec::new(),
        }
    }
}

/// Type which is able to check whether it's safe to make a type
/// fully representable by cxx. For instance if it is a struct containing
/// a struct containing a std::string, the answer is no, because that
/// std::string contains a self-referential pointer.
/// It is possible that this is duplicative of the information stored
/// elsewhere in the `Api` list and could possibly be removed or simplified.
pub struct ByValueChecker {
    // Mapping from type name to whether it is safe to be POD
    results: HashMap<TypeName, StructDetails>,
}

impl ByValueChecker {
    pub fn new() -> Self {
        let mut results = HashMap::new();
        for (tn, by_value_safe) in KNOWN_TYPES.get_pod_safe_types() {
            let safety = if by_value_safe {
                PodState::IsPod
            } else {
                PodState::UnsafeToBePod(format!("type {} is not safe for POD", tn))
            };
            results.insert(tn, StructDetails::new(safety));
        }
        ByValueChecker { results }
    }

    pub fn ingest_blocklist<'a>(&mut self, blocklist: impl Iterator<Item = &'a String>) {
        for blocklisted in blocklist {
            let tn = TypeName::new_from_user_input(blocklisted);
            let safety = PodState::UnsafeToBePod(format!("type {} is on the blocklist", &tn));
            self.results.insert(tn, StructDetails::new(safety));
        }
    }

    pub fn ingest_struct(&mut self, def: &ItemStruct, ns: &Namespace) {
        // For this struct, work out whether it _could_ be safe as a POD.
        let tyname = TypeName::new(ns, &def.ident.to_string());
        let mut field_safety_problem = PodState::SafeToBePod;
        let fieldlist = Self::get_field_types(def);
        for ty_id in &fieldlist {
            match self.results.get(ty_id) {
                None => {
                    field_safety_problem = PodState::UnsafeToBePod(format!(
                        "Type {} could not be POD because its dependent type {} isn't known",
                        tyname, ty_id
                    ));
                    break;
                }
                Some(deets) => {
                    if let PodState::UnsafeToBePod(reason) = &deets.state {
                        let new_reason = format!("Type {} could not be POD because its dependent type {} isn't safe to be POD. Because: {}", tyname, ty_id, reason);
                        field_safety_problem = PodState::UnsafeToBePod(new_reason);
                        break;
                    }
                }
            }
        }
        let has_vtable = Self::has_vtable(def);
        if has_vtable {
            let reason = format!(
                "Type {} could not be POD because it has virtual functions.",
                tyname
            );
            field_safety_problem = PodState::UnsafeToBePod(reason);
        }
        let mut my_details = StructDetails::new(field_safety_problem);
        my_details.dependent_structs = fieldlist;
        self.results.insert(tyname, my_details);
    }

    pub fn ingest_pod_type(&mut self, tyname: TypeName) {
        self.results
            .insert(tyname, StructDetails::new(PodState::IsPod));
    }

    pub fn ingest_simple_typedef(&mut self, tyname: TypeName, target: TypeName) {
        self.results
            .insert(tyname, StructDetails::new(PodState::IsAlias(target)));
    }

    pub fn ingest_nonpod_type(&mut self, tyname: TypeName) {
        let new_reason = format!("Type {} is a typedef to a complex type", tyname);
        self.results.insert(
            tyname,
            StructDetails::new(PodState::UnsafeToBePod(new_reason)),
        );
    }

    pub fn satisfy_requests(&mut self, mut requests: Vec<TypeName>) -> Result<(), String> {
        while !requests.is_empty() {
            let ty_id = requests.remove(requests.len() - 1);
            let deets = self.results.get_mut(&ty_id);
            let mut alias_to_consider = None;
            match deets {
                None => {
                    return Err(format!(
                        "Unable to make {} POD because we never saw a struct definition",
                        ty_id
                    ))
                }
                Some(deets) => match &deets.state {
                    PodState::UnsafeToBePod(error_msg) => return Err(error_msg.clone()),
                    PodState::IsPod => {}
                    PodState::SafeToBePod => {
                        deets.state = PodState::IsPod;
                        requests.extend_from_slice(&deets.dependent_structs);
                    }
                    PodState::IsAlias(target_type) => {
                        alias_to_consider = Some(target_type.clone());
                    }
                },
            }
            // Do the following outside the match to avoid borrow checker violation.
            if let Some(alias) = alias_to_consider {
                match self.results.get(&alias) {
                    None => requests.extend_from_slice(&[alias, ty_id]), // try again after resolving alias target
                    Some(alias_target_deets) => {
                        self.results.get_mut(&ty_id).unwrap().state =
                            alias_target_deets.state.clone();
                    }
                }
            }
        }
        Ok(())
    }

    /// Return whether a given type is POD (i.e. can be represented by value in Rust) or not.
    /// Unless we've got a definite record that it _is_, we return false.
    /// Some types won't be in our `results` map. For example: (a) AutocxxConcrete types
    /// which we've synthesized; (b) types we couldn't parse but returned ignorable
    /// errors so that we could continue. Assume non-POD for all such cases.
    pub fn is_pod(&self, ty_id: &TypeName) -> bool {
        matches!(
            self.results.get(ty_id),
            Some(StructDetails {
                state: PodState::IsPod,
                dependent_structs: _,
            })
        )
    }

    fn get_field_types(def: &ItemStruct) -> Vec<TypeName> {
        let mut results = Vec::new();
        for f in &def.fields {
            let fty = &f.ty;
            if let Type::Path(p) = fty {
                results.push(TypeName::from_type_path(&p));
            }
            // TODO handle anything else which bindgen might spit out, e.g. arrays?
        }
        results
    }

    fn has_vtable(def: &ItemStruct) -> bool {
        for f in &def.fields {
            if f.ident.as_ref().map(|id| id == "vtable_").unwrap_or(false) {
                return true;
            }
        }
        false
    }
}

#[cfg(test)]
mod tests {
    use super::ByValueChecker;
    use crate::types::{Namespace, TypeName};
    use syn::{parse_quote, ItemStruct};

    #[test]
    fn test_primitive_by_itself() {
        let bvc = ByValueChecker::new();
        let t_id = TypeName::new_from_user_input("u32");
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_primitives() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Foo {
                a: i32,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        bvc.satisfy_requests(vec![t_id.clone()]).unwrap();
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_nested_primitives() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Foo {
                a: i32,
                b: i64,
            }
        };
        bvc.ingest_struct(&t, &Namespace::new());
        let t: ItemStruct = parse_quote! {
            struct Bar {
                a: Foo,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        bvc.satisfy_requests(vec![t_id.clone()]).unwrap();
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_with_up() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Bar {
                a: cxx::UniquePtr<CxxString>,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        bvc.satisfy_requests(vec![t_id.clone()]).unwrap();
        assert!(bvc.is_pod(&t_id));
    }

    #[test]
    fn test_with_cxxstring() {
        let mut bvc = ByValueChecker::new();
        let t: ItemStruct = parse_quote! {
            struct Bar {
                a: CxxString,
                b: i64,
            }
        };
        let t_id = TypeName::from_ident(&t.ident);
        bvc.ingest_struct(&t, &Namespace::new());
        assert!(bvc.satisfy_requests(vec![t_id]).is_err());
    }
}
<|endoftext|>


<commit_before>#![feature(libc,question_mark)]
extern crate libc;

use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::process::{Command, Stdio};
use std::str::from_utf8_unchecked;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {super::filename (path)}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}

/// Takes a netstring from the front of the slice.
///
/// Returns the unpacked netstring and the remainder of the slice.
pub fn netstring (at: &[u8]) -> Result<(&[u8], &[u8]), String> {
  let length_end = match at.iter().position (|&ch| ch < b'0' || ch > b'9') {Some (l) if l > 0 => l, _ => return ERR! ("No len.")};
  match at.get (length_end) {Some (&ch) if ch == b':' => (), _ => return ERR! ("No colon.")};
  let length = unsafe {from_utf8_unchecked (&at[0 .. length_end])};
  let length: usize = try_s! (length.parse());
  let bulk_pos = 0 + length_end + 1;
  let bulk_end = bulk_pos + length;
  match at.get (bulk_end) {Some (&ch) if ch == b',' => (), _ => return ERR! ("No comma.")}
  Ok ((&at[bulk_pos .. bulk_end], &at[bulk_end + 1 ..]))}

/// Wraps `gethostname` to fetch the current hostname into a temporary buffer.
#[cfg(unix)]
pub fn with_hostname (visitor: &mut FnMut (&[u8])) -> Result<(), std::io::Error> {
  use libc::{size_t, gethostname};  // http://man7.org/linux/man-pages/man2/gethostname.2.html
  use std::ffi::CStr;
  use std::io;

  let mut buf = [0; 128];
  let rc = unsafe {gethostname (buf.as_mut_ptr(), (buf.len() - 1) as size_t)};
  if rc == 0 {
    let cs = unsafe {CStr::from_ptr (buf.as_ptr())};
    Ok (visitor (cs.to_bytes()))
  } else {
    Err (io::Error::last_os_error())}}

#[cfg(unix)] #[test] fn test_hostname() {
  let mut hostname = String::new();
  with_hostname (&mut |bytes| hostname = String::from_utf8_lossy (bytes) .into_owned()) .unwrap();}

/// Read contents of the file into a String.
///
/// Returns an empty string if the file is not present under the given path.
pub fn slurp (path: &AsRef<Path>) -> String {
  let mut file = match fs::File::open (path) {
    Ok (f) => f,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => return String::new(),
    Err (err) => panic! ("Can't open {:?}: {}", path.as_ref(), err)};
  let mut buf = String::new();
  file.read_to_string (&mut buf) .expect ("!read");
  buf}

/// Runs a command in a shell, returning stderr+stdout on success.
///
/// Sometimes we need something simpler than constructing a Command.
///
/// If the command failed then returns it's stderr
pub fn slurp_prog (command: &str) -> Result<String, String> {
  let output = match Command::new ("bash") .arg ("-c") .arg (command) .output() {
    Ok (output) => output,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => {  // "sh" was not found, try a different name.
      try_s! (Command::new ("sh") .arg ("-c") .arg (command) .output())},
    Err (err) => return ERR! ("{}", err)};

  let combined_output: String = if output.stderr.is_empty() {
    try_s! (String::from_utf8 (output.stdout))
  } else if output.stdout.is_empty() {
    try_s! (String::from_utf8 (output.stderr))
  } else {
    let mut buf = String::with_capacity (output.stderr.len() + output.stdout.len());
    buf.push_str (try_s! (std::str::from_utf8 (&output.stderr[..])));
    buf.push_str (try_s! (std::str::from_utf8 (&output.stdout[..])));
    buf};

  if output.status.success() {Ok (combined_output)} else {Err (combined_output)}}

#[test] fn test_slurp_prog() {
  let foo = match slurp_prog ("echo foo") {Ok (foo) => foo, Err (err) => panic! ("{}", err)};
  assert_eq! (foo.trim(), "foo");}

/// Run a command, printing it first. Stdout and stderr are forwarded through (`inherit`).
pub fn cmd (cmd: &str) -> Result<(), String> {
  println! ("$ {}", cmd);
  let status = try_s! (Command::new ("bash") .arg ("-c") .arg (cmd) .stdout (Stdio::inherit()) .stderr (Stdio::inherit()) .status());
  if !status.success() {Err (format! ("Command returned an error status: {}", status))} else {Ok(())}}
<commit_msg>+any_to_str<commit_after>#![feature(libc,question_mark)]
extern crate libc;

use std::any::Any;
use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::process::{Command, Stdio};
use std::str::from_utf8_unchecked;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {super::filename (path)}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}

/// Takes a netstring from the front of the slice.
///
/// Returns the unpacked netstring and the remainder of the slice.
pub fn netstring (at: &[u8]) -> Result<(&[u8], &[u8]), String> {
  let length_end = match at.iter().position (|&ch| ch < b'0' || ch > b'9') {Some (l) if l > 0 => l, _ => return ERR! ("No len.")};
  match at.get (length_end) {Some (&ch) if ch == b':' => (), _ => return ERR! ("No colon.")};
  let length = unsafe {from_utf8_unchecked (&at[0 .. length_end])};
  let length: usize = try_s! (length.parse());
  let bulk_pos = 0 + length_end + 1;
  let bulk_end = bulk_pos + length;
  match at.get (bulk_end) {Some (&ch) if ch == b',' => (), _ => return ERR! ("No comma.")}
  Ok ((&at[bulk_pos .. bulk_end], &at[bulk_end + 1 ..]))}

/// Wraps `gethostname` to fetch the current hostname into a temporary buffer.
#[cfg(unix)]
pub fn with_hostname (visitor: &mut FnMut (&[u8])) -> Result<(), std::io::Error> {
  use libc::{size_t, gethostname};  // http://man7.org/linux/man-pages/man2/gethostname.2.html
  use std::ffi::CStr;
  use std::io;

  let mut buf = [0; 128];
  let rc = unsafe {gethostname (buf.as_mut_ptr(), (buf.len() - 1) as size_t)};
  if rc == 0 {
    let cs = unsafe {CStr::from_ptr (buf.as_ptr())};
    Ok (visitor (cs.to_bytes()))
  } else {
    Err (io::Error::last_os_error())}}

#[cfg(unix)] #[test] fn test_hostname() {
  let mut hostname = String::new();
  with_hostname (&mut |bytes| hostname = String::from_utf8_lossy (bytes) .into_owned()) .unwrap();}

/// Read contents of the file into a String.
///
/// Returns an empty string if the file is not present under the given path.
pub fn slurp (path: &AsRef<Path>) -> String {
  let mut file = match fs::File::open (path) {
    Ok (f) => f,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => return String::new(),
    Err (err) => panic! ("Can't open {:?}: {}", path.as_ref(), err)};
  let mut buf = String::new();
  file.read_to_string (&mut buf) .expect ("!read");
  buf}

/// Runs a command in a shell, returning stderr+stdout on success.
///
/// Sometimes we need something simpler than constructing a Command.
///
/// If the command failed then returns it's stderr
pub fn slurp_prog (command: &str) -> Result<String, String> {
  let output = match Command::new ("bash") .arg ("-c") .arg (command) .output() {
    Ok (output) => output,
    Err (ref err) if err.kind() == io::ErrorKind::NotFound => {  // "sh" was not found, try a different name.
      try_s! (Command::new ("sh") .arg ("-c") .arg (command) .output())},
    Err (err) => return ERR! ("{}", err)};

  let combined_output: String = if output.stderr.is_empty() {
    try_s! (String::from_utf8 (output.stdout))
  } else if output.stdout.is_empty() {
    try_s! (String::from_utf8 (output.stderr))
  } else {
    let mut buf = String::with_capacity (output.stderr.len() + output.stdout.len());
    buf.push_str (try_s! (std::str::from_utf8 (&output.stderr[..])));
    buf.push_str (try_s! (std::str::from_utf8 (&output.stdout[..])));
    buf};

  if output.status.success() {Ok (combined_output)} else {Err (combined_output)}}

#[test] fn test_slurp_prog() {
  let foo = match slurp_prog ("echo foo") {Ok (foo) => foo, Err (err) => panic! ("{}", err)};
  assert_eq! (foo.trim(), "foo");}

/// Run a command, printing it first. Stdout and stderr are forwarded through (`inherit`).
pub fn cmd (cmd: &str) -> Result<(), String> {
  println! ("$ {}", cmd);
  let status = try_s! (Command::new ("bash") .arg ("-c") .arg (cmd) .stdout (Stdio::inherit()) .stderr (Stdio::inherit()) .status());
  if !status.success() {Err (format! ("Command returned an error status: {}", status))} else {Ok(())}}

/// Useful with panic handlers.
pub fn any_to_str<'a> (message: &'a Box<Any + Send + 'static>) -> Option<&'a str> {
  if let Some (message) = message.downcast_ref::<&str>() {return Some (message)}
  if let Some (message) = message.downcast_ref::<String>() {return Some (&message[..])}
  return None}
<|endoftext|>