<commit_before>#![cfg(feature = "quickcheck")]

extern crate num_bigint;
extern crate num_integer;
extern crate num_traits;

extern crate quickcheck;
#[macro_use]
extern crate quickcheck_macros;

use num_bigint::{BigInt, BigUint};
use num_traits::{Num, One, Pow, Zero};
use quickcheck::TestResult;

#[quickcheck]
fn quickcheck_unsigned_eq_reflexive(a: BigUint) -> bool {
    a == a
}

#[quickcheck]
fn quickcheck_signed_eq_reflexive(a: BigInt) -> bool {
    a == a
}

#[quickcheck]
fn quickcheck_unsigned_eq_symmetric(a: BigUint, b: BigUint) -> bool {
    if a == b {
        b == a
    } else {
        b != a
    }
}

#[quickcheck]
fn quickcheck_signed_eq_symmetric(a: BigInt, b: BigInt) -> bool {
    if a == b {
        b == a
    } else {
        b != a
    }
}

#[quickcheck]
fn quickcheck_unsigned_add_primitive(a: u128, b: u128) -> TestResult {
    let actual = BigUint::from(a) + BigUint::from(b);
    match a.checked_add(b) {
        None => TestResult::discard(),
        Some(expected) => TestResult::from_bool(BigUint::from(expected) == actual),
    }
}

#[quickcheck]
fn quickcheck_signed_add_primitive(a: i128, b: i128) -> TestResult {
    let actual = BigInt::from(a) + BigInt::from(b);
    match a.checked_add(b) {
        None => TestResult::discard(),
        Some(expected) => TestResult::from_bool(BigInt::from(expected) == actual),
    }
}

#[quickcheck]
fn quickcheck_unsigned_add_commutative(a: BigUint, b: BigUint) -> bool {
    a.clone() + b.clone() == b + a
}

#[quickcheck]
fn quickcheck_signed_add_commutative(a: BigInt, b: BigInt) -> bool {
    a.clone() + b.clone() == b + a
}

#[quickcheck]
fn quickcheck_unsigned_add_zero(a: BigUint) -> bool {
    a.clone() == a + BigUint::zero()
}

#[quickcheck]
fn quickcheck_signed_add_zero(a: BigInt) -> bool {
    a.clone() == a + BigInt::zero()
}

#[quickcheck]
fn quickcheck_unsigned_add_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
    (a.clone() + b.clone()) + c.clone() == a + (b + c)
}

#[quickcheck]
fn quickcheck_signed_add_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
    (a.clone() + b.clone()) + c.clone() == a + (b + c)
}

#[quickcheck]
fn quickcheck_unsigned_mul_primitive(a: u64, b: u64) -> bool {
    //maximum value of u64 means no overflow
    BigUint::from(a as u128 * b as u128) == BigUint::from(a) * BigUint::from(b)
}

#[quickcheck]
fn quickcheck_signed_mul_primitive(a: i64, b: i64) -> bool {
    //maximum value of i64 means no overflow
    BigInt::from(a as i128 * b as i128) == BigInt::from(a) * BigInt::from(b)
}

#[quickcheck]
fn quickcheck_unsigned_mul_zero(a: BigUint) -> bool {
    a * BigUint::zero() == BigUint::zero()
}

#[quickcheck]
fn quickcheck_signed_mul_zero(a: BigInt) -> bool {
    a * BigInt::zero() == BigInt::zero()
}

#[quickcheck]
fn quickcheck_unsigned_mul_one(a: BigUint) -> bool {
    a.clone() * BigUint::one() == a
}

#[quickcheck]
fn quickcheck_signed_mul_one(a: BigInt) -> bool {
    a.clone() * BigInt::one() == a
}

#[quickcheck]
fn quickcheck_unsigned_mul_commutative(a: BigUint, b: BigUint) -> bool {
    a.clone() * b.clone() == b * a
}

#[quickcheck]
fn quickcheck_signed_mul_commutative(a: BigInt, b: BigInt) -> bool {
    a.clone() * b.clone() == b * a
}

#[quickcheck]
fn quickcheck_unsigned_mul_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
    (a.clone() * b.clone()) * c.clone() == a * (b * c)
}

#[quickcheck]
fn quickcheck_signed_mul_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
    (a.clone() * b.clone()) * c.clone() == a * (b * c)
}

#[quickcheck]
fn quickcheck_unsigned_distributive(a: BigUint, b: BigUint, c: BigUint) -> bool {
    a.clone() * (b.clone() + c.clone()) == a.clone() * b + a * c
}

#[quickcheck]
fn quickcheck_signed_distributive(a: BigInt, b: BigInt, c: BigInt) -> bool {
    a.clone() * (b.clone() + c.clone()) == a.clone() * b + a * c
}

#[quickcheck]
///Tests that exactly one of a<b a>b a=b is true
fn quickcheck_unsigned_ge_le_eq_mut_exclusive(a: BigUint, b: BigUint) -> bool {
    let gt_lt_eq = vec![a > b, a < b, a == b];
    gt_lt_eq
        .iter()
        .fold(0, |acc, e| if *e { acc + 1 } else { acc })
        == 1
}

#[quickcheck]
///Tests that exactly one of a<b a>b a=b is true
fn quickcheck_signed_ge_le_eq_mut_exclusive(a: BigInt, b: BigInt) -> bool {
    let gt_lt_eq = vec![a > b, a < b, a == b];
    gt_lt_eq
        .iter()
        .fold(0, |acc, e| if *e { acc + 1 } else { acc })
        == 1
}

#[quickcheck]
fn quickcheck_unsigned_sub_primitive(a: u128, b: u128) -> bool {
    if b < a {
        BigUint::from(a - b) == BigUint::from(a) - BigUint::from(b)
    } else {
        BigUint::from(b - a) == BigUint::from(b) - BigUint::from(a)
    }
}

#[quickcheck]
fn quickcheck_signed_sub_primitive(a: i128, b: i128) -> bool {
    if b < a {
        BigInt::from(a - b) == BigInt::from(a) - BigInt::from(b)
    } else {
        BigInt::from(b - a) == BigInt::from(b) - BigInt::from(a)
    }
}

#[quickcheck]
/// Tests correctness of subtraction assuming addition is correct
fn quickcheck_unsigned_sub(a: BigUint, b: BigUint) -> bool {
    if b < a {
        a.clone() - b.clone() + b == a
    } else {
        b.clone() - a.clone() + a == b
    }
}

#[quickcheck]
/// Tests correctness of subtraction assuming addition is correct
fn quickcheck_signed_sub(a: BigInt, b: BigInt) -> bool {
    if b < a {
        a.clone() - b.clone() + b == a
    } else {
        b.clone() - a.clone() + a == b
    }
}

#[quickcheck]
fn quickcheck_unsigned_div_primitive(a: u128, b: u128) -> TestResult {
    if b == 0 {
        TestResult::discard()
    } else {
        TestResult::from_bool(BigUint::from(a / b) == BigUint::from(a) / BigUint::from(b))
    }
}

#[quickcheck]
fn quickcheck_signed_div_primitive(a: i128, b: i128) -> TestResult {
    if b == 0 {
        TestResult::discard()
    } else {
        TestResult::from_bool(BigInt::from(a / b) == BigInt::from(a) / BigInt::from(b))
    }
}

#[quickcheck]
fn quickcheck_unsigned_pow_zero(a: BigUint) -> bool {
    a.pow(0_u32) == BigUint::one()
}

#[quickcheck]
fn quickcheck_unsigned_pow_one(a: BigUint) -> bool {
    a.pow(1_u32) == a
}

#[quickcheck]
fn quickcheck_unsigned_sqrt(a: BigUint) -> bool {
    (a.clone() * a.clone()).sqrt() == a
}

#[quickcheck]
fn quickcheck_unsigned_cbrt(a: BigUint) -> bool {
    (a.clone() * a.clone() * a.clone()).cbrt() == a
}

#[quickcheck]
fn quickcheck_signed_cbrt(a: BigInt) -> bool {
    (a.clone() * a.clone() * a.clone()).cbrt() == a
}

#[quickcheck]
fn quickcheck_unsigned_conversion(a: BigUint) -> bool {
    let mut success = true;
    for radix in 2..=36 {
        let string = a.to_str_radix(radix);
        success &= a == BigUint::from_str_radix(&string, radix).unwrap()
    }
    success
}

#[quickcheck]
fn quickcheck_signed_conversion(a: BigInt) -> bool {
    let mut success = true;
    for radix in 2..=36 {
        let string = a.to_str_radix(radix);
        success &= a == BigInt::from_str_radix(&string, radix).unwrap()
    }
    success
}

#[quickcheck]
fn quickcheck_unsigned_modpow(a: BigUint, exp: u8, modulus: BigUint) -> TestResult {
    if modulus.clone().is_zero() {
        TestResult::discard()
    } else {
        let expected = a.clone().pow(exp) % modulus.clone();
        let result = a.modpow(&BigUint::from(exp), &BigUint::from(modulus));
        TestResult::from_bool(expected == result)
    }
}
<commit_msg>fix slow quickchecks<commit_after>#![cfg(feature = "quickcheck")]

extern crate num_bigint;
extern crate num_integer;
extern crate num_traits;

extern crate quickcheck;
#[macro_use]
extern crate quickcheck_macros;

use num_bigint::{BigInt, BigUint};
use num_traits::{Num, One, Pow, Zero};
use quickcheck::TestResult;

#[quickcheck]
fn quickcheck_unsigned_eq_reflexive(a: BigUint) -> bool {
    a == a
}

#[quickcheck]
fn quickcheck_signed_eq_reflexive(a: BigInt) -> bool {
    a == a
}

#[quickcheck]
fn quickcheck_unsigned_eq_symmetric(a: BigUint, b: BigUint) -> bool {
    if a == b {
        b == a
    } else {
        b != a
    }
}

#[quickcheck]
fn quickcheck_signed_eq_symmetric(a: BigInt, b: BigInt) -> bool {
    if a == b {
        b == a
    } else {
        b != a
    }
}

#[quickcheck]
fn quickcheck_unsigned_add_primitive(a: u128, b: u128) -> TestResult {
    let actual = BigUint::from(a) + BigUint::from(b);
    match a.checked_add(b) {
        None => TestResult::discard(),
        Some(expected) => TestResult::from_bool(BigUint::from(expected) == actual),
    }
}

#[quickcheck]
fn quickcheck_signed_add_primitive(a: i128, b: i128) -> TestResult {
    let actual = BigInt::from(a) + BigInt::from(b);
    match a.checked_add(b) {
        None => TestResult::discard(),
        Some(expected) => TestResult::from_bool(BigInt::from(expected) == actual),
    }
}

