<commit_before>#![cfg(test)]

#[cfg(feature = "serialization-serde")]
extern crate serde_json;

use ring::digest::{Algorithm, Context, SHA512};

use crate::hashutils::{HashUtils, Hashable};
use crate::merkletree::MerkleTree;
use crate::proof::Positioned;

static DIGEST: &Algorithm = &SHA512;

#[test]
fn test_from_str_vec() {
    let values = vec!["one", "two", "three", "four"];

    let hashes = vec![
        DIGEST.hash_leaf(&values[0].as_bytes()),
        DIGEST.hash_leaf(&values[1].as_bytes()),
        DIGEST.hash_leaf(&values[2].as_bytes()),
        DIGEST.hash_leaf(&values[3].as_bytes()),
    ];

    let count = values.len();
    let tree = MerkleTree::from_vec(DIGEST, values);

    let h01 = DIGEST.hash_nodes(&hashes[0], &hashes[1]);
    let h23 = DIGEST.hash_nodes(&hashes[2], &hashes[3]);

    let root_hash = DIGEST.hash_nodes(&h01, &h23);

    assert_eq!(tree.count(), count);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_from_vec_empty() {
    let values: Vec<Vec<u8>> = vec![];
    let tree = MerkleTree::from_vec(DIGEST, values);
    let empty_hash: Vec<u8> = DIGEST.hash_empty().as_ref().into();
    let root_hash = tree.root_hash().clone();

    assert_eq!(root_hash, empty_hash);
}

#[test]
fn test_from_vec1() {
    let values = vec!["hello, world".to_string()];
    let tree = MerkleTree::from_vec(DIGEST, values);

    let root_hash = &DIGEST.hash_leaf(b"hello, world");

    assert_eq!(tree.count(), 1);
    assert_eq!(tree.height(), 0);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_from_vec3() {
    let values = vec![vec![1], vec![2], vec![3]];
    let tree = MerkleTree::from_vec(DIGEST, values);

    let hashes = vec![
        DIGEST.hash_leaf(&vec![1]),
        DIGEST.hash_leaf(&vec![2]),
        DIGEST.hash_leaf(&vec![3]),
    ];

    let h01 = DIGEST.hash_nodes(&hashes[0], &hashes[1]);
    let h2 = &hashes[2];
    let root_hash = &DIGEST.hash_nodes(&h01, h2);

    assert_eq!(tree.count(), 3);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_from_vec9() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());

    let hashes = values
        .iter()
        .map(|v| DIGEST.hash_leaf(v))
        .collect::<Vec<_>>();

    let h01 = DIGEST.hash_nodes(&hashes[0], &hashes[1]);
    let h23 = DIGEST.hash_nodes(&hashes[2], &hashes[3]);
    let h45 = DIGEST.hash_nodes(&hashes[4], &hashes[5]);
    let h67 = DIGEST.hash_nodes(&hashes[6], &hashes[7]);
    let h8 = &hashes[8];
    let h0123 = DIGEST.hash_nodes(&h01, &h23);
    let h4567 = DIGEST.hash_nodes(&h45, &h67);
    let h1to7 = DIGEST.hash_nodes(&h0123, &h4567);

    let root_hash = &DIGEST.hash_nodes(&h1to7, h8);

    assert_eq!(tree.count(), 9);
    assert_eq!(tree.height(), 4);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_valid_proof() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let root_hash = tree.root_hash();

    for value in values {
        let proof = tree.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

        assert!(is_valid);
    }
}

#[test]
fn test_valid_proof_str() {
    let values = vec!["Hello", "my", "name", "is", "Rusty"];
    let tree = MerkleTree::from_vec(DIGEST, values);
    let root_hash = tree.root_hash();

    let value = "Rusty";

    let proof = tree.gen_proof(&value);
    let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

    assert!(is_valid);
}

#[test]
fn test_wrong_proof() {
    let values1 = vec![vec![1], vec![2], vec![3], vec![4]];
    let tree1 = MerkleTree::from_vec(DIGEST, values1.clone());

    let values2 = vec![vec![4], vec![5], vec![6], vec![7]];
    let tree2 = MerkleTree::from_vec(DIGEST, values2);

    let root_hash = tree2.root_hash();

    for value in values1 {
        let proof = tree1.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(root_hash)).unwrap_or(false);

        assert_eq!(is_valid, false);
    }
}

#[test]
fn test_nth_proof() {
    // Calculation depends on the total count. Try a few numbers: odd, even, powers of two...
    for &count in &[1, 2, 3, 10, 15, 16, 17, 22] {
        let values = (1..=count).map(|x| vec![x as u8]).collect::<Vec<_>>();
        let tree = MerkleTree::from_vec(DIGEST, values.clone());
        let root_hash = tree.root_hash();

        for i in 0..count {
            let proof = tree.gen_nth_proof(i).expect("gen proof by index");
            assert_eq!(vec![i as u8 + 1], proof.value);
            assert!(proof.validate(&root_hash));
            assert_eq!(i, proof.index(tree.count()));
        }

        assert!(tree.gen_nth_proof(count).is_none());
        assert!(tree.gen_nth_proof(count + 1000).is_none());
    }
}

#[test]
fn test_mutate_proof_first_lemma() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let root_hash = tree.root_hash();

    for (i, value) in values.into_iter().enumerate() {
        let mut proof = tree.gen_proof(value).unwrap();

        match i % 3 {
            0 => {
                proof.lemma.node_hash = vec![1, 2, 3];
            }
            1 => {
                proof.lemma.sibling_hash = Some(Positioned::Left(vec![1, 2, 3]));
            }
            _ => {
                proof.lemma.sibling_hash = Some(Positioned::Right(vec![1, 2, 3]));
            }
        }

        let is_valid = proof.validate(root_hash);
        assert_eq!(is_valid, false);
    }
}

#[test]
fn test_tree_iter() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let iter = tree.iter().cloned().collect::<Vec<_>>();

    assert_eq!(values, iter);
}

#[test]
fn test_tree_into_iter() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let iter = tree.into_iter().collect::<Vec<_>>();

    assert_eq!(values, iter);
}

#[test]
fn test_tree_into_iter_loop() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());

    let mut collected = Vec::new();

    for value in tree {
        collected.push(value);
    }

    assert_eq!(values, collected);
}

#[test]
fn test_tree_into_iter_loop_borrow() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());

    let mut collected = Vec::new();

    for value in &tree {
        collected.push(value);
    }

    let refs = values.iter().collect::<Vec<_>>();

    assert_eq!(refs, collected);
}

pub struct PublicKey {
    zero_values: Vec<Vec<u8>>,
    one_values: Vec<Vec<u8>>,
}

impl PublicKey {
    pub fn new(zero_values: Vec<Vec<u8>>, one_values: Vec<Vec<u8>>) -> Self {
        PublicKey {
            zero_values,
            one_values,
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        self.zero_values
            .iter()
            .chain(self.one_values.iter())
            .fold(Vec::new(), |mut acc, i| {
                acc.append(&mut i.clone());
                acc
            })
    }
}

impl Hashable for PublicKey {
    fn update_context(&self, context: &mut Context) {
        context.update(&self.to_bytes());
    }
}

#[test]
fn test_custom_hashable_impl() {
    let keys = (0..10)
        .map(|i| {
            let zero_values = vec![vec![i], vec![i + 1], vec![i + 2]];
            let one_values = vec![vec![i + 3], vec![i + 4], vec![i + 5]];

            PublicKey::new(zero_values, one_values)
        })
        .collect::<Vec<_>>();

    let tree = MerkleTree::from_vec(DIGEST, keys);

    assert_eq!(tree.count(), 10);
    assert_eq!(tree.height(), 4);
}

#[cfg(feature = "serialization-serde")]
#[test]
fn test_serialize_proof_with_serde() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(digest, values);
    let proof = tree.gen_proof(vec![5]);

    let serialized = serde_json::to_string(&proof).expect("serialize proof");

    assert_eq!(
        proof,
        serde_json::from_str(&serialized).expect("deserialize proof")
    );
}
<commit_msg>Fix typo in tests<commit_after>#![cfg(test)]

#[cfg(feature = "serialization-serde")]
extern crate serde_json;

use ring::digest::{Algorithm, Context, SHA512};

use crate::hashutils::{HashUtils, Hashable};
use crate::merkletree::MerkleTree;
use crate::proof::Positioned;

static DIGEST: &Algorithm = &SHA512;

#[test]
fn test_from_str_vec() {
    let values = vec!["one", "two", "three", "four"];

    let hashes = vec![
        DIGEST.hash_leaf(&values[0].as_bytes()),
        DIGEST.hash_leaf(&values[1].as_bytes()),
        DIGEST.hash_leaf(&values[2].as_bytes()),
        DIGEST.hash_leaf(&values[3].as_bytes()),
    ];

    let count = values.len();
    let tree = MerkleTree::from_vec(DIGEST, values);

    let h01 = DIGEST.hash_nodes(&hashes[0], &hashes[1]);
    let h23 = DIGEST.hash_nodes(&hashes[2], &hashes[3]);

    let root_hash = DIGEST.hash_nodes(&h01, &h23);

    assert_eq!(tree.count(), count);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_from_vec_empty() {
    let values: Vec<Vec<u8>> = vec![];
    let tree = MerkleTree::from_vec(DIGEST, values);
    let empty_hash: Vec<u8> = DIGEST.hash_empty().as_ref().into();
    let root_hash = tree.root_hash().clone();

    assert_eq!(root_hash, empty_hash);
}

#[test]
fn test_from_vec1() {
    let values = vec!["hello, world".to_string()];
    let tree = MerkleTree::from_vec(DIGEST, values);

    let root_hash = &DIGEST.hash_leaf(b"hello, world");

    assert_eq!(tree.count(), 1);
    assert_eq!(tree.height(), 0);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_from_vec3() {
    let values = vec![vec![1], vec![2], vec![3]];
    let tree = MerkleTree::from_vec(DIGEST, values);

    let hashes = vec![
        DIGEST.hash_leaf(&vec![1]),
        DIGEST.hash_leaf(&vec![2]),
        DIGEST.hash_leaf(&vec![3]),
    ];

    let h01 = DIGEST.hash_nodes(&hashes[0], &hashes[1]);
    let h2 = &hashes[2];
    let root_hash = &DIGEST.hash_nodes(&h01, h2);

    assert_eq!(tree.count(), 3);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_from_vec9() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());

    let hashes = values
        .iter()
        .map(|v| DIGEST.hash_leaf(v))
        .collect::<Vec<_>>();

    let h01 = DIGEST.hash_nodes(&hashes[0], &hashes[1]);
    let h23 = DIGEST.hash_nodes(&hashes[2], &hashes[3]);
    let h45 = DIGEST.hash_nodes(&hashes[4], &hashes[5]);
    let h67 = DIGEST.hash_nodes(&hashes[6], &hashes[7]);
    let h8 = &hashes[8];
    let h0123 = DIGEST.hash_nodes(&h01, &h23);
    let h4567 = DIGEST.hash_nodes(&h45, &h67);
    let h1to7 = DIGEST.hash_nodes(&h0123, &h4567);

    let root_hash = &DIGEST.hash_nodes(&h1to7, h8);

    assert_eq!(tree.count(), 9);
    assert_eq!(tree.height(), 4);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_ref());
}

#[test]
fn test_valid_proof() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let root_hash = tree.root_hash();

    for value in values {
        let proof = tree.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

        assert!(is_valid);
    }
}

#[test]
fn test_valid_proof_str() {
    let values = vec!["Hello", "my", "name", "is", "Rusty"];
    let tree = MerkleTree::from_vec(DIGEST, values);
    let root_hash = tree.root_hash();

    let value = "Rusty";

    let proof = tree.gen_proof(&value);
    let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

    assert!(is_valid);
}

#[test]
fn test_wrong_proof() {
    let values1 = vec![vec![1], vec![2], vec![3], vec![4]];
    let tree1 = MerkleTree::from_vec(DIGEST, values1.clone());

    let values2 = vec![vec![4], vec![5], vec![6], vec![7]];
    let tree2 = MerkleTree::from_vec(DIGEST, values2);

    let root_hash = tree2.root_hash();

    for value in values1 {
        let proof = tree1.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(root_hash)).unwrap_or(false);

        assert_eq!(is_valid, false);
    }
}

#[test]
fn test_nth_proof() {
    // Calculation depends on the total count. Try a few numbers: odd, even, powers of two...
    for &count in &[1, 2, 3, 10, 15, 16, 17, 22] {
        let values = (1..=count).map(|x| vec![x as u8]).collect::<Vec<_>>();
        let tree = MerkleTree::from_vec(DIGEST, values.clone());
        let root_hash = tree.root_hash();

        for i in 0..count {
            let proof = tree.gen_nth_proof(i).expect("gen proof by index");
            assert_eq!(vec![i as u8 + 1], proof.value);
            assert!(proof.validate(&root_hash));
            assert_eq!(i, proof.index(tree.count()));
        }

        assert!(tree.gen_nth_proof(count).is_none());
        assert!(tree.gen_nth_proof(count + 1000).is_none());
    }
}

#[test]
fn test_mutate_proof_first_lemma() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let root_hash = tree.root_hash();

    for (i, value) in values.into_iter().enumerate() {
        let mut proof = tree.gen_proof(value).unwrap();

        match i % 3 {
            0 => {
                proof.lemma.node_hash = vec![1, 2, 3];
            }
            1 => {
                proof.lemma.sibling_hash = Some(Positioned::Left(vec![1, 2, 3]));
            }
            _ => {
                proof.lemma.sibling_hash = Some(Positioned::Right(vec![1, 2, 3]));
            }
        }

        let is_valid = proof.validate(root_hash);
        assert_eq!(is_valid, false);
    }
}

#[test]
fn test_tree_iter() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let iter = tree.iter().cloned().collect::<Vec<_>>();

    assert_eq!(values, iter);
}

#[test]
fn test_tree_into_iter() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());
    let iter = tree.into_iter().collect::<Vec<_>>();

    assert_eq!(values, iter);
}

#[test]
fn test_tree_into_iter_loop() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());

    let mut collected = Vec::new();

    for value in tree {
        collected.push(value);
    }

    assert_eq!(values, collected);
}

#[test]
fn test_tree_into_iter_loop_borrow() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values.clone());

    let mut collected = Vec::new();

    for value in &tree {
        collected.push(value);
    }

    let refs = values.iter().collect::<Vec<_>>();

    assert_eq!(refs, collected);
}

pub struct PublicKey {
    zero_values: Vec<Vec<u8>>,
    one_values: Vec<Vec<u8>>,
}

impl PublicKey {
    pub fn new(zero_values: Vec<Vec<u8>>, one_values: Vec<Vec<u8>>) -> Self {
        PublicKey {
            zero_values,
            one_values,
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        self.zero_values
            .iter()
            .chain(self.one_values.iter())
            .fold(Vec::new(), |mut acc, i| {
                acc.append(&mut i.clone());
                acc
            })
    }
}

impl Hashable for PublicKey {
    fn update_context(&self, context: &mut Context) {
        context.update(&self.to_bytes());
    }
}

#[test]
fn test_custom_hashable_impl() {
    let keys = (0..10)
        .map(|i| {
            let zero_values = vec![vec![i], vec![i + 1], vec![i + 2]];
            let one_values = vec![vec![i + 3], vec![i + 4], vec![i + 5]];

            PublicKey::new(zero_values, one_values)
        })
        .collect::<Vec<_>>();

    let tree = MerkleTree::from_vec(DIGEST, keys);

    assert_eq!(tree.count(), 10);
    assert_eq!(tree.height(), 4);
}

#[cfg(feature = "serialization-serde")]
#[test]
fn test_serialize_proof_with_serde() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree = MerkleTree::from_vec(DIGEST, values);
    let proof = tree.gen_proof(vec![5]);

    let serialized = serde_json::to_string(&proof).expect("serialize proof");

    assert_eq!(
        proof,
        serde_json::from_str(&serialized).expect("deserialize proof")
    );
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#![cfg(test)]

use model::Board;

fn perft(board: &Board, depth: u8) -> u32 {
    if depth == 0 {
        1
    } else {
        let mut sum = 0;
        for mv in board.generate_moves() {
            let mut new_board = *board;
            new_board.apply_move(&mv);
            sum += perft(&new_board, depth - 1);
        }
        sum
    }
}

#[test]
fn perft_depth_4() {
    // These counts have not been verified by an external source. They only test for consistency
    // with earlier versions of the program.
    let counts = [48, 2304, 110304, 5280654];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}

#[test]
#[ignore]
fn perft_depth_5() {
    // These counts have not been verified by an external source. They only test for consistency
    // with earlier versions of the program.
    let counts = [48, 2304, 110304, 5280654, 254945184];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}
<commit_msg>Add perft depth 6<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#![cfg(test)]

use model::Board;

fn perft(board: &Board, depth: u8) -> u64 {
    if depth == 0 {
        1
    } else {
        let mut sum = 0;
        for mv in board.generate_moves() {
            let mut new_board = *board;
            new_board.apply_move(&mv);
            sum += perft(&new_board, depth - 1);
        }
        sum
    }
}

#[test]
fn perft_depth_4() {
    // These counts have not been verified by an external source. They only test for consistency
    // with earlier versions of the program.
    let counts = [48, 2304, 110304, 5280654];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}

#[test]
#[ignore]
fn perft_depth_5() {
    // These counts have not been verified by an external source. They only test for consistency
    // with earlier versions of the program.
    let counts = [48, 2304, 110304, 5280654, 254945184];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}

#[test]
#[ignore]
fn perft_depth_6() {
    // These counts have not been verified by an external source. They only test for consistency
    // with earlier versions of the program.
    let counts = [48, 2304, 110304, 5280654, 254945184, 12307984056];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}
<|endoftext|>


<commit_before>use phf;
use std::ascii::AsciiExt;
use super::namepart::NamePart;

static TWO_CHAR_TITLES: [&'static str; 4] = ["mr", "ms", "sr", "dr"];

static PREFIX_TITLE_PARTS: phf::Set<&'static str> = phf_set! {
    "Aunt",
    "Auntie",
    "Attaché",
    "Dame",
    "Marchioness",
    "Marquess",
    "Marquis",
    "Marquise",
    "King",
    "King'S",
    "Queen",
    "Queen'S",
    "1lt",
    "1st",
    "1sgt",
    "1stlt",
    "1stsgt",
    "2lt",
    "2nd",
    "2ndlt",
    "A1c",
    "Abbess",
    "Abbot",
    "Academic",
    "Acolyte",
    "Adept",
    "Adjutant",
    "Adm",
    "Admiral",
    "Advocate",
    "Akhoond",
    "Air",
    "Ald",
    "Alderman",
    "Almoner",
    "Ambassador",
    "Amn",
    "Analytics",
    "Appellate",
    "Apprentice",
    "Arbitrator",
    "Archbishop",
    "Archdeacon",
    "Archdruid",
    "Archduchess",
    "Archduke",
    "Arhat",
    "Assistant",
    "Assoc",
    "Associate",
    "Asst",
    "Attache",
    "Attorney",
    "Ayatollah",
    "Baba",
    "Bailiff",
    "Banner",
    "Bard",
    "Baron",
    "Barrister",
    "Bearer",
    "Bench",
    "Bgen",
    "Bishop",
    "Blessed",
    "Bodhisattva",
    "Brig",
    "Brigadier",
    "Briggen",
    "Brother",
    "Buddha",
    "Burgess",
    "Business",
    "Bwana",
    "Canon",
    "Capt",
    "Captain",
    "Cardinal",
    "Chargé",
    "Catholicos",
    "Ccmsgt",
    "Cdr",
    "Ceo",
    "Cfo",
    "Chair",
    "Chairs",
    "Chancellor",
    "Chaplain",
    "Chief",
    "Chieftain",
    "Civil",
    "Clerk",
    "Cmd",
    "Cmdr",
    "Cmsaf",
    "Cmsgt",
    "Co-Chair",
    "Co-Chairs",
    "Coach",
    "Col",
    "Colonel",
    "Commander",
    "Commander-In-Chief",
    "Commodore",
    "Comptroller",
    "Controller",
    "Corporal",
    "Corporate",
    "Councillor",
    "Count",
    "Countess",
    "Courtier",
    "Cpl",
    "Cpo",
    "Cpt",
    "Credit",
    "Criminal",
    "Csm",
    "Curator",
    "Customs",
    "Cwo",
    "Cwo-2",
    "Cwo-3",
    "Cwo-4",
    "Cwo-5",
    "Cwo2",
    "Cwo3",
    "Cwo4",
    "Cwo5",
    "D'Affaires",
    "Deacon",
    "Delegate",
    "Deputy",
    "Designated",
    "Det",
    "Dir",
    "Director",
    "Discovery",
    "District",
    "Division",
    "Docent",
    "Docket",
    "Doctor",
    "Doyen",
    "Dpty",
    "Druid",
    "Duke",
    "Dutchess",
    "Edmi",
    "Edohen",
    "Effendi",
    "Ekegbian",
    "Elder",
    "Elerunwon",
    "Emperor",
    "Empress",
    "Ens",
    "Envoy",
    "Exec",
    "Executive",
    "Fadm",
    "Family",
    "Father",
    "Federal",
    "Field",
    "Financial",
    "First",
    "Flag",
    "Flying",
    "Flight",
    "Flt",
    "Foreign",
    "Forester",
    "Frau",
    "Friar",
    "Gen",
    "General",
    "Generalissimo",
    "Gentiluomo",
    "Giani",
    "Goodman",
    "Goodwife",
    "Governor",
    "Grand",
    "Group",
    "Guru",
    "Gyani",
    "Gysgt",
    "Hajji",
    "Headman",
    "Her",
    "Herr",
    "Hereditary",
    "High",
    "His",
    "Hon",
    "Honorable",
    "Honourable",
    "Imam",
    "Information",
    "Insp",
    "Intelligence",
    "Intendant",
    "Journeyman",
    "Judge",
    "Judicial",
    "Justice",
    "Junior",
    "Kingdom",
    "Knowledge",
    "Lady",
    "Lama",
    "Lamido",
    "Law",
    "Lcdr",
    "Lcpl",
    "Leader",
    "Lieutenant",
    "Lord",
    "Leut",
    "Lieut",
    "Ltc",
    "Ltcol",
    "Ltg",
    "Ltgen",
    "Ltjg",
    "Madam",
    "Madame",
    "Mag",
    "Mag-Judge",
    "Mag/Judge",
    "Magistrate",
    "Magistrate-Judge",
    "Maharajah",
    "Maharani",
    "Mahdi",
    "Maid",
    "Maj",
    "Majesty",
    "Majgen",
    "Major",
    "Manager",
    "Marcher",
    "Marketing",
    "Marshal",
    "Master",
    "Matriarch",
    "Matron",
    "Mayor",
    "Mcpo",
    "Mcpoc",
    "Mcpon",
    "Member",
    "Metropolitan",
    "Mgr",
    "Mgysgt",
    "Minister",
    "Miss",
    "Misses",
    "Mister",
    "Mme",
    "Monsignor",
    "Most",
    "Mother",
    "Mpco-Cg",
    "Mrs",
    "Msg",
    "Msgr",
    "Msgt",
    "Mufti",
    "Mullah",
    "Municipal",
    "Murshid",
    "Nanny",
    "National",
    "Nurse",
    "Officer",
    "Operating",
    "Pastor",
    "Patriarch",
    "Petty",
    "Pfc",
    "Pharaoh",
    "Pilot",
    "Pir",
    "Po1",
    "Po2",
    "Po3",
    "Police",
    "Political",
    "Pope",
    "Prefect",
    "Prelate",
    "Premier",
    "Pres",
    "Presbyter",
    "President",
    "Presiding",
    "Priest",
    "Priestess",
    "Primate",
    "Prime",
    "Prin",
    "Prince",
    "Princess",
    "Principal",
    "Prior",
    "Private",
    "Pro",
    "Prof",
    "Professor",
    "Provost",
    "Pslc",
    "Pte",
    "Pursuivant",
    "Pv2",
    "Pvt",
    "Rabbi",
    "Radm",
    "Rangatira",
    "Ranger",
    "Rdml",
    "Rear",
    "Rebbe",
    "Registrar",
    "Rep",
    "Representative",
    "Resident",
    "Rev",
    "Revenue",
    "Reverend",
    "Reverand",
    "Revd",
    "Right",
    "Risk",
    "Royal",
    "Saint",
    "Sargent",
    "Sargeant",
    "Saoshyant",
    "Scpo",
    "Secretary",
    "Security",
    "Seigneur",
    "Senator",
    "Senior",
    "Senior-Judge",
    "Sergeant",
    "Servant",
    "Sfc",
    "Sgm",
    "Sgt",
    "Sgtmaj",
    "Sgtmajmc",
    "Shehu",
    "Sheikh",
    "Sheriff",
    "Siddha",
    "Sir",
    "Sister",
    "Sma",
    "Smsgt",
    "Solicitor",
    "Spc",
    "Speaker",
    "Special",
    "Sra",
    "Ssg",
    "Ssgt",
    "Staff",
    "State",
    "States",
    "Strategy",
    "Subaltern",
    "Subedar",
    "Sultan",
    "Sultana",
    "Superior",
    "Supreme",
    "Surgeon",
    "Swordbearer",
    "Sysselmann",
    "Tax",
    "Technical",
    "Timi",
    "Tirthankar",
    "Treasurer",
    "Tsar",
    "Tsarina",
    "Tsgt",
    "Uncle",
    "United",
    "Vadm",
    "Vardapet",
    "Venerable",
    "Verderer",
    "Very",
    "Vicar",
    "Vice",
    "Viscount",
    "Vizier",
    "Warden",
    "Warrant",
    "Wing",
    "Wo-1",
    "Wo-2",
    "Wo-3",
    "Wo-4",
    "Wo-5",
    "Wo1",
    "Wo2",
    "Wo3",
    "Wo4",
    "Wo5",
    "Woodman",
    "And",
    "The",
    "Und",
};

static POSTFIX_TITLES: phf::Set<&'static str> = phf_set! {
    "Esq",
    "Esquire",
    "Attorney-at-law",
    "Et",
    "Al",
};

fn might_be_title_part(word: &NamePart) -> bool {
    if word.chars < 3 {
        // Allow any word with 1 or 2 characters as part of a title (but see below)
        true
    } else if !word.is_namelike() {
        true
    } else {
        PREFIX_TITLE_PARTS.contains(&*word.namecased)
    }
}

fn might_be_last_title_part(word: &NamePart) -> bool {
    // Don't allow 1 or 2-character words as the whole or final piece of
    // a title, except a set of very-common two-character title abbreviations,
    // because otherwise we are more likely dealing with initials
    if word.chars < 3 || word.word.chars().filter(|c| c.is_alphanumeric()).count() < 2 {
        word.chars == 2 && TWO_CHAR_TITLES.iter().any(|title| title.eq_ignore_ascii_case(word.word))
    } else {
        might_be_title_part(word)
    }
}

fn is_prefix_title(words: &[NamePart]) -> bool {
    match words.last() {
        Some(word) => {
            if !might_be_last_title_part(&word) {
                return false;
            }
        }
        None => {
            return false;
        }
    }

    if words.len() > 1 {
        words[0..words.len() - 1].iter().all(|word| might_be_title_part(&word))
    } else {
        true
    }
}

pub fn is_postfix_title(word: &NamePart, might_be_initials: bool) -> bool {
    if word.is_namelike() {
        POSTFIX_TITLES.contains(&*word.namecased)
    } else if word.is_initials() {
        !might_be_initials && word.word.chars().filter(|c| c.is_alphabetic()).count() > 1
    } else {
        true
    }
}

pub fn strip_prefix_title<'a>(words: &mut Vec<NamePart<'a>>) -> Option<Vec<NamePart<'a>>> {
    let mut prefix_len = words.len() - 1;
    while prefix_len > 0 {
        let found_prefix = {
            let next_word = &words[prefix_len];
            (next_word.is_namelike() || next_word.is_initials()) &&
            is_prefix_title(&words[0..prefix_len])
        };

        if found_prefix {
            return Some(words.drain(0..prefix_len).collect::<Vec<_>>());
        }

        prefix_len -= 1;
    }

    None
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::namepart::{Location, NamePart};

    #[test]
    fn is_postfix_title_esq() {
        let part = NamePart::from_word("esq", true, Location::Start);
        assert!(is_postfix_title(&part, true));
    }

    #[test]
    fn is_postfix_title_et_al() {
        let parts: Vec<_> = NamePart::all_from_text("et al", true, Location::Start).collect();
        for part in parts {
            assert!(is_postfix_title(&part, true));
        }
    }

    #[test]
    fn is_postfix_title_abbr() {
        let part = NamePart::from_word("asd.", true, Location::Start);
        assert!(is_postfix_title(&part, true));
    }

    #[test]
    fn is_postfix_title_initialism() {
        let part = NamePart::from_word("a.s.d.", true, Location::Start);
        assert!(is_postfix_title(&part, false));
        assert!(!is_postfix_title(&part, true));
    }

    #[test]
    fn strip_prefix_title_none() {
        let mut parts: Vec<_> = NamePart::all_from_text("Jane Doe", true, Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_abbr() {
        let mut parts: Vec<_> = NamePart::all_from_text("Dr. Jane Doe", true, Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_multi_abbr() {
        let mut parts: Vec<_> = NamePart::all_from_text("Revd. Dr. Jane Doe",
                                                        true,
                                                        Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_word() {
        let mut parts: Vec<_> = NamePart::all_from_text("Lady Jane Doe", true, Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_multi_word() {
        let mut parts: Vec<_> = NamePart::all_from_text("1st (B) Ltc Jane Doe",
                                                        true,
                                                        Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_short() {
        let mut parts: Vec<_> = NamePart::all_from_text("Dr. Doe", true, Location::Start).collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }
}
<commit_msg>Generalize use of numerals for title detection<commit_after>use phf;
use std::ascii::AsciiExt;
use super::namepart::NamePart;

static TWO_CHAR_TITLES: [&'static str; 4] = ["mr", "ms", "sr", "dr"];

static PREFIX_TITLE_PARTS: phf::Set<&'static str> = phf_set! {
    "Aunt",
    "Auntie",
    "Attaché",
    "Dame",
    "Marchioness",
    "Marquess",
    "Marquis",
    "Marquise",
    "King",
    "King'S",
    "Queen",
    "Queen'S",
    "Abbess",
    "Abbot",
    "Academic",
    "Acolyte",
    "Adept",
    "Adjutant",
    "Adm",
    "Admiral",
    "Advocate",
    "Akhoond",
    "Air",
    "Ald",
    "Alderman",
    "Almoner",
    "Ambassador",
    "Amn",
    "Analytics",
    "Appellate",
    "Apprentice",
    "Arbitrator",
    "Archbishop",
    "Archdeacon",
    "Archdruid",
    "Archduchess",
    "Archduke",
    "Arhat",
    "Assistant",
    "Assoc",
    "Associate",
    "Asst",
    "Attache",
    "Attorney",
    "Ayatollah",
    "Baba",
    "Bailiff",
    "Banner",
    "Bard",
    "Baron",
    "Barrister",
    "Bearer",
    "Bench",
    "Bgen",
    "Bishop",
    "Blessed",
    "Bodhisattva",
    "Brig",
    "Brigadier",
    "Briggen",
    "Brother",
    "Buddha",
    "Burgess",
    "Business",
    "Bwana",
    "Canon",
    "Capt",
    "Captain",
    "Cardinal",
    "Chargé",
    "Catholicos",
    "Ccmsgt",
    "Cdr",
    "Ceo",
    "Cfo",
    "Chair",
    "Chairs",
    "Chancellor",
    "Chaplain",
    "Chief",
    "Chieftain",
    "Civil",
    "Clerk",
    "Cmd",
    "Cmdr",
    "Cmsaf",
    "Cmsgt",
    "Co-Chair",
    "Co-Chairs",
    "Coach",
    "Col",
    "Colonel",
    "Commander",
    "Commander-In-Chief",
    "Commodore",
    "Comptroller",
    "Controller",
    "Corporal",
    "Corporate",
    "Councillor",
    "Count",
    "Countess",
    "Courtier",
    "Cpl",
    "Cpo",
    "Cpt",
    "Credit",
    "Criminal",
    "Csm",
    "Curator",
    "Customs",
    "Cwo",
    "D'Affaires",
    "Deacon",
    "Delegate",
    "Deputy",
    "Designated",
    "Det",
    "Dir",
    "Director",
    "Discovery",
    "District",
    "Division",
    "Docent",
    "Docket",
    "Doctor",
    "Doyen",
    "Dpty",
    "Druid",
    "Duke",
    "Dutchess",
    "Edmi",
    "Edohen",
    "Effendi",
    "Ekegbian",
    "Elder",
    "Elerunwon",
    "Emperor",
    "Empress",
    "Ens",
    "Envoy",
    "Exec",
    "Executive",
    "Fadm",
    "Family",
    "Father",
    "Federal",
    "Field",
    "Financial",
    "First",
    "Flag",
    "Flying",
    "Flight",
    "Flt",
    "Foreign",
    "Forester",
    "Frau",
    "Friar",
    "Gen",
    "General",
    "Generalissimo",
    "Gentiluomo",
    "Giani",
    "Goodman",
    "Goodwife",
    "Governor",
    "Grand",
    "Group",
    "Guru",
    "Gyani",
    "Gysgt",
    "Hajji",
    "Headman",
    "Her",
    "Herr",
    "Hereditary",
    "High",
    "His",
    "Hon",
    "Honorable",
    "Honourable",
    "Imam",
    "Information",
    "Insp",
    "Intelligence",
    "Intendant",
    "Journeyman",
    "Judge",
    "Judicial",
    "Justice",
    "Junior",
    "Kingdom",
    "Knowledge",
    "Lady",
    "Lama",
    "Lamido",
    "Law",
    "Lcdr",
    "Lcpl",
    "Leader",
    "Lieutenant",
    "Lord",
    "Leut",
    "Lieut",
    "Ltc",
    "Ltcol",
    "Ltg",
    "Ltgen",
    "Ltjg",
    "Madam",
    "Madame",
    "Mag",
    "Mag-Judge",
    "Mag/Judge",
    "Magistrate",
    "Magistrate-Judge",
    "Maharajah",
    "Maharani",
    "Mahdi",
    "Maid",
    "Maj",
    "Majesty",
    "Majgen",
    "Major",
    "Manager",
    "Marcher",
    "Marketing",
    "Marshal",
    "Master",
    "Matriarch",
    "Matron",
    "Mayor",
    "Mcpo",
    "Mcpoc",
    "Mcpon",
    "Member",
    "Metropolitan",
    "Mgr",
    "Mgysgt",
    "Minister",
    "Miss",
    "Misses",
    "Mister",
    "Mme",
    "Monsignor",
    "Most",
    "Mother",
    "Mpco-Cg",
    "Mrs",
    "Msg",
    "Msgr",
    "Msgt",
    "Mufti",
    "Mullah",
    "Municipal",
    "Murshid",
    "Nanny",
    "National",
    "Nurse",
    "Officer",
    "Operating",
    "Pastor",
    "Patriarch",
    "Petty",
    "Pfc",
    "Pharaoh",
    "Pilot",
    "Pir",
    "Police",
    "Political",
    "Pope",
    "Prefect",
    "Prelate",
    "Premier",
    "Pres",
    "Presbyter",
    "President",
    "Presiding",
    "Priest",
    "Priestess",
    "Primate",
    "Prime",
    "Prin",
    "Prince",
    "Princess",
    "Principal",
    "Prior",
    "Private",
    "Pro",
    "Prof",
    "Professor",
    "Provost",
    "Pslc",
    "Pte",
    "Pursuivant",
    "Pvt",
    "Rabbi",
    "Radm",
    "Rangatira",
    "Ranger",
    "Rdml",
    "Rear",
    "Rebbe",
    "Registrar",
    "Rep",
    "Representative",
    "Resident",
    "Rev",
    "Revenue",
    "Reverend",
    "Reverand",
    "Revd",
    "Right",
    "Risk",
    "Royal",
    "Saint",
    "Sargent",
    "Sargeant",
    "Saoshyant",
    "Scpo",
    "Secretary",
    "Security",
    "Seigneur",
    "Senator",
    "Senior",
    "Senior-Judge",
    "Sergeant",
    "Servant",
    "Sfc",
    "Sgm",
    "Sgt",
    "Sgtmaj",
    "Sgtmajmc",
    "Shehu",
    "Sheikh",
    "Sheriff",
    "Siddha",
    "Sir",
    "Sister",
    "Sma",
    "Smsgt",
    "Solicitor",
    "Spc",
    "Speaker",
    "Special",
    "Sra",
    "Ssg",
    "Ssgt",
    "Staff",
    "State",
    "States",
    "Strategy",
    "Subaltern",
    "Subedar",
    "Sultan",
    "Sultana",
    "Superior",
    "Supreme",
    "Surgeon",
    "Swordbearer",
    "Sysselmann",
    "Tax",
    "Technical",
    "Timi",
    "Tirthankar",
    "Treasurer",
    "Tsar",
    "Tsarina",
    "Tsgt",
    "Uncle",
    "United",
    "Vadm",
    "Vardapet",
    "Venerable",
    "Verderer",
    "Very",
    "Vicar",
    "Vice",
    "Viscount",
    "Vizier",
    "Warden",
    "Warrant",
    "Wing",
    "Woodman",
    "And",
    "The",
    "Und",
};

static POSTFIX_TITLES: phf::Set<&'static str> = phf_set! {
    "Esq",
    "Esquire",
    "Attorney-at-law",
    "Et",
    "Al",
};

fn might_be_title_part(word: &NamePart) -> bool {
    if word.chars < 3 {
        // Allow any word with 1 or 2 characters as part of a title (but see below)
        true
    } else if !word.is_namelike() {
        true
    } else if word.word.chars().any(char::is_numeric) {
        true
    } else {
        PREFIX_TITLE_PARTS.contains(&*word.namecased)
    }
}

fn might_be_last_title_part(word: &NamePart) -> bool {
    // Don't allow 1 or 2-character words as the whole or final piece of
    // a title, except a set of very-common two-character title abbreviations,
    // because otherwise we are more likely dealing with initials
    if word.chars < 3 || word.word.chars().filter(|c| c.is_alphanumeric()).count() < 2 {
        word.chars == 2 && TWO_CHAR_TITLES.iter().any(|title| title.eq_ignore_ascii_case(word.word))
    } else {
        might_be_title_part(word)
    }
}

fn is_prefix_title(words: &[NamePart]) -> bool {
    match words.last() {
        Some(word) => {
            if !might_be_last_title_part(&word) {
                return false;
            }
        }
        None => {
            return false;
        }
    }

    if words.len() > 1 {
        words[0..words.len() - 1].iter().all(|word| might_be_title_part(&word))
    } else {
        true
    }
}

pub fn is_postfix_title(word: &NamePart, might_be_initials: bool) -> bool {
    if word.is_namelike() {
        POSTFIX_TITLES.contains(&*word.namecased) || word.word.chars().any(char::is_numeric)
    } else if word.is_initials() {
        !might_be_initials && word.word.chars().filter(|c| c.is_alphabetic()).count() > 1
    } else {
        true
    }
}

pub fn strip_prefix_title<'a>(words: &mut Vec<NamePart<'a>>) -> Option<Vec<NamePart<'a>>> {
    let mut prefix_len = words.len() - 1;
    while prefix_len > 0 {
        let found_prefix = {
            let next_word = &words[prefix_len];
            (next_word.is_namelike() || next_word.is_initials()) &&
            is_prefix_title(&words[0..prefix_len])
        };

        if found_prefix {
            return Some(words.drain(0..prefix_len).collect::<Vec<_>>());
        }

        prefix_len -= 1;
    }

    None
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::namepart::{Location, NamePart};

    #[test]
    fn is_postfix_title_esq() {
        let part = NamePart::from_word("esq", true, Location::Start);
        assert!(is_postfix_title(&part, true));
    }

    #[test]
    fn is_postfix_title_et_al() {
        let parts: Vec<_> = NamePart::all_from_text("et al", true, Location::Start).collect();
        for part in parts {
            assert!(is_postfix_title(&part, true));
        }
    }

    #[test]
    fn is_postfix_title_abbr() {
        let part = NamePart::from_word("asd.", true, Location::Start);
        assert!(is_postfix_title(&part, true));
    }

    #[test]
    fn is_postfix_title_initialism() {
        let part = NamePart::from_word("a.s.d.", true, Location::Start);
        assert!(is_postfix_title(&part, false));
        assert!(!is_postfix_title(&part, true));
    }

    #[test]
    fn strip_prefix_title_none() {
        let mut parts: Vec<_> = NamePart::all_from_text("Jane Doe", true, Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_abbr() {
        let mut parts: Vec<_> = NamePart::all_from_text("Dr. Jane Doe", true, Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_multi_abbr() {
        let mut parts: Vec<_> = NamePart::all_from_text("Revd. Dr. Jane Doe",
                                                        true,
                                                        Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_word() {
        let mut parts: Vec<_> = NamePart::all_from_text("Lady Jane Doe", true, Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_multi_word() {
        let mut parts: Vec<_> = NamePart::all_from_text("1st (B) Ltc Jane Doe",
                                                        true,
                                                        Location::Start)
                                    .collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Jane Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }

    #[test]
    fn strip_prefix_title_short() {
        let mut parts: Vec<_> = NamePart::all_from_text("Dr. Doe", true, Location::Start).collect();
        strip_prefix_title(&mut parts);
        assert_eq!("Doe",
                   parts.iter().fold("".to_string(), |s, ref p| s + " " + p.word).trim());
    }
}
<|endoftext|>


<commit_before>//! Miscellaneous types used by the library.

use std::cell::{Cell, RefCell};
use std::fmt;

pub use maybe_owned::MaybeOwned;
#[cfg(feature="either")]
pub use either::Either;

// function that becomes uncallable after it returns false.
// callbacks use a MaybeOwned<T> argument so we can choose at runtime if we will send a ref or an owned value
struct FnCell<T>
{
    f: Box<Fn(MaybeOwned<T>) -> bool>,
    alive: Cell<bool>,
}

impl<T> FnCell<T>
{
    fn new<F>(f: F) -> Self
        where F: Fn(MaybeOwned<T>) -> bool + 'static
    {
        FnCell{ f: Box::new(f), alive: Cell::new(true) }
    }

    fn call(&self, arg: MaybeOwned<T>) -> bool
    {
        let is_alive = self.alive.get() && (self.f)(arg);
        self.alive.set(is_alive);
        is_alive
    }

    fn is_alive(&self) -> bool
    {
        self.alive.get()
    }
}

impl<T> fmt::Debug for FnCell<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "FnCell {{ f: Fn@{:p}, alive: {} }}", self.f, self.alive.get())
    }
}

// a collection of callbacks
#[derive(Debug)]
pub(crate) struct Callbacks<T>
{
    fs: RefCell<Vec<FnCell<T>>>,
}

impl<T> Callbacks<T>
{
    pub fn new() -> Self
    {
        Callbacks{ fs: Default::default() }
    }

    pub fn push<F>(&self, cb: F)
        where F: Fn(MaybeOwned<T>) -> bool + 'static
    {
        self.fs.borrow_mut().push(FnCell::new(cb))
    }

    // sends a ref to the first N-1 callbacks, and the owned value to the last
    // this way we prevent tons of cloning
    pub fn call(&self, arg: T)
    {
        let fs = self.fs.borrow();
        let n = fs.len();

        let mut i = 0;
        let mut n_dead = 0;
        for _ in 1..n
        {
            if !fs[i].call(MaybeOwned::Borrowed(&arg)) { n_dead += 1 }
            i += 1;
        }
        if n > 0 && !fs[i].call(MaybeOwned::Owned(arg)) { n_dead += 1 }
        drop(fs);

        if n_dead > 0 { self.cleanup(n_dead); }
    }

    fn call_ref(&self, arg: &T)
    {
        let n_dead = self.fs.borrow().iter().fold(0, |a, f| {
            if f.call(MaybeOwned::Borrowed(arg)) { a } else { a + 1 }
        });

        if n_dead > 0 { self.cleanup(n_dead); }
    }

    // we use this to passthrough an unprocessed value
    pub fn call_dyn(&self, arg: MaybeOwned<T>)
    {
        match arg
        {
            MaybeOwned::Borrowed(r) => self.call_ref(r),
            MaybeOwned::Owned(v) => self.call(v),
        }
    }

    // removes the dead callbacks
    fn cleanup(&self, n_dead: usize)
    {
        if let Ok(mut fs) = self.fs.try_borrow_mut()
        {
            let mut i = 0;
            let mut removed = 0;
            while removed < n_dead && i < fs.len()
            {
                if fs[i].is_alive()
                {
                    i += 1;
                }
                else
                {
                    fs.swap_remove(i);
                    removed += 1;
                }
            }
        }
    }
}

impl<T> Default for Callbacks<T>
{
    fn default() -> Self
    {
        Callbacks::new()
    }
}

/// Generic sum type of two elements.
///
/// It's used to provide generics over the `Option`/`Result`/`Either` types
pub trait SumType2
{
    type Type1;
    type Type2;

    fn from_type1(val: Self::Type1) -> Self;
    fn from_type2(val: Self::Type2) -> Self;

    fn is_type1(&self) -> bool;
    fn is_type2(&self) -> bool;

    fn into_type1(self) -> Option<Self::Type1>;
    fn into_type2(self) -> Option<Self::Type2>;
}

impl<T> SumType2 for Option<T>
{
    type Type1 = T;
    type Type2 = ();

    fn from_type1(val: Self::Type1) -> Self { Some(val) }
    fn from_type2(_: Self::Type2) -> Self { None }

    fn is_type1(&self) -> bool { self.is_some() }
    fn is_type2(&self) -> bool { self.is_none() }

    fn into_type1(self) -> Option<Self::Type1> { self }
    fn into_type2(self) -> Option<Self::Type2> { self.ok_or(()).err() }
}

impl<T, E> SumType2 for Result<T, E>
{
    type Type1 = T;
    type Type2 = E;

    fn from_type1(val: Self::Type1) -> Self { Ok(val) }
    fn from_type2(val: Self::Type2) -> Self { Err(val) }

    fn is_type1(&self) -> bool { self.is_ok() }
    fn is_type2(&self) -> bool { self.is_err() }

    fn into_type1(self) -> Option<Self::Type1> { self.ok() }
    fn into_type2(self) -> Option<Self::Type2> { self.err() }
}

#[cfg(feature="either")]
impl<L, R> SumType2 for ::either::Either<L, R>
{
    type Type1 = L;
    type Type2 = R;

    fn from_type1(val: Self::Type1) -> Self { ::either::Either::Left(val) }
    fn from_type2(val: Self::Type2) -> Self { ::either::Either::Right(val) }

    fn is_type1(&self) -> bool { self.is_left() }
    fn is_type2(&self) -> bool { self.is_right() }

    fn into_type1(self) -> Option<Self::Type1> { self.left() }
    fn into_type2(self) -> Option<Self::Type2> { self.right() }
}
<commit_msg>make iterator chain prettier<commit_after>//! Miscellaneous types used by the library.

use std::cell::{Cell, RefCell};
use std::fmt;

pub use maybe_owned::MaybeOwned;
#[cfg(feature="either")]
pub use either::Either;

// function that becomes uncallable after it returns false.
// callbacks use a MaybeOwned<T> argument so we can choose at runtime if we will send a ref or an owned value
struct FnCell<T>
{
    f: Box<Fn(MaybeOwned<T>) -> bool>,
    alive: Cell<bool>,
}

impl<T> FnCell<T>
{
    fn new<F>(f: F) -> Self
        where F: Fn(MaybeOwned<T>) -> bool + 'static
    {
        FnCell{ f: Box::new(f), alive: Cell::new(true) }
    }

    fn call(&self, arg: MaybeOwned<T>) -> bool
    {
        let is_alive = self.alive.get() && (self.f)(arg);
        self.alive.set(is_alive);
        is_alive
    }

    fn is_alive(&self) -> bool
    {
        self.alive.get()
    }
}

impl<T> fmt::Debug for FnCell<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "FnCell {{ f: Fn@{:p}, alive: {} }}", self.f, self.alive.get())
    }
}

// a collection of callbacks
#[derive(Debug)]
pub(crate) struct Callbacks<T>
{
    fs: RefCell<Vec<FnCell<T>>>,
}

impl<T> Callbacks<T>
{
    pub fn new() -> Self
    {
        Callbacks{ fs: Default::default() }
    }

    pub fn push<F>(&self, cb: F)
        where F: Fn(MaybeOwned<T>) -> bool + 'static
    {
        self.fs.borrow_mut().push(FnCell::new(cb))
    }

    // sends a ref to the first N-1 callbacks, and the owned value to the last
    // this way we prevent tons of cloning
    pub fn call(&self, arg: T)
    {
        let fs = self.fs.borrow();
        let n = fs.len();

        let mut i = 0;
        let mut n_dead = 0;
        for _ in 1..n
        {
            if !fs[i].call(MaybeOwned::Borrowed(&arg)) { n_dead += 1 }
            i += 1;
        }
        if n > 0 && !fs[i].call(MaybeOwned::Owned(arg)) { n_dead += 1 }
        drop(fs);

        if n_dead > 0 { self.cleanup(n_dead); }
    }

    fn call_ref(&self, arg: &T)
    {
        let n_dead = self.fs.borrow().iter()
            .map(|f| f.call(MaybeOwned::Borrowed(arg)))
            .fold(0, |a, alive| if alive { a } else { a + 1 });

        if n_dead > 0 { self.cleanup(n_dead); }
    }

    // we use this to passthrough an unprocessed value
    pub fn call_dyn(&self, arg: MaybeOwned<T>)
    {
        match arg
        {
            MaybeOwned::Borrowed(r) => self.call_ref(r),
            MaybeOwned::Owned(v) => self.call(v),
        }
    }

    // removes the dead callbacks
    fn cleanup(&self, n_dead: usize)
    {
        if let Ok(mut fs) = self.fs.try_borrow_mut()
        {
            let mut i = 0;
            let mut removed = 0;
            while removed < n_dead && i < fs.len()
            {
                if fs[i].is_alive()
                {
                    i += 1;
                }
                else
                {
                    fs.swap_remove(i);
                    removed += 1;
                }
            }
        }
    }
}

impl<T> Default for Callbacks<T>
{
    fn default() -> Self
    {
        Callbacks::new()
    }
}

/// Generic sum type of two elements.
///
/// It's used to provide generics over the `Option`/`Result`/`Either` types
pub trait SumType2
{
    type Type1;
    type Type2;

    fn from_type1(val: Self::Type1) -> Self;
    fn from_type2(val: Self::Type2) -> Self;

    fn is_type1(&self) -> bool;
    fn is_type2(&self) -> bool;

    fn into_type1(self) -> Option<Self::Type1>;
    fn into_type2(self) -> Option<Self::Type2>;
}

impl<T> SumType2 for Option<T>
{
    type Type1 = T;
    type Type2 = ();

    fn from_type1(val: Self::Type1) -> Self { Some(val) }
    fn from_type2(_: Self::Type2) -> Self { None }

    fn is_type1(&self) -> bool { self.is_some() }
    fn is_type2(&self) -> bool { self.is_none() }

    fn into_type1(self) -> Option<Self::Type1> { self }
    fn into_type2(self) -> Option<Self::Type2> { self.ok_or(()).err() }
}

impl<T, E> SumType2 for Result<T, E>
{
    type Type1 = T;
    type Type2 = E;

    fn from_type1(val: Self::Type1) -> Self { Ok(val) }
    fn from_type2(val: Self::Type2) -> Self { Err(val) }

    fn is_type1(&self) -> bool { self.is_ok() }
    fn is_type2(&self) -> bool { self.is_err() }

    fn into_type1(self) -> Option<Self::Type1> { self.ok() }
    fn into_type2(self) -> Option<Self::Type2> { self.err() }
}

#[cfg(feature="either")]
impl<L, R> SumType2 for ::either::Either<L, R>
{
    type Type1 = L;
    type Type2 = R;

    fn from_type1(val: Self::Type1) -> Self { ::either::Either::Left(val) }
    fn from_type2(val: Self::Type2) -> Self { ::either::Either::Right(val) }

    fn is_type1(&self) -> bool { self.is_left() }
    fn is_type2(&self) -> bool { self.is_right() }

    fn into_type1(self) -> Option<Self::Type1> { self.left() }
    fn into_type2(self) -> Option<Self::Type2> { self.right() }
}
<|endoftext|>


<commit_before>//! Utils for testing and debugging.

use image::{
    DynamicImage,
    GenericImage,
    GrayImage,
    Luma,
    open,
    Pixel,
    Rgb,
    RgbImage
};

use quickcheck::{
    Arbitrary,
    Gen
};

use std::fmt::Debug;
use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| p != q);
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
     })
}

/// Panics if any pixels differ between the two images by more than the
/// given tolerance in a single channel.
#[macro_export]
macro_rules! assert_pixels_eq_within {
    ($actual:expr, $expected:expr, $channel_tolerance:expr) => ({

        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| {

            use image::Pixel;
            let cp = p.2.channels();
            let cq = q.2.channels();
            if cp.len() != cq.len() {
                panic!("pixels have different channel counts. \
                    actual: {:?}, expected: {:?}", cp.len(), cq.len())
            }

            let mut large_diff = false;
            for i in 0..cp.len() {
                let sp = cp[i];
                let sq = cq[i];
                // Handle unsigned subpixels
                let diff = if sp > sq {sp - sq} else {sq - sp};
                if diff > $channel_tolerance {
                    large_diff = true;
                    break;
                }
            }

            large_diff
        });
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
    })
}

/// Panics if image dimensions do not match.
#[macro_export]
macro_rules! assert_dimensions_match {
    ($actual:expr, $expected:expr) => ({

        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }
     })
}

/// Lists pixels that differ between left and right images.
pub fn pixel_diffs<I, F>(left: &I, right: &I, is_diff: F)
        -> Vec<((u32, u32, I::Pixel), (u32, u32, I::Pixel))>
    where I: GenericImage,
          I::Pixel: PartialEq,
          F: Fn((u32, u32, I::Pixel), (u32, u32, I::Pixel)) -> bool {

    // Can't just call $image.pixels(), as that needn't hit the
    // trait pixels method - ImageBuffer defines its own pixels
    // method with a different signature
    GenericImage::pixels(left)
        .zip(GenericImage::pixels(right))
        .filter(|&(p, q)| is_diff(p, q))//p != q)
        .collect::<Vec<_>>()
}

/// Gives a summary description of a list of pixel diffs for use in error messages.
pub fn describe_pixel_diffs<I, P>(diffs: I) -> String
    where I: Iterator<Item=(P, P)>,
          P: Debug {

    let mut err = "pixels do not match. ".to_string();
    err.push_str(&(diffs
        .take(5)
        .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
        .collect::<Vec<_>>()
        .join("")));
    err
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> DynamicImage {
     open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> GrayImage {
    let mut image = GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> RgbImage {
    use std::cmp;
    let mut image = RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, Rgb([r, g, b]));
        }
    }
    image
}

/// Wrapper for GrayImage to allow us to write an Arbitrary instance.
pub struct GrayTestImage(GrayImage);

impl Clone for GrayTestImage {
    fn clone(&self) -> Self {
        let mut out = GrayImage::new(self.0.width(), self.0.height());
        out.copy_from(&self.0, 0, 0);
        GrayTestImage(out)
    }
}

impl Arbitrary for GrayTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = GrayImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let val: u8 = g.gen();
                image.put_pixel(x, y, Luma([val]));
            }
        }
        GrayTestImage(image)
    }
}

fn small_image_dimensions<G: Gen>(g: &mut G) -> (u32, u32) {
    let dims: (u8, u8) = Arbitrary::arbitrary(g);
    (dims.0 as u32, dims.1 as u32)
}

/// Wrapper for RgbImage to allow us to write an Arbitrary instance.
pub struct RgbTestImage(RgbImage);

impl Clone for RgbTestImage {
    fn clone(&self) -> Self {
        let mut out = RgbImage::new(self.0.width(), self.0.height());
        out.copy_from(&self.0, 0, 0);
        RgbTestImage(out)
    }
}

impl Arbitrary for RgbTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = RgbImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let red: u8 = g.gen();
                let green: u8 = g.gen();
                let blue: u8 = g.gen();
                image.put_pixel(x, y, Rgb([red, green, blue]));
            }
        }
        RgbTestImage(image)
    }
}

#[cfg(test)]
mod test {

    use image::{
        GrayImage,
        ImageBuffer
    };

    #[test]
    fn test_assert_pixels_eq_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(image, image);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 11, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(diff, image);
    }

    #[test]
    fn test_assert_pixels_eq_within_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 02, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_within_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 03, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }
}
<commit_msg>Auto-derive Clone impls for GrayTestImage and RgbTestImage<commit_after>//! Utils for testing and debugging.

use image::{
    DynamicImage,
    GenericImage,
    GrayImage,
    Luma,
    open,
    Pixel,
    Rgb,
    RgbImage
};

use quickcheck::{
    Arbitrary,
    Gen
};

use std::fmt::Debug;
use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| p != q);
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
     })
}

/// Panics if any pixels differ between the two images by more than the
/// given tolerance in a single channel.
#[macro_export]
macro_rules! assert_pixels_eq_within {
    ($actual:expr, $expected:expr, $channel_tolerance:expr) => ({

        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| {

            use image::Pixel;
            let cp = p.2.channels();
            let cq = q.2.channels();
            if cp.len() != cq.len() {
                panic!("pixels have different channel counts. \
                    actual: {:?}, expected: {:?}", cp.len(), cq.len())
            }

            let mut large_diff = false;
            for i in 0..cp.len() {
                let sp = cp[i];
                let sq = cq[i];
                // Handle unsigned subpixels
                let diff = if sp > sq {sp - sq} else {sq - sp};
                if diff > $channel_tolerance {
                    large_diff = true;
                    break;
                }
            }

            large_diff
        });
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
    })
}

/// Panics if image dimensions do not match.
#[macro_export]
macro_rules! assert_dimensions_match {
    ($actual:expr, $expected:expr) => ({

        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }
     })
}

/// Lists pixels that differ between left and right images.
pub fn pixel_diffs<I, F>(left: &I, right: &I, is_diff: F)
        -> Vec<((u32, u32, I::Pixel), (u32, u32, I::Pixel))>
    where I: GenericImage,
          I::Pixel: PartialEq,
          F: Fn((u32, u32, I::Pixel), (u32, u32, I::Pixel)) -> bool {

    // Can't just call $image.pixels(), as that needn't hit the
    // trait pixels method - ImageBuffer defines its own pixels
    // method with a different signature
    GenericImage::pixels(left)
        .zip(GenericImage::pixels(right))
        .filter(|&(p, q)| is_diff(p, q))//p != q)
        .collect::<Vec<_>>()
}

/// Gives a summary description of a list of pixel diffs for use in error messages.
pub fn describe_pixel_diffs<I, P>(diffs: I) -> String
    where I: Iterator<Item=(P, P)>,
          P: Debug {

    let mut err = "pixels do not match. ".to_string();
    err.push_str(&(diffs
        .take(5)
        .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
        .collect::<Vec<_>>()
        .join("")));
    err
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> DynamicImage {
     open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> GrayImage {
    let mut image = GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> RgbImage {
    use std::cmp;
    let mut image = RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, Rgb([r, g, b]));
        }
    }
    image
}

/// Wrapper for GrayImage to allow us to write an Arbitrary instance.
#[derive(Clone)]
pub struct GrayTestImage(GrayImage);

impl Arbitrary for GrayTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = GrayImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let val: u8 = g.gen();
                image.put_pixel(x, y, Luma([val]));
            }
        }
        GrayTestImage(image)
    }
}

fn small_image_dimensions<G: Gen>(g: &mut G) -> (u32, u32) {
    let dims: (u8, u8) = Arbitrary::arbitrary(g);
    (dims.0 as u32, dims.1 as u32)
}

/// Wrapper for RgbImage to allow us to write an Arbitrary instance.
#[derive(Clone)]
pub struct RgbTestImage(RgbImage);

impl Arbitrary for RgbTestImage {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let (width, height) = small_image_dimensions(g);
        let mut image = RgbImage::new(width, height);
        for y in 0..height {
            for x in 0..width {
                let red: u8 = g.gen();
                let green: u8 = g.gen();
                let blue: u8 = g.gen();
                image.put_pixel(x, y, Rgb([red, green, blue]));
            }
        }
        RgbTestImage(image)
    }
}

#[cfg(test)]
mod test {

    use image::{
        GrayImage,
        ImageBuffer
    };

    #[test]
    fn test_assert_pixels_eq_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(image, image);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 11, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(diff, image);
    }

    #[test]
    fn test_assert_pixels_eq_within_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 02, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_within_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 03, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }
}
<|endoftext|>


<commit_before>use std::io::{stderr, Write, ErrorKind};
use std::ascii::AsciiExt;
use std::str;
use std::fmt;
use std::fmt::Error;
use std::process;

pub struct Options {
   pub print_offset: OffsetRadix,
   pub match_length: usize,
   pub path: String,
   pub zork_mode: bool
}

#[derive(Clone, Copy)]
pub enum OffsetRadix {
    None,
    Hex,
    Octal,
    Decimal
}

pub trait StringExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], writer: &mut W, options: &Options);
    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String;
}

// trait MinLengthContribution {
//     fn contribution(&self) -> usize;
// }

pub struct AsciiExtractor {

}

impl StringExtractor for AsciiExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], w:  &mut W, opts: &Options) {
        let min_consecutive_chars = opts.match_length;
        let mut current_bytes : Vec<u8> = Vec::new();

        let mut offset = 0usize;

        for b in bytes {
            if b.is_ascii() {
                current_bytes.push(*b);
            }
            else  {
                if current_bytes.len() >= min_consecutive_chars {
                    let result = str::from_utf8(&current_bytes);
                    if let Ok(string) = result {
                        let offset_string = self.offset_string(offset, opts.print_offset);
                        let write_result = writeln!(w, "{}{}", offset_string, string);
                        if let Err(e) = write_result {
                            match e.kind() {
                                ErrorKind::BrokenPipe => break,
                                _ => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    process::exit(1);
                                }
                            }
                        }
                    }
                }
                current_bytes.truncate(0);
                offset += 1;
            }
        }
        if current_bytes.len() >= min_consecutive_chars {
            let result = str::from_utf8(&current_bytes);
            if let Ok(string) = result {
                let offset_string = self.offset_string(offset, opts.print_offset);
                let write_result = writeln!(w, "{}{}", offset_string, string);
                match write_result {
                    Ok(_) => (),
                    Err(e) => match e.kind() {
                        ErrorKind::BrokenPipe => (),
                        _ => {
                            writeln!(stderr(), "{}", e).unwrap();
                            process::exit(1);
                        }
                    }
                }
            }
        }
    }

    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String {
        let mut output = "".to_string();
        match radix {
            OffsetRadix::Hex => fmt::write(&mut output, format_args!("0x{:X}: ", offset)).unwrap(),
            OffsetRadix::Octal => fmt::write(&mut output, format_args!("0o{:o}: ", offset)).unwrap(),
            OffsetRadix::Decimal => fmt::write(&mut output, format_args!("{}: ", offset)).unwrap(),
            OffsetRadix::None => ()
        }

        output
    }
}

pub fn string_to_offset_radix(input: Option<&str>) -> Result<OffsetRadix, ()> {
    match input{
        Some(string) => match string {
            "x" => Ok(OffsetRadix::Hex),
            "o" => Ok(OffsetRadix::Octal),
            "d" => Ok(OffsetRadix::Decimal),
            _ => Err(())
        },
        None => Ok(OffsetRadix::None)
    }
}

#[test]
fn it_writes_to_the_buffer() {

    use std::io::Cursor;

    let opts = Options {
        print_offset: OffsetRadix::None,
        match_length: 3,
        path: "".to_string(),
        zork_mode: false
    };

    let mut cursor = Cursor::new(Vec::new());
    bytes_to_strings("hello".as_bytes(), &mut cursor, &opts);
    let expected = "hello\n";
    let vec = cursor.into_inner();
    let actual = String::from_utf8(vec).unwrap();
    assert_eq!(expected, actual);
}

#[test]
fn it_omits_intermediate_nonsense() {
    use std::io::Cursor;
    let mut cursor = Cursor::new(Vec::new());

    let opts = Options {
        print_offset: OffsetRadix::None,
        match_length: 3,
        path: "".to_string(),
        zork_mode: false
    };

    let mut bytes : Vec<u8> = Vec::new();
    for b in "Hello".as_bytes() {
        bytes.push(*b);
    }
    bytes.push(254u8);
    bytes.push(254u8);
    for b in "World".as_bytes() {
        bytes.push(*b);
    }
    bytes_to_strings(&bytes, &mut cursor, &opts);
    let expected = "Hello\nWorld\n";
    let vec = cursor.into_inner();
    let actual = String::from_utf8(vec).unwrap();
    assert_eq!(expected, actual);
}
<commit_msg>clean up commented code and whitespace<commit_after>use std::io::{stderr, Write, ErrorKind};
use std::ascii::AsciiExt;
use std::str;
use std::fmt;
use std::fmt::Error;
use std::process;

pub struct Options {
   pub print_offset: OffsetRadix,
   pub match_length: usize,
   pub path: String,
   pub zork_mode: bool
}

#[derive(Clone, Copy)]
pub enum OffsetRadix {
    None,
    Hex,
    Octal,
    Decimal
}

pub trait StringExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], writer: &mut W, options: &Options);
    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String;
}

pub struct AsciiExtractor {

}

impl StringExtractor for AsciiExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], w:  &mut W, opts: &Options) {
        let min_consecutive_chars = opts.match_length;
        let mut current_bytes : Vec<u8> = Vec::new();

        let mut offset = 0usize;

        for b in bytes {
            if b.is_ascii() {
                current_bytes.push(*b);
            }
            else  {
                if current_bytes.len() >= min_consecutive_chars {
                    let result = str::from_utf8(&current_bytes);
                    if let Ok(string) = result {
                        let offset_string = self.offset_string(offset, opts.print_offset);
                        let write_result = writeln!(w, "{}{}", offset_string, string);
                        if let Err(e) = write_result {
                            match e.kind() {
                                ErrorKind::BrokenPipe => break,
                                _ => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    process::exit(1);
                                }
                            }
                        }
                    }
                }
                current_bytes.truncate(0);
                offset += 1;
            }
        }
        if current_bytes.len() >= min_consecutive_chars {
            let result = str::from_utf8(&current_bytes);
            if let Ok(string) = result {
                let offset_string = self.offset_string(offset, opts.print_offset);
                let write_result = writeln!(w, "{}{}", offset_string, string);
                match write_result {
                    Ok(_) => (),
                    Err(e) => match e.kind() {
                        ErrorKind::BrokenPipe => (),
                        _ => {
                            writeln!(stderr(), "{}", e).unwrap();
                            process::exit(1);
                        }
                    }
                }
            }
        }
    }

    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String {
        let mut output = "".to_string();
        match radix {
            OffsetRadix::Hex => fmt::write(&mut output, format_args!("0x{:X}: ", offset)).unwrap(),
            OffsetRadix::Octal => fmt::write(&mut output, format_args!("0o{:o}: ", offset)).unwrap(),
            OffsetRadix::Decimal => fmt::write(&mut output, format_args!("{}: ", offset)).unwrap(),
            OffsetRadix::None => ()
        }

        output
    }
}

pub fn string_to_offset_radix(input: Option<&str>) -> Result<OffsetRadix, ()> {
    match input{
        Some(string) => match string {
            "x" => Ok(OffsetRadix::Hex),
            "o" => Ok(OffsetRadix::Octal),
            "d" => Ok(OffsetRadix::Decimal),
            _ => Err(())
        },
        None => Ok(OffsetRadix::None)
    }
}

#[test]
fn it_writes_to_the_buffer() {

    use std::io::Cursor;

    let opts = Options {
        print_offset: OffsetRadix::None,
        match_length: 3,
        path: "".to_string(),
        zork_mode: false
    };

    let mut cursor = Cursor::new(Vec::new());
    bytes_to_strings("hello".as_bytes(), &mut cursor, &opts);
    let expected = "hello\n";
    let vec = cursor.into_inner();
    let actual = String::from_utf8(vec).unwrap();
    assert_eq!(expected, actual);
}

#[test]
fn it_omits_intermediate_nonsense() {
    use std::io::Cursor;
    let mut cursor = Cursor::new(Vec::new());

    let opts = Options {
        print_offset: OffsetRadix::None,
        match_length: 3,
        path: "".to_string(),
        zork_mode: false
    };

    let mut bytes : Vec<u8> = Vec::new();
    for b in "Hello".as_bytes() {
        bytes.push(*b);
    }
    bytes.push(254u8);
    bytes.push(254u8);
    for b in "World".as_bytes() {
        bytes.push(*b);
    }
    bytes_to_strings(&bytes, &mut cursor, &opts);
    let expected = "Hello\nWorld\n";
    let vec = cursor.into_inner();
    let actual = String::from_utf8(vec).unwrap();
    assert_eq!(expected, actual);
}
<|endoftext|>


<commit_before>// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use vmm_vhost::message::VhostUserProtocolFeatures;

use crate::virtio::device_constants::gpu;
use crate::virtio::vhost::user::vmm::Connection;
use crate::virtio::vhost::user::vmm::QueueSizes;
use crate::virtio::vhost::user::vmm::Result;
use crate::virtio::vhost::user::vmm::VhostUserVirtioDevice;
use crate::virtio::DeviceType;

impl VhostUserVirtioDevice {
    pub fn new_gpu(base_features: u64, connection: Connection) -> Result<VhostUserVirtioDevice> {
        let queue_sizes = QueueSizes::Fixed(gpu::QUEUE_SIZES.to_vec());
        let max_queues = gpu::QUEUE_SIZES.len();

        let allow_features = 1 << gpu::VIRTIO_GPU_F_VIRGL
            | 1 << gpu::VIRTIO_GPU_F_RESOURCE_UUID
            | 1 << gpu::VIRTIO_GPU_F_RESOURCE_BLOB
            | 1 << gpu::VIRTIO_GPU_F_CONTEXT_INIT
            | 1 << gpu::VIRTIO_GPU_F_RESOURCE_SYNC
            | 1 << gpu::VIRTIO_GPU_F_CREATE_GUEST_HANDLE;

        let allow_protocol_features = VhostUserProtocolFeatures::CONFIG
            | VhostUserProtocolFeatures::SLAVE_REQ
            | VhostUserProtocolFeatures::SHARED_MEMORY_REGIONS;

        VhostUserVirtioDevice::new(
            connection,
            DeviceType::Gpu,
            queue_sizes,
            max_queues,
            allow_features,
            allow_protocol_features,
            base_features,
            None,
            true,
        )
    }
}
<commit_msg>devices: vhost-user: GPU: Add EDID to allowed features<commit_after>// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use vmm_vhost::message::VhostUserProtocolFeatures;

use crate::virtio::device_constants::gpu;
use crate::virtio::vhost::user::vmm::Connection;
use crate::virtio::vhost::user::vmm::QueueSizes;
use crate::virtio::vhost::user::vmm::Result;
use crate::virtio::vhost::user::vmm::VhostUserVirtioDevice;
use crate::virtio::DeviceType;

impl VhostUserVirtioDevice {
    pub fn new_gpu(base_features: u64, connection: Connection) -> Result<VhostUserVirtioDevice> {
        let queue_sizes = QueueSizes::Fixed(gpu::QUEUE_SIZES.to_vec());
        let max_queues = gpu::QUEUE_SIZES.len();

        let allow_features = 1 << gpu::VIRTIO_GPU_F_VIRGL
            | 1 << gpu::VIRTIO_GPU_F_RESOURCE_UUID
            | 1 << gpu::VIRTIO_GPU_F_RESOURCE_BLOB
            | 1 << gpu::VIRTIO_GPU_F_CONTEXT_INIT
            | 1 << gpu::VIRTIO_GPU_F_EDID
            | 1 << gpu::VIRTIO_GPU_F_RESOURCE_SYNC
            | 1 << gpu::VIRTIO_GPU_F_CREATE_GUEST_HANDLE;

        let allow_protocol_features = VhostUserProtocolFeatures::CONFIG
            | VhostUserProtocolFeatures::SLAVE_REQ
            | VhostUserProtocolFeatures::SHARED_MEMORY_REGIONS;

        VhostUserVirtioDevice::new(
            connection,
            DeviceType::Gpu,
            queue_sizes,
            max_queues,
            allow_features,
            allow_protocol_features,
            base_features,
            None,
            true,
        )
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

#[macro_use] extern crate lazy_static;
extern crate bincode;
extern crate test;

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::{Path};
use test::{black_box, Bencher};

extern crate hyphenation;
use hyphenation::*;
use hyphenation::extended::*;
use hyphenation::Language::*;

fn fiat_std(lang : Language) -> Standard {
    let filename = format!("{}.standard.bincode", lang.code());
    let file = File::open(Path::new("dictionaries").join(filename)).unwrap();
    Standard::from_reader(lang, &mut BufReader::new(file)).unwrap()
}

fn fiat_ext(lang : Language) -> Extended {
    let filename = format!("{}.extended.bincode", lang.code());
    let file = File::open(Path::new("dictionaries").join(filename)).unwrap();
    Extended::from_reader(lang, &mut BufReader::new(file)).unwrap()
}

lazy_static! {
    static ref EN_US : Standard = fiat_std(EnglishUS);
    static ref HU_EXT : Extended = fiat_ext(Hungarian);
    static ref HU_STD : Standard = fiat_std(Hungarian);
    static ref TR : Standard = fiat_std(Turkish);

    static ref WORDS : Vec<String> = {
        let file = File::open(Path::new("/usr/share/dict/words")).unwrap();
        let words : Vec<_> = BufReader::new(file).lines().map(|l| l.unwrap()).collect();

        words
    };
}

#[bench]
fn word_opportunities_en_us(b : &mut Bencher) {
    lazy_static::initialize(&EN_US);
    b.iter(|| {
        for w in WORDS.iter() {
            EN_US.opportunities(w);
        }
    })
}

#[bench]
fn word_hyphenate_en_us(b : &mut Bencher) {
    lazy_static::initialize(&EN_US);
    b.iter(|| {
        for w in WORDS.iter() {
            EN_US.hyphenate(w);
        }
    })
}

#[bench]
fn word_segments_en_us(b : &mut Bencher) {
    lazy_static::initialize(&EN_US);
    b.iter(||
        for w in WORDS.iter() {
            for s in EN_US.hyphenate(w).into_iter().segments() { black_box(s); }
        }
    )
}

#[bench]
fn standard_opportunities_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_STD);
    b.iter(|| HU_STD.opportunities("asszonnyal"))
}

#[bench]
fn extended_opportunities_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_EXT);
    b.iter(|| HU_EXT.opportunities("asszonnyal"))
}

#[bench]
fn standard_segments_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_STD);
    let w = "asszonnyal";
    b.iter(|| for s in HU_STD.hyphenate(w).into_iter().segments() { black_box(s); })
}

#[bench]
fn extended_segments_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_EXT);
    let w = "asszonnyal";
    b.iter(|| for s in HU_EXT.hyphenate(w).into_iter().segments() { black_box(s); })
}

#[bench]
fn special_casing_ignored(b : &mut Bencher) {
    lazy_static::initialize(&TR);
    b.iter(|| TR.opportunities("İLGİNÇ"))
}

#[bench]
fn special_casing_handled(b : &mut Bencher) {
    lazy_static::initialize(&TR);
    b.iter(|| TR.hyphenate("İLGİNÇ").breaks)
}

#[cfg(feature = "embed_all")] #[bench]
fn deserialize_patterns_en_us(b : &mut Bencher) {
    b.iter(|| EnglishUS.from_embed_allded(Standard).unwrap())
}
<commit_msg>Remove iteration benchmark<commit_after>#![feature(test)]

#[macro_use] extern crate lazy_static;
extern crate bincode;
extern crate test;

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::{Path};
use test::{black_box, Bencher};

extern crate hyphenation;
use hyphenation::*;
use hyphenation::extended::*;
use hyphenation::Language::*;

fn fiat_std(lang : Language) -> Standard {
    let filename = format!("{}.standard.bincode", lang.code());
    let file = File::open(Path::new("dictionaries").join(filename)).unwrap();
    Standard::from_reader(lang, &mut BufReader::new(file)).unwrap()
}

fn fiat_ext(lang : Language) -> Extended {
    let filename = format!("{}.extended.bincode", lang.code());
    let file = File::open(Path::new("dictionaries").join(filename)).unwrap();
    Extended::from_reader(lang, &mut BufReader::new(file)).unwrap()
}

lazy_static! {
    static ref EN_US : Standard = fiat_std(EnglishUS);
    static ref HU_EXT : Extended = fiat_ext(Hungarian);
    static ref HU_STD : Standard = fiat_std(Hungarian);
    static ref TR : Standard = fiat_std(Turkish);

    static ref WORDS : Vec<String> = {
        let file = File::open(Path::new("/usr/share/dict/words")).unwrap();
        let words : Vec<_> = BufReader::new(file).lines().map(|l| l.unwrap()).collect();

        words
    };
}

#[bench]
fn word_opportunities_en_us(b : &mut Bencher) {
    lazy_static::initialize(&EN_US);
    b.iter(|| {
        for w in WORDS.iter() {
            EN_US.opportunities(w);
        }
    })
}

#[bench]
fn word_hyphenate_en_us(b : &mut Bencher) {
    lazy_static::initialize(&EN_US);
    b.iter(|| {
        for w in WORDS.iter() {
            EN_US.hyphenate(w);
        }
    })
}

#[bench]
fn standard_opportunities_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_STD);
    b.iter(|| HU_STD.opportunities("asszonnyal"))
}

#[bench]
fn extended_opportunities_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_EXT);
    b.iter(|| HU_EXT.opportunities("asszonnyal"))
}

#[bench]
fn standard_segments_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_STD);
    let w = "asszonnyal";
    b.iter(|| for s in HU_STD.hyphenate(w).into_iter().segments() { black_box(s); })
}

#[bench]
fn extended_segments_hu(b : &mut Bencher) {
    lazy_static::initialize(&HU_EXT);
    let w = "asszonnyal";
    b.iter(|| for s in HU_EXT.hyphenate(w).into_iter().segments() { black_box(s); })
}

#[bench]
fn special_casing_ignored(b : &mut Bencher) {
    lazy_static::initialize(&TR);
    b.iter(|| TR.opportunities("İLGİNÇ"))
}

#[bench]
fn special_casing_handled(b : &mut Bencher) {
    lazy_static::initialize(&TR);
    b.iter(|| TR.hyphenate("İLGİNÇ").breaks)
}

#[cfg(feature = "embed_all")] #[bench]
fn deserialize_patterns_en_us(b : &mut Bencher) {
    b.iter(|| EnglishUS.from_embed_allded(Standard).unwrap())
}
<|endoftext|>


<commit_before>use gfx::{format, Device};
use gfx_glyph::*;
use std::{env, error::Error};

fn main() -> Result<(), Box<dyn Error>> {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "gfx_glyph=warn");
    }

    env_logger::init();

    if cfg!(target_os = "linux") {
        // winit wayland is currently still wip
        if env::var("WINIT_UNIX_BACKEND").is_err() {
            env::set_var("WINIT_UNIX_BACKEND", "x11");
        }
        // disables vsync sometimes on x11
        if env::var("vblank_mode").is_err() {
            env::set_var("vblank_mode", "0");
        }
    }

    if cfg!(debug_assertions) && env::var("yes_i_really_want_debug_mode").is_err() {
        eprintln!(
            "Note: Release mode will improve performance greatly.\n    \
             e.g. use `cargo run --example depth --release`"
        );
    }

    let mut events_loop = glutin::EventsLoop::new();
    let title = "gfx_glyph example - resize to see multi-text layout";
    let window_builder = glutin::WindowBuilder::new()
        .with_title(title)
        .with_dimensions((700, 320).into());
    let context = glutin::ContextBuilder::new();
    let (window_ctx, mut device, mut factory, mut main_color, mut main_depth) =
        gfx_window_glutin::init::<format::Srgba8, format::Depth>(
            window_builder,
            context,
            &events_loop,
        )
        .unwrap();
    let window = window_ctx.window();

    let fonts: Vec<&[u8]> = vec![
        include_bytes!("../../fonts/DejaVuSans.ttf"),
        include_bytes!("../../fonts/OpenSans-Italic.ttf"),
    ];
    let italic_font = FontId(1);

    let mut glyph_brush = GlyphBrushBuilder::using_fonts_bytes(fonts)
        .initial_cache_size((512, 512))
        // Enable depth testing with less-equal drawing and update the depth buffer
        .depth_test(gfx::preset::depth::LESS_EQUAL_WRITE)
        .build(factory.clone());

    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

    let mut running = true;
    let mut loop_helper = spin_sleep::LoopHelper::builder().build_with_target_rate(250.0);

    while running {
        loop_helper.loop_start();

        events_loop.poll_events(|event| {
            use glutin::*;
            if let Event::WindowEvent { event, .. } = event {
                match event {
                    WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                virtual_keycode: Some(VirtualKeyCode::Escape),
                                ..
                            },
                        ..
                    }
                    | WindowEvent::CloseRequested => running = false,
                    WindowEvent::Resized(size) => {
                        window_ctx.resize(size.to_physical(window.get_hidpi_factor()));
                        gfx_window_glutin::update_views(
                            &window_ctx,
                            &mut main_color,
                            &mut main_depth,
                        );
                    }
                    _ => {}
                }
            }
        });

        encoder.clear(&main_color, [0.02, 0.02, 0.02, 1.0]);
        encoder.clear_depth(&main_depth, 1.0);

        let (width, height, ..) = main_color.get_dimensions();
        let (width, height) = (f32::from(width), f32::from(height));

        // first section is queued, and therefore drawn, first with lower z
        glyph_brush.queue(Section {
            screen_position: (width / 2.0, 100.0),
            bounds: (width, height - 100.0),
            text: "On top",
            scale: Scale::uniform(95.0),
            color: [0.8, 0.8, 0.8, 1.0],
            font_id: italic_font,
            layout: Layout::default().h_align(HorizontalAlign::Center),
            z: 0.2,
        });

        // 2nd section is drawn last but with higher z,
        // draws are subject to depth testing
        glyph_brush.queue(Section {
            bounds: (width, height),
            text: &include_str!("lipsum.txt").replace("\n\n", "").repeat(10),
            scale: Scale::uniform(30.0),
            color: [0.05, 0.05, 0.1, 1.0],
            z: 1.0,
            ..Section::default()
        });

        glyph_brush
            .use_queue()
            .depth_target(&main_depth)
            .draw(&mut encoder, &main_color)?;

        encoder.flush(&mut device);
        window_ctx.swap_buffers()?;
        device.cleanup();

        if let Some(rate) = loop_helper.report_rate() {
            window.set_title(&format!("{} - {:.0} FPS", title, rate));
        }

        loop_helper.loop_sleep();
    }
    Ok(())
}
<commit_msg>Remove depth-test setting in depth example<commit_after>use gfx::{format, Device};
use gfx_glyph::*;
use std::{env, error::Error};

fn main() -> Result<(), Box<dyn Error>> {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "gfx_glyph=warn");
    }

    env_logger::init();

    if cfg!(target_os = "linux") {
        // winit wayland is currently still wip
        if env::var("WINIT_UNIX_BACKEND").is_err() {
            env::set_var("WINIT_UNIX_BACKEND", "x11");
        }
        // disables vsync sometimes on x11
        if env::var("vblank_mode").is_err() {
            env::set_var("vblank_mode", "0");
        }
    }

    if cfg!(debug_assertions) && env::var("yes_i_really_want_debug_mode").is_err() {
        eprintln!(
            "Note: Release mode will improve performance greatly.\n    \
             e.g. use `cargo run --example depth --release`"
        );
    }

    let mut events_loop = glutin::EventsLoop::new();
    let title = "gfx_glyph example - resize to see multi-text layout";
    let window_builder = glutin::WindowBuilder::new()
        .with_title(title)
        .with_dimensions((700, 320).into());
    let context = glutin::ContextBuilder::new();
    let (window_ctx, mut device, mut factory, mut main_color, mut main_depth) =
        gfx_window_glutin::init::<format::Srgba8, format::Depth>(
            window_builder,
            context,
            &events_loop,
        )
        .unwrap();
    let window = window_ctx.window();

    let fonts: Vec<&[u8]> = vec![
        include_bytes!("../../fonts/DejaVuSans.ttf"),
        include_bytes!("../../fonts/OpenSans-Italic.ttf"),
    ];
    let italic_font = FontId(1);

    let mut glyph_brush = GlyphBrushBuilder::using_fonts_bytes(fonts)
        .initial_cache_size((512, 512))
        .build(factory.clone());

    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

    let mut running = true;
    let mut loop_helper = spin_sleep::LoopHelper::builder().build_with_target_rate(250.0);

    while running {
        loop_helper.loop_start();

        events_loop.poll_events(|event| {
            use glutin::*;
            if let Event::WindowEvent { event, .. } = event {
                match event {
                    WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                virtual_keycode: Some(VirtualKeyCode::Escape),
                                ..
                            },
                        ..
                    }
                    | WindowEvent::CloseRequested => running = false,
                    WindowEvent::Resized(size) => {
                        window_ctx.resize(size.to_physical(window.get_hidpi_factor()));
                        gfx_window_glutin::update_views(
                            &window_ctx,
                            &mut main_color,
                            &mut main_depth,
                        );
                    }
                    _ => {}
                }
            }
        });

        encoder.clear(&main_color, [0.02, 0.02, 0.02, 1.0]);
        encoder.clear_depth(&main_depth, 1.0);

        let (width, height, ..) = main_color.get_dimensions();
        let (width, height) = (f32::from(width), f32::from(height));

        // first section is queued, and therefore drawn, first with lower z
        glyph_brush.queue(Section {
            screen_position: (width / 2.0, 100.0),
            bounds: (width, height - 100.0),
            text: "On top",
            scale: Scale::uniform(95.0),
            color: [0.8, 0.8, 0.8, 1.0],
            font_id: italic_font,
            layout: Layout::default().h_align(HorizontalAlign::Center),
            z: 0.2,
        });

        // 2nd section is drawn last but with higher z,
        // draws are subject to depth testing
        glyph_brush.queue(Section {
            bounds: (width, height),
            text: &include_str!("lipsum.txt").replace("\n\n", "").repeat(10),
            scale: Scale::uniform(30.0),
            color: [0.05, 0.05, 0.1, 1.0],
            z: 1.0,
            ..Section::default()
        });

        glyph_brush
            .use_queue()
            // Enable depth testing with default less-equal drawing and update the depth buffer
            .depth_target(&main_depth)
            .draw(&mut encoder, &main_color)?;

        encoder.flush(&mut device);
        window_ctx.swap_buffers()?;
        device.cleanup();

        if let Some(rate) = loop_helper.report_rate() {
            window.set_title(&format!("{} - {:.0} FPS", title, rate));
        }

        loop_helper.loop_sleep();
    }
    Ok(())
}
<|endoftext|>