<commit_before>use regex::Regex;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;

use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn test_diff_in<F>(s: &str, include: &str, should_skip: F, stats: &mut TestStats)
where
    F: Fn(&str) -> bool,
{
    let rel_path_prefix = "../protobuf-test/";

    let include_full = format!("{}{}", rel_path_prefix, include);
    let s_full = format!("{}{}", rel_path_prefix, s);

    let inputs = to_paths(glob_simple(&format!("{}/*.proto", s_full)));
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    for input in &inputs {
        let label = input.display().to_string();
        assert!(label.starts_with(rel_path_prefix));
        let label = &label[rel_path_prefix.len()..];
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));
        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(temp_dir.path(), Path::new(&protoc_rs), Path::new(&pure_rs));
        }
    }
}

#[test]
fn test_diff() {
    let should_skip = |path: &str| {
        fs::read_to_string(path)
            .unwrap()
            .contains("@skip-codegen-identical-test")
    };

    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };
    test_diff_in("src/v2", "src/v2", should_skip, &mut stats);
    test_diff_in("src/v3", "src/v3", should_skip, &mut stats);
    test_diff_in("src/common/v2", "src/common/v2", should_skip, &mut stats);
    // TODO: test v3 files are generated, copy them here,
    //   do not rely on protobuf-test crate copying them
    //test_diff_in("src/common/v3", "src/common/v3", should_skip, &mut stats);
    test_diff_in("../interop/cxx", "../interop/cxx", should_skip, &mut stats);
    test_diff_in("src/google/protobuf", "src", |_| true, &mut stats);

    println!("{:?}", stats);
    assert!(stats.passed != 0, "sanity check");
    assert!(stats.failed == 0, "at least one test failed");
}
<commit_msg>Test common/v3 tests too<commit_after>use regex::Regex;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;

use protobuf_test_common::build::copy_tests_v2_v3;
use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn test_diff_in<F>(root: &str, s: &str, include: &str, should_skip: F, stats: &mut TestStats)
where
    F: Fn(&str) -> bool,
{
    let include_full = format!("{}/{}", root, include);
    let s_full = format!("{}/{}", root, s);

    let inputs_glob = format!("{}/*.proto", s_full);
    let inputs = to_paths(glob_simple(&inputs_glob));
    assert!(!inputs.is_empty(), "glob is empty: {}", inputs_glob);
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    for input in &inputs {
        let label = input.display().to_string();
        assert!(label.starts_with(&format!("{}/", root)));
        let label = &label[format!("{}/", root).len()..];
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));
        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(temp_dir.path(), Path::new(&protoc_rs), Path::new(&pure_rs));
        }
    }
}

#[test]
fn test_diff() {
    let should_skip = |path: &str| {
        fs::read_to_string(path)
            .unwrap()
            .contains("@skip-codegen-identical-test")
    };

    let common_v3_root = tempfile::Builder::new()
        .prefix("common-v3")
        .tempdir()
        .unwrap();
    fs::create_dir_all(format!(
        "{}/src/common/v3",
        common_v3_root.path().to_str().unwrap()
    ))
    .unwrap();

    copy_tests_v2_v3(
        "../protobuf-test/src/common/v2",
        &format!("{}/src/common/v3", common_v3_root.path().to_str().unwrap()),
    );

    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };
    test_diff_in(
        "../protobuf-test",
        "src/v2",
        "src/v2",
        should_skip,
        &mut stats,
    );
    test_diff_in(
        "../protobuf-test",
        "src/v3",
        "src/v3",
        should_skip,
        &mut stats,
    );
    test_diff_in(
        "../protobuf-test",
        "src/common/v2",
        "src/common/v2",
        should_skip,
        &mut stats,
    );
    test_diff_in(
        common_v3_root.path().to_str().unwrap(),
        "src/common/v3",
        "src/common/v3",
        should_skip,
        &mut stats,
    );
    test_diff_in(
        "../protobuf-test",
        "../interop/cxx",
        "../interop/cxx",
        should_skip,
        &mut stats,
    );
    test_diff_in(
        "../protobuf-test",
        "src/google/protobuf",
        "src",
        |_| true,
        &mut stats,
    );

    println!("{:?}", stats);
    assert!(stats.passed != 0, "sanity check");
    assert!(stats.failed == 0, "at least one test failed");
}
<|endoftext|>


<commit_before>mod error;
mod records;

pub use self::error::{Error, Result};
pub use self::records::{ChildTransaction, NewTransaction, TransactionByHash,
                        TransactionById};
use counters::Counters;
use mysql;

pub struct Mapper<'a> {
  select_transactions_by_hash: mysql::Stmt<'a>,
  select_transactions_by_id: mysql::Stmt<'a>,
  select_child_transactions: mysql::Stmt<'a>,
  insert_transaction: mysql::Stmt<'a>,
  insert_transaction_placeholder: mysql::Stmt<'a>,
  update_transaction: mysql::Stmt<'a>,
  approve_transaction: mysql::Stmt<'a>,
  direct_approve_transaction: mysql::Stmt<'a>,
  solidate_branch_transaction: mysql::Stmt<'a>,
  solidate_trunk_transaction: mysql::Stmt<'a>,
  select_addresses: mysql::Stmt<'a>,
  insert_address: mysql::Stmt<'a>,
  select_bundles: mysql::Stmt<'a>,
  insert_bundle: mysql::Stmt<'a>,
  update_bundle: mysql::Stmt<'a>,
  insert_event: mysql::Stmt<'a>,
}

impl<'a> Mapper<'a> {
  pub fn new(pool: &mysql::Pool) -> Result<Self> {
    Ok(Self {
      select_transactions_by_hash: pool.prepare(
        r#"
          SELECT id_tx, id_trunk, id_branch, solid FROM tx WHERE hash = :hash
        "#,
      )?,
      select_transactions_by_id: pool.prepare(
        r#"
          SELECT
            id_tx, id_trunk, id_branch, id_bundle, current_idx, mst_a
          FROM tx
          WHERE id_tx = :id_tx
        "#,
      )?,
      select_child_transactions: pool.prepare(
        r#"
          SELECT
            id_tx, id_trunk, id_branch, height, solid
          FROM tx
          WHERE id_trunk = :id_tx OR id_branch = :id_tx
        "#,
      )?,
      insert_transaction_placeholder: pool.prepare(
        r#"
          INSERT INTO tx (
            id_tx, hash, da, solid
          ) VALUES (
            :id_tx, :hash, 1, solid
          )
        "#,
      )?,
      insert_transaction: pool.prepare(
        r#"
          INSERT INTO tx (
            id_tx, hash, id_trunk, id_branch, id_address, id_bundle, tag, value,
            timestamp, current_idx, last_idx, is_mst, mst_a, solid
          ) VALUES (
            :id_tx, :hash, :id_trunk, :id_branch, :id_address, :id_bundle, :tag,
            :value, :timestamp, :current_idx, :last_idx, :is_mst, :mst_a, :solid
          )
        "#,
      )?,
      update_transaction: pool.prepare(
        r#"
          UPDATE tx SET
            id_trunk = :id_trunk,
            id_branch = :id_branch,
            id_address = :id_address,
            id_bundle = :id_bundle,
            tag = :tag,
            value = :value,
            timestamp = :timestamp,
            current_idx = :current_idx,
            last_idx = :last_idx,
            is_mst = :is_mst,
            mst_a = :mst_a,
            solid = :solid
          WHERE hash = :hash
        "#,
      )?,
      approve_transaction: pool.prepare(
        r#"
          UPDATE tx SET mst_a = :mst_a WHERE id_tx = :id_tx
        "#,
      )?,
      direct_approve_transaction: pool.prepare(
        r#"
          UPDATE tx SET da = da + 1 WHERE id_tx = :id_tx
        "#,
      )?,
      solidate_branch_transaction: pool.prepare(
        r#"
          UPDATE tx SET solid = :solid WHERE id_tx = :id_tx
        "#,
      )?,
      solidate_trunk_transaction: pool.prepare(
        r#"
          UPDATE tx SET height = :height, solid = :solid WHERE id_tx = :id_tx
        "#,
      )?,
      select_addresses: pool.prepare(
        r#"
          SELECT id_address FROM address WHERE address = :address
        "#,
      )?,
      insert_address: pool.prepare(
        r#"
          INSERT INTO address (
            id_address, address
          ) VALUES (
            :id_address, :address
          )
        "#,
      )?,
      select_bundles: pool.prepare(
        r#"
          SELECT id_bundle FROM bundle WHERE bundle = :bundle
        "#,
      )?,
      insert_bundle: pool.prepare(
        r#"
          INSERT INTO bundle (
            id_bundle, bundle, created, size
          ) VALUES (
            :id_bundle, :bundle, :created, :size
          )
        "#,
      )?,
      update_bundle: pool.prepare(
        r#"
          UPDATE bundle SET
            confirmed = :confirmed
          WHERE id_bundle = :id_bundle
        "#,
      )?,
      insert_event: pool.prepare(
        r#"
          INSERT INTO txload (
            event, count, timestamp
          ) VALUES (
            :event, :count, :timestamp
          )
        "#,
      )?,
    })
  }

  pub fn select_transaction_by_hash(
    &mut self,
    hash: &str,
  ) -> Result<Option<TransactionByHash>> {
    match self
      .select_transactions_by_hash
      .first_exec(params!{"hash" => hash})? {
      Some(mut row) => Ok(Some(TransactionByHash {
        id_tx: row.take_opt("id_tx").ok_or(Error::ColumnNotFound)?,
        id_trunk: row.take_opt("id_trunk").ok_or(Error::ColumnNotFound)?,
        id_branch: row.take_opt("id_branch").ok_or(Error::ColumnNotFound)?,
        solid: row.take_opt("solid").ok_or(Error::ColumnNotFound)?,
      })),
      None => Ok(None),
    }
  }

  pub fn select_transaction_by_id(
    &mut self,
    id_tx: u64,
  ) -> Result<TransactionById> {
    let mut row = self
      .select_transactions_by_id
      .first_exec(params!{"id_tx" => id_tx})?
      .ok_or(Error::RecordNotFound)?;
    Ok(TransactionById {
      mst_a: row.take_opt("mst_a").ok_or(Error::ColumnNotFound)?,
      id_trunk: row.take_opt("id_trunk").ok_or(Error::ColumnNotFound)?,
      id_branch: row.take_opt("id_branch").ok_or(Error::ColumnNotFound)?,
      id_bundle: row.take_opt("id_bundle").ok_or(Error::ColumnNotFound)?,
      current_idx: row.take_opt("current_idx").ok_or(Error::ColumnNotFound)?,
    })
  }

  pub fn select_child_transactions(
    &mut self,
    id_tx: u64,
  ) -> Result<Vec<ChildTransaction>> {
    let mut records = Vec::new();
    let results = self
      .select_child_transactions
      .execute(params!{"id_tx" => id_tx})?;
    for row in results {
      let mut row = row?;
      records.push(ChildTransaction {
        id_tx: row.take_opt("id_tx").ok_or(Error::ColumnNotFound)?,
        id_trunk: row.take_opt("id_trunk").ok_or(Error::ColumnNotFound)?,
        id_branch: row.take_opt("id_branch").ok_or(Error::ColumnNotFound)?,
        height: row.take_opt("height").ok_or(Error::ColumnNotFound)?,
        solid: row.take_opt("solid").ok_or(Error::ColumnNotFound)?,
      });
    }
    Ok(records)
  }

  pub fn insert_transaction(
    &mut self,
    counters: &Counters,
    transaction: NewTransaction,
  ) -> Result<mysql::QueryResult> {
    let id_tx = counters.next_transaction();
    let mut params = transaction.to_params();
    params.push(("id_tx".to_owned(), mysql::Value::from(id_tx)));
    Ok(self.insert_transaction.execute(params)?)
  }

  pub fn update_transaction(
    &mut self,
    transaction: NewTransaction,
  ) -> Result<mysql::QueryResult> {
    Ok(self.update_transaction.execute(transaction.to_params())?)
  }

  pub fn approve_transaction(&mut self, id: u64) -> Result<mysql::QueryResult> {
    Ok(self.approve_transaction.execute(params!{
      "id_tx" => id,
      "mst_a" => true,
    })?)
  }

  pub fn direct_approve_transaction(
    &mut self,
    id: u64,
  ) -> Result<mysql::QueryResult> {
    Ok(self
      .direct_approve_transaction
      .execute(params!{"id_tx" => id})?)
  }

  pub fn solidate_branch_transaction(
    &mut self,
    id: u64,
    solid: u8,
  ) -> Result<mysql::QueryResult> {
    Ok(self.solidate_branch_transaction.execute(params!{
      "id_tx" => id,
      "solid" => solid,
    })?)
  }

  pub fn solidate_trunk_transaction(
    &mut self,
    id: u64,
    height: i32,
    solid: u8,
  ) -> Result<mysql::QueryResult> {
    Ok(self.solidate_trunk_transaction.execute(params!{
      "id_tx" => id,
      "height" => height,
      "solid" => solid,
    })?)
  }

  pub fn insert_transaction_placeholder(
    &mut self,
    counters: &Counters,
    hash: &str,
    solid: u8,
  ) -> Result<u64> {
    let id_tx = counters.next_transaction();
    self.insert_transaction_placeholder.execute(params!{
      "id_tx" => id_tx,
      "hash" => hash,
      "solid" => solid,
    })?;
    Ok(id_tx)
  }

  pub fn fetch_address(
    &mut self,
    counters: &Counters,
    address: &str,
  ) -> Result<u64> {
    match self
      .select_addresses
      .first_exec(params!{"address" => address})? {
      Some(mut result) => Ok(
        result.take_opt("id_address").ok_or(Error::ColumnNotFound)??,
      ),
      None => {
        let id_address = counters.next_address();
        self.insert_address.execute(params!{
          "id_address" => id_address,
          "address" => address,
        })?;
        Ok(id_address)
      }
    }
  }

  pub fn fetch_bundle(
    &mut self,
    counters: &Counters,
    created: f64,
    bundle: &str,
    size: i32,
  ) -> Result<u64> {
    match self.select_bundles.first_exec(params!{"bundle" => bundle})? {
      Some(mut result) => Ok(
        result.take_opt("id_bundle").ok_or(Error::ColumnNotFound)??,
      ),
      None => {
        let id_bundle = counters.next_bundle();
        self.insert_bundle.execute(params!{
          "id_bundle" => id_bundle,
          "bundle" => bundle,
          "created" => created,
          "size" => size,
        })?;
        Ok(id_bundle)
      }
    }
  }

  pub fn update_bundle(
    &mut self,
    id: u64,
    confirmed: f64,
  ) -> Result<mysql::QueryResult> {
    Ok(self.update_bundle.execute(params!{
      "id_bundle" => id,
      "confirmed" => confirmed,
    })?)
  }

  pub fn new_transaction_received_event(
    &mut self,
    timestamp: f64,
  ) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "NTX",
      "count" => 1,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn milestone_received_event(&mut self, timestamp: f64) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "MST",
      "count" => 1,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn subtanble_confirmation_event(
    &mut self,
    timestamp: f64,
    count: i32,
  ) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "CNF",
      "count" => count,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn unsolid_transaction_event(&mut self, timestamp: f64) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "UNS",
      "count" => 1,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn subtangle_solidation_event(
    &mut self,
    timestamp: f64,
    count: i32,
  ) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "SOL",
      "count" => count,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }
}
<commit_msg>Fixed genesis transactions handling<commit_after>mod error;
mod records;

pub use self::error::{Error, Result};
pub use self::records::{ChildTransaction, NewTransaction, TransactionByHash,
                        TransactionById};
use counters::Counters;
use mysql;

pub struct Mapper<'a> {
  select_transactions_by_hash: mysql::Stmt<'a>,
  select_transactions_by_id: mysql::Stmt<'a>,
  select_child_transactions: mysql::Stmt<'a>,
  insert_transaction: mysql::Stmt<'a>,
  insert_transaction_placeholder: mysql::Stmt<'a>,
  update_transaction: mysql::Stmt<'a>,
  approve_transaction: mysql::Stmt<'a>,
  direct_approve_transaction: mysql::Stmt<'a>,
  solidate_branch_transaction: mysql::Stmt<'a>,
  solidate_trunk_transaction: mysql::Stmt<'a>,
  select_addresses: mysql::Stmt<'a>,
  insert_address: mysql::Stmt<'a>,
  select_bundles: mysql::Stmt<'a>,
  insert_bundle: mysql::Stmt<'a>,
  update_bundle: mysql::Stmt<'a>,
  insert_event: mysql::Stmt<'a>,
}

impl<'a> Mapper<'a> {
  pub fn new(pool: &mysql::Pool) -> Result<Self> {
    Ok(Self {
      select_transactions_by_hash: pool.prepare(
        r#"
          SELECT id_tx, id_trunk, id_branch, solid FROM tx WHERE hash = :hash
        "#,
      )?,
      select_transactions_by_id: pool.prepare(
        r#"
          SELECT
            id_tx, id_trunk, id_branch, id_bundle, current_idx, mst_a
          FROM tx
          WHERE id_tx = :id_tx
        "#,
      )?,
      select_child_transactions: pool.prepare(
        r#"
          SELECT
            id_tx, id_trunk, id_branch, height, solid
          FROM tx
          WHERE id_trunk = :id_tx OR id_branch = :id_tx
        "#,
      )?,
      insert_transaction_placeholder: pool.prepare(
        r#"
          INSERT INTO tx (
            id_tx, hash, da, solid
          ) VALUES (
            :id_tx, :hash, 1, :solid
          )
        "#,
      )?,
      insert_transaction: pool.prepare(
        r#"
          INSERT INTO tx (
            id_tx, hash, id_trunk, id_branch, id_address, id_bundle, tag, value,
            timestamp, current_idx, last_idx, is_mst, mst_a, solid
          ) VALUES (
            :id_tx, :hash, :id_trunk, :id_branch, :id_address, :id_bundle, :tag,
            :value, :timestamp, :current_idx, :last_idx, :is_mst, :mst_a, :solid
          )
        "#,
      )?,
      update_transaction: pool.prepare(
        r#"
          UPDATE tx SET
            id_trunk = :id_trunk,
            id_branch = :id_branch,
            id_address = :id_address,
            id_bundle = :id_bundle,
            tag = :tag,
            value = :value,
            timestamp = :timestamp,
            current_idx = :current_idx,
            last_idx = :last_idx,
            is_mst = :is_mst,
            mst_a = :mst_a,
            solid = :solid
          WHERE hash = :hash
        "#,
      )?,
      approve_transaction: pool.prepare(
        r#"
          UPDATE tx SET mst_a = :mst_a WHERE id_tx = :id_tx
        "#,
      )?,
      direct_approve_transaction: pool.prepare(
        r#"
          UPDATE tx SET da = da + 1 WHERE id_tx = :id_tx
        "#,
      )?,
      solidate_branch_transaction: pool.prepare(
        r#"
          UPDATE tx SET solid = :solid WHERE id_tx = :id_tx
        "#,
      )?,
      solidate_trunk_transaction: pool.prepare(
        r#"
          UPDATE tx SET height = :height, solid = :solid WHERE id_tx = :id_tx
        "#,
      )?,
      select_addresses: pool.prepare(
        r#"
          SELECT id_address FROM address WHERE address = :address
        "#,
      )?,
      insert_address: pool.prepare(
        r#"
          INSERT INTO address (
            id_address, address
          ) VALUES (
            :id_address, :address
          )
        "#,
      )?,
      select_bundles: pool.prepare(
        r#"
          SELECT id_bundle FROM bundle WHERE bundle = :bundle
        "#,
      )?,
      insert_bundle: pool.prepare(
        r#"
          INSERT INTO bundle (
            id_bundle, bundle, created, size
          ) VALUES (
            :id_bundle, :bundle, :created, :size
          )
        "#,
      )?,
      update_bundle: pool.prepare(
        r#"
          UPDATE bundle SET
            confirmed = :confirmed
          WHERE id_bundle = :id_bundle
        "#,
      )?,
      insert_event: pool.prepare(
        r#"
          INSERT INTO txload (
            event, count, timestamp
          ) VALUES (
            :event, :count, :timestamp
          )
        "#,
      )?,
    })
  }

  pub fn select_transaction_by_hash(
    &mut self,
    hash: &str,
  ) -> Result<Option<TransactionByHash>> {
    match self
      .select_transactions_by_hash
      .first_exec(params!{"hash" => hash})? {
      Some(mut row) => Ok(Some(TransactionByHash {
        id_tx: row.take_opt("id_tx").ok_or(Error::ColumnNotFound)?,
        id_trunk: row.take_opt("id_trunk").ok_or(Error::ColumnNotFound)?,
        id_branch: row.take_opt("id_branch").ok_or(Error::ColumnNotFound)?,
        solid: row.take_opt("solid").ok_or(Error::ColumnNotFound)?,
      })),
      None => Ok(None),
    }
  }

  pub fn select_transaction_by_id(
    &mut self,
    id_tx: u64,
  ) -> Result<TransactionById> {
    let mut row = self
      .select_transactions_by_id
      .first_exec(params!{"id_tx" => id_tx})?
      .ok_or(Error::RecordNotFound)?;
    Ok(TransactionById {
      mst_a: row.take_opt("mst_a").ok_or(Error::ColumnNotFound)?,
      id_trunk: row.take_opt("id_trunk").ok_or(Error::ColumnNotFound)?,
      id_branch: row.take_opt("id_branch").ok_or(Error::ColumnNotFound)?,
      id_bundle: row.take_opt("id_bundle").ok_or(Error::ColumnNotFound)?,
      current_idx: row.take_opt("current_idx").ok_or(Error::ColumnNotFound)?,
    })
  }

  pub fn select_child_transactions(
    &mut self,
    id_tx: u64,
  ) -> Result<Vec<ChildTransaction>> {
    let mut records = Vec::new();
    let results = self
      .select_child_transactions
      .execute(params!{"id_tx" => id_tx})?;
    for row in results {
      let mut row = row?;
      records.push(ChildTransaction {
        id_tx: row.take_opt("id_tx").ok_or(Error::ColumnNotFound)?,
        id_trunk: row.take_opt("id_trunk").ok_or(Error::ColumnNotFound)?,
        id_branch: row.take_opt("id_branch").ok_or(Error::ColumnNotFound)?,
        height: row.take_opt("height").ok_or(Error::ColumnNotFound)?,
        solid: row.take_opt("solid").ok_or(Error::ColumnNotFound)?,
      });
    }
    Ok(records)
  }

  pub fn insert_transaction(
    &mut self,
    counters: &Counters,
    transaction: NewTransaction,
  ) -> Result<mysql::QueryResult> {
    let id_tx = counters.next_transaction();
    let mut params = transaction.to_params();
    params.push(("id_tx".to_owned(), mysql::Value::from(id_tx)));
    Ok(self.insert_transaction.execute(params)?)
  }

  pub fn update_transaction(
    &mut self,
    transaction: NewTransaction,
  ) -> Result<mysql::QueryResult> {
    Ok(self.update_transaction.execute(transaction.to_params())?)
  }

  pub fn approve_transaction(&mut self, id: u64) -> Result<mysql::QueryResult> {
    Ok(self.approve_transaction.execute(params!{
      "id_tx" => id,
      "mst_a" => true,
    })?)
  }

  pub fn direct_approve_transaction(
    &mut self,
    id: u64,
  ) -> Result<mysql::QueryResult> {
    Ok(self
      .direct_approve_transaction
      .execute(params!{"id_tx" => id})?)
  }

  pub fn solidate_branch_transaction(
    &mut self,
    id: u64,
    solid: u8,
  ) -> Result<mysql::QueryResult> {
    Ok(self.solidate_branch_transaction.execute(params!{
      "id_tx" => id,
      "solid" => solid,
    })?)
  }

  pub fn solidate_trunk_transaction(
    &mut self,
    id: u64,
    height: i32,
    solid: u8,
  ) -> Result<mysql::QueryResult> {
    Ok(self.solidate_trunk_transaction.execute(params!{
      "id_tx" => id,
      "height" => height,
      "solid" => solid,
    })?)
  }

  pub fn insert_transaction_placeholder(
    &mut self,
    counters: &Counters,
    hash: &str,
    solid: u8,
  ) -> Result<u64> {
    let id_tx = counters.next_transaction();
    self.insert_transaction_placeholder.execute(params!{
      "id_tx" => id_tx,
      "hash" => hash,
      "solid" => solid,
    })?;
    Ok(id_tx)
  }

  pub fn fetch_address(
    &mut self,
    counters: &Counters,
    address: &str,
  ) -> Result<u64> {
    match self
      .select_addresses
      .first_exec(params!{"address" => address})? {
      Some(mut result) => Ok(
        result.take_opt("id_address").ok_or(Error::ColumnNotFound)??,
      ),
      None => {
        let id_address = counters.next_address();
        self.insert_address.execute(params!{
          "id_address" => id_address,
          "address" => address,
        })?;
        Ok(id_address)
      }
    }
  }

  pub fn fetch_bundle(
    &mut self,
    counters: &Counters,
    created: f64,
    bundle: &str,
    size: i32,
  ) -> Result<u64> {
    match self.select_bundles.first_exec(params!{"bundle" => bundle})? {
      Some(mut result) => Ok(
        result.take_opt("id_bundle").ok_or(Error::ColumnNotFound)??,
      ),
      None => {
        let id_bundle = counters.next_bundle();
        self.insert_bundle.execute(params!{
          "id_bundle" => id_bundle,
          "bundle" => bundle,
          "created" => created,
          "size" => size,
        })?;
        Ok(id_bundle)
      }
    }
  }

  pub fn update_bundle(
    &mut self,
    id: u64,
    confirmed: f64,
  ) -> Result<mysql::QueryResult> {
    Ok(self.update_bundle.execute(params!{
      "id_bundle" => id,
      "confirmed" => confirmed,
    })?)
  }

  pub fn new_transaction_received_event(
    &mut self,
    timestamp: f64,
  ) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "NTX",
      "count" => 1,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn milestone_received_event(&mut self, timestamp: f64) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "MST",
      "count" => 1,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn subtanble_confirmation_event(
    &mut self,
    timestamp: f64,
    count: i32,
  ) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "CNF",
      "count" => count,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn unsolid_transaction_event(&mut self, timestamp: f64) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "UNS",
      "count" => 1,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }

  pub fn subtangle_solidation_event(
    &mut self,
    timestamp: f64,
    count: i32,
  ) -> Result<()> {
    self.insert_event.execute(params!{
      "event" => "SOL",
      "count" => count,
      "timestamp" => timestamp,
    })?;
    Ok(())
  }
}
<|endoftext|>


<commit_before>//! calculate cyclomatic complexity and warn about overly complex functions

use rustc::lint::*;
use rustc::middle::cfg::CFG;
use rustc::middle::ty;
use rustc_front::hir::*;
use rustc_front::intravisit::{Visitor, walk_expr};
use syntax::ast::Attribute;
use syntax::attr::*;
use syntax::codemap::Span;

use utils::{in_macro, LimitStack, span_help_and_lint};

/// **What it does:** This lint checks for methods with high cyclomatic complexity
///
/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better.
///
/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity
///
/// **Example:** No. You'll see it when you get the warning.
declare_lint! {
    pub CYCLOMATIC_COMPLEXITY, Warn,
    "finds functions that should be split up into multiple functions"
}

pub struct CyclomaticComplexity {
    limit: LimitStack,
}

impl CyclomaticComplexity {
    pub fn new(limit: u64) -> Self {
        CyclomaticComplexity { limit: LimitStack::new(limit) }
    }
}

impl LintPass for CyclomaticComplexity {
    fn get_lints(&self) -> LintArray {
        lint_array!(CYCLOMATIC_COMPLEXITY)
    }
}

impl CyclomaticComplexity {
    fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) {
        if in_macro(cx, span) {
            return;
        }
        let cfg = CFG::new(cx.tcx, block);
        let n = cfg.graph.len_nodes() as u64;
        let e = cfg.graph.len_edges() as u64;
        let cc = e + 2 - n;
        let mut arm_counter = MatchArmCounter(0);
        arm_counter.visit_block(block);
        let narms = arm_counter.0;

        let mut diverge_counter = DivergenceCounter(0, &cx.tcx);
        diverge_counter.visit_block(block);
        let divergence = diverge_counter.0;

        if cc + divergence < narms {
            report_cc_bug(cx, cc, narms, divergence, span);
        } else {
            let rust_cc = cc + divergence - narms;
            if rust_cc > self.limit.limit() {
                span_help_and_lint(cx,
                                   CYCLOMATIC_COMPLEXITY,
                                   span,
                                   &format!("the function has a cyclomatic complexity of {}", rust_cc),
                                   "you could split it up into multiple smaller functions");
            }
        }
    }
}

impl LateLintPass for CyclomaticComplexity {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if let ItemFn(_, _, _, _, _, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
        if let ImplItemKind::Method(_, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
        if let MethodTraitItem(_, Some(ref block)) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
    fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
}

struct MatchArmCounter(u64);

impl<'a> Visitor<'a> for MatchArmCounter {
    fn visit_expr(&mut self, e: &'a Expr) {
        match e.node {
            ExprMatch(_, ref arms, _) => {
                walk_expr(self, e);
                let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum();
                if arms_n > 1 {
                    self.0 += arms_n - 2;
                }
            }
            ExprClosure(..) => {}
            _ => walk_expr(self, e),
        }
    }
}

struct DivergenceCounter<'a, 'tcx: 'a>(u64, &'a ty::ctxt<'tcx>);

impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> {
    fn visit_expr(&mut self, e: &'a Expr) {
        match e.node {
            ExprCall(ref callee, _) => {
                walk_expr(self, e);
                let ty = self.1.node_id_to_type(callee.id);
                if let ty::TyBareFn(_, ty) = ty.sty {
                    if ty.sig.skip_binder().output.diverges() {
                        self.0 += 1;
                    }
                }
            }
            ExprClosure(..) => {}
            _ => walk_expr(self, e),
        }
    }
}

#[cfg(feature="debugging")]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    cx.sess().span_bug(span,
                       &format!("Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
                                 div = {}. Please file a bug report.",
                                cc,
                                narms,
                                div));;
}
#[cfg(not(feature="debugging"))]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow {
        cx.sess().span_note_without_error(span,
                                          &format!("Clippy encountered a bug calculating cyclomatic complexity \
                                                    (hide this message with `#[allow(cyclomatic_complexity)]`): cc \
                                                    = {}, arms = {}, div = {}. Please file a bug report.",
                                                   cc,
                                                   narms,
                                                   div));
    }
}
<commit_msg>s/ctxt/TyCtxt<commit_after>//! calculate cyclomatic complexity and warn about overly complex functions

use rustc::lint::*;
use rustc::middle::cfg::CFG;
use rustc::middle::ty;
use rustc_front::hir::*;
use rustc_front::intravisit::{Visitor, walk_expr};
use syntax::ast::Attribute;
use syntax::attr::*;
use syntax::codemap::Span;

use utils::{in_macro, LimitStack, span_help_and_lint};

/// **What it does:** This lint checks for methods with high cyclomatic complexity
///
/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better.
///
/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity
///
/// **Example:** No. You'll see it when you get the warning.
declare_lint! {
    pub CYCLOMATIC_COMPLEXITY, Warn,
    "finds functions that should be split up into multiple functions"
}

pub struct CyclomaticComplexity {
    limit: LimitStack,
}

impl CyclomaticComplexity {
    pub fn new(limit: u64) -> Self {
        CyclomaticComplexity { limit: LimitStack::new(limit) }
    }
}

impl LintPass for CyclomaticComplexity {
    fn get_lints(&self) -> LintArray {
        lint_array!(CYCLOMATIC_COMPLEXITY)
    }
}

impl CyclomaticComplexity {
    fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) {
        if in_macro(cx, span) {
            return;
        }
        let cfg = CFG::new(cx.tcx, block);
        let n = cfg.graph.len_nodes() as u64;
        let e = cfg.graph.len_edges() as u64;
        let cc = e + 2 - n;
        let mut arm_counter = MatchArmCounter(0);
        arm_counter.visit_block(block);
        let narms = arm_counter.0;

        let mut diverge_counter = DivergenceCounter(0, &cx.tcx);
        diverge_counter.visit_block(block);
        let divergence = diverge_counter.0;

        if cc + divergence < narms {
            report_cc_bug(cx, cc, narms, divergence, span);
        } else {
            let rust_cc = cc + divergence - narms;
            if rust_cc > self.limit.limit() {
                span_help_and_lint(cx,
                                   CYCLOMATIC_COMPLEXITY,
                                   span,
                                   &format!("the function has a cyclomatic complexity of {}", rust_cc),
                                   "you could split it up into multiple smaller functions");
            }
        }
    }
}

impl LateLintPass for CyclomaticComplexity {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if let ItemFn(_, _, _, _, _, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
        if let ImplItemKind::Method(_, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
        if let MethodTraitItem(_, Some(ref block)) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
    fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
}

struct MatchArmCounter(u64);

impl<'a> Visitor<'a> for MatchArmCounter {
    fn visit_expr(&mut self, e: &'a Expr) {
        match e.node {
            ExprMatch(_, ref arms, _) => {
                walk_expr(self, e);
                let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum();
                if arms_n > 1 {
                    self.0 += arms_n - 2;
                }
            }
            ExprClosure(..) => {}
            _ => walk_expr(self, e),
        }
    }
}

struct DivergenceCounter<'a, 'tcx: 'a>(u64, &'a ty::TyCtxt<'tcx>);

impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> {
    fn visit_expr(&mut self, e: &'a Expr) {
        match e.node {
            ExprCall(ref callee, _) => {
                walk_expr(self, e);
                let ty = self.1.node_id_to_type(callee.id);
                if let ty::TyBareFn(_, ty) = ty.sty {
                    if ty.sig.skip_binder().output.diverges() {
                        self.0 += 1;
                    }
                }
            }
            ExprClosure(..) => {}
            _ => walk_expr(self, e),
        }
    }
}

#[cfg(feature="debugging")]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    cx.sess().span_bug(span,
                       &format!("Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
                                 div = {}. Please file a bug report.",
                                cc,
                                narms,
                                div));;
}
#[cfg(not(feature="debugging"))]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow {
        cx.sess().span_note_without_error(span,
                                          &format!("Clippy encountered a bug calculating cyclomatic complexity \
                                                    (hide this message with `#[allow(cyclomatic_complexity)]`): cc \
                                                    = {}, arms = {}, div = {}. Please file a bug report.",
                                                   cc,
                                                   narms,
                                                   div));
    }
}
<|endoftext|>


<commit_before>
use BuildQuery;

// https://docs.gitlab.com/ce/api/projects.html

// Get a list of projects for which the authenticated user is a member.
// GET /projects
//
// Get a list of projects which the authenticated user can see.
// GET /projects/visible
//
// Get a list of projects which are owned by the authenticated user.
// GET /projects/owned
//
// Get a list of projects which are starred by the authenticated user.
// GET /projects/starred
//
// Get a list of all GitLab projects (admin only).
// GET /projects/all
//
// Get a specific project, identified by project `ID` or `NAMESPACE/PROJECT_NAME`, which is owned by the authenticated user. If using namespaced projects call make sure that the `NAMESPACE/PROJECT_NAME` is URL-encoded, eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`).
// GET /projects/:id
//
// Get the events for the specified project. Sorted from newest to oldest
// GET /projects/:id/events
//
// Creates a new project owned by the authenticated user.
// POST /projects
//
// Creates a new project owned by the specified user. Available only for admins.
// POST /projects/user/:user_id
//
// Updates an existing project
// PUT /projects/:id
//
// Forks a project into the user namespace of the authenticated user or the one provided.
// POST /projects/fork/:id
//
// Stars a given project. Returns status code `201` and the project on success and `304` if the project is already starred.
// POST /projects/:id/star
//
// Unstars a given project. Returns status code `200` and the project on success and `304` if the project is not starred.
// DELETE /projects/:id/star
//
// Archives the project if the user is either admin or the project owner of this project. This action is idempotent, thus archiving an already archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't have the proper access rights, code `403` is returned. Status `404` is returned if the project doesn't exist, or is hidden to the user.
// POST /projects/:id/archive
//
//
// Unarchives the project if the user is either admin or the project owner of this project. This action is idempotent, thus unarchiving an non-archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't have the proper access rights, code `403` is returned. Status `404` is returned if the project doesn't exist, or is hidden to the user.
// POST /projects/:id/unarchive
//
//
// Removes a project including all associated resources (issues, merge requests etc.)
// DELETE /projects/:id
//
//
// Uploads a file to the specified project to be used in an issue or merge request description, or a comment.
// POST /projects/:id/uploads
//
//
// Allow to share project with group.
// POST /projects/:id/share
//
//
// Get a list of project hooks.
// GET /projects/:id/hooks
//
//
// Get a specific hook for a project.
// GET /projects/:id/hooks/:hook_id
//
//
// Adds a hook to a specified project.
// POST /projects/:id/hooks
//
//
// Edits a hook for a specified project.
// PUT /projects/:id/hooks/:hook_id
//
//
// Removes a hook from a project. This is an idempotent method and can be called multiple times. Either the hook is available or not.
// DELETE /projects/:id/hooks/:hook_id
//
//
// Lists all branches of a project.
// GET /projects/:id/repository/branches
//
//
// A specific branch of a project.
// GET /projects/:id/repository/branches/:branch
//
//
// Protects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/protect
//
//
// Unprotects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/unprotect
//
//
// Create a forked from/to relation between existing projects.
// POST /projects/:id/fork/:forked_from_id
//
//
// Delete an existing forked from relationship
// DELETE /projects/:id/fork
//
//
// Search for projects by name which are accessible to the authenticated user.
// GET /projects/search/:query

// https://docs.gitlab.com/ce/api/projects.html#list-projects

#[derive(Debug, Copy, Clone)]
pub enum ListingVisibility {
    Public,
    Internal,
    Private,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Id,
    Name,
    Path,
    CreatedAt,
    UpdatedAt,
    LastActivityAt,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Limit by archived status
    archived:  Option<bool>,
    /// Limit by visibility.
    visibility: Option<ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by:  Option<ListingOrderBy>,
    /// Return requests sorted. Default is `ListingSort::Desc`.
    sort: Option<ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search:  String,
    /// Return only the ID, URL, name, and path of each project
    simple: Option<bool>,
}
<commit_msg>Add impl Listing<commit_after>
use BuildQuery;

// https://docs.gitlab.com/ce/api/projects.html

// Get a list of projects for which the authenticated user is a member.
// GET /projects
//
// Get a list of projects which the authenticated user can see.
// GET /projects/visible
//
// Get a list of projects which are owned by the authenticated user.
// GET /projects/owned
//
// Get a list of projects which are starred by the authenticated user.
// GET /projects/starred
//
// Get a list of all GitLab projects (admin only).
// GET /projects/all
//
// Get a specific project, identified by project `ID` or `NAMESPACE/PROJECT_NAME`, which is owned by the authenticated user. If using namespaced projects call make sure that the `NAMESPACE/PROJECT_NAME` is URL-encoded, eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`).
// GET /projects/:id
//
// Get the events for the specified project. Sorted from newest to oldest
// GET /projects/:id/events
//
// Creates a new project owned by the authenticated user.
// POST /projects
//
// Creates a new project owned by the specified user. Available only for admins.
// POST /projects/user/:user_id
//
// Updates an existing project
// PUT /projects/:id
//
// Forks a project into the user namespace of the authenticated user or the one provided.
// POST /projects/fork/:id
//
// Stars a given project. Returns status code `201` and the project on success and `304` if the project is already starred.
// POST /projects/:id/star
//
// Unstars a given project. Returns status code `200` and the project on success and `304` if the project is not starred.
// DELETE /projects/:id/star
//
// Archives the project if the user is either admin or the project owner of this project. This action is idempotent, thus archiving an already archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't have the proper access rights, code `403` is returned. Status `404` is returned if the project doesn't exist, or is hidden to the user.
// POST /projects/:id/archive
//
//
// Unarchives the project if the user is either admin or the project owner of this project. This action is idempotent, thus unarchiving an non-archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't have the proper access rights, code `403` is returned. Status `404` is returned if the project doesn't exist, or is hidden to the user.
// POST /projects/:id/unarchive
//
//
// Removes a project including all associated resources (issues, merge requests etc.)
// DELETE /projects/:id
//
//
// Uploads a file to the specified project to be used in an issue or merge request description, or a comment.
// POST /projects/:id/uploads
//
//
// Allow to share project with group.
// POST /projects/:id/share
//
//
// Get a list of project hooks.
// GET /projects/:id/hooks
//
//
// Get a specific hook for a project.
// GET /projects/:id/hooks/:hook_id
//
//
// Adds a hook to a specified project.
// POST /projects/:id/hooks
//
//
// Edits a hook for a specified project.
// PUT /projects/:id/hooks/:hook_id
//
//
// Removes a hook from a project. This is an idempotent method and can be called multiple times. Either the hook is available or not.
// DELETE /projects/:id/hooks/:hook_id
//
//
// Lists all branches of a project.
// GET /projects/:id/repository/branches
//
//
// A specific branch of a project.
// GET /projects/:id/repository/branches/:branch
//
//
// Protects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/protect
//
//
// Unprotects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/unprotect
//
//
// Create a forked from/to relation between existing projects.
// POST /projects/:id/fork/:forked_from_id
//
//
// Delete an existing forked from relationship
// DELETE /projects/:id/fork
//
//
// Search for projects by name which are accessible to the authenticated user.
// GET /projects/search/:query

// https://docs.gitlab.com/ce/api/projects.html#list-projects

#[derive(Debug, Copy, Clone)]
pub enum ListingVisibility {
    Public,
    Internal,
    Private,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Id,
    Name,
    Path,
    CreatedAt,
    UpdatedAt,
    LastActivityAt,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Limit by archived status
    archived:  Option<bool>,
    /// Limit by visibility.
    visibility: Option<ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by:  Option<ListingOrderBy>,
    /// Return requests sorted. Default is `ListingSort::Desc`.
    sort: Option<ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search:  String,
    /// Return only the ID, URL, name, and path of each project
    simple: Option<bool>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn archived(&mut self, archived: bool) -> &mut Listing {
        self.archived = Some(archived);
        self
    }
    pub fn visibility(&mut self, visibility: ListingVisibility) -> &mut Listing {
        self.visibility = Some(visibility);
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn simple(&mut self, simple: bool) -> &mut Listing {
        self.simple = Some(simple);
        self
    }
}

<|endoftext|>


<commit_before>// ref: https://github.com/memcached/memcached/blob/master/doc/protocol.txt

// Request structs

#[derive(Debug, PartialEq, Clone)]
pub struct Get {
    pub key: String,
}

impl Get {
    pub fn new(key: &str) -> Get {
        Get { key: key.to_string() }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Set {
    pub key: String,
    pub flags: u16,
    pub exptime: u32, // relative (secs) or absolute (unixtime) expiry time
    pub data: Vec<u8>,
    pub noreply: bool,
}

impl Set {
    pub fn new(key: &str,
               flags: u16,
               exptime: u32,
               data: Vec<u8>,
               noreply: bool)
               -> Set {
        Set {
            key: key.to_string(),
            flags: flags,
            exptime: exptime,
            data: data,
            noreply: noreply,
        }
    }
}

// Response structs

#[derive(Debug, PartialEq, Clone)]
pub struct ClientError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct ServerError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Stat {
    pub key: String,
    pub value: String,
}

impl Stat {
    pub fn new(key: &str, value: String) -> Stat {
        Stat {
            key: key.to_string(),
            value: value,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Value {
    pub key: String,
    pub data: Vec<u8>,
}

impl Value {
    pub fn new(key: &str, data: Vec<u8>) -> Value {
        Value {
            key: key.to_string(),
            data: data,
        }
    }
}

// High level groupings

#[derive(Debug, PartialEq, Clone)]
pub enum Cmd {
    Get(Get),
    Set(Set),
    Stats,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Resp {
    Error,
    ClientError(ClientError),
    ServerError(ServerError),

    Stats(Vec<Stat>),
    Stored,
    Value(Value),
}
<commit_msg>add comments<commit_after>// ref: https://github.com/memcached/memcached/blob/master/doc/protocol.txt

// Request structs

#[derive(Debug, PartialEq, Clone)]
pub struct Get {
    pub key: String,
}

impl Get {
    pub fn new(key: &str) -> Get {
        Get { key: key.to_string() }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Set {
    pub key: String, // alphanumeric characters
    pub flags: u16, // arbitrary bit pattern chosen by the client
    pub exptime: u32, // relative (secs) or absolute (unixtime) expiry time
    pub data: Vec<u8>, // binary data
    pub noreply: bool, // indicates whether the server should reply to the set
}

impl Set {
    pub fn new(key: &str,
               flags: u16,
               exptime: u32,
               data: Vec<u8>,
               noreply: bool)
               -> Set {
        Set {
            key: key.to_string(),
            flags: flags,
            exptime: exptime,
            data: data,
            noreply: noreply,
        }
    }
}

// Response structs

#[derive(Debug, PartialEq, Clone)]
pub struct ClientError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct ServerError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Stat {
    pub key: String,
    pub value: String,
}

impl Stat {
    pub fn new(key: &str, value: String) -> Stat {
        Stat {
            key: key.to_string(),
            value: value,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Value {
    pub key: String,
    pub data: Vec<u8>,
}

impl Value {
    pub fn new(key: &str, data: Vec<u8>) -> Value {
        Value {
            key: key.to_string(),
            data: data,
        }
    }
}

// High level groupings

#[derive(Debug, PartialEq, Clone)]
pub enum Cmd {
    Get(Get),
    Set(Set),
    Stats,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Resp {
    Error,
    ClientError(ClientError),
    ServerError(ServerError),

    Stats(Vec<Stat>),
    Stored,
    Value(Value),
}
<|endoftext|>


<commit_before>//! way-cooler registry.

use std::ops::Deref;
use std::cmp::Eq;
use std::fmt::Display;
use std::hash::Hash;
use std::borrow::Borrow;

use hlua::any::AnyLuaValue;
use convert::{ToTable, FromTable, ConverterError};

use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

mod types;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryValue>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> =
        RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq, Eq)]
pub enum RegistryError {
    /// The value in the registry could not be parsed
    InvalidLua(ConverterError),
    /// The registry key was not found
    KeyNotFound
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().unwrap()
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().unwrap()
}

/// Gets a Lua object from a registry key
pub fn get_lua<K>(name: &K) -> Option<(AccessFlags, Arc<AnyLuaValue>)>
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("get_lua: {}", *name);
    let reg = read_lock();
    reg.get(name).map(|val| (val.flags(), val.get_lua()))
}

/// Gets an object from the registry, decoding its internal Lua
/// representation.
#[allow(dead_code)]
pub fn get<K, T>(name: &K) -> Result<(AccessFlags, T), RegistryError>
    where T: FromTable, String: Borrow<K>, K: Hash + Eq + Display {
    if let Some(lua_pair) = get_lua(name) {
        let (access, lua_arc) = lua_pair;
        // Ultimately, values must be cloned out of the registry as well
        match T::from_lua_table(lua_arc.deref().clone()) {
            Ok(val) => Ok((access, val)),
            Err(e) => Err(RegistryError::InvalidLua(e))
        }
    }
    else {
        Err(RegistryError::KeyNotFound)
    }
}

/// Set a key in the registry to a particular value
#[allow(dead_code)]
pub fn set<T: ToTable>(key: String, flags: AccessFlags, val: T) {
    trace!("set: {:?} {}", flags, key);
    let regvalue = RegistryValue::new(flags, val);
    let mut write_reg = write_lock();
    write_reg.insert(key, regvalue);
}

/// Whether this map contains a key
#[allow(dead_code)]
pub fn contains_key<K>(key: &K) -> bool
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("contains_key: {}", *key);
    let read_reg = read_lock();
    read_reg.contains_key(key)
}
<commit_msg>Remove unwraps from registry<commit_after>//! way-cooler registry.

use std::ops::Deref;
use std::cmp::Eq;
use std::fmt::Display;
use std::hash::Hash;
use std::borrow::Borrow;

use hlua::any::AnyLuaValue;
use convert::{ToTable, FromTable, ConverterError};

use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

mod types;
pub use self::types::*; // Export constants too

#[cfg(test)]
mod tests;

pub type RegMap = HashMap<String, RegistryValue>;

lazy_static! {
    /// Registry variable for the registry
    static ref REGISTRY: RwLock<RegMap> =
        RwLock::new(HashMap::new());
}

/// Error types that can happen
#[derive(Debug, PartialEq, Eq)]
pub enum RegistryError {
    /// The value in the registry could not be parsed
    InvalidLua(ConverterError),
    /// The registry key was not found
    KeyNotFound
}

/// Acquires a read lock on the registry.
pub fn read_lock<'a>() -> RwLockReadGuard<'a, RegMap> {
    REGISTRY.read().expect("Unable to read from registry!")
}

/// Acquires a write lock on the registry.
pub fn write_lock<'a>() -> RwLockWriteGuard<'a, RegMap> {
    REGISTRY.write().expect("Unable to write to registry!")
}

/// Gets a Lua object from a registry key
pub fn get_lua<K>(name: &K) -> Option<(AccessFlags, Arc<AnyLuaValue>)>
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("get_lua: {}", *name);
    let reg = read_lock();
    reg.get(name).map(|val| (val.flags(), val.get_lua()))
}

/// Gets an object from the registry, decoding its internal Lua
/// representation.
#[allow(dead_code)]
pub fn get<K, T>(name: &K) -> Result<(AccessFlags, T), RegistryError>
    where T: FromTable, String: Borrow<K>, K: Hash + Eq + Display {
    if let Some(lua_pair) = get_lua(name) {
        let (access, lua_arc) = lua_pair;
        // Ultimately, values must be cloned out of the registry as well
        match T::from_lua_table(lua_arc.deref().clone()) {
            Ok(val) => Ok((access, val)),
            Err(e) => Err(RegistryError::InvalidLua(e))
        }
    }
    else {
        Err(RegistryError::KeyNotFound)
    }
}

/// Set a key in the registry to a particular value
#[allow(dead_code)]
pub fn set<T: ToTable>(key: String, flags: AccessFlags, val: T) {
    trace!("set: {:?} {}", flags, key);
    let regvalue = RegistryValue::new(flags, val);
    let mut write_reg = write_lock();
    write_reg.insert(key, regvalue);
}

/// Whether this map contains a key
#[allow(dead_code)]
pub fn contains_key<K>(key: &K) -> bool
where String: Borrow<K>, K: Hash + Eq + Display {
    trace!("contains_key: {}", *key);
    let read_reg = read_lock();
    read_reg.contains_key(key)
}
<|endoftext|>


<commit_before>//! Colors used for drawing to a Cairo buffer

use std::convert::From;

/// Color to draw to the screen, including the alpha channel.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Color {
    red: u8,
    green: u8,
    blue: u8,
    alpha: u8
}

impl Color {
    /// Makes a new solid color, with no transparency.
    pub fn solid_color(red: u8, green: u8, blue: u8) -> Self {
        Color {
            red: red,
            green: green,
            blue: blue,
            alpha: 255
        }
    }

    /// Gets the values of the colors, in this order:
    /// (Red, Green, Blue, Alpha)
    pub fn values(&self) -> (u8, u8, u8, u8) {
        (self.red, self.green, self.blue, self.alpha)
    }
}

impl From<u32> for Color {
    fn from(val: u32) -> Self {
        let blue = ((val & 0xff0000) >> 16) as u8;
        let green = ((val & 0x00ff00) >> 8) as u8;
        let red = (val & 0x0000ff) as u8;
        Color::solid_color(red, green, blue)
    }
}
<commit_msg>Allow colors to contain alpha values<commit_after>//! Colors used for drawing to a Cairo buffer

use std::convert::From;

/// Color to draw to the screen, including the alpha channel.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Color {
    red: u8,
    green: u8,
    blue: u8,
    alpha: u8
}

impl Color {

    // Makes a new color with an alphachannel
    pub fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
        Color {
            red: red,
            green: green,
            blue: blue,
            alpha: alpha
        }
    }

    /// Gets the values of the colors, in this order:
    /// (Red, Green, Blue, Alpha)
    pub fn values(&self) -> (u8, u8, u8, u8) {
        (self.red, self.green, self.blue, self.alpha)
    }
}

impl From<u32> for Color {
    fn from(val: u32) -> Self {
        let blue  =  (val & 0x000000ff) as u8;
        let green = ((val & 0x0000ff00) >> 8) as u8;
        let red   = ((val & 0x00ff0000) >> 16) as u8;
        let alpha = ((val & 0xff000000) >> 24) as u8;
        Color::rgba(red, green, blue, (255 - alpha))
    }
}
<|endoftext|>


<commit_before>use runtime::Runtime;
use std::error::Error;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::fmt::Display;
use std::result::Result;

use storage::backend::StorageBackend;
use self::command::ExecutableCommand;

mod command;
pub mod bm;

#[derive(Debug)]
pub struct ModuleError {
    desc: String,
}

impl ModuleError {
    fn mk(desc: &'static str) -> ModuleError {
        ModuleError {
            desc: desc.to_owned().to_string(),
        }
    }
}

impl Error for ModuleError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Display for ModuleError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "ModuleError: {}", self.description())
    }
}

pub type ModuleResult = Result<(), ModuleError>;

pub trait Module {

    fn new(rt : &Runtime) -> Self;
    fn callnames() -> &'static [&'static str];
    fn name(&self) -> &'static str;
    fn shutdown(&self, rt : &Runtime) -> ModuleResult;

    fn get_commands<C: ExecutableCommand>(&self, rt: &Runtime) -> Vec<C>;

}

<commit_msg>Make command submodule public<commit_after>use runtime::Runtime;
use std::error::Error;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::fmt::Display;
use std::result::Result;

use storage::backend::StorageBackend;
use self::command::ExecutableCommand;

pub mod command;
pub mod bm;

#[derive(Debug)]
pub struct ModuleError {
    desc: String,
}

impl ModuleError {
    fn mk(desc: &'static str) -> ModuleError {
        ModuleError {
            desc: desc.to_owned().to_string(),
        }
    }
}

impl Error for ModuleError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Display for ModuleError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "ModuleError: {}", self.description())
    }
}

pub type ModuleResult = Result<(), ModuleError>;

pub trait Module {

    fn new(rt : &Runtime) -> Self;
    fn callnames() -> &'static [&'static str];
    fn name(&self) -> &'static str;
    fn shutdown(&self, rt : &Runtime) -> ModuleResult;

    fn get_commands<C: ExecutableCommand>(&self, rt: &Runtime) -> Vec<C>;

}

<|endoftext|>


<commit_before>use crate::error::Error;
use crate::nameserver::{NameServerConfig, NameServerConfigGroup};
use crate::system_config;
use crate::Result;

use futures::future::join_all;
use futures::stream::{self, StreamExt};
use futures::{Future, TryFutureExt};
use rand::seq::SliceRandom;
use std::sync::Arc;
use std::time::Duration;

pub mod lookup;
pub mod predefined;
pub mod query;

pub use lookup::{Lookup, Lookups};
pub use query::{MultiQuery, UniQuery};

#[derive(Debug)]
pub struct ResolverConfig {
    name_server_config: NameServerConfig,
}

impl ResolverConfig {
    pub fn new(name_server_config: NameServerConfig) -> Self {
        ResolverConfig { name_server_config }
    }
}

impl From<NameServerConfig> for ResolverConfig {
    fn from(ns_config: NameServerConfig) -> Self {
        ResolverConfig {
            name_server_config: ns_config,
        }
    }
}

#[derive(Debug, Clone)]
pub struct ResolverOpts {
    pub attempts: usize,
    /// Maximum number of concurrent queries send with this resolver
    pub max_concurrent_requests: usize,
    pub ndots: usize,
    pub preserve_intermediates: bool,
    pub timeout: Duration,
}

impl ResolverOpts {
    /// Creates `ResolverOpts` from local system configuration.
    ///
    /// Unix: Parses `/etc/resolv.conf`.
    pub fn from_system_config() -> Result<ResolverOpts> {
        let opts = system_config::load_from_system_config()?;
        Ok(opts)
    }
}

impl Default for ResolverOpts {
    fn default() -> Self {
        ResolverOpts {
            attempts: 2,
            max_concurrent_requests: 5,
            ndots: 1,
            preserve_intermediates: false,
            timeout: Duration::from_secs(5),
        }
    }
}

#[derive(Debug)]
pub struct ResolverConfigGroup {
    configs: Vec<ResolverConfig>,
}

impl ResolverConfigGroup {
    pub fn new(resolver_configs: Vec<ResolverConfig>) -> ResolverConfigGroup {
        ResolverConfigGroup {
            configs: resolver_configs,
        }
    }

    /// Merges this `ResolverConfigGroup` with another
    pub fn merge(&mut self, other: Self) {
        self.configs.extend(other.configs)
    }
}

impl From<NameServerConfigGroup> for ResolverConfigGroup {
    fn from(configs: NameServerConfigGroup) -> Self {
        let resolver_confings: Vec<_> = configs.into_iter().map(From::from).collect();
        ResolverConfigGroup::new(resolver_confings)
    }
}

impl IntoIterator for ResolverConfigGroup {
    type Item = ResolverConfig;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.configs.into_iter()
    }
}

#[derive(Debug, Clone)]
pub struct Resolver {
    pub(crate) inner: Arc<trust_dns_resolver::TokioAsyncResolver>,
    pub(crate) opts: Arc<ResolverOpts>,
    pub(crate) name_server: Arc<NameServerConfig>,
}

impl Resolver {
    pub async fn new(config: ResolverConfig, opts: ResolverOpts) -> Result<Self> {
        let name_server = config.name_server_config.clone();
        let tr_opts = opts.clone().into();
        let tr_resolver = trust_dns_resolver::TokioAsyncResolver::tokio(config.into(), tr_opts)
            .map_err(Error::from)
            .await?;

        Ok(Resolver {
            inner: Arc::new(tr_resolver),
            opts: Arc::new(opts),
            name_server: Arc::new(name_server),
        })
    }

    pub async fn lookup<T: Into<MultiQuery>>(&self, query: T) -> Lookups {
        lookup::lookup(self.clone(), query).await
    }

    pub fn name(&self) -> String {
        self.name_server.to_string()
    }
}

#[derive(Debug, Clone)]
pub struct ResolverGroupOpts {
    /// Maximum number of concurrent active resolvers
    pub max_concurrent: usize,
}

impl Default for ResolverGroupOpts {
    fn default() -> Self {
        ResolverGroupOpts { max_concurrent: 10 }
    }
}

#[derive(Debug)]
pub struct ResolverGroup {
    pub(crate) resolvers: Vec<Resolver>,
    pub(crate) opts: ResolverGroupOpts,
}

impl ResolverGroup {
    pub fn new<T: Into<Vec<Resolver>>>(resolvers: T, opts: ResolverGroupOpts) -> Self {
        ResolverGroup {
            resolvers: resolvers.into(),
            opts,
        }
    }

    pub async fn from_configs<T: IntoIterator<Item = ResolverConfig>>(
        configs: T,
        resolver_opts: ResolverOpts,
        opts: ResolverGroupOpts,
    ) -> Result<Self> {
        // Create resolver futures
        let futures: Vec<_> = configs
            .into_iter()
            .map(|config| Resolver::new(config, resolver_opts.clone()))
            .collect();

        // Wait all futures
        let resolvers: Result<Vec<_>> = join_all(futures).await.into_iter().collect();

        // Check for Err
        let resolvers = resolvers?;

        Ok(Self::new(resolvers, opts))
    }

    pub async fn from_system_config(opts: ResolverGroupOpts) -> Result<Self> {
        let resolver_opts = ResolverOpts::from_system_config()?;
        let configs: ResolverConfigGroup = NameServerConfigGroup::from_system_config()?.into();
        ResolverGroup::from_configs(configs, resolver_opts, opts).await
    }

    pub async fn lookup<T: Into<MultiQuery>>(&self, query: T) -> Lookups {
        let multi_query = query.into();
        let futures: Vec<_> = self
            .resolvers
            .iter()
            .map(|resolver| resolver.lookup(multi_query.clone()))
            .collect();

        self.run_lookups(futures).await
    }

    pub async fn rnd_lookup<T: Into<MultiQuery>>(&self, query: T) -> Lookups {
        let mut rng = rand::thread_rng();
        let multi_query = query.into();
        let resolvers = self.resolvers.as_slice();

        let futures: Vec<_> = multi_query
            .into_uni_queries()
            .into_iter()
            .map(|q| resolvers.choose(&mut rng).unwrap().lookup(q)) // Safe unwrap: we know, there are resolvers
            .collect();

        self.run_lookups(futures).await
    }

    async fn run_lookups(&self, futures: Vec<impl Future<Output = Lookups>>) -> Lookups {
        let lookups: Vec<Lookup> = stream::iter(futures)
            .buffer_unordered(self.opts.max_concurrent)
            .collect::<Vec<_>>()
            .await
            .into_iter()
            .flatten()
            .collect();

        lookups.into()
    }

    /// Merges this `ResolverGroup` with another
    ///
    /// Attention: the `ResolverGroupOpts` of this `ResolverGroup` will apply
    pub fn merge(&mut self, other: Self) {
        self.resolvers.extend(other.resolvers)
    }

    pub fn add(&mut self, resolver: Resolver) {
        self.resolvers.push(resolver)
    }

    pub fn set_opts(&mut self, opts: ResolverGroupOpts) {
        self.opts = opts
    }

    pub fn opts(&self) -> &ResolverGroupOpts {
        &self.opts
    }

    pub fn len(&self) -> usize {
        self.resolvers.len()
    }

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

#[doc(hidden)]
impl From<resolv_conf::Config> for ResolverOpts {
    fn from(config: resolv_conf::Config) -> Self {
        ResolverOpts {
            attempts: config.attempts as usize,
            ndots: config.ndots as usize,
            timeout: Duration::from_secs(config.timeout as u64),
            ..Default::default()
        }
    }
}

#[doc(hidden)]
impl From<ResolverOpts> for trust_dns_resolver::config::ResolverOpts {
    fn from(opts: ResolverOpts) -> Self {
        trust_dns_resolver::config::ResolverOpts {
            attempts: opts.attempts,
            ndots: opts.ndots,
            num_concurrent_reqs: opts.max_concurrent_requests,
            preserve_intermediates: opts.preserve_intermediates,
            timeout: opts.timeout,
            ..Default::default()
        }
    }
}

#[doc(hidden)]
impl From<ResolverConfig> for trust_dns_resolver::config::ResolverConfig {
    fn from(rc: ResolverConfig) -> Self {
        let mut config = Self::new();
        config.add_name_server(rc.name_server_config.into());

        config
    }
}
<commit_msg>Fix ResolverOpts::attempts counts re-tries<commit_after>use crate::error::Error;
use crate::nameserver::{NameServerConfig, NameServerConfigGroup};
use crate::system_config;
use crate::Result;

use futures::future::join_all;
use futures::stream::{self, StreamExt};
use futures::{Future, TryFutureExt};
use rand::seq::SliceRandom;
use std::sync::Arc;
use std::time::Duration;

pub mod lookup;
pub mod predefined;
pub mod query;

pub use lookup::{Lookup, Lookups};
pub use query::{MultiQuery, UniQuery};

#[derive(Debug)]
pub struct ResolverConfig {
    name_server_config: NameServerConfig,
}

impl ResolverConfig {
    pub fn new(name_server_config: NameServerConfig) -> Self {
        ResolverConfig { name_server_config }
    }
}

impl From<NameServerConfig> for ResolverConfig {
    fn from(ns_config: NameServerConfig) -> Self {
        ResolverConfig {
            name_server_config: ns_config,
        }
    }
}

#[derive(Debug, Clone)]
pub struct ResolverOpts {
    pub attempts: usize,
    /// Maximum number of concurrent queries send with this resolver
    pub max_concurrent_requests: usize,
    pub ndots: usize,
    pub preserve_intermediates: bool,
    pub timeout: Duration,
}

impl ResolverOpts {
    /// Creates `ResolverOpts` from local system configuration.
    ///
    /// Unix: Parses `/etc/resolv.conf`.
    pub fn from_system_config() -> Result<ResolverOpts> {
        let opts = system_config::load_from_system_config()?;
        Ok(opts)
    }
}

impl Default for ResolverOpts {
    fn default() -> Self {
        ResolverOpts {
            attempts: 2,
            max_concurrent_requests: 5,
            ndots: 1,
            preserve_intermediates: false,
            timeout: Duration::from_secs(5),
        }
    }
}

#[derive(Debug)]
pub struct ResolverConfigGroup {
    configs: Vec<ResolverConfig>,
}

impl ResolverConfigGroup {
    pub fn new(resolver_configs: Vec<ResolverConfig>) -> ResolverConfigGroup {
        ResolverConfigGroup {
            configs: resolver_configs,
        }
    }

    /// Merges this `ResolverConfigGroup` with another
    pub fn merge(&mut self, other: Self) {
        self.configs.extend(other.configs)
    }
}

impl From<NameServerConfigGroup> for ResolverConfigGroup {
    fn from(configs: NameServerConfigGroup) -> Self {
        let resolver_confings: Vec<_> = configs.into_iter().map(From::from).collect();
        ResolverConfigGroup::new(resolver_confings)
    }
}

impl IntoIterator for ResolverConfigGroup {
    type Item = ResolverConfig;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.configs.into_iter()
    }
}

#[derive(Debug, Clone)]
pub struct Resolver {
    pub(crate) inner: Arc<trust_dns_resolver::TokioAsyncResolver>,
    pub(crate) opts: Arc<ResolverOpts>,
    pub(crate) name_server: Arc<NameServerConfig>,
}

impl Resolver {
    pub async fn new(config: ResolverConfig, opts: ResolverOpts) -> Result<Self> {
        let name_server = config.name_server_config.clone();
        let tr_opts = opts.clone().into();
        let tr_resolver = trust_dns_resolver::TokioAsyncResolver::tokio(config.into(), tr_opts)
            .map_err(Error::from)
            .await?;

        Ok(Resolver {
            inner: Arc::new(tr_resolver),
            opts: Arc::new(opts),
            name_server: Arc::new(name_server),
        })
    }

    pub async fn lookup<T: Into<MultiQuery>>(&self, query: T) -> Lookups {
        lookup::lookup(self.clone(), query).await
    }

    pub fn name(&self) -> String {
        self.name_server.to_string()
    }
}

#[derive(Debug, Clone)]
pub struct ResolverGroupOpts {
    /// Maximum number of concurrent active resolvers
    pub max_concurrent: usize,
}

impl Default for ResolverGroupOpts {
    fn default() -> Self {
        ResolverGroupOpts { max_concurrent: 10 }
    }
}

#[derive(Debug)]
pub struct ResolverGroup {
    pub(crate) resolvers: Vec<Resolver>,
    pub(crate) opts: ResolverGroupOpts,
}

impl ResolverGroup {
    pub fn new<T: Into<Vec<Resolver>>>(resolvers: T, opts: ResolverGroupOpts) -> Self {
        ResolverGroup {
            resolvers: resolvers.into(),
            opts,
        }
    }

    pub async fn from_configs<T: IntoIterator<Item = ResolverConfig>>(
        configs: T,
        resolver_opts: ResolverOpts,
        opts: ResolverGroupOpts,
    ) -> Result<Self> {
        // Create resolver futures
        let futures: Vec<_> = configs
            .into_iter()
            .map(|config| Resolver::new(config, resolver_opts.clone()))
            .collect();

        // Wait all futures
        let resolvers: Result<Vec<_>> = join_all(futures).await.into_iter().collect();

        // Check for Err
        let resolvers = resolvers?;

        Ok(Self::new(resolvers, opts))
    }

    pub async fn from_system_config(opts: ResolverGroupOpts) -> Result<Self> {
        let resolver_opts = ResolverOpts::from_system_config()?;
        let configs: ResolverConfigGroup = NameServerConfigGroup::from_system_config()?.into();
        ResolverGroup::from_configs(configs, resolver_opts, opts).await
    }

    pub async fn lookup<T: Into<MultiQuery>>(&self, query: T) -> Lookups {
        let multi_query = query.into();
        let futures: Vec<_> = self
            .resolvers
            .iter()
            .map(|resolver| resolver.lookup(multi_query.clone()))
            .collect();

        self.run_lookups(futures).await
    }

    pub async fn rnd_lookup<T: Into<MultiQuery>>(&self, query: T) -> Lookups {
        let mut rng = rand::thread_rng();
        let multi_query = query.into();
        let resolvers = self.resolvers.as_slice();

        let futures: Vec<_> = multi_query
            .into_uni_queries()
            .into_iter()
            .map(|q| resolvers.choose(&mut rng).unwrap().lookup(q)) // Safe unwrap: we know, there are resolvers
            .collect();

        self.run_lookups(futures).await
    }

    async fn run_lookups(&self, futures: Vec<impl Future<Output = Lookups>>) -> Lookups {
        let lookups: Vec<Lookup> = stream::iter(futures)
            .buffer_unordered(self.opts.max_concurrent)
            .collect::<Vec<_>>()
            .await
            .into_iter()
            .flatten()
            .collect();

        lookups.into()
    }

    /// Merges this `ResolverGroup` with another
    ///
    /// Attention: the `ResolverGroupOpts` of this `ResolverGroup` will apply
    pub fn merge(&mut self, other: Self) {
        self.resolvers.extend(other.resolvers)
    }

    pub fn add(&mut self, resolver: Resolver) {
        self.resolvers.push(resolver)
    }

    pub fn set_opts(&mut self, opts: ResolverGroupOpts) {
        self.opts = opts
    }

    pub fn opts(&self) -> &ResolverGroupOpts {
        &self.opts
    }

    pub fn len(&self) -> usize {
        self.resolvers.len()
    }

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

#[doc(hidden)]
impl From<resolv_conf::Config> for ResolverOpts {
    fn from(config: resolv_conf::Config) -> Self {
        ResolverOpts {
            attempts: config.attempts as usize,
            ndots: config.ndots as usize,
            timeout: Duration::from_secs(config.timeout as u64),
            ..Default::default()
        }
    }
}

#[doc(hidden)]
impl From<ResolverOpts> for trust_dns_resolver::config::ResolverOpts {
    fn from(opts: ResolverOpts) -> Self {
        trust_dns_resolver::config::ResolverOpts {
            // TODO: This is currently broken or I misunderstood the docs - cf. https://github.com/bluejekyll/trust-dns/issues/1176
            attempts: if opts.attempts <= 0 { 0 } else { opts.attempts - 1},
            ndots: opts.ndots,
            num_concurrent_reqs: opts.max_concurrent_requests,
            preserve_intermediates: opts.preserve_intermediates,
            timeout: opts.timeout,
            ..Default::default()
        }
    }
}

#[doc(hidden)]
impl From<ResolverConfig> for trust_dns_resolver::config::ResolverConfig {
    fn from(rc: ResolverConfig) -> Self {
        let mut config = Self::new();
        config.add_name_server(rc.name_server_config.into());

        config
    }
}
<|endoftext|>


<commit_before>// std imports

// srmat imports

use matrix::MatrixF64;

/// A Gauss elimination problem specification
pub struct GaussElimination<'a, 'b>{
    pub a : &'a MatrixF64,
    pub b : &'b MatrixF64
}

impl<'a, 'b> GaussElimination<'a, 'b>{

    /// Setup of a new Gauss elimination problem.
    pub fn new(a : &'a MatrixF64, b : &'b MatrixF64) -> GaussElimination<'a, 'b>{
        assert!(a.is_square());
        assert_eq!(a.num_rows(), b.num_rows());
        GaussElimination{a : a , b : b}
    }

    /// Carries out the procedure of Gauss elimination.
    pub fn solve(&self) -> MatrixF64 {
        let mut m = self.a.clone();
        m.append_columns(self.b);
        let rows = m.num_rows();
        let cols = m.num_cols();
        // Forward elimination process.
        for k in range(0, rows){
            // We are working on k-th column.
            // Create a view of the remaining elements in column
            //let col_k_remaining = m.view(k, k, rows - k, 1);
            //let (max_val, rr, _) = col_k_remaining.abs_max_scalar();
            //if rr > k {
            //    // We need to exchange rows of the submatrix.
            //}
            // Pick up the pivot
            let pivot = m.get(k, k);
            let mut lower_right  = m.view(k + 1, k, rows - k - 1, cols -k);
            //println!("Pivot: {}", pivot);
            //println!("{}", lower_right);
            for r in range(0, lower_right.num_rows()){
                let first = lower_right.get(r, 0);
                let factor = first  / pivot;
                lower_right.ero_scale_add(r, -1, -factor);
            }
            //println!("m: {}", m);
        }
        // Backward substitution starts now.
        let mut b = m.view(0, self.a.num_cols(),
            self.b.num_rows(),
            self.b.num_cols());
        let mut r = m.num_rows() - 1;
        loop {
            let pivot = m.get(r, r);
            b.ero_scale(r, 1.0/pivot);
            for j in range(r+1, m.num_rows()){
                let factor = m.get(r, j) / pivot;
                b.ero_scale_add(r, j as int, -factor);
            }
            if r == 0 {
                break;
            }
            r -= 1;
        }
        // We extract the result.
        b.to_matrix()
    }

}
<commit_msg>Some examples for GE.<commit_after>// std imports

// srmat imports

use matrix::MatrixF64;

/// A Gauss elimination problem specification
pub struct GaussElimination<'a, 'b>{
    pub a : &'a MatrixF64,
    pub b : &'b MatrixF64
}

impl<'a, 'b> GaussElimination<'a, 'b>{

    /// Setup of a new Gauss elimination problem.
    pub fn new(a : &'a MatrixF64, b : &'b MatrixF64) -> GaussElimination<'a, 'b>{
        assert!(a.is_square());
        assert_eq!(a.num_rows(), b.num_rows());
        GaussElimination{a : a , b : b}
    }

    /// Carries out the procedure of Gauss elimination.
    pub fn solve(&self) -> MatrixF64 {
        let mut m = self.a.clone();
        m.append_columns(self.b);
        let rows = m.num_rows();
        let cols = m.num_cols();
        // Forward elimination process.
        for k in range(0, rows){
            // We are working on k-th column.
            // Create a view of the remaining elements in column
            //let col_k_remaining = m.view(k, k, rows - k, 1);
            //let (max_val, rr, _) = col_k_remaining.abs_max_scalar();
            //if rr > k {
            //    // We need to exchange rows of the submatrix.
            //}
            // Pick up the pivot
            let pivot = m.get(k, k);
            let mut lower_right  = m.view(k + 1, k, rows - k - 1, cols -k);
            //println!("Pivot: {}", pivot);
            //println!("{}", lower_right);
            for r in range(0, lower_right.num_rows()){
                let first = lower_right.get(r, 0);
                let factor = first  / pivot;
                lower_right.ero_scale_add(r, -1, -factor);
            }
            //println!("m: {}", m);
        }
        // Backward substitution starts now.
        let mut b = m.view(0, self.a.num_cols(),
            self.b.num_rows(),
            self.b.num_cols());
        let mut r = m.num_rows() - 1;
        loop {
            let pivot = m.get(r, r);
            b.ero_scale(r, 1.0/pivot);
            for j in range(r+1, m.num_rows()){
                let factor = m.get(r, j) / pivot;
                b.ero_scale_add(r, j as int, -factor);
            }
            if r == 0 {
                break;
            }
            r -= 1;
        }
        // We extract the result.
        b.to_matrix()
    }

}

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

    #[test]
    fn test_ge_0(){
        let a = matrix_f64(2,2, [1., 4., 2., 5.]);
        println!("{}", a);
        let b = vector_f64([3.0, 6.0]);
        let x = GaussElimination::new(&a, &b).solve();
        println!("{}", x);
        assert_eq!(x, vector_f64([-1., 2.]));
    }

    #[test]
    fn test_ge_1(){
        let mut a = from_range(3, 3, 1.0, 100.0);
        let x = from_range(3, 1, 1.0, 100.0);
        // a above is rank-2.
        a.set(2,2, 11.0);
        let b  = a * x;
        println!("A: {}", a);
        println!("x: {}", x);
        println!("b: {}", b);
        let ge = GaussElimination::new(&a, &b);
        let z = ge.solve();
        println!("z: {}", z);
        assert_eq!(x, z);
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};
use std::str::FromStr;
use std::ascii::AsciiExt;

use self::Charset::*;

/// A Mime charset.
///
/// The string representation is normalised to upper case.
///
/// See http://www.iana.org/assignments/character-sets/character-sets.xhtml
#[derive(Clone,Debug,PartialEq)]
#[allow(non_camel_case_types)]
pub enum Charset{
    /// US ASCII
    Us_Ascii,
    /// ISO-8859-1
    Iso_8859_1,
    /// ISO-8859-2
    Iso_8859_2,
    /// ISO-8859-3
    Iso_8859_3,
    /// ISO-8859-4
    Iso_8859_4,
    /// ISO-8859-5
    Iso_8859_5,
    /// ISO-8859-6
    Iso_8859_6,
    /// ISO-8859-7
    Iso_8859_7,
    /// ISO-8859-8
    Iso_8859_8,
    /// ISO-8859-9
    Iso_8859_9,
    /// ISO-8859-10
    Iso_8859_10,
    /// Shift_JIS
    Shift_Jis,
    /// EUC-JP
    Euc_Jp,
    /// ISO-2022-KR
    Iso_2022_Kr,
    /// EUC-KR
    Euc_Kr,
    /// ISO-2022-JP
    Iso_2022_Jp,
    /// ISO-2022-JP-2
    Iso_2022_Jp_2,
    /// ISO-8859-6-E
    Iso_8859_6_E,
    /// ISO-8859-6-I
    Iso_8859_6_I,
    /// ISO-8859-8-E
    Iso_8859_8_E,
    /// ISO-8859-8-I
    Iso_8859_8_I,
    /// GB2312
    Gb2312,
    /// Big5
    Big5,
    /// KOI8-R
    Koi8_R,
    /// An arbitrary charset specified as a string
    Ext(String)
}

impl Charset {
    fn name(&self) -> &str {
        match *self {
            Us_Ascii => "US-ASCII",
            Iso_8859_1 => "ISO-8859-1",
            Iso_8859_2 => "ISO-8859-2",
            Iso_8859_3 => "ISO-8859-3",
            Iso_8859_4 => "ISO-8859-4",
            Iso_8859_5 => "ISO-8859-5",
            Iso_8859_6 => "ISO-8859-6",
            Iso_8859_7 => "ISO-8859-7",
            Iso_8859_8 => "ISO-8859-8",
            Iso_8859_9 => "ISO-8859-9",
            Iso_8859_10 => "ISO-8859-10",
            Shift_Jis => "Shift-JIS",
            Euc_Jp => "EUC-JP",
            Iso_2022_Kr => "ISO-2022-KR",
            Euc_Kr => "EUC-KR",
            Iso_2022_Jp => "ISO-2022-JP",
            Iso_2022_Jp_2 => "ISO-2022-JP-2",
            Iso_8859_6_E => "ISO-8859-6-E",
            Iso_8859_6_I => "ISO-8859-6-I",
            Iso_8859_8_E => "ISO-8859-8-E",
            Iso_8859_8_I => "ISO-8859-8-I",
            Gb2312 => "GB2312",
            Big5 => "5",
            Koi8_R => "KOI8-R",
            Ext(ref s) => &s
        }
    }
}

impl Display for Charset {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.name())
    }
}

impl FromStr for Charset {
    type Err = ();
    fn from_str(s: &str) -> Result<Charset, ()> {
        Ok(match s.to_ascii_uppercase().as_slice() {
            "US-ASCII" => Us_Ascii,
            "ISO-8859-1" => Iso_8859_1,
            "ISO-8859-2" => Iso_8859_2,
            "ISO-8859-3" => Iso_8859_3,
            "ISO-8859-4" => Iso_8859_4,
            "ISO-8859-5" => Iso_8859_5,
            "ISO-8859-6" => Iso_8859_6,
            "ISO-8859-7" => Iso_8859_7,
            "ISO-8859-8" => Iso_8859_8,
            "ISO-8859-9" => Iso_8859_9,
            "ISO-8859-10" => Iso_8859_10,
            "Shift-JIS" => Shift_Jis,
            "EUC-JP" => Euc_Jp,
            "ISO-2022-KR" => Iso_2022_Kr,
            "EUC-KR" => Euc_Kr,
            "ISO-2022-JP" => Iso_2022_Jp,
            "ISO-2022-JP-2" => Iso_2022_Jp_2,
            "ISO-8859-6-E" => Iso_8859_6_E,
            "ISO-8859-6-I" => Iso_8859_6_I,
            "ISO-8859-8-E" => Iso_8859_8_E,
            "ISO-8859-8-I" => Iso_8859_8_I,
            "GB2312" => Gb2312,
            "5" => Big5,
            "KOI8-R" => Koi8_R,
            s => Ext(s.to_string())
        })
    }
}

#[test]
fn test_parse() {
    assert_eq!(Us_Ascii,"us-ascii".parse().unwrap());
    assert_eq!(Us_Ascii,"US-Ascii".parse().unwrap());
    assert_eq!(Us_Ascii,"US-ASCII".parse().unwrap());
    assert_eq!(Ext("ABCD".to_string()),"abcd".parse().unwrap());
}

#[test]
fn test_display() {
    assert_eq!("US-ASCII", format!("{}", Us_Ascii));
    assert_eq!("ABCD", format!("{}", Ext("ABCD".to_string())));
}
<commit_msg>fix(header): Fix charset parsing bug.<commit_after>use std::fmt::{self, Display};
use std::str::FromStr;
use std::ascii::AsciiExt;

use self::Charset::*;

/// A Mime charset.
///
/// The string representation is normalised to upper case.
///
/// See http://www.iana.org/assignments/character-sets/character-sets.xhtml
#[derive(Clone,Debug,PartialEq)]
#[allow(non_camel_case_types)]
pub enum Charset{
    /// US ASCII
    Us_Ascii,
    /// ISO-8859-1
    Iso_8859_1,
    /// ISO-8859-2
    Iso_8859_2,
    /// ISO-8859-3
    Iso_8859_3,
    /// ISO-8859-4
    Iso_8859_4,
    /// ISO-8859-5
    Iso_8859_5,
    /// ISO-8859-6
    Iso_8859_6,
    /// ISO-8859-7
    Iso_8859_7,
    /// ISO-8859-8
    Iso_8859_8,
    /// ISO-8859-9
    Iso_8859_9,
    /// ISO-8859-10
    Iso_8859_10,
    /// Shift_JIS
    Shift_Jis,
    /// EUC-JP
    Euc_Jp,
    /// ISO-2022-KR
    Iso_2022_Kr,
    /// EUC-KR
    Euc_Kr,
    /// ISO-2022-JP
    Iso_2022_Jp,
    /// ISO-2022-JP-2
    Iso_2022_Jp_2,
    /// ISO-8859-6-E
    Iso_8859_6_E,
    /// ISO-8859-6-I
    Iso_8859_6_I,
    /// ISO-8859-8-E
    Iso_8859_8_E,
    /// ISO-8859-8-I
    Iso_8859_8_I,
    /// GB2312
    Gb2312,
    /// Big5
    Big5,
    /// KOI8-R
    Koi8_R,
    /// An arbitrary charset specified as a string
    Ext(String)
}

impl Charset {
    fn name(&self) -> &str {
        match *self {
            Us_Ascii => "US-ASCII",
            Iso_8859_1 => "ISO-8859-1",
            Iso_8859_2 => "ISO-8859-2",
            Iso_8859_3 => "ISO-8859-3",
            Iso_8859_4 => "ISO-8859-4",
            Iso_8859_5 => "ISO-8859-5",
            Iso_8859_6 => "ISO-8859-6",
            Iso_8859_7 => "ISO-8859-7",
            Iso_8859_8 => "ISO-8859-8",
            Iso_8859_9 => "ISO-8859-9",
            Iso_8859_10 => "ISO-8859-10",
            Shift_Jis => "Shift-JIS",
            Euc_Jp => "EUC-JP",
            Iso_2022_Kr => "ISO-2022-KR",
            Euc_Kr => "EUC-KR",
            Iso_2022_Jp => "ISO-2022-JP",
            Iso_2022_Jp_2 => "ISO-2022-JP-2",
            Iso_8859_6_E => "ISO-8859-6-E",
            Iso_8859_6_I => "ISO-8859-6-I",
            Iso_8859_8_E => "ISO-8859-8-E",
            Iso_8859_8_I => "ISO-8859-8-I",
            Gb2312 => "GB2312",
            Big5 => "5",
            Koi8_R => "KOI8-R",
            Ext(ref s) => &s
        }
    }
}

impl Display for Charset {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.name())
    }
}

impl FromStr for Charset {
    type Err = ();
    fn from_str(s: &str) -> Result<Charset, ()> {
        Ok(match s.to_ascii_uppercase().as_slice() {
            "US-ASCII" => Us_Ascii,
            "ISO-8859-1" => Iso_8859_1,
            "ISO-8859-2" => Iso_8859_2,
            "ISO-8859-3" => Iso_8859_3,
            "ISO-8859-4" => Iso_8859_4,
            "ISO-8859-5" => Iso_8859_5,
            "ISO-8859-6" => Iso_8859_6,
            "ISO-8859-7" => Iso_8859_7,
            "ISO-8859-8" => Iso_8859_8,
            "ISO-8859-9" => Iso_8859_9,
            "ISO-8859-10" => Iso_8859_10,
            "SHIFT-JIS" => Shift_Jis,
            "EUC-JP" => Euc_Jp,
            "ISO-2022-KR" => Iso_2022_Kr,
            "EUC-KR" => Euc_Kr,
            "ISO-2022-JP" => Iso_2022_Jp,
            "ISO-2022-JP-2" => Iso_2022_Jp_2,
            "ISO-8859-6-E" => Iso_8859_6_E,
            "ISO-8859-6-I" => Iso_8859_6_I,
            "ISO-8859-8-E" => Iso_8859_8_E,
            "ISO-8859-8-I" => Iso_8859_8_I,
            "GB2312" => Gb2312,
            "5" => Big5,
            "KOI8-R" => Koi8_R,
            s => Ext(s.to_string())
        })
    }
}

#[test]
fn test_parse() {
    assert_eq!(Us_Ascii,"us-ascii".parse().unwrap());
    assert_eq!(Us_Ascii,"US-Ascii".parse().unwrap());
    assert_eq!(Us_Ascii,"US-ASCII".parse().unwrap());
    assert_eq!(Shift_Jis,"Shift-JIS".parse().unwrap());
    assert_eq!(Ext("ABCD".to_string()),"abcd".parse().unwrap());
}

#[test]
fn test_display() {
    assert_eq!("US-ASCII", format!("{}", Us_Ascii));
    assert_eq!("ABCD", format!("{}", Ext("ABCD".to_string())));
}
<|endoftext|>