#[quickcheck]
fn quickcheck_unsigned_add_commutative(a: BigUint, b: BigUint) -> bool {
    a.clone() + b.clone() == b + a
}

#[quickcheck]
fn quickcheck_signed_add_commutative(a: BigInt, b: BigInt) -> bool {
    a.clone() + b.clone() == b + a
}

#[quickcheck]
fn quickcheck_unsigned_add_zero(a: BigUint) -> bool {
    a.clone() == a + BigUint::zero()
}

#[quickcheck]
fn quickcheck_signed_add_zero(a: BigInt) -> bool {
    a.clone() == a + BigInt::zero()
}

#[quickcheck]
fn quickcheck_unsigned_add_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
    (a.clone() + b.clone()) + c.clone() == a + (b + c)
}

#[quickcheck]
fn quickcheck_signed_add_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
    (a.clone() + b.clone()) + c.clone() == a + (b + c)
}

#[quickcheck]
fn quickcheck_unsigned_mul_primitive(a: u64, b: u64) -> bool {
    //maximum value of u64 means no overflow
    BigUint::from(a as u128 * b as u128) == BigUint::from(a) * BigUint::from(b)
}

#[quickcheck]
fn quickcheck_signed_mul_primitive(a: i64, b: i64) -> bool {
    //maximum value of i64 means no overflow
    BigInt::from(a as i128 * b as i128) == BigInt::from(a) * BigInt::from(b)
}

#[quickcheck]
fn quickcheck_unsigned_mul_zero(a: BigUint) -> bool {
    a * BigUint::zero() == BigUint::zero()
}

#[quickcheck]
fn quickcheck_signed_mul_zero(a: BigInt) -> bool {
    a * BigInt::zero() == BigInt::zero()
}

#[quickcheck]
fn quickcheck_unsigned_mul_one(a: BigUint) -> bool {
    a.clone() * BigUint::one() == a
}

#[quickcheck]
fn quickcheck_signed_mul_one(a: BigInt) -> bool {
    a.clone() * BigInt::one() == a
}

#[quickcheck]
fn quickcheck_unsigned_mul_commutative(a: BigUint, b: BigUint) -> bool {
    a.clone() * b.clone() == b * a
}

#[quickcheck]
fn quickcheck_signed_mul_commutative(a: BigInt, b: BigInt) -> bool {
    a.clone() * b.clone() == b * a
}

#[quickcheck]
fn quickcheck_unsigned_mul_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
    (a.clone() * b.clone()) * c.clone() == a * (b * c)
}

#[quickcheck]
fn quickcheck_signed_mul_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
    (a.clone() * b.clone()) * c.clone() == a * (b * c)
}

#[quickcheck]
fn quickcheck_unsigned_distributive(a: BigUint, b: BigUint, c: BigUint) -> bool {
    a.clone() * (b.clone() + c.clone()) == a.clone() * b + a * c
}

#[quickcheck]
fn quickcheck_signed_distributive(a: BigInt, b: BigInt, c: BigInt) -> bool {
    a.clone() * (b.clone() + c.clone()) == a.clone() * b + a * c
}

#[quickcheck]
///Tests that exactly one of a<b a>b a=b is true
fn quickcheck_unsigned_ge_le_eq_mut_exclusive(a: BigUint, b: BigUint) -> bool {
    let gt_lt_eq = vec![a > b, a < b, a == b];
    gt_lt_eq
        .iter()
        .fold(0, |acc, e| if *e { acc + 1 } else { acc })
        == 1
}

#[quickcheck]
///Tests that exactly one of a<b a>b a=b is true
fn quickcheck_signed_ge_le_eq_mut_exclusive(a: BigInt, b: BigInt) -> bool {
    let gt_lt_eq = vec![a > b, a < b, a == b];
    gt_lt_eq
        .iter()
        .fold(0, |acc, e| if *e { acc + 1 } else { acc })
        == 1
}

#[quickcheck]
fn quickcheck_unsigned_sub_primitive(a: u128, b: u128) -> bool {
    if b < a {
        BigUint::from(a - b) == BigUint::from(a) - BigUint::from(b)
    } else {
        BigUint::from(b - a) == BigUint::from(b) - BigUint::from(a)
    }
}

#[quickcheck]
fn quickcheck_signed_sub_primitive(a: i128, b: i128) -> bool {
    if b < a {
        BigInt::from(a - b) == BigInt::from(a) - BigInt::from(b)
    } else {
        BigInt::from(b - a) == BigInt::from(b) - BigInt::from(a)
    }
}

#[quickcheck]
/// Tests correctness of subtraction assuming addition is correct
fn quickcheck_unsigned_sub(a: BigUint, b: BigUint) -> bool {
    if b < a {
        a.clone() - b.clone() + b == a
    } else {
        b.clone() - a.clone() + a == b
    }
}

#[quickcheck]
/// Tests correctness of subtraction assuming addition is correct
fn quickcheck_signed_sub(a: BigInt, b: BigInt) -> bool {
    if b < a {
        a.clone() - b.clone() + b == a
    } else {
        b.clone() - a.clone() + a == b
    }
}

#[quickcheck]
fn quickcheck_unsigned_div_primitive(a: u128, b: u128) -> TestResult {
    if b == 0 {
        TestResult::discard()
    } else {
        TestResult::from_bool(BigUint::from(a / b) == BigUint::from(a) / BigUint::from(b))
    }
}

#[quickcheck]
fn quickcheck_signed_div_primitive(a: i128, b: i128) -> TestResult {
    if b == 0 {
        TestResult::discard()
    } else {
        TestResult::from_bool(BigInt::from(a / b) == BigInt::from(a) / BigInt::from(b))
    }
}

#[quickcheck]
fn quickcheck_unsigned_pow_zero(a: BigUint) -> bool {
    a.pow(0_u32) == BigUint::one()
}

#[quickcheck]
fn quickcheck_unsigned_pow_one(a: BigUint) -> bool {
    a.pow(1_u32) == a
}

#[quickcheck]
fn quickcheck_unsigned_sqrt(a: BigUint) -> bool {
    (a.clone() * a.clone()).sqrt() == a
}

#[quickcheck]
fn quickcheck_unsigned_cbrt(a: BigUint) -> bool {
    (a.clone() * a.clone() * a.clone()).cbrt() == a
}

#[quickcheck]
fn quickcheck_signed_cbrt(a: BigInt) -> bool {
    (a.clone() * a.clone() * a.clone()).cbrt() == a
}

#[quickcheck]
fn quickcheck_unsigned_conversion(a: BigUint, radix: u8) -> TestResult {
    let radix = radix as u32;
    if radix > 36 || radix < 2 {
        return TestResult::discard();
    }
    let string = a.to_str_radix(radix);
    TestResult::from_bool(a == BigUint::from_str_radix(&string, radix).unwrap())
}

#[quickcheck]
fn quickcheck_signed_conversion(a: BigInt, radix: u8) -> TestResult {
    let radix = radix as u32;
    if radix > 36 || radix < 2 {
        return TestResult::discard();
    }
    let string = a.to_str_radix(radix);
    TestResult::from_bool(a == BigInt::from_str_radix(&string, radix).unwrap())
}
<|endoftext|>


<commit_before>extern crate noise_search;

use std::io::{Read, Write, BufReader};
use std::fs::{self, File};
use std::env;

use noise_search::repl::repl;

#[test]
fn test_repl() {
    // We load up tests scripts from repl-tests and evaluate them. The output should be idenitical
    // to the test script files. If not, then the test is failed and a new file is written with
    // .reject extension in the same directory where it can be investigated.

    // To update the test files with new command and output, simply edit/add commands and run
    // update-test-repl.sh script from the project root directory. Then examin or do a git diff to
    // see if the output is as expected.

    let mut test_dir = env::current_dir().unwrap();
    test_dir.push("repl-tests");
    let mut failures = 0;
    let mut total = 0;
    // Sort files by last modified date to make debugging easier
    let mut entries: Vec<_> = fs::read_dir(test_dir)
        .unwrap()
        .map(|r| r.unwrap())
        .collect();
    entries.sort_by_key(|entry| entry.metadata().unwrap().modified().unwrap());
    for entry in entries {
        let mut path = entry.path();
        if path.extension().unwrap().to_str().unwrap() != "noise" {
            continue;
        }
        total += 1;
        let test_name = path.file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .to_string();
        println!("About to run test {} ", test_name);
        let mut file = File::open(path.clone()).unwrap();
        let mut file_buffer = Vec::new();
        file.read_to_end(&mut file_buffer).unwrap();

        let mut test_result_buffer = Vec::new();
        let file = File::open(path.clone()).unwrap();
        repl(&mut BufReader::new(file), &mut test_result_buffer, true);

        if file_buffer != test_result_buffer {
            failures += 1;
            path.set_extension("reject");
            let reject = path.file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .to_string();

            let mut file = File::create(path.clone()).unwrap();
            file.write_all(&test_result_buffer).unwrap();
            file.sync_all().unwrap();

            println!("Repl test {} failure. Failing output written to {} in repl-tests dir.",
                     test_name,
                     reject);
        } else {
            println!("{} successful",
                     path.file_name()
                         .unwrap()
                         .to_str()
                         .unwrap()
                         .to_string());
        }
    }
    if total == 0 {
        panic!("No tests were run!");
    }
    if failures > 0 {
        panic!("Failed {} tests in repl-test out of {}", failures, total);
    }
}
<commit_msg>Run latest modified test first<commit_after>extern crate noise_search;

use std::io::{Read, Write, BufReader};
use std::fs::{self, File};
use std::env;

use noise_search::repl::repl;

#[test]
fn test_repl() {
    // We load up tests scripts from repl-tests and evaluate them. The output should be idenitical
    // to the test script files. If not, then the test is failed and a new file is written with
    // .reject extension in the same directory where it can be investigated.

    // To update the test files with new command and output, simply edit/add commands and run
    // update-test-repl.sh script from the project root directory. Then examin or do a git diff to
    // see if the output is as expected.

    let mut test_dir = env::current_dir().unwrap();
    test_dir.push("repl-tests");
    let mut failures = 0;
    let mut total = 0;
    // Sort files by last modified date to make debugging easier
    let mut entries: Vec<_> = fs::read_dir(test_dir)
        .unwrap()
        .map(|r| r.unwrap())
        .collect();
    entries.sort_by_key(|entry| entry.metadata().unwrap().modified().unwrap());
    entries.reverse();
    for entry in entries {
        let mut path = entry.path();
        if path.extension().unwrap().to_str().unwrap() != "noise" {
            continue;
        }
        total += 1;
        let test_name = path.file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .to_string();
        println!("About to run test {} ", test_name);
        let mut file = File::open(path.clone()).unwrap();
        let mut file_buffer = Vec::new();
        file.read_to_end(&mut file_buffer).unwrap();

        let mut test_result_buffer = Vec::new();
        let file = File::open(path.clone()).unwrap();
        repl(&mut BufReader::new(file), &mut test_result_buffer, true);

        if file_buffer != test_result_buffer {
            failures += 1;
            path.set_extension("reject");
            let reject = path.file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .to_string();

            let mut file = File::create(path.clone()).unwrap();
            file.write_all(&test_result_buffer).unwrap();
            file.sync_all().unwrap();

            println!("Repl test {} failure. Failing output written to {} in repl-tests dir.",
                     test_name,
                     reject);
        } else {
            println!("{} successful",
                     path.file_name()
                         .unwrap()
                         .to_str()
                         .unwrap()
                         .to_string());
        }
    }
    if total == 0 {
        panic!("No tests were run!");
    }
    if failures > 0 {
        panic!("Failed {} tests in repl-test out of {}", failures, total);
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::{CStr, CString};
use std::fmt;
use std::ptr;
use super::error::SBError;
use super::platform::SBPlatform;
use super::stream::SBStream;
use super::target::SBTarget;
use sys;

/// Creates [`SBTarget`]s, provides access to them and manages
/// the overall debugging experience.
///
/// # Initialization and Teardown
///
/// LLDB must be initialized before the functionality is used. This
/// is done with `SBDebugger::initialize()`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// ```
///
/// Similarly, it must be terminated after you are done using it:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// // Use LLDB functionality ...
/// SBDebugger::terminate();
/// ```
///
/// Once you've initialized LLDB, you're ready to create an instance
/// of `SBDebugger`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
///
/// let debugger = SBDebugger::create(false);
/// // ... configure the debugger if needed ...
/// // ... create a target and do stuff ...
///
/// SBDebugger::terminate();
/// ```
///
/// # Configuration
///
/// ## Async Mode
///
/// While it is best to use LLDB in asynchronous mode, it does offer a
/// synchronous mode, which can be easier to use for quick experiments
/// or scripts.
///
/// In synchronous mode, calls to the LLDB API do not return until the
/// underlying action has been completed. This means that the thread
/// from which you call LLDB will be blocked during that time, so this
/// is not an ideal way to use LLDB for building interactive tools
/// or a new user interface.
///
/// In asynchronous mode, calls to the LLDB API will return immediately
/// without waiting for the action to complete. This means that actions
/// like launching a target, continuing the execution of a process and
/// so on won't be completed immediately and you must process events
/// to see what the results of an action are.
///
/// Synchronous mode can be enabled by using [`set_async`] and passing it
/// a `false` value. You can see if you're in asynchronous mode or not
/// by calling [`async`].
///
/// # Target Management
///
/// The `SBDebugger` instance tracks the various targets that are
/// currently known to the debugger.
///
/// Typically, you create a target with [`create_target`],
/// [`create_target_simple`] or one of the related methods.
///
/// Sometimes, you'll want to create a target without an associated
/// executable. A common use case for this is to attach to a process
/// by name or process ID where you don't know the executable in advance.
/// The most convenient way to do this is:
///
/// ```
/// # use lldb::SBDebugger;
/// # SBDebugger::initialize();
/// let debugger = SBDebugger::create(false);
/// if let Some(target) = debugger.create_target_simple("") {
///     println!("Got a target: {:?}", target);
///     // Now, maybe we'd like to attach to something.
/// }
/// # SBDebugger::terminate();
/// ```
///
/// You can iterate over these targets which have been created by
/// using [`targets`]:
///
/// ```no_run
/// # use lldb::{SBDebugger, SBTarget};
/// # fn look_at_targets(debugger: SBDebugger) {
/// // Iterate over the targets...
/// for target in debugger.targets() {
///     println!("Hello {:?}!", target);
/// }
/// // Or collect them into a vector!
/// let targets = debugger.targets().collect::<Vec<SBTarget>>();
/// # }
/// ```
///
/// # Platform Management
///
/// ...
///
/// [`SBTarget`]: struct.SBTarget.html
/// [`set_async`]: #method.set_async
/// [`async`]: #method.async
/// [`create_target`]: #method.create_target
/// [`create_target_simple`]: #method.create_target_simple
/// [`targets`]: #method.targets
pub struct SBDebugger {
    /// The underlying raw `SBDebuggerRef`.
    pub raw: sys::SBDebuggerRef,
}

impl SBDebugger {
    /// Initialize LLDB.
    ///
    /// This should be called before LLDB functionality is used.
    pub fn initialize() {
        unsafe { sys::SBDebuggerInitialize() };
    }

    /// Tear down LLDB.
    ///
    /// This should be called once the application no longer needs
    /// to use LLDB functionality. Typically, this is called as the
    /// application exits.
    pub fn terminate() {
        unsafe { sys::SBDebuggerTerminate() };
    }

    /// Create a new instance of `SBDebugger`.
    ///
    /// If `source_init_files` is `true`, then `~/.lldbinit` will
    /// be processed.
    pub fn create(source_init_files: bool) -> SBDebugger {
        SBDebugger {
            raw: unsafe { sys::SBDebuggerCreate2(source_init_files as u8) },
        }
    }

    /// Get whether or not the debugger is in async mode.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn async(&self) -> bool {
        unsafe { sys::SBDebuggerGetAsync(self.raw) != 0 }
    }

    /// Set the debugger to be in async mode or not.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn set_async(&self, async: bool) {
        unsafe { sys::SBDebuggerSetAsync(self.raw, async as u8) }
    }

    /// Get the LLDB version string.
    pub fn version() -> String {
        unsafe {
            match CStr::from_ptr(sys::SBDebuggerGetVersionString()).to_str() {
                Ok(s) => s.to_owned(),
                _ => panic!("No version string?"),
            }
        }
    }

    /// Create a target.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    pub fn create_target(
        &self,
        executable: &str,
        target_triple: Option<&str>,
        platform_name: Option<&str>,
        add_dependent_modules: bool,
    ) -> Result<SBTarget, SBError> {
        let executable = CString::new(executable).unwrap();
        let target_triple = target_triple.map(|s| CString::new(s).unwrap());
        let platform_name = platform_name.map(|s| CString::new(s).unwrap());
        let error = SBError::new();
        let target = unsafe {
            sys::SBDebuggerCreateTarget(
                self.raw,
                executable.as_ptr(),
                target_triple.map_or(ptr::null(), |s| s.as_ptr()),
                platform_name.map_or(ptr::null(), |s| s.as_ptr()),
                add_dependent_modules as u8,
                error.raw,
            )
        };
        if error.is_success() {
            Ok(SBTarget::wrap(target))
        } else {
            Err(error)
        }
    }

    /// Create a target from just an executable name.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    ///
    /// Using [`create_target`] is preferred in most cases as
    /// that provides access to an `SBError` to inform the caller
    /// about what might have gone wrong.
    pub fn create_target_simple(&self, executable: &str) -> Option<SBTarget> {
        let executable = CString::new(executable).unwrap();
        SBTarget::maybe_wrap(unsafe { sys::SBDebuggerCreateTarget2(self.raw, executable.as_ptr()) })
    }

    /// Get an iterator over the [targets] known to this debugger instance.
    ///
    /// [targets]: struct.SBTarget.html
    pub fn targets(&self) -> SBDebuggerTargetIter {
        SBDebuggerTargetIter {
            debugger: self,
            idx: 0,
        }
    }

    /// Get the currently selected [`SBTarget`].
    ///
    /// [SBTarget]: struct.SBTarget.html
    pub fn selected_target(&self) -> Option<SBTarget> {
        SBTarget::maybe_wrap(unsafe { sys::SBDebuggerGetSelectedTarget(self.raw) })
    }

    /// Set the selected [`SBTarget`].
    ///
    /// [SBTarget]: struct.SBTarget.html
    pub fn set_selected_target(&self, target: &SBTarget) {
        unsafe { sys::SBDebuggerSetSelectedTarget(self.raw, target.raw) };
    }

    /// Get the currently selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn selected_platform(&self) -> SBPlatform {
        unsafe {
            SBPlatform {
                raw: sys::SBDebuggerGetSelectedPlatform(self.raw),
            }
        }
    }

    /// Set the selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn set_selected_platform(&self, platform: &SBPlatform) {
        unsafe { sys::SBDebuggerSetSelectedPlatform(self.raw, platform.raw) };
    }
}

/// Iterate over the [targets] known to a [debugger].
///
/// [targets]: struct.SBTarget.html
/// [debugger]: struct.SBDebugger.html
pub struct SBDebuggerTargetIter<'d> {
    debugger: &'d SBDebugger,
    idx: usize,
}

impl<'d> Iterator for SBDebuggerTargetIter<'d> {
    type Item = SBTarget;

    fn next(&mut self) -> Option<SBTarget> {
        if self.idx < unsafe { sys::SBDebuggerGetNumTargets(self.debugger.raw) as usize } {
            let r = Some(SBTarget {
                raw: unsafe { sys::SBDebuggerGetTargetAtIndex(self.debugger.raw, self.idx as u32) },
            });
            self.idx += 1;
            r
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let sz = unsafe { sys::SBDebuggerGetNumTargets(self.debugger.raw) } as usize;
        (sz - self.idx, Some(sz))
    }
}

impl<'d> ExactSizeIterator for SBDebuggerTargetIter<'d> {}

impl fmt::Debug for SBDebugger {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBDebuggerGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBDebugger {{ {} }}", stream.data())
    }
}

impl Drop for SBDebugger {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBDebugger(self.raw) };
    }
}

#[cfg(feature = "graphql")]
impl ::juniper::Context for SBDebugger {}

#[cfg(feature = "graphql")]
graphql_object!(SBDebugger: SBDebugger | &self | {
    field targets() -> Vec<SBTarget> {
        self.targets().collect()
    }

    field selected_target() -> Option<SBTarget> {
        self.selected_target()
    }

    field selected_platform() -> SBPlatform {
        self.selected_platform()
    }
});

#[cfg(test)]
mod tests {
    use super::SBDebugger;

    #[test]
    fn it_works() {
        assert!(!SBDebugger::version().is_empty());
    }
}
<commit_msg>Add bindings for getting platforms and available platform info from SBDebugger.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::{CStr, CString};
use std::fmt;
use std::ptr;
use super::error::SBError;
use super::platform::SBPlatform;
use super::stream::SBStream;
use super::structureddata::SBStructuredData;
use super::target::SBTarget;
use sys;

/// Creates [`SBTarget`]s, provides access to them and manages
/// the overall debugging experience.
///
/// # Initialization and Teardown
///
/// LLDB must be initialized before the functionality is used. This
/// is done with `SBDebugger::initialize()`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// ```
///
/// Similarly, it must be terminated after you are done using it:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// // Use LLDB functionality ...
/// SBDebugger::terminate();
/// ```
///
/// Once you've initialized LLDB, you're ready to create an instance
/// of `SBDebugger`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
///
/// let debugger = SBDebugger::create(false);
/// // ... configure the debugger if needed ...
/// // ... create a target and do stuff ...
///
/// SBDebugger::terminate();
/// ```
///
/// # Configuration
///
/// ## Async Mode
///
/// While it is best to use LLDB in asynchronous mode, it does offer a
/// synchronous mode, which can be easier to use for quick experiments
/// or scripts.
///
/// In synchronous mode, calls to the LLDB API do not return until the
/// underlying action has been completed. This means that the thread
/// from which you call LLDB will be blocked during that time, so this
/// is not an ideal way to use LLDB for building interactive tools
/// or a new user interface.
///
/// In asynchronous mode, calls to the LLDB API will return immediately
/// without waiting for the action to complete. This means that actions
/// like launching a target, continuing the execution of a process and
/// so on won't be completed immediately and you must process events
/// to see what the results of an action are.
///
/// Synchronous mode can be enabled by using [`set_async`] and passing it
/// a `false` value. You can see if you're in asynchronous mode or not
/// by calling [`async`].
///
/// # Target Management
///
/// The `SBDebugger` instance tracks the various targets that are
/// currently known to the debugger.
///
/// Typically, you create a target with [`create_target`],
/// [`create_target_simple`] or one of the related methods.
///
/// Sometimes, you'll want to create a target without an associated
/// executable. A common use case for this is to attach to a process
/// by name or process ID where you don't know the executable in advance.
/// The most convenient way to do this is:
///
/// ```
/// # use lldb::SBDebugger;
/// # SBDebugger::initialize();
/// let debugger = SBDebugger::create(false);
/// if let Some(target) = debugger.create_target_simple("") {
///     println!("Got a target: {:?}", target);
///     // Now, maybe we'd like to attach to something.
/// }
/// # SBDebugger::terminate();
/// ```
///
/// You can iterate over these targets which have been created by
/// using [`targets`]:
///
/// ```no_run
/// # use lldb::{SBDebugger, SBTarget};
/// # fn look_at_targets(debugger: SBDebugger) {
/// // Iterate over the targets...
/// for target in debugger.targets() {
///     println!("Hello {:?}!", target);
/// }
/// // Or collect them into a vector!
/// let targets = debugger.targets().collect::<Vec<SBTarget>>();
/// # }
/// ```
///
/// # Platform Management
///
/// ...
///
/// [`SBTarget`]: struct.SBTarget.html
/// [`set_async`]: #method.set_async
/// [`async`]: #method.async
/// [`create_target`]: #method.create_target
/// [`create_target_simple`]: #method.create_target_simple
/// [`targets`]: #method.targets
pub struct SBDebugger {
    /// The underlying raw `SBDebuggerRef`.
    pub raw: sys::SBDebuggerRef,
}

impl SBDebugger {
    /// Initialize LLDB.
    ///
    /// This should be called before LLDB functionality is used.
    pub fn initialize() {
        unsafe { sys::SBDebuggerInitialize() };
    }

    /// Tear down LLDB.
    ///
    /// This should be called once the application no longer needs
    /// to use LLDB functionality. Typically, this is called as the
    /// application exits.
    pub fn terminate() {
        unsafe { sys::SBDebuggerTerminate() };
    }

    /// Create a new instance of `SBDebugger`.
    ///
    /// If `source_init_files` is `true`, then `~/.lldbinit` will
    /// be processed.
    pub fn create(source_init_files: bool) -> SBDebugger {
        SBDebugger {
            raw: unsafe { sys::SBDebuggerCreate2(source_init_files as u8) },
        }
    }

    /// Get whether or not the debugger is in async mode.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn async(&self) -> bool {
        unsafe { sys::SBDebuggerGetAsync(self.raw) != 0 }
    }

    /// Set the debugger to be in async mode or not.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn set_async(&self, async: bool) {
        unsafe { sys::SBDebuggerSetAsync(self.raw, async as u8) }
    }

    /// Get the LLDB version string.
    pub fn version() -> String {
        unsafe {
            match CStr::from_ptr(sys::SBDebuggerGetVersionString()).to_str() {
                Ok(s) => s.to_owned(),
                _ => panic!("No version string?"),
            }
        }
    }

    /// Create a target.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    pub fn create_target(
        &self,
        executable: &str,
        target_triple: Option<&str>,
        platform_name: Option<&str>,
        add_dependent_modules: bool,
    ) -> Result<SBTarget, SBError> {
        let executable = CString::new(executable).unwrap();
        let target_triple = target_triple.map(|s| CString::new(s).unwrap());
        let platform_name = platform_name.map(|s| CString::new(s).unwrap());
        let error = SBError::new();
        let target = unsafe {
            sys::SBDebuggerCreateTarget(
                self.raw,
                executable.as_ptr(),
                target_triple.map_or(ptr::null(), |s| s.as_ptr()),
                platform_name.map_or(ptr::null(), |s| s.as_ptr()),
                add_dependent_modules as u8,
                error.raw,
            )
        };
        if error.is_success() {
            Ok(SBTarget::wrap(target))
        } else {
            Err(error)
        }
    }

    /// Create a target from just an executable name.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    ///
    /// Using [`create_target`] is preferred in most cases as
    /// that provides access to an `SBError` to inform the caller
    /// about what might have gone wrong.
    pub fn create_target_simple(&self, executable: &str) -> Option<SBTarget> {
        let executable = CString::new(executable).unwrap();
        SBTarget::maybe_wrap(unsafe { sys::SBDebuggerCreateTarget2(self.raw, executable.as_ptr()) })
    }

    /// Get an iterator over the [targets] known to this debugger instance.
    ///
    /// [targets]: struct.SBTarget.html
    pub fn targets(&self) -> SBDebuggerTargetIter {
        SBDebuggerTargetIter {
            debugger: self,
            idx: 0,
        }
    }

    /// Get the currently selected [`SBTarget`].
    ///
    /// [SBTarget]: struct.SBTarget.html
    pub fn selected_target(&self) -> Option<SBTarget> {
        SBTarget::maybe_wrap(unsafe { sys::SBDebuggerGetSelectedTarget(self.raw) })
    }

    /// Set the selected [`SBTarget`].
    ///
    /// [SBTarget]: struct.SBTarget.html
    pub fn set_selected_target(&self, target: &SBTarget) {
        unsafe { sys::SBDebuggerSetSelectedTarget(self.raw, target.raw) };
    }

    /// Get the currently selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn selected_platform(&self) -> SBPlatform {
        unsafe {
            SBPlatform {
                raw: sys::SBDebuggerGetSelectedPlatform(self.raw),
            }
        }
    }

    /// Set the selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn set_selected_platform(&self, platform: &SBPlatform) {
        unsafe { sys::SBDebuggerSetSelectedPlatform(self.raw, platform.raw) };
    }

    /// Get an iterator over the [platforms] known to this debugger instance.
    ///
    /// [platforms]: struct.SBPlatform.html
    pub fn platforms(&self) -> SBDebuggerPlatformIter {
        SBDebuggerPlatformIter {
            debugger: self,
            idx: 0,
        }
    }

    /// Get an iterator over the available platforms known to this debugger instance.
    pub fn available_platforms(&self) -> SBDebuggerAvailablePlatformIter {
        SBDebuggerAvailablePlatformIter {
            debugger: self,
            idx: 0,
        }
    }
}

/// Iterate over the [targets] known to a [debugger].
///
/// [targets]: struct.SBTarget.html
/// [debugger]: struct.SBDebugger.html
pub struct SBDebuggerTargetIter<'d> {
    debugger: &'d SBDebugger,
    idx: usize,
}

impl<'d> Iterator for SBDebuggerTargetIter<'d> {
    type Item = SBTarget;

    fn next(&mut self) -> Option<SBTarget> {
        if self.idx < unsafe { sys::SBDebuggerGetNumTargets(self.debugger.raw) as usize } {
            let r = Some(SBTarget {
                raw: unsafe { sys::SBDebuggerGetTargetAtIndex(self.debugger.raw, self.idx as u32) },
            });
            self.idx += 1;
            r
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let sz = unsafe { sys::SBDebuggerGetNumTargets(self.debugger.raw) } as usize;
        (sz - self.idx, Some(sz))
    }
}

impl<'d> ExactSizeIterator for SBDebuggerTargetIter<'d> {}

impl fmt::Debug for SBDebugger {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBDebuggerGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBDebugger {{ {} }}", stream.data())
    }
}

impl Drop for SBDebugger {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBDebugger(self.raw) };
    }
}

/// Iterate over the [platforms].
///
/// [platforms]: struct.SBPlatform.html
pub struct SBDebuggerPlatformIter<'d> {
    debugger: &'d SBDebugger,
    idx: u32,
}

impl<'d> Iterator for SBDebuggerPlatformIter<'d> {
    type Item = SBPlatform;

    fn next(&mut self) -> Option<SBPlatform> {
        if self.idx < unsafe { sys::SBDebuggerGetNumPlatforms(self.debugger.raw) } {
            let r = Some(SBPlatform::wrap(unsafe {
                sys::SBDebuggerGetPlatformAtIndex(self.debugger.raw, self.idx)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let sz = unsafe { sys::SBDebuggerGetNumPlatforms(self.debugger.raw) } as usize;
        (sz - self.idx as usize, Some(sz))
    }
}

impl<'d> ExactSizeIterator for SBDebuggerPlatformIter<'d> {}

/// Iterate over the available platforms.
pub struct SBDebuggerAvailablePlatformIter<'d> {
    debugger: &'d SBDebugger,
    idx: u32,
}

impl<'d> Iterator for SBDebuggerAvailablePlatformIter<'d> {
    type Item = SBStructuredData;

    fn next(&mut self) -> Option<SBStructuredData> {
        if self.idx < unsafe { sys::SBDebuggerGetNumAvailablePlatforms(self.debugger.raw) } {
            let r = Some(SBStructuredData::wrap(unsafe {
                sys::SBDebuggerGetAvailablePlatformInfoAtIndex(self.debugger.raw, self.idx)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let sz = unsafe { sys::SBDebuggerGetNumAvailablePlatforms(self.debugger.raw) } as usize;
        (sz - self.idx as usize, Some(sz))
    }
}

impl<'d> ExactSizeIterator for SBDebuggerAvailablePlatformIter<'d> {}

#[cfg(feature = "graphql")]
impl ::juniper::Context for SBDebugger {}

#[cfg(feature = "graphql")]
graphql_object!(SBDebugger: SBDebugger | &self | {
    field targets() -> Vec<SBTarget> {
        self.targets().collect()
    }

    field selected_target() -> Option<SBTarget> {
        self.selected_target()
    }

    field selected_platform() -> SBPlatform {
        self.selected_platform()
    }

    field platforms() -> Vec<SBPlatform> {
        self.platforms().collect()
    }

    field available_platforms() -> Vec<SBStructuredData> {
        self.available_platforms().collect()
    }
});

#[cfg(test)]
mod tests {
    use super::SBDebugger;

    #[test]
    fn it_works() {
        assert!(!SBDebugger::version().is_empty());
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use ndarray::Array2;

use crate::serialization::{Sketch, SketchDistance};
use crate::sketch_schemes::KmerCount;

pub fn distance(
    query_sketch: &Sketch,
    ref_sketch: &Sketch,
    old_mode: bool,
) -> Result<SketchDistance, &'static str> {
    let distances = if old_mode {
        old_distance(&query_sketch.hashes, &ref_sketch.hashes)
    } else {
        // since we always examine to the lowest of the sketch maxima, a
        // min_scale of 0 is a noop; otherwise we only set a scale if both of
        // the sketches are scaled (there may be a slight improvement in
        // comparing a unscaled "higher range" sketch to a scaled lower range
        // using the scale, but that makes things more complicated because we
        // need two scale values, etc)
        let mut min_scale = 0.;
        if let Some(scale1) = query_sketch.sketch_params.hash_info().3 {
            if let Some(scale2) = ref_sketch.sketch_params.hash_info().3 {
                min_scale = f64::min(scale1, scale2);
            }
        }
        raw_distance(&query_sketch.hashes, &ref_sketch.hashes, min_scale)
    };

    let containment = distances.0;
    let jaccard = distances.1;
    let common_hashes = distances.2;
    let total_hashes = distances.3;
    let k = query_sketch.sketch_params.k() as f64;
    let mash_distance: f64 = -1.0 * ((2.0 * jaccard) / (1.0 + jaccard)).ln() / k;
    Ok(SketchDistance {
        containment,
        jaccard,
        mash_distance: f64::min(1f64, f64::max(0f64, mash_distance)),
        common_hashes,
        total_hashes,
        query: query_sketch.name.to_string(),
        reference: ref_sketch.name.to_string(),
    })
}

/// This computes the set statistics between two sets of hashes.
///
/// It stops once either one of the sets has "run out" of hashes, i.e. at the
/// smallest max hash of the two sets, or when it's reached a "scale" boundary
/// if the sets were sketched in a scaled fashion. In general this is a better
/// approximation of the true document distance when either the two
/// original documents were of different sizes or of unknown sizes.
pub fn raw_distance(
    query_hashes: &[KmerCount],
    ref_hashes: &[KmerCount],
    scale: f64,
) -> (f64, f64, u64, u64) {
    if query_hashes.is_empty() || ref_hashes.is_empty() {
        return (0., 0., 0, 0);
    }

    let mut i: usize = 0;
    let mut j: usize = 0;
    let mut common: u64 = 0;
    loop {
        match query_hashes[i].hash.cmp(&ref_hashes[j].hash) {
            Ordering::Less => {
                if i + 1 == query_hashes.len() {
                    break;
                }
                i += 1;
            }
            Ordering::Greater => {
                if j + 1 == ref_hashes.len() {
                    break;
                }
                j += 1;
            }
            Ordering::Equal => {
                common += 1;
                if i + 1 == query_hashes.len() || j + 1 == ref_hashes.len() {
                    break;
                }
                i += 1;
                j += 1;
            }
        }
    }

    // at this point we've exhausted one of the two sketches, but we may have
    // more counts in the other to compare if these were scaled sketches
    if scale > 0. {
        let max_hash = u64::max_value() / (1. / scale) as u64;
        while i + 1 < query_hashes.len() {
            if query_hashes[i + 1].hash < max_hash {
                i += 1;
            } else {
                break;
            }
        }
        while j + 1 < ref_hashes.len() {
            if ref_hashes[j + 1].hash < max_hash {
                j += 1;
            } else {
                break;
            }
        }
    }

    // note that i and j are both 1 short at this point since they're array
    // indices instead of counts so we adjust them both upwards by 1 (unless
    // all of one sketch is greater than the largest hash in the other)
    if !(i == 0 && query_hashes[0].hash > ref_hashes[ref_hashes.len() - 1].hash) {
        i += 1;
    }
    let containment = if !(j == 0 && ref_hashes[0].hash > query_hashes[query_hashes.len() - 1].hash)
    {
        j += 1;
        common as f64 / j as f64
    } else {
        0.
    };
    let total = i as u64 + j as u64 - common;
    let jaccard: f64 = common as f64 / total as f64;

    (containment, jaccard, common, total)
}

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

    fn kc(arr: &[u64]) -> Vec<KmerCount> {
        arr.iter()
            .map(|x| KmerCount {
                hash: *x,
                kmer: vec![],
                count: 1,
                extra_count: 1,
                label: None,
            })
            .collect()
    }

    #[test]
    fn test_raw_distance() {
        let (cont, jac, com, total) = raw_distance(&kc(&[0, 1, 2]), &kc(&[1, 2]), 0.);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        let (cont, jac, com, total) = raw_distance(&kc(&[0, 2]), &kc(&[1, 2]), 0.);
        assert_eq!(cont, 1. / 2.);
        assert_eq!(jac, 1. / 3.);
        assert_eq!(com, 1);
        assert_eq!(total, 3);

        let (cont, jac, com, total) = raw_distance(&kc(&[0, 1]), &kc(&[2, 3]), 0.);
        assert_eq!(cont, 0. / 2.);
        assert_eq!(jac, 0. / 2.);
        assert_eq!(com, 0);
        assert_eq!(total, 2);
    }

    #[test]
    fn test_raw_distance_scaled() {
        // note  below that a scale cutoff of 1e-18 translates to a max_hash of 18

        // if the hashes extend above the scale just ignore
        let (cont, jac, com, total) = raw_distance(&kc(&[10, 15, 20]), &kc(&[15, 20]), 1e-18);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        // otherwise, include the extra hashes outside the range
        let (cont, jac, com, total) = raw_distance(&kc(&[5, 10, 15]), &kc(&[5, 10]), 1e-18);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        // only include up to the scale boundary though
        let (cont, jac, com, total) = raw_distance(&kc(&[5, 10, 15, 20]), &kc(&[5, 10]), 1e-18);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        // and check in the reverse for the containment
        let (cont, jac, com, total) = raw_distance(&kc(&[5, 10]), &kc(&[5, 10, 15, 20]), 1e-18);
        assert_eq!(cont, 2. / 3.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);
    }

    /// This is a straight transcription of the calculation used in Mash
    /// itself; now used for compatibility testing
    fn mash_paper_distance(sketch2: &[KmerCount], sketch1: &[KmerCount]) -> (f64, f64, u64, u64) {
        let mut i: usize = 0;
        let mut j: usize = 0;
        let mut common: u64 = 0;
        let mut total: u64 = 0;
        let sketch_size = sketch1.len();

        while (total < sketch_size as u64) && (i < sketch1.len()) && (j < sketch2.len()) {
            if sketch1[i].hash < sketch2[j].hash {
                i += 1;
            } else if sketch2[j].hash < sketch1[i].hash {
                j += 1;
            } else {
                i += 1;
                j += 1;
                common += 1;
            }
            total += 1;
        }

        if total < sketch_size as u64 {
            if i < sketch1.len() {
                total += (sketch1.len() - 1) as u64;
            }

            if j < sketch2.len() {
                total += (sketch2.len() - 1) as u64;
            }

            if total > sketch_size as u64 {
                total = sketch_size as u64;
            }
        }

        let containment: f64 = common as f64 / i as f64;
        let jaccard: f64 = common as f64 / total as f64;
        (containment, jaccard, common, total)
    }

    #[test]
    fn test_mash_compatibility() {
        // these are the same test conditions as in `test_raw_distance` but
        // against our translation of the mash distance code. this is just
        // here to sanity check some of our assumptions about how the
        // distances should be calculated; the main difference being in how
        // the original formula calculated the denominator

        let (cont, _jac, _com, _total) = mash_paper_distance(&kc(&[0, 1, 2]), &kc(&[1, 2]));
        assert_eq!(cont, 2. / 2.); // note this is actually 1./1.
                                   // assert_eq!(jac, 2. / 3.);
                                   // assert_eq!(com, 2);
                                   // assert_eq!(total, 3);

        let (_cont, _jac, _com, _total) = mash_paper_distance(&kc(&[0, 2]), &kc(&[1, 2]));
        // assert_eq!(cont, 1. / 2.);
        // assert_eq!(jac, 1. / 3.);
        // assert_eq!(com, 1);
        // assert_eq!(total, 3);

        let (_cont, jac, com, total) = mash_paper_distance(&kc(&[0, 1]), &kc(&[2, 3]));
        // assert_eq!(cont, 0. / 2.);
        assert_eq!(jac, 0. / 2.);
        assert_eq!(com, 0);
        assert_eq!(total, 2);
    }

    #[test]
    fn test_distance_scaled() -> Result<(), Box<dyn std::error::Error>> {
        use crate::sketch_schemes::scaled::ScaledSketcher;
        use crate::sketch_schemes::SketchScheme;

        let mut queue1 = ScaledSketcher::new(3, 0.001, 2, 42);
        queue1.push(b"ca", 0);
        queue1.push(b"cc", 1);
        queue1.push(b"ac", 0);
        queue1.push(b"ac", 1);
        let array1 = queue1.to_sketch();

        let mut queue2 = ScaledSketcher::new(3, 0.001, 2, 42);
        queue2.push(b"ca", 0);
        queue2.push(b"cc", 1);
        queue2.push(b"ac", 0);
        queue2.push(b"ac", 1);
        let array2 = queue2.to_sketch();

        let dist = distance(&array1, &array2, false)?;
        assert_eq!(dist.jaccard, 1.0);
        assert_eq!(dist.containment, 1.0);
        assert_eq!(dist.common_hashes, 3);

        Ok(())
    }
}

/// This computes set statistics from one set of hashes to another.
///
/// Every hash in the reference set is considered while only those hashes in the
/// query set that are in the same range as the reference set are compared. This
/// should be a more accurate representation of the query set's containment in
/// the reference set because we consider all of the reference set. In
/// practice, there may be issues especially if the query is sketched to a
/// different effective scale than the reference.
pub fn old_distance(query_sketch: &[KmerCount], ref_sketch: &[KmerCount]) -> (f64, f64, u64, u64) {
    let mut i: usize = 0;
    let mut common: u64 = 0;
    let mut total: u64 = 0;

    for ref_hash in ref_sketch {
        while (query_sketch[i].hash < ref_hash.hash) && (i < query_sketch.len() - 1) {
            i += 1;
        }

        if query_sketch[i].hash == ref_hash.hash {
            common += 1;
        }

        total += 1;
    }

    // Numerator is A-intersect-B, |A| is the denominator, we enforce |A| == |B|
    let containment: f64 = common as f64 / total as f64;
    let jaccard: f64 = common as f64 / (common + 2 * (total - common)) as f64;
    (containment, jaccard, common, total)
}

// TODO: add another method like this to allow 0's in ref sketch for hashes present in sketches?
// TODO: maybe we want to do NNLS on these matrices in Rust? for example code, see:
// https://github.com/igmanthony/fnnls/blob/master/src/fnnls.rs
// (for comments about that code also see https://github.com/rust-ndarray/ndarray/issues/649 )
pub fn minmer_matrix<U>(ref_sketch: &[KmerCount], sketches: &[U]) -> Array2<i32>
where
    U: AsRef<[KmerCount]>,
{
    let mut result = Array2::<i32>::zeros((sketches.len(), ref_sketch.len()));

    for (i, sketch) in sketches.iter().map(|s| s.as_ref()).enumerate() {
        let mut ref_pos = 0;
        for hash in sketch.iter() {
            while (hash.hash > ref_sketch[ref_pos].hash) && (ref_pos < ref_sketch.len() - 1) {
                ref_pos += 1;
            }

            if hash.hash == ref_sketch[ref_pos].hash {
                result[[i, ref_pos]] = hash.count as i32;
            }
        }
    }
    result
}
<commit_msg> Make raw_distance function commutative  (#47)<commit_after>use std::cmp::Ordering;

use ndarray::Array2;

use crate::serialization::{Sketch, SketchDistance};
use crate::sketch_schemes::KmerCount;

pub fn distance(
    query_sketch: &Sketch,
    ref_sketch: &Sketch,
    old_mode: bool,
) -> Result<SketchDistance, &'static str> {
    let distances = if old_mode {
        old_distance(&query_sketch.hashes, &ref_sketch.hashes)
    } else {
        // since we always examine to the lowest of the sketch maxima, a
        // min_scale of 0 is a noop; otherwise we only set a scale if both of
        // the sketches are scaled (there may be a slight improvement in
        // comparing a unscaled "higher range" sketch to a scaled lower range
        // using the scale, but that makes things more complicated because we
        // need two scale values, etc)
        let mut min_scale = 0.;
        if let Some(scale1) = query_sketch.sketch_params.hash_info().3 {
            if let Some(scale2) = ref_sketch.sketch_params.hash_info().3 {
                min_scale = f64::min(scale1, scale2);
            }
        }
        raw_distance(&query_sketch.hashes, &ref_sketch.hashes, min_scale)
    };

    let containment = distances.0;
    let jaccard = distances.1;
    let common_hashes = distances.2;
    let total_hashes = distances.3;
    let k = query_sketch.sketch_params.k() as f64;
    let mash_distance: f64 = -1.0 * ((2.0 * jaccard) / (1.0 + jaccard)).ln() / k;
    Ok(SketchDistance {
        containment,
        jaccard,
        mash_distance: f64::min(1f64, f64::max(0f64, mash_distance)),
        common_hashes,
        total_hashes,
        query: query_sketch.name.to_string(),
        reference: ref_sketch.name.to_string(),
    })
}

/// Estimates set statistics based on two slices of `KmerCount` sorted by hash,
/// ignoring hashes past a certain point (details below).
///
/// Returns a tuple of the form (containment,
/// [jaccard index](https://en.wikipedia.org/wiki/Jaccard_index),
/// size of [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory)),
/// size of [union](https://en.wikipedia.org/wiki/Union_(set_theory))).
///
/// Ignores hashes that are greater than `scale` * the maximum possible hash
/// (i.e. `u64::max_value()`). A scale of `0_f64` indicates to not ignore
/// hashes for this reason. Additionally ignores a slice's hashes if they are
/// greater than the other slice's maximum hash; this method better
/// approximates the document distance when the documents are of different
/// or of unknown sizes.
///
/// If the `KmerCount` slice arguments are not sorted by hash, the values of
/// the returned set statistics are unspecified.
pub fn raw_distance(
    query_hashes: &[KmerCount],
    ref_hashes: &[KmerCount],
    scale: f64,
) -> (f64, f64, u64, u64) {
    fn kmers_are_sorted(kmer_counts: &[KmerCount]) -> bool {
        for slice in kmer_counts.windows(2) {
            if slice[0].hash > slice[1].hash {
                return false;
            }
        }
        true
    }
    debug_assert!(kmers_are_sorted(query_hashes));
    debug_assert!(kmers_are_sorted(ref_hashes));

    let mut i: usize = 0;
    let mut j: usize = 0;
    let mut common: u64 = 0;
    while let (Some(query), Some(refer)) = (query_hashes.get(i), ref_hashes.get(j)) {
        match query.hash.cmp(&refer.hash) {
            Ordering::Less => i += 1,
            Ordering::Greater => j += 1,
            Ordering::Equal => {
                common += 1;
                i += 1;
                j += 1;
            }
        }
    }

    // at this point we've exhausted one of the two sketches, but we may have
    // more counts in the other to compare if these were scaled sketches
    if scale > 0. {
        let max_hash = u64::max_value() / scale.recip() as u64;
        while query_hashes
            .get(i)
            .map(|kmer_count| kmer_count.hash < max_hash)
            .unwrap_or(false)
        {
            i += 1;
        }
        while ref_hashes
            .get(j)
            .map(|kmer_count| kmer_count.hash < max_hash)
            .unwrap_or(false)
        {
            j += 1;
        }
    }

    let containment = if j == 0 { 0. } else { common as f64 / j as f64 };
    let total = i as u64 - common + j as u64;
    let jaccard: f64 = if total == 0 {
        1.
    } else {
        common as f64 / total as f64
    };

    (containment, jaccard, common, total)
}

#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;

    fn kc(arr: &[u64]) -> Vec<KmerCount> {
        arr.iter()
            .map(|x| KmerCount {
                hash: *x,
                kmer: vec![],
                count: 1,
                extra_count: 1,
                label: None,
            })
            .collect()
    }

    proptest! {
        #[test]
        fn test_raw_distance_commutes(mut query_hashes: Vec<u64>, mut ref_hashes: Vec<u64>) {
            query_hashes.sort();
            ref_hashes.sort();
            let lhs = kc(&query_hashes);
            let rhs = kc(&ref_hashes);
            prop_assert_eq!(raw_distance(&lhs, &rhs, 0.), raw_distance(&rhs, &lhs, 0.));
        }
    }

    #[test]
    fn test_raw_distance() {
        let (cont, jac, com, total) = raw_distance(&kc(&[0, 1, 2]), &kc(&[1, 2]), 0.);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        let (cont, jac, com, total) = raw_distance(&kc(&[0, 2]), &kc(&[1, 2]), 0.);
        assert_eq!(cont, 1. / 2.);
        assert_eq!(jac, 1. / 3.);
        assert_eq!(com, 1);
        assert_eq!(total, 3);

        let (cont, jac, com, total) = raw_distance(&kc(&[0, 1]), &kc(&[2, 3]), 0.);
        assert_eq!(cont, 0. / 2.);
        assert_eq!(jac, 0. / 2.);
        assert_eq!(com, 0);
        assert_eq!(total, 2);

        assert_eq!((0., 1., 0, 0), raw_distance(&kc(&[]), &kc(&[]), 0.));
        assert_eq!((0., 1., 0, 0), raw_distance(&kc(&[]), &kc(&[5]), 0.));
    }

    #[test]
    fn test_raw_distance_scaled() {
        // note  below that a scale cutoff of 1e-18 translates to a max_hash of 18

        // if the hashes extend above the scale just ignore
        let (cont, jac, com, total) = raw_distance(&kc(&[10, 15, 20]), &kc(&[15, 20]), 1e-18);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        // otherwise, include the extra hashes outside the range
        let (cont, jac, com, total) = raw_distance(&kc(&[5, 10, 15]), &kc(&[5, 10]), 1e-18);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        // only include up to the scale boundary though
        let (cont, jac, com, total) = raw_distance(&kc(&[5, 10, 15, 20]), &kc(&[5, 10]), 1e-18);
        assert_eq!(cont, 2. / 2.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);

        // and check in the reverse for the containment
        let (cont, jac, com, total) = raw_distance(&kc(&[5, 10]), &kc(&[5, 10, 15, 20]), 1e-18);
        assert_eq!(cont, 2. / 3.);
        assert_eq!(jac, 2. / 3.);
        assert_eq!(com, 2);
        assert_eq!(total, 3);
    }

    /// This is a straight transcription of the calculation used in Mash
    /// itself; now used for compatibility testing
    fn mash_paper_distance(sketch2: &[KmerCount], sketch1: &[KmerCount]) -> (f64, f64, u64, u64) {
        let mut i: usize = 0;
        let mut j: usize = 0;
        let mut common: u64 = 0;
        let mut total: u64 = 0;
        let sketch_size = sketch1.len();

        while (total < sketch_size as u64) && (i < sketch1.len()) && (j < sketch2.len()) {
            if sketch1[i].hash < sketch2[j].hash {
                i += 1;
            } else if sketch2[j].hash < sketch1[i].hash {
                j += 1;
            } else {
                i += 1;
                j += 1;
                common += 1;
            }
            total += 1;
        }

        if total < sketch_size as u64 {
            if i < sketch1.len() {
                total += (sketch1.len() - 1) as u64;
            }

            if j < sketch2.len() {
                total += (sketch2.len() - 1) as u64;
            }

            if total > sketch_size as u64 {
                total = sketch_size as u64;
            }
        }

        let containment: f64 = common as f64 / i as f64;
        let jaccard: f64 = common as f64 / total as f64;
        (containment, jaccard, common, total)
    }

    #[test]
    fn test_mash_compatibility() {
        // these are the same test conditions as in `test_raw_distance` but
        // against our translation of the mash distance code. this is just
        // here to sanity check some of our assumptions about how the
        // distances should be calculated; the main difference being in how
        // the original formula calculated the denominator

        let (cont, _jac, _com, _total) = mash_paper_distance(&kc(&[0, 1, 2]), &kc(&[1, 2]));
        assert_eq!(cont, 2. / 2.); // note this is actually 1./1.
                                   // assert_eq!(jac, 2. / 3.);
                                   // assert_eq!(com, 2);
                                   // assert_eq!(total, 3);

        let (_cont, _jac, _com, _total) = mash_paper_distance(&kc(&[0, 2]), &kc(&[1, 2]));
        // assert_eq!(cont, 1. / 2.);
        // assert_eq!(jac, 1. / 3.);
        // assert_eq!(com, 1);
        // assert_eq!(total, 3);

        let (_cont, jac, com, total) = mash_paper_distance(&kc(&[0, 1]), &kc(&[2, 3]));
        // assert_eq!(cont, 0. / 2.);
        assert_eq!(jac, 0. / 2.);
        assert_eq!(com, 0);
        assert_eq!(total, 2);
    }

    #[test]
    fn test_distance_scaled() -> Result<(), Box<dyn std::error::Error>> {
        use crate::sketch_schemes::scaled::ScaledSketcher;
        use crate::sketch_schemes::SketchScheme;

        let mut queue1 = ScaledSketcher::new(3, 0.001, 2, 42);
        queue1.push(b"ca", 0);
        queue1.push(b"cc", 1);
        queue1.push(b"ac", 0);
        queue1.push(b"ac", 1);
        let array1 = queue1.to_sketch();

        let mut queue2 = ScaledSketcher::new(3, 0.001, 2, 42);
        queue2.push(b"ca", 0);
        queue2.push(b"cc", 1);
        queue2.push(b"ac", 0);
        queue2.push(b"ac", 1);
        let array2 = queue2.to_sketch();

        let dist = distance(&array1, &array2, false)?;
        assert_eq!(dist.jaccard, 1.0);
        assert_eq!(dist.containment, 1.0);
        assert_eq!(dist.common_hashes, 3);

        Ok(())
    }
}

/// This computes set statistics from one set of hashes to another.
///
/// Every hash in the reference set is considered while only those hashes in the
/// query set that are in the same range as the reference set are compared. This
/// should be a more accurate representation of the query set's containment in
/// the reference set because we consider all of the reference set. In
/// practice, there may be issues especially if the query is sketched to a
/// different effective scale than the reference.
pub fn old_distance(query_sketch: &[KmerCount], ref_sketch: &[KmerCount]) -> (f64, f64, u64, u64) {
    let mut i: usize = 0;
    let mut common: u64 = 0;
    let mut total: u64 = 0;

    for ref_hash in ref_sketch {
        while (query_sketch[i].hash < ref_hash.hash) && (i < query_sketch.len() - 1) {
            i += 1;
        }

        if query_sketch[i].hash == ref_hash.hash {
            common += 1;
        }

        total += 1;
    }

    // Numerator is A-intersect-B, |A| is the denominator, we enforce |A| == |B|
    let containment: f64 = common as f64 / total as f64;
    let jaccard: f64 = common as f64 / (common + 2 * (total - common)) as f64;
    (containment, jaccard, common, total)
}

// TODO: add another method like this to allow 0's in ref sketch for hashes present in sketches?
// TODO: maybe we want to do NNLS on these matrices in Rust? for example code, see:
// https://github.com/igmanthony/fnnls/blob/master/src/fnnls.rs
// (for comments about that code also see https://github.com/rust-ndarray/ndarray/issues/649 )
pub fn minmer_matrix<U>(ref_sketch: &[KmerCount], sketches: &[U]) -> Array2<i32>
where
    U: AsRef<[KmerCount]>,
{
    let mut result = Array2::<i32>::zeros((sketches.len(), ref_sketch.len()));

    for (i, sketch) in sketches.iter().map(|s| s.as_ref()).enumerate() {
        let mut ref_pos = 0;
        for hash in sketch.iter() {
            while (hash.hash > ref_sketch[ref_pos].hash) && (ref_pos < ref_sketch.len() - 1) {
                ref_pos += 1;
            }

            if hash.hash == ref_sketch[ref_pos].hash {
                result[[i, ref_pos]] = hash.count as i32;
            }
        }
    }
    result
}
<|endoftext|>


<commit_before>use indoc::indoc;
use serde::de::{Deserialize, SeqAccess, Visitor};
use serde_derive::Deserialize;
use serde_yaml::Deserializer;
use std::collections::BTreeMap;
use std::fmt::{self, Debug};

fn test_error<T>(yaml: &str, expected: &str)
where
    T: serde::de::DeserializeOwned + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        b:
          - !C
            d: fase
    "};
    let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 1 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_second_document_syntax_error() {
    let yaml = indoc! {"
        ---
        0
        ---
        ]
    "};

    let mut de = Deserializer::from_str(yaml);
    let first_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(first_doc);
    assert_eq!(0, result.unwrap());

    let second_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(second_doc);
    let expected = "did not find expected node content at line 4 column 1, while parsing a block node at line 4 column 1";
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_missing_enum_tag() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        "V": 16
        "other": 32
    "#};
    let expected = "invalid type: map, expected a YAML tag starting with '!' at position 0";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_variant_not_a_seq() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        !V
        value: 0
    "#};
    let expected = "invalid type: map, expected usize at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "[".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 129";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_billion_laughs() {
    #[derive(Debug)]
    struct X;

    impl<'de> Deserialize<'de> for X {
        fn deserialize<D>(deserializer: D) -> Result<X, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            impl<'de> Visitor<'de> for X {
                type Value = X;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("exponential blowup")
                }

                fn visit_unit<E>(self) -> Result<X, E> {
                    Ok(X)
                }

                fn visit_seq<S>(self, mut seq: S) -> Result<X, S::Error>
                where
                    S: SeqAccess<'de>,
                {
                    while let Some(X) = seq.next_element()? {}
                    Ok(X)
                }
            }

            deserializer.deserialize_any(X)
        }
    }

    let yaml = indoc! {"
        a: &a ~
        b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
        c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
        d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
        e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
        f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
        g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
        h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
        i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
    "};
    let expected = "repetition limit exceeded";
    test_error::<BTreeMap<String, X>>(yaml, expected);
}
<commit_msg>Ignore zero_sized_map_values pedantic clippy lint<commit_after>#![allow(clippy::zero_sized_map_values)]

use indoc::indoc;
use serde::de::{Deserialize, SeqAccess, Visitor};
use serde_derive::Deserialize;
use serde_yaml::Deserializer;
use std::collections::BTreeMap;
use std::fmt::{self, Debug};

fn test_error<T>(yaml: &str, expected: &str)
where
    T: serde::de::DeserializeOwned + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        b:
          - !C
            d: fase
    "};
    let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 1 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_second_document_syntax_error() {
    let yaml = indoc! {"
        ---
        0
        ---
        ]
    "};

    let mut de = Deserializer::from_str(yaml);
    let first_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(first_doc);
    assert_eq!(0, result.unwrap());

    let second_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(second_doc);
    let expected = "did not find expected node content at line 4 column 1, while parsing a block node at line 4 column 1";
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_missing_enum_tag() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        "V": 16
        "other": 32
    "#};
    let expected = "invalid type: map, expected a YAML tag starting with '!' at position 0";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_variant_not_a_seq() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        !V
        value: 0
    "#};
    let expected = "invalid type: map, expected usize at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "[".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 129";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_billion_laughs() {
    #[derive(Debug)]
    struct X;

    impl<'de> Deserialize<'de> for X {
        fn deserialize<D>(deserializer: D) -> Result<X, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            impl<'de> Visitor<'de> for X {
                type Value = X;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("exponential blowup")
                }

                fn visit_unit<E>(self) -> Result<X, E> {
                    Ok(X)
                }

                fn visit_seq<S>(self, mut seq: S) -> Result<X, S::Error>
                where
                    S: SeqAccess<'de>,
                {
                    while let Some(X) = seq.next_element()? {}
                    Ok(X)
                }
            }

            deserializer.deserialize_any(X)
        }
    }

    let yaml = indoc! {"
        a: &a ~
        b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
        c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
        d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
        e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
        f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
        g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
        h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
        i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
    "};
    let expected = "repetition limit exceeded";
    test_error::<BTreeMap<String, X>>(yaml, expected);
}
<|endoftext|>


<commit_before>use card;
use std::fmt;

mod tests;

pub struct Hand {
    pub cards: Vec<card::Card>
}

impl Hand {
    pub fn new(mut cards: Vec<card::Card>) -> Hand {
        cards.sort();
        Hand {
            cards: cards
        }
    }

    pub fn has_flush(&self) -> bool {
        let suit: card::Suit = self.cards.get(0).unwrap().suit.clone();
        for card in &self.cards {
            if card.suit != suit {
                return false
            }
        }
        true
    }
}

impl fmt::Display for Hand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {} {} {} {}", self.cards.get(0).unwrap(),
                                    self.cards.get(1).unwrap(),
                                    self.cards.get(2).unwrap(),
                                    self.cards.get(3).unwrap(),
                                    self.cards.get(4).unwrap())
    }
}

#[derive(Debug, PartialEq)]
pub enum PokerHand {
    HighCard((card::Card)),
    OnePair((card::Card, card::Card)),
    TwoPair((card::Card, card::Card), (card::Card)),
    Trips((card::Card, card::Card, card::Card)),
    Straight((card::Card, card::Card, card::Card, card::Card, card::Card)),
    Flush((card::Card, card::Card, card::Card, card::Card, card::Card)),
    FullHouse((card::Card, card::Card, card::Card), (card::Card, card::Card)),
    Quads((card::Card, card::Card, card::Card, card::Card)),
    StraightFlush((card::Card, card::Card, card::Card, card::Card, card::Card)),
}

impl PokerHand {
    fn raw_value(&self) -> u32 {
        match *self {
            PokerHand::HighCard(_) => 0,
            PokerHand::OnePair(_) => 1,
            PokerHand::TwoPair(_, _) => 2,
            PokerHand::Trips(_) => 3,
            PokerHand::Straight(_) => 4,
            PokerHand::Flush(_) => 5,
            PokerHand::FullHouse(_, _) => 6,
            PokerHand::Quads(_) => 7,
            PokerHand::StraightFlush(_) => 8,
        }
    }
}
<commit_msg>Fixed bug in TwoPair tuple<commit_after>use card;
use std::fmt;

mod tests;

pub struct Hand {
    pub cards: Vec<card::Card>
}

impl Hand {
    pub fn new(mut cards: Vec<card::Card>) -> Hand {
        cards.sort();
        Hand {
            cards: cards
        }
    }

    pub fn has_flush(&self) -> bool {
        let suit: card::Suit = self.cards.get(0).unwrap().suit.clone();
        for card in &self.cards {
            if card.suit != suit {
                return false
            }
        }
        true
    }
}

impl fmt::Display for Hand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {} {} {} {}", self.cards.get(0).unwrap(),
                                    self.cards.get(1).unwrap(),
                                    self.cards.get(2).unwrap(),
                                    self.cards.get(3).unwrap(),
                                    self.cards.get(4).unwrap())
    }
}

#[derive(Debug, PartialEq)]
pub enum PokerHand {
    HighCard((card::Card)),
    OnePair((card::Card, card::Card)),
    TwoPair((card::Card, card::Card), (card::Card, card::Card)),
    Trips((card::Card, card::Card, card::Card)),
    Straight((card::Card, card::Card, card::Card, card::Card, card::Card)),
    Flush((card::Card, card::Card, card::Card, card::Card, card::Card)),
    FullHouse((card::Card, card::Card, card::Card), (card::Card, card::Card)),
    Quads((card::Card, card::Card, card::Card, card::Card)),
    StraightFlush((card::Card, card::Card, card::Card, card::Card, card::Card)),
}

impl PokerHand {
    fn raw_value(&self) -> u32 {
        match *self {
            PokerHand::HighCard(_) => 0,
            PokerHand::OnePair(_) => 1,
            PokerHand::TwoPair(_, _) => 2,
            PokerHand::Trips(_) => 3,
            PokerHand::Straight(_) => 4,
            PokerHand::Flush(_) => 5,
            PokerHand::FullHouse(_, _) => 6,
            PokerHand::Quads(_) => 7,
            PokerHand::StraightFlush(_) => 8,
        }
    }
}
<|endoftext|>


<commit_before>#![allow(clippy::derive_partial_eq_without_eq, clippy::eq_op)]

use indoc::indoc;
use serde::de::IntoDeserializer;
use serde::Deserialize;
use serde_derive::Deserialize;
use serde_yaml::{Number, Value};

#[test]
fn test_nan() {
    let pos_nan = serde_yaml::from_str::<Value>(".nan").unwrap();
    assert!(pos_nan.is_f64());
    assert_eq!(pos_nan, pos_nan);

    let neg_fake_nan = serde_yaml::from_str::<Value>("-.nan").unwrap();
    assert!(neg_fake_nan.is_string());

    let significand_mask = 0xF_FFFF_FFFF_FFFF;
    let bits = (f64::NAN.to_bits() ^ significand_mask) | 1;
    let different_pos_nan = Value::Number(Number::from(f64::from_bits(bits)));
    assert_eq!(pos_nan, different_pos_nan);
}

#[test]
fn test_digits() {
    let num_string = serde_yaml::from_str::<Value>("01").unwrap();
    assert!(num_string.is_string());
}

#[test]
fn test_into_deserializer() {
    #[derive(Debug, Deserialize, PartialEq)]
    struct Test {
        first: String,
        second: u32,
    }

    let value = serde_yaml::from_str::<Value>("xyz").unwrap();
    let s = String::deserialize(value.into_deserializer()).unwrap();
    assert_eq!(s, "xyz");

    let value = serde_yaml::from_str::<Value>("- first\n- second\n- third").unwrap();
    let arr = Vec::<String>::deserialize(value.into_deserializer()).unwrap();
    assert_eq!(arr, &["first", "second", "third"]);

    let value = serde_yaml::from_str::<Value>("first: abc\nsecond: 99").unwrap();
    let test = Test::deserialize(value.into_deserializer()).unwrap();
    assert_eq!(
        test,
        Test {
            first: "abc".to_string(),
            second: 99
        }
    );
}

#[test]
fn test_merge() {
    // From https://yaml.org/type/merge.html.
    let yaml = indoc! {"
        ---
        - &CENTER { x: 1, y: 2 }
        - &LEFT { x: 0, y: 2 }
        - &BIG { r: 10 }
        - &SMALL { r: 1 }

        # All the following maps are equal:

        - # Explicit keys
          x: 1
          y: 2
          r: 10
          label: center/big

        - # Merge one map
          << : *CENTER
          r: 10
          label: center/big

        - # Merge multiple maps
          << : [ *CENTER, *BIG ]
          label: center/big

        - # Override
          << : [ *BIG, *LEFT, *SMALL ]
          x: 1
          label: center/big
    "};

    let mut value: Value = serde_yaml::from_str(yaml).unwrap();
    value.apply_merge().unwrap();
    for i in 5..=7 {
        assert_eq!(value[4], value[i]);
    }
}

#[test]
fn test_debug() {
    let yaml = indoc! {"
        Null: ~
        Bool: true
        Number: 1
        String: ...
        Sequence:
          - true
        EmptySequence: []
        EmptyMapping: {}
        Tagged: !tag true
    "};

    let value: Value = serde_yaml::from_str(yaml).unwrap();
    let debug = format!("{:#?}", value);

    let expected = indoc! {r#"
        Mapping {
            "Null": Null,
            "Bool": Bool(true),
            "Number": Number(1),
            "String": String("..."),
            "Sequence": Sequence [
                Bool(true),
            ],
            "EmptySequence": Sequence [],
            "EmptyMapping": Mapping {},
            "Tagged": TaggedValue {
                tag: !tag,
                value: Bool(true),
            },
        }"#
    };

    assert_eq!(debug, expected);
}
<commit_msg>Add TaggedValue to_value/from_value test<commit_after>#![allow(clippy::derive_partial_eq_without_eq, clippy::eq_op)]

use indoc::indoc;
use serde::de::IntoDeserializer;
use serde::Deserialize;
use serde_derive::{Deserialize, Serialize};
use serde_yaml::{Number, Value};

#[test]
fn test_nan() {
    let pos_nan = serde_yaml::from_str::<Value>(".nan").unwrap();
    assert!(pos_nan.is_f64());
    assert_eq!(pos_nan, pos_nan);

    let neg_fake_nan = serde_yaml::from_str::<Value>("-.nan").unwrap();
    assert!(neg_fake_nan.is_string());

    let significand_mask = 0xF_FFFF_FFFF_FFFF;
    let bits = (f64::NAN.to_bits() ^ significand_mask) | 1;
    let different_pos_nan = Value::Number(Number::from(f64::from_bits(bits)));
    assert_eq!(pos_nan, different_pos_nan);
}

#[test]
fn test_digits() {
    let num_string = serde_yaml::from_str::<Value>("01").unwrap();
    assert!(num_string.is_string());
}

#[test]
fn test_into_deserializer() {
    #[derive(Debug, Deserialize, PartialEq)]
    struct Test {
        first: String,
        second: u32,
    }

    let value = serde_yaml::from_str::<Value>("xyz").unwrap();
    let s = String::deserialize(value.into_deserializer()).unwrap();
    assert_eq!(s, "xyz");

    let value = serde_yaml::from_str::<Value>("- first\n- second\n- third").unwrap();
    let arr = Vec::<String>::deserialize(value.into_deserializer()).unwrap();
    assert_eq!(arr, &["first", "second", "third"]);

    let value = serde_yaml::from_str::<Value>("first: abc\nsecond: 99").unwrap();
    let test = Test::deserialize(value.into_deserializer()).unwrap();
    assert_eq!(
        test,
        Test {
            first: "abc".to_string(),
            second: 99
        }
    );
}

#[test]
fn test_merge() {
    // From https://yaml.org/type/merge.html.
    let yaml = indoc! {"
        ---
        - &CENTER { x: 1, y: 2 }
        - &LEFT { x: 0, y: 2 }
        - &BIG { r: 10 }
        - &SMALL { r: 1 }

        # All the following maps are equal:

        - # Explicit keys
          x: 1
          y: 2
          r: 10
          label: center/big

        - # Merge one map
          << : *CENTER
          r: 10
          label: center/big

        - # Merge multiple maps
          << : [ *CENTER, *BIG ]
          label: center/big

        - # Override
          << : [ *BIG, *LEFT, *SMALL ]
          x: 1
          label: center/big
    "};

    let mut value: Value = serde_yaml::from_str(yaml).unwrap();
    value.apply_merge().unwrap();
    for i in 5..=7 {
        assert_eq!(value[4], value[i]);
    }
}

#[test]
fn test_debug() {
    let yaml = indoc! {"
        Null: ~
        Bool: true
        Number: 1
        String: ...
        Sequence:
          - true
        EmptySequence: []
        EmptyMapping: {}
        Tagged: !tag true
    "};

    let value: Value = serde_yaml::from_str(yaml).unwrap();
    let debug = format!("{:#?}", value);

    let expected = indoc! {r#"
        Mapping {
            "Null": Null,
            "Bool": Bool(true),
            "Number": Number(1),
            "String": String("..."),
            "Sequence": Sequence [
                Bool(true),
            ],
            "EmptySequence": Sequence [],
            "EmptyMapping": Mapping {},
            "Tagged": TaggedValue {
                tag: !tag,
                value: Bool(true),
            },
        }"#
    };

    assert_eq!(debug, expected);
}

#[test]
fn test_tagged() {
    #[derive(Serialize)]
    enum Enum {
        Variant(usize),
    }

    let value = serde_yaml::to_value(&Enum::Variant(0)).unwrap();

    let deserialized: serde_yaml::Value = serde_yaml::from_value(value.clone()).unwrap();
    assert_eq!(value, deserialized);

    let serialized = serde_yaml::to_value(&value).unwrap();
    assert_eq!(value, serialized);
}
<|endoftext|>


<commit_before>
tag list[T] {
    cons(T, @list[T]);
    nil;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Flesh out the std.list module a touch.<commit_after>
import util.option;
import util.some;
import util.none;

// FIXME: It would probably be more appealing to define this as
// type list[T] = rec(T hd, option[@list[T]] tl), but at the moment
// our recursion rules do not permit that.

tag list[T] {
    cons(T, @list[T]);
    nil;
}

fn foldl[T,U](&list[T] ls, U u, fn(&T t, U u) -> U f) -> U {
  alt(ls) {
    case (cons[T](?hd, ?tl)) {
      auto u_ = f(hd, u);
      // FIXME: should use 'be' here, not 'ret'. But parametric
      // tail calls currently don't work.
      ret foldl[T,U](*tl, u_, f);
    }
    case (nil[T]) {
      ret u;
    }
  }
}

fn find[T](&list[T] ls,
             (fn(&T) -> option[T]) f) -> option[T] {
  alt(ls) {
    case (cons[T](?hd, ?tl)) {
        alt (f(hd)) {
            case (none[T]) {
                // FIXME: should use 'be' here, not 'ret'. But parametric tail
                // calls currently don't work.
                ret find[T](*tl, f);
            }
            case (some[T](?res)) {
                ret some[T](res);
            }
        }
    }
    case (nil[T]) {
        ret none[T];
    }
  }
}

fn length[T](&list[T] ls) -> uint {
  fn count[T](&T t, uint u) -> uint {
    ret u + 1u;
  }
  ret foldl[T,uint](ls, 0u, bind count[T](_, _));
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>