<commit_before>use bio::io::fastq;
use rust_htslib::bam;
use rust_htslib::bam::Read;
use std::fs;
use std::process::Command;

/// Compare an output file to the expected output and delete the output file.
fn test_output(result: &str, expected: &str) {
    assert!(Command::new("cmp")
        .arg(result)
        .arg(expected)
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    fs::remove_file(result).unwrap();
}

/// Compare two fastq files, ignoring the name lines
/// Reads are sorted by their sequence, which is not 100% robust
/// if mutations/ sequencing errors are considered.
fn compare_fastq(result: &str, expected: &str) {
    let result_reader = fastq::Reader::from_file(result).unwrap();
    let mut result_recs: Vec<fastq::Record> =
        result_reader.records().filter_map(Result::ok).collect();
    result_recs.sort_by_key(|x| x.seq().to_owned());
    let expected_reader = fastq::Reader::from_file(expected).unwrap();
    let mut expected_recs: Vec<fastq::Record> =
        expected_reader.records().filter_map(Result::ok).collect();
    expected_recs.sort_by_key(|x| x.seq().to_owned());

    for (result, expected) in result_recs.iter().zip(expected_recs.iter()) {
        assert_eq!(result.seq(), expected.seq());
        assert_eq!(result.qual(), expected.qual());
    }
}

fn compare_bam(result: &str, expected: &str) {
    let mut result_reader = bam::Reader::from_path(result).unwrap();
    let mut result_recs: Vec<bam::Record> =
        result_reader.records().filter_map(Result::ok).collect();
    result_recs.sort_by_key(|x| x.seq().as_bytes().to_owned());
    let mut expected_reader = bam::Reader::from_path(expected).unwrap();
    let mut expected_recs: Vec<bam::Record> =
        expected_reader.records().filter_map(Result::ok).collect();
    expected_recs.sort_by_key(|x| x.seq().as_bytes().to_owned());
    for (result, expected) in result_recs.iter().zip(expected_recs.iter()) {
        assert_eq!(result.seq().as_bytes(), expected.seq().as_bytes());
        assert_eq!(result.qual(), expected.qual());
    }
}

#[test]
fn fastq_split() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt fastq-split tests/A.fastq tests/B.fastq < tests/test.fastq")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/A.fastq", "tests/expected/A.fastq");
    test_output("tests/B.fastq", "tests/expected/B.fastq");
}

#[test]
fn fastq_filter() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg(
            "target/debug/rbt fastq-filter tests/ids.txt < tests/test.fastq > tests/filtered.fastq"
        )
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/filtered.fastq", "tests/expected/B.fastq");
}

#[test]
fn bam_depth() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt bam-depth tests/test.bam < tests/pos.txt > tests/depth.txt")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/depth.txt", "tests/expected/depth.txt");
}

#[test]
fn vcf_to_txt() {
    assert!(Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt vcf-to-txt --genotypes --fmt S --info T X SOMATIC < tests/test.vcf > tests/variant-table.txt")
            .spawn().unwrap().wait().unwrap().success());
    test_output(
        "tests/variant-table.txt",
        "tests/expected/variant-table.txt",
    );
}

#[test]
fn vcf_match() {
    assert!(Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt vcf-match -d 50 -l 20 tests/test3.vcf < tests/test2.vcf > tests/matching.bcf")
            .spawn().unwrap().wait().unwrap().success());
    test_output("tests/matching.bcf", "tests/expected/matching.bcf");
}

#[test]
fn vcf_match_same() {
    assert!(Command::new("bash").arg("-c")
                                .arg("target/debug/rbt vcf-match -d 50 -l 20 tests/test4.vcf < tests/test4.vcf > tests/matching-same.bcf")
                                .spawn().unwrap().wait().unwrap().success());
    test_output(
        "tests/matching-same.bcf",
        "tests/expected/matching-same.bcf",
    );
}

#[test]
fn vcf_fix_iupac_alleles() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg(
            "target/debug/rbt vcf-fix-iupac-alleles < tests/test-iupac.vcf > tests/iupac-fixed.bcf"
        )
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/iupac-fixed.bcf", "tests/expected/iupac-fixed.bcf");
}

#[test]
fn vcf_baf() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt vcf-baf < tests/test-freebayes.vcf > tests/baf.bcf")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/baf.bcf", "tests/expected/baf.bcf");
}

#[test]
fn test_oncoprint() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt oncoprint a=tests/test-oncoprint.vcf b=tests/test-oncoprint.vcf > tests/oncoprint.html")
            .spawn()
            .unwrap()
            .wait()
            .unwrap()
            .success()
    );
    test_output("tests/oncoprint.html", "tests/expected/oncoprint.html");
}

#[test]
fn test_collapse_reads_to_fragments_two_cluster() {
    assert!(
        Command::new("bash")
                .arg("-c")
                .arg("target/debug/rbt collapse-reads-to-fragments fastq --umi-len 3 -u --max-umi-dist 0 --max-seq-dist 2 tests/test-consensus.fastq tests/test-consensus.fastq /tmp/test-consensus.1.fastq /tmp/test-consensus.2.fastq")
            .spawn().unwrap().wait().unwrap().success());
    compare_fastq(
        "/tmp/test-consensus.1.fastq",
        "tests/expected/test-consensus.1.fastq",
    );
    compare_fastq(
        "/tmp/test-consensus.2.fastq",
        "tests/expected/test-consensus.2.fastq",
    );
}

#[test]
fn test_collapse_reads_to_fragments_single_cluster() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt collapse-reads-to-fragments fastq --umi-len 3 -u --max-umi-dist 2 --max-seq-dist 2 tests/test-consensus.fastq tests/test-consensus.fastq /tmp/test-consensus_single.1.fastq /tmp/test-consensus_single.2.fastq")
            .spawn().unwrap().wait().unwrap().success());
    compare_fastq(
        "/tmp/test-consensus_single.1.fastq",
        "tests/expected/test-consensus_single.1.fastq",
    );
    compare_fastq(
        "/tmp/test-consensus_single.2.fastq",
        "tests/expected/test-consensus_single.2.fastq",
    );
}

#[test]
fn test_collapse_reads_to_fragments_reads() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt collapse-reads-to-fragments fastq --umi-len 10 --max-umi-dist 0 --max-seq-dist 8 --insert-size 450 --std-dev 50  tests/overlapping-consensus.1.fastq tests/overlapping-consensus.2.fastq /tmp/test_overlapping-consensus.1.fastq /tmp/test_overlapping-consensus.2.fastq /tmp/test_overlapping-consensus.3.fastq")
            .spawn().unwrap().wait().unwrap().success());
    compare_fastq(
        "/tmp/test_overlapping-consensus.1.fastq",
        "tests/expected/test_overlapping-consensus.1.fastq",
    );
    compare_fastq(
        "/tmp/test_overlapping-consensus.2.fastq",
        "tests/expected/test_overlapping-consensus.2.fastq",
    );
    compare_fastq(
        "/tmp/test_overlapping-consensus.3.fastq",
        "tests/expected/test_overlapping-consensus.3.fastq",
    );
}

#[test]
fn test_collapse_reads_to_fragments_from_bam() {
    assert!(
    Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt collapse-reads-to-fragments bam --max-seq-dist 8 tests/overlapping_consensus_marked.bam /tmp/overlapping_consensus_marked.bam")
        .spawn().unwrap().wait().unwrap().success());
    compare_bam(
        "/tmp/overlapping_consensus_marked.bam",
        "tests/expected/overlapping_consensus_marked.bam",
    );
}

#[test]
fn test_vcf_annotate_dgidb() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt vcf-annotate-dgidb tests/annotate_dgidb_test.vcf > /tmp/annotate_dgidb_test.bcf")
            .spawn().unwrap().wait().unwrap().success());
    test_output(
        "/tmp/annotate_dgidb_test.bcf",
        "tests/expected/annotate_dgidb_test.bcf",
    );
}

#[test]
fn test_stats_fasta_file() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt sequence-stats < tests/stats.fasta > /tmp/result.fasta.stats")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());

    test_output(
        "/tmp/result.fasta.stats",
        "tests/expected/result.fasta.stats",
    );
}

#[test]
fn test_stats_fastq_file() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt sequences-stats -q < tests/stats.fastq > /tmp/result.fastq.stats")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());

    test_output(
        "/tmp/result.fastq.stats",
        "tests/expected/result.fastq.stats",
    );
}
<commit_msg>fix test<commit_after>use bio::io::fastq;
use rust_htslib::bam;
use rust_htslib::bam::Read;
use std::fs;
use std::process::Command;

/// Compare an output file to the expected output and delete the output file.
fn test_output(result: &str, expected: &str) {
    assert!(Command::new("cmp")
        .arg(result)
        .arg(expected)
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    fs::remove_file(result).unwrap();
}

/// Compare two fastq files, ignoring the name lines
/// Reads are sorted by their sequence, which is not 100% robust
/// if mutations/ sequencing errors are considered.
fn compare_fastq(result: &str, expected: &str) {
    let result_reader = fastq::Reader::from_file(result).unwrap();
    let mut result_recs: Vec<fastq::Record> =
        result_reader.records().filter_map(Result::ok).collect();
    result_recs.sort_by_key(|x| x.seq().to_owned());
    let expected_reader = fastq::Reader::from_file(expected).unwrap();
    let mut expected_recs: Vec<fastq::Record> =
        expected_reader.records().filter_map(Result::ok).collect();
    expected_recs.sort_by_key(|x| x.seq().to_owned());

    for (result, expected) in result_recs.iter().zip(expected_recs.iter()) {
        assert_eq!(result.seq(), expected.seq());
        assert_eq!(result.qual(), expected.qual());
    }
}

fn compare_bam(result: &str, expected: &str) {
    let mut result_reader = bam::Reader::from_path(result).unwrap();
    let mut result_recs: Vec<bam::Record> =
        result_reader.records().filter_map(Result::ok).collect();
    result_recs.sort_by_key(|x| x.seq().as_bytes().to_owned());
    let mut expected_reader = bam::Reader::from_path(expected).unwrap();
    let mut expected_recs: Vec<bam::Record> =
        expected_reader.records().filter_map(Result::ok).collect();
    expected_recs.sort_by_key(|x| x.seq().as_bytes().to_owned());
    for (result, expected) in result_recs.iter().zip(expected_recs.iter()) {
        assert_eq!(result.seq().as_bytes(), expected.seq().as_bytes());
        assert_eq!(result.qual(), expected.qual());
    }
}

#[test]
fn fastq_split() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt fastq-split tests/A.fastq tests/B.fastq < tests/test.fastq")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/A.fastq", "tests/expected/A.fastq");
    test_output("tests/B.fastq", "tests/expected/B.fastq");
}

#[test]
fn fastq_filter() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg(
            "target/debug/rbt fastq-filter tests/ids.txt < tests/test.fastq > tests/filtered.fastq"
        )
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/filtered.fastq", "tests/expected/B.fastq");
}

#[test]
fn bam_depth() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt bam-depth tests/test.bam < tests/pos.txt > tests/depth.txt")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/depth.txt", "tests/expected/depth.txt");
}

#[test]
fn vcf_to_txt() {
    assert!(Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt vcf-to-txt --genotypes --fmt S --info T X SOMATIC < tests/test.vcf > tests/variant-table.txt")
            .spawn().unwrap().wait().unwrap().success());
    test_output(
        "tests/variant-table.txt",
        "tests/expected/variant-table.txt",
    );
}

#[test]
fn vcf_match() {
    assert!(Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt vcf-match -d 50 -l 20 tests/test3.vcf < tests/test2.vcf > tests/matching.bcf")
            .spawn().unwrap().wait().unwrap().success());
    test_output("tests/matching.bcf", "tests/expected/matching.bcf");
}

#[test]
fn vcf_match_same() {
    assert!(Command::new("bash").arg("-c")
                                .arg("target/debug/rbt vcf-match -d 50 -l 20 tests/test4.vcf < tests/test4.vcf > tests/matching-same.bcf")
                                .spawn().unwrap().wait().unwrap().success());
    test_output(
        "tests/matching-same.bcf",
        "tests/expected/matching-same.bcf",
    );
}

#[test]
fn vcf_fix_iupac_alleles() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg(
            "target/debug/rbt vcf-fix-iupac-alleles < tests/test-iupac.vcf > tests/iupac-fixed.bcf"
        )
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/iupac-fixed.bcf", "tests/expected/iupac-fixed.bcf");
}

#[test]
fn vcf_baf() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt vcf-baf < tests/test-freebayes.vcf > tests/baf.bcf")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());
    test_output("tests/baf.bcf", "tests/expected/baf.bcf");
}

#[test]
fn test_oncoprint() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt oncoprint a=tests/test-oncoprint.vcf b=tests/test-oncoprint.vcf > tests/oncoprint.html")
            .spawn()
            .unwrap()
            .wait()
            .unwrap()
            .success()
    );
    test_output("tests/oncoprint.html", "tests/expected/oncoprint.html");
}

#[test]
fn test_collapse_reads_to_fragments_two_cluster() {
    assert!(
        Command::new("bash")
                .arg("-c")
                .arg("target/debug/rbt collapse-reads-to-fragments fastq --umi-len 3 -u --max-umi-dist 0 --max-seq-dist 2 tests/test-consensus.fastq tests/test-consensus.fastq /tmp/test-consensus.1.fastq /tmp/test-consensus.2.fastq")
            .spawn().unwrap().wait().unwrap().success());
    compare_fastq(
        "/tmp/test-consensus.1.fastq",
        "tests/expected/test-consensus.1.fastq",
    );
    compare_fastq(
        "/tmp/test-consensus.2.fastq",
        "tests/expected/test-consensus.2.fastq",
    );
}

#[test]
fn test_collapse_reads_to_fragments_single_cluster() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt collapse-reads-to-fragments fastq --umi-len 3 -u --max-umi-dist 2 --max-seq-dist 2 tests/test-consensus.fastq tests/test-consensus.fastq /tmp/test-consensus_single.1.fastq /tmp/test-consensus_single.2.fastq")
            .spawn().unwrap().wait().unwrap().success());
    compare_fastq(
        "/tmp/test-consensus_single.1.fastq",
        "tests/expected/test-consensus_single.1.fastq",
    );
    compare_fastq(
        "/tmp/test-consensus_single.2.fastq",
        "tests/expected/test-consensus_single.2.fastq",
    );
}

#[test]
fn test_collapse_reads_to_fragments_reads() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt collapse-reads-to-fragments fastq --umi-len 10 --max-umi-dist 0 --max-seq-dist 8 --insert-size 450 --std-dev 50  tests/overlapping-consensus.1.fastq tests/overlapping-consensus.2.fastq /tmp/test_overlapping-consensus.1.fastq /tmp/test_overlapping-consensus.2.fastq /tmp/test_overlapping-consensus.3.fastq")
            .spawn().unwrap().wait().unwrap().success());
    compare_fastq(
        "/tmp/test_overlapping-consensus.1.fastq",
        "tests/expected/test_overlapping-consensus.1.fastq",
    );
    compare_fastq(
        "/tmp/test_overlapping-consensus.2.fastq",
        "tests/expected/test_overlapping-consensus.2.fastq",
    );
    compare_fastq(
        "/tmp/test_overlapping-consensus.3.fastq",
        "tests/expected/test_overlapping-consensus.3.fastq",
    );
}

#[test]
fn test_collapse_reads_to_fragments_from_bam() {
    assert!(
    Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt collapse-reads-to-fragments bam --max-seq-dist 8 tests/overlapping_consensus_marked.bam /tmp/overlapping_consensus_marked.bam")
        .spawn().unwrap().wait().unwrap().success());
    compare_bam(
        "/tmp/overlapping_consensus_marked.bam",
        "tests/expected/overlapping_consensus_marked.bam",
    );
}

#[test]
fn test_vcf_annotate_dgidb() {
    assert!(
        Command::new("bash")
            .arg("-c")
            .arg("target/debug/rbt vcf-annotate-dgidb tests/annotate_dgidb_test.vcf > /tmp/annotate_dgidb_test.bcf")
            .spawn().unwrap().wait().unwrap().success());
    test_output(
        "/tmp/annotate_dgidb_test.bcf",
        "tests/expected/annotate_dgidb_test.bcf",
    );
}

#[test]
fn test_stats_fasta_file() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt sequence-stats < tests/stats.fasta > /tmp/result.fasta.stats")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());

    test_output(
        "/tmp/result.fasta.stats",
        "tests/expected/result.fasta.stats",
    );
}

#[test]
fn test_stats_fastq_file() {
    assert!(Command::new("bash")
        .arg("-c")
        .arg("target/debug/rbt sequence-stats -q < tests/stats.fastq > /tmp/result.fastq.stats")
        .spawn()
        .unwrap()
        .wait()
        .unwrap()
        .success());

    test_output(
        "/tmp/result.fastq.stats",
        "tests/expected/result.fastq.stats",
    );
}
<|endoftext|>


<commit_before>mod common;

use crate::common::assert_linked_with;
use linkify::LinkFinder;

#[test]
fn no_links() {
    assert_not_linked("");
    assert_not_linked("foo");
    assert_not_linked(":");
    assert_not_linked("://");
    assert_not_linked(":::");
}

#[test]
fn schemes() {
    assert_not_linked("://foo");
    assert_not_linked("1://foo");
    assert_not_linked("123://foo");
    assert_not_linked("+://foo");
    assert_not_linked("-://foo");
    assert_not_linked(".://foo");
    assert_not_linked("1abc://foo");
    assert_linked("a://foo", "|a://foo|");
    assert_linked("a123://foo", "|a123://foo|");
    assert_linked("a123b://foo", "|a123b://foo|");
    assert_linked("a+b://foo", "|a+b://foo|");
    assert_linked("a-b://foo", "|a-b://foo|");
    assert_linked("a.b://foo", "|a.b://foo|");
    assert_linked("ABC://foo", "|ABC://foo|");
    assert_linked(".http://example.org/", ".|http://example.org/|");
    assert_linked("1.http://example.org/", "1.|http://example.org/|");
}

#[test]
fn authority() {
    assert_not_linked("ab://");
    assert_not_linked("http://");
    assert_not_linked("http:// ");
    assert_not_linked("\"http://\"");
    assert_not_linked("\"http://...\", ");

    assert_linked("http://a.", "|http://a|.");
}

#[test]
fn single_links() {
    assert_linked("ab://c", "|ab://c|");
    assert_linked("http://example.org/", "|http://example.org/|");
    assert_linked("http://example.org/123", "|http://example.org/123|");
    assert_linked(
        "http://example.org/?foo=test&bar=123",
        "|http://example.org/?foo=test&bar=123|",
    );
    assert_linked(
        "http://example.org/?foo=%20",
        "|http://example.org/?foo=%20|",
    );
    assert_linked("http://example.org/%3C", "|http://example.org/%3C|");
}

#[test]
fn space_characters_stop_url() {
    assert_linked("foo http://example.org/", "foo |http://example.org/|");
    assert_linked("http://example.org/ bar", "|http://example.org/| bar");
    assert_linked("http://example.org/\tbar", "|http://example.org/|\tbar");
    assert_linked("http://example.org/\nbar", "|http://example.org/|\nbar");
    assert_linked(
        "http://example.org/\u{0B}bar",
        "|http://example.org/|\u{0B}bar",
    );
    assert_linked(
        "http://example.org/\u{0C}bar",
        "|http://example.org/|\u{0C}bar",
    );
    assert_linked("http://example.org/\rbar", "|http://example.org/|\rbar");
}

#[test]
fn illegal_characters_stop_url() {
    assert_linked("http://example.org/<", "|http://example.org/|<");
    assert_linked("http://example.org/>", "|http://example.org/|>");
    assert_linked("http://example.org/<>", "|http://example.org/|<>");
    assert_linked("http://example.org/\u{00}", "|http://example.org/|\u{00}");
    assert_linked("http://example.org/\u{0E}", "|http://example.org/|\u{0E}");
    assert_linked("http://example.org/\u{7F}", "|http://example.org/|\u{7F}");
    assert_linked("http://example.org/\u{9F}", "|http://example.org/|\u{9F}");
}

#[test]
fn delimiter_at_end() {
    assert_linked("http://example.org/.", "|http://example.org/|.");
    assert_linked("http://example.org/..", "|http://example.org/|..");
    assert_linked("http://example.org/,", "|http://example.org/|,");
    assert_linked("http://example.org/:", "|http://example.org/|:");
    assert_linked("http://example.org/?", "|http://example.org/|?");
    assert_linked("http://example.org/!", "|http://example.org/|!");
    assert_linked("http://example.org/;", "|http://example.org/|;");
}

#[test]
fn matching_punctuation() {
    assert_linked("http://example.org/a(b)", "|http://example.org/a(b)|");
    assert_linked("http://example.org/a[b]", "|http://example.org/a[b]|");
    assert_linked("http://example.org/a{b}", "|http://example.org/a{b}|");
    assert_linked("http://example.org/a'b'", "|http://example.org/a'b'|");
    assert_linked("(http://example.org/)", "(|http://example.org/|)");
    assert_linked("[http://example.org/]", "[|http://example.org/|]");
    assert_linked("{http://example.org/}", "{|http://example.org/|}");
    assert_linked("\"http://example.org/\"", "\"|http://example.org/|\"");
    assert_linked("'http://example.org/'", "'|http://example.org/|'");
}

#[test]
fn matching_punctuation_tricky() {
    assert_linked("((http://example.org/))", "((|http://example.org/|))");
    assert_linked(
        "((http://example.org/a(b)))",
        "((|http://example.org/a(b)|))",
    );
    assert_linked("[(http://example.org/)]", "[(|http://example.org/|)]");
    assert_linked("(http://example.org/).", "(|http://example.org/|).");
    assert_linked("(http://example.org/.)", "(|http://example.org/|.)");
    assert_linked("http://example.org/>", "|http://example.org/|>");
    // not sure about these
    assert_linked("http://example.org/(", "|http://example.org/|(");
    assert_linked("http://example.org/(.", "|http://example.org/|(.");
    assert_linked("http://example.org/]()", "|http://example.org/|]()");
}

#[test]
fn single_quote() {
    assert_linked(
        "http://example.org/\'_(foo)",
        "|http://example.org/\'_(foo)|",
    );
    assert_linked(
        "http://example.org/\'_(foo)\'",
        "|http://example.org/\'_(foo)\'|",
    );
    assert_linked("http://example.org/\'\'", "|http://example.org/\'\'|");
    assert_linked("http://example.org/\'\'\'", "|http://example.org/\'\'|\'");
    assert_linked("http://example.org/\'.", "|http://example.org/|\'.");
    assert_linked("http://example.org/\'a", "|http://example.org/\'a|");
    assert_linked("http://example.org/it's", "|http://example.org/it's|");
}

#[test]
fn double_quote() {
    // " not allowed in URLs
    assert_linked("http://example.org/\"a", "|http://example.org/|\"a");
    assert_linked("http://example.org/\"a\"", "|http://example.org/|\"a\"");
}

#[test]
fn grave_quote() {
    // ` not allowed in URLs
    assert_linked("http://example.org/`a", "|http://example.org/|`a");
    assert_linked("http://example.org/`a`", "|http://example.org/|`a`");
}

#[test]
fn html() {
    assert_linked("http://example.org\">", "|http://example.org|\">");
    assert_linked("http://example.org'>", "|http://example.org|'>");
    assert_linked("http://example.org\"/>", "|http://example.org|\"/>");
    assert_linked("http://example.org'/>", "|http://example.org|'/>");
    assert_linked("http://example.org
", "|http://example.org|
");
    assert_linked("http://example.org
", "|http://example.org|
");
}

#[test]
fn css() {
    assert_linked("http://example.org\");", "|http://example.org|\");");
    assert_linked("http://example.org');", "|http://example.org|');");
}

#[test]
fn images() {
    assert_linked(
        r#""#,
        r#""#,
    );
}

#[test]
fn slash() {
    assert_linked("http://example.org/", "|http://example.org/|");
    assert_linked("http://example.org/a/", "|http://example.org/a/|");
    assert_linked("http://example.org//", "|http://example.org//|");
}

#[test]
fn multiple() {
    assert_linked(
        "http://one.org/ http://two.org/",
        "|http://one.org/| |http://two.org/|",
    );
    assert_linked(
        "http://one.org/ : http://two.org/",
        "|http://one.org/| : |http://two.org/|",
    );
    assert_linked(
        "(http://one.org/)(http://two.org/)",
        "(|http://one.org/|)(|http://two.org/|)",
    );
}

#[test]
fn international() {
    assert_linked("http://üñîçøðé.com/ä", "|http://üñîçøðé.com/ä|");
    assert_linked("http://example.org/\u{A1}", "|http://example.org/\u{A1}|");
    assert_linked("http://example.org/\u{A2}", "|http://example.org/\u{A2}|");
    assert_linked(
        "http://example.org/\u{1F600}",
        "|http://example.org/\u{1F600}|",
    );
    assert_linked("http://example.org/\u{A2}/", "|http://example.org/\u{A2}/|");
    assert_linked(
        "http://xn--c1h.example.com/",
        "|http://xn--c1h.example.com/|",
    );
}

#[test]
fn fuzz() {
    assert_not_linked("ab:/ϸ");
}

fn assert_not_linked(s: &str) {
    assert_linked(s, s);
}

fn assert_linked(input: &str, expected: &str) {
    let finder = LinkFinder::new();
    assert_linked_with(&finder, input, expected);
}
<commit_msg>Test complex html<commit_after>mod common;

use crate::common::assert_linked_with;
use linkify::LinkFinder;

#[test]
fn no_links() {
    assert_not_linked("");
    assert_not_linked("foo");
    assert_not_linked(":");
    assert_not_linked("://");
    assert_not_linked(":::");
}

#[test]
fn schemes() {
    assert_not_linked("://foo");
    assert_not_linked("1://foo");
    assert_not_linked("123://foo");
    assert_not_linked("+://foo");
    assert_not_linked("-://foo");
    assert_not_linked(".://foo");
    assert_not_linked("1abc://foo");
    assert_linked("a://foo", "|a://foo|");
    assert_linked("a123://foo", "|a123://foo|");
    assert_linked("a123b://foo", "|a123b://foo|");
    assert_linked("a+b://foo", "|a+b://foo|");
    assert_linked("a-b://foo", "|a-b://foo|");
    assert_linked("a.b://foo", "|a.b://foo|");
    assert_linked("ABC://foo", "|ABC://foo|");
    assert_linked(".http://example.org/", ".|http://example.org/|");
    assert_linked("1.http://example.org/", "1.|http://example.org/|");
}

#[test]
fn authority() {
    assert_not_linked("ab://");
    assert_not_linked("http://");
    assert_not_linked("http:// ");
    assert_not_linked("\"http://\"");
    assert_not_linked("\"http://...\", ");

    assert_linked("http://a.", "|http://a|.");
}

#[test]
fn single_links() {
    assert_linked("ab://c", "|ab://c|");
    assert_linked("http://example.org/", "|http://example.org/|");
    assert_linked("http://example.org/123", "|http://example.org/123|");
    assert_linked(
        "http://example.org/?foo=test&bar=123",
        "|http://example.org/?foo=test&bar=123|",
    );
    assert_linked(
        "http://example.org/?foo=%20",
        "|http://example.org/?foo=%20|",
    );
    assert_linked("http://example.org/%3C", "|http://example.org/%3C|");
}

#[test]
fn space_characters_stop_url() {
    assert_linked("foo http://example.org/", "foo |http://example.org/|");
    assert_linked("http://example.org/ bar", "|http://example.org/| bar");
    assert_linked("http://example.org/\tbar", "|http://example.org/|\tbar");
    assert_linked("http://example.org/\nbar", "|http://example.org/|\nbar");
    assert_linked(
        "http://example.org/\u{0B}bar",
        "|http://example.org/|\u{0B}bar",
    );
    assert_linked(
        "http://example.org/\u{0C}bar",
        "|http://example.org/|\u{0C}bar",
    );
    assert_linked("http://example.org/\rbar", "|http://example.org/|\rbar");
}

#[test]
fn illegal_characters_stop_url() {
    assert_linked("http://example.org/<", "|http://example.org/|<");
    assert_linked("http://example.org/>", "|http://example.org/|>");
    assert_linked("http://example.org/<>", "|http://example.org/|<>");
    assert_linked("http://example.org/\u{00}", "|http://example.org/|\u{00}");
    assert_linked("http://example.org/\u{0E}", "|http://example.org/|\u{0E}");
    assert_linked("http://example.org/\u{7F}", "|http://example.org/|\u{7F}");
    assert_linked("http://example.org/\u{9F}", "|http://example.org/|\u{9F}");
}

#[test]
fn delimiter_at_end() {
    assert_linked("http://example.org/.", "|http://example.org/|.");
    assert_linked("http://example.org/..", "|http://example.org/|..");
    assert_linked("http://example.org/,", "|http://example.org/|,");
    assert_linked("http://example.org/:", "|http://example.org/|:");
    assert_linked("http://example.org/?", "|http://example.org/|?");
    assert_linked("http://example.org/!", "|http://example.org/|!");
    assert_linked("http://example.org/;", "|http://example.org/|;");
}

#[test]
fn matching_punctuation() {
    assert_linked("http://example.org/a(b)", "|http://example.org/a(b)|");
    assert_linked("http://example.org/a[b]", "|http://example.org/a[b]|");
    assert_linked("http://example.org/a{b}", "|http://example.org/a{b}|");
    assert_linked("http://example.org/a'b'", "|http://example.org/a'b'|");
    assert_linked("(http://example.org/)", "(|http://example.org/|)");
    assert_linked("[http://example.org/]", "[|http://example.org/|]");
    assert_linked("{http://example.org/}", "{|http://example.org/|}");
    assert_linked("\"http://example.org/\"", "\"|http://example.org/|\"");
    assert_linked("'http://example.org/'", "'|http://example.org/|'");
}

#[test]
fn matching_punctuation_tricky() {
    assert_linked("((http://example.org/))", "((|http://example.org/|))");
    assert_linked(
        "((http://example.org/a(b)))",
        "((|http://example.org/a(b)|))",
    );
    assert_linked("[(http://example.org/)]", "[(|http://example.org/|)]");
    assert_linked("(http://example.org/).", "(|http://example.org/|).");
    assert_linked("(http://example.org/.)", "(|http://example.org/|.)");
    assert_linked("http://example.org/>", "|http://example.org/|>");
    // not sure about these
    assert_linked("http://example.org/(", "|http://example.org/|(");
    assert_linked("http://example.org/(.", "|http://example.org/|(.");
    assert_linked("http://example.org/]()", "|http://example.org/|]()");
}

#[test]
fn single_quote() {
    assert_linked(
        "http://example.org/\'_(foo)",
        "|http://example.org/\'_(foo)|",
    );
    assert_linked(
        "http://example.org/\'_(foo)\'",
        "|http://example.org/\'_(foo)\'|",
    );
    assert_linked("http://example.org/\'\'", "|http://example.org/\'\'|");
    assert_linked("http://example.org/\'\'\'", "|http://example.org/\'\'|\'");
    assert_linked("http://example.org/\'.", "|http://example.org/|\'.");
    assert_linked("http://example.org/\'a", "|http://example.org/\'a|");
    assert_linked("http://example.org/it's", "|http://example.org/it's|");
}

#[test]
fn double_quote() {
    // " not allowed in URLs
    assert_linked("http://example.org/\"a", "|http://example.org/|\"a");
    assert_linked("http://example.org/\"a\"", "|http://example.org/|\"a\"");
}

#[test]
fn grave_quote() {
    // ` not allowed in URLs
    assert_linked("http://example.org/`a", "|http://example.org/|`a");
    assert_linked("http://example.org/`a`", "|http://example.org/|`a`");
}

#[test]
fn html() {
    assert_linked("http://example.org\">", "|http://example.org|\">");
    assert_linked("http://example.org'>", "|http://example.org|'>");
    assert_linked("http://example.org\"/>", "|http://example.org|\"/>");
    assert_linked("http://example.org'/>", "|http://example.org|'/>");
    assert_linked("http://example.org
", "|http://example.org|
");
    assert_linked("http://example.org
", "|http://example.org|
");
}

#[test]
fn css() {
    assert_linked("http://example.org\");", "|http://example.org|\");");
    assert_linked("http://example.org');", "|http://example.org|');");
}

#[test]
fn images() {
    assert_linked(
        r#""#,
        r#""#,
    );
}

#[test]
fn complex_html() {
    assert_linked(
        r#"

"#,
        r#"

"#,
    );

    assert_linked(
        r#"

"#,
        r#"

"#,
    );

    assert_linked(
        r#"

"#,
        r#"

"#,
    )
}

#[test]
fn slash() {
    assert_linked("http://example.org/", "|http://example.org/|");
    assert_linked("http://example.org/a/", "|http://example.org/a/|");
    assert_linked("http://example.org//", "|http://example.org//|");
}

#[test]
fn multiple() {
    assert_linked(
        "http://one.org/ http://two.org/",
        "|http://one.org/| |http://two.org/|",
    );
    assert_linked(
        "http://one.org/ : http://two.org/",
        "|http://one.org/| : |http://two.org/|",
    );
    assert_linked(
        "(http://one.org/)(http://two.org/)",
        "(|http://one.org/|)(|http://two.org/|)",
    );
}

#[test]
fn international() {
    assert_linked("http://üñîçøðé.com/ä", "|http://üñîçøðé.com/ä|");
    assert_linked("http://example.org/\u{A1}", "|http://example.org/\u{A1}|");
    assert_linked("http://example.org/\u{A2}", "|http://example.org/\u{A2}|");
    assert_linked(
        "http://example.org/\u{1F600}",
        "|http://example.org/\u{1F600}|",
    );
    assert_linked("http://example.org/\u{A2}/", "|http://example.org/\u{A2}/|");
    assert_linked(
        "http://xn--c1h.example.com/",
        "|http://xn--c1h.example.com/|",
    );
}

#[test]
fn fuzz() {
    assert_not_linked("ab:/ϸ");
}

fn assert_not_linked(s: &str) {
    assert_linked(s, s);
}

fn assert_linked(input: &str, expected: &str) {
    let finder = LinkFinder::new();
    assert_linked_with(&finder, input, expected);
}
<|endoftext|>


<commit_before>//! 64-bit specific Apple (ios/darwin) definitions

pub type c_long = i64;
pub type c_ulong = u64;
pub type boolean_t = ::c_uint;

s! {
    pub struct timeval32 {
        pub tv_sec: i32,
        pub tv_usec: i32,
    }

    pub struct if_data {
        pub ifi_type: ::c_uchar,
        pub ifi_typelen: ::c_uchar,
        pub ifi_physical: ::c_uchar,
        pub ifi_addrlen: ::c_uchar,
        pub ifi_hdrlen: ::c_uchar,
        pub ifi_recvquota: ::c_uchar,
        pub ifi_xmitquota: ::c_uchar,
        pub ifi_unused1: ::c_uchar,
        pub ifi_mtu: u32,
        pub ifi_metric: u32,
        pub ifi_baudrate: u32,
        pub ifi_ipackets: u32,
        pub ifi_ierrors: u32,
        pub ifi_opackets: u32,
        pub ifi_oerrors: u32,
        pub ifi_collisions: u32,
        pub ifi_ibytes: u32,
        pub ifi_obytes: u32,
        pub ifi_imcasts: u32,
        pub ifi_omcasts: u32,
        pub ifi_iqdrops: u32,
        pub ifi_noproto: u32,
        pub ifi_recvtiming: u32,
        pub ifi_xmittiming: u32,
        pub ifi_lastchange: timeval32,
        pub ifi_unused2: u32,
        pub ifi_hwassist: u32,
        pub ifi_reserved1: u32,
        pub ifi_reserved2: u32,
    }

    pub struct bpf_hdr {
        pub bh_tstamp: ::timeval32,
        pub bh_caplen: u32,
        pub bh_datalen: u32,
        pub bh_hdrlen: ::c_ushort,
    }
}

s_no_extra_traits! {
    pub struct pthread_attr_t {
        __sig: c_long,
        __opaque: [::c_char; 56]
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for pthread_attr_t {
            fn eq(&self, other: &pthread_attr_t) -> bool {
                self.__sig == other.__sig
                    && self.__opaque
                    .iter()
                    .zip(other.__opaque.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for pthread_attr_t {}
        impl ::fmt::Debug for pthread_attr_t {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("pthread_attr_t")
                    .field("__sig", &self.__sig)
                // FIXME: .field("__opaque", &self.__opaque)
                    .finish()
            }
        }
        impl ::hash::Hash for pthread_attr_t {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.__sig.hash(state);
                self.__opaque.hash(state);
            }
        }
    }
}

#[doc(hidden)]
#[deprecated(since = "0.2.55")]
pub const NET_RT_MAXID: ::c_int = 11;

pub const __PTHREAD_MUTEX_SIZE__: usize = 56;
pub const __PTHREAD_COND_SIZE__: usize = 40;
pub const __PTHREAD_CONDATTR_SIZE__: usize = 8;
pub const __PTHREAD_RWLOCK_SIZE__: usize = 192;
pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 16;

pub const TIOCTIMESTAMP: ::c_ulong = 0x40107459;
pub const TIOCDCDTIMESTAMP: ::c_ulong = 0x40107458;

pub const BIOCSETF: ::c_ulong = 0x80104267;
pub const BIOCSRTIMEOUT: ::c_ulong = 0x8010426d;
pub const BIOCGRTIMEOUT: ::c_ulong = 0x4010426e;
pub const BIOCSETFNR: ::c_ulong = 0x8010427e;

extern "C" {
    pub fn exchangedata(
        path1: *const ::c_char,
        path2: *const ::c_char,
        options: ::c_uint,
    ) -> ::c_int;
}

cfg_if! {
    if #[cfg(libc_align)] {
        mod align;
        pub use self::align::*;
    }
}
<commit_msg>Add definition of ucontext_t for macOS<commit_after>//! 64-bit specific Apple (ios/darwin) definitions

pub type c_long = i64;
pub type c_ulong = u64;
pub type boolean_t = ::c_uint;
pub type mcontext_t = *mut __darwin_mcontext64;

s! {
    pub struct timeval32 {
        pub tv_sec: i32,
        pub tv_usec: i32,
    }

    pub struct if_data {
        pub ifi_type: ::c_uchar,
        pub ifi_typelen: ::c_uchar,
        pub ifi_physical: ::c_uchar,
        pub ifi_addrlen: ::c_uchar,
        pub ifi_hdrlen: ::c_uchar,
        pub ifi_recvquota: ::c_uchar,
        pub ifi_xmitquota: ::c_uchar,
        pub ifi_unused1: ::c_uchar,
        pub ifi_mtu: u32,
        pub ifi_metric: u32,
        pub ifi_baudrate: u32,
        pub ifi_ipackets: u32,
        pub ifi_ierrors: u32,
        pub ifi_opackets: u32,
        pub ifi_oerrors: u32,
        pub ifi_collisions: u32,
        pub ifi_ibytes: u32,
        pub ifi_obytes: u32,
        pub ifi_imcasts: u32,
        pub ifi_omcasts: u32,
        pub ifi_iqdrops: u32,
        pub ifi_noproto: u32,
        pub ifi_recvtiming: u32,
        pub ifi_xmittiming: u32,
        pub ifi_lastchange: timeval32,
        pub ifi_unused2: u32,
        pub ifi_hwassist: u32,
        pub ifi_reserved1: u32,
        pub ifi_reserved2: u32,
    }

    pub struct bpf_hdr {
        pub bh_tstamp: ::timeval32,
        pub bh_caplen: u32,
        pub bh_datalen: u32,
        pub bh_hdrlen: ::c_ushort,
    }

    pub struct ucontext_t {
        pub uc_onstack: ::c_int,
        pub uc_sigmask: ::sigset_t,
        pub uc_stack: ::stack_t,
        pub uc_link: *mut ::ucontext_t,
        pub uc_mcsize: usize,
        pub uc_mcontext: mcontext_t,
    }

    pub struct __darwin_mcontext64 {
        pub __es: __darwin_x86_exception_state64,
        pub __ss: __darwin_x86_thread_state64,
        pub __fs: __darwin_x86_float_state64,
    }

    pub struct __darwin_x86_exception_state64 {
        pub __trapno: u16,
        pub __cpu: u16,
        pub __err: u32,
        pub __faultvaddr: u64,
    }

    pub struct __darwin_x86_thread_state64 {
        pub __rax: u64,
        pub __rbx: u64,
        pub __rcx: u64,
        pub __rdx: u64,
        pub __rdi: u64,
        pub __rsi: u64,
        pub __rbp: u64,
        pub __rsp: u64,
        pub __r8: u64,
        pub __r9: u64,
        pub __r10: u64,
        pub __r11: u64,
        pub __r12: u64,
        pub __r13: u64,
        pub __r14: u64,
        pub __r15: u64,
        pub __rip: u64,
        pub __rflags: u64,
        pub __cs: u64,
        pub __fs: u64,
        pub __gs: u64,
    }

    pub struct __darwin_x86_float_state64 {
        pub __fpu_reserved: [::c_int; 2],
        __fpu_fcw: ::c_short,
        __fpu_fsw: ::c_short,
        pub __fpu_ftw: u8,
        pub __fpu_rsrv1: u8,
        pub __fpu_fop: u16,
        pub __fpu_ip: u32,
        pub __fpu_cs: u16,
        pub __fpu_rsrv2: u16,
        pub __fpu_dp: u32,
        pub __fpu_ds: u16,
        pub __fpu_rsrv3: u16,
        pub __fpu_mxcsr: u32,
        pub __fpu_mxcsrmask: u32,
        pub __fpu_stmm0: __darwin_mmst_reg,
        pub __fpu_stmm1: __darwin_mmst_reg,
        pub __fpu_stmm2: __darwin_mmst_reg,
        pub __fpu_stmm3: __darwin_mmst_reg,
        pub __fpu_stmm4: __darwin_mmst_reg,
        pub __fpu_stmm5: __darwin_mmst_reg,
        pub __fpu_stmm6: __darwin_mmst_reg,
        pub __fpu_stmm7: __darwin_mmst_reg,
        pub __fpu_xmm0: __darwin_xmm_reg,
        pub __fpu_xmm1: __darwin_xmm_reg,
        pub __fpu_xmm2: __darwin_xmm_reg,
        pub __fpu_xmm3: __darwin_xmm_reg,
        pub __fpu_xmm4: __darwin_xmm_reg,
        pub __fpu_xmm5: __darwin_xmm_reg,
        pub __fpu_xmm6: __darwin_xmm_reg,
        pub __fpu_xmm7: __darwin_xmm_reg,
        pub __fpu_xmm8: __darwin_xmm_reg,
        pub __fpu_xmm9: __darwin_xmm_reg,
        pub __fpu_xmm10: __darwin_xmm_reg,
        pub __fpu_xmm11: __darwin_xmm_reg,
        pub __fpu_xmm12: __darwin_xmm_reg,
        pub __fpu_xmm13: __darwin_xmm_reg,
        pub __fpu_xmm14: __darwin_xmm_reg,
        pub __fpu_xmm15: __darwin_xmm_reg,
        // this field is actually [u8; 96], but defining it with a bigger type
        // allows us to auto-implement traits for it since the length of the
        // array is less than 32
        __fpu_rsrv4: [u32; 24],
        pub __fpu_reserved1: ::c_int,
    }

    pub struct __darwin_mmst_reg {
        pub __mmst_reg: [::c_char; 10],
        pub __mmst_rsrv: [::c_char; 6],
    }

    pub struct __darwin_xmm_reg {
        pub __xmm_reg: [::c_char; 16],
    }
}

s_no_extra_traits! {
    pub struct pthread_attr_t {
        __sig: c_long,
        __opaque: [::c_char; 56]
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for pthread_attr_t {
            fn eq(&self, other: &pthread_attr_t) -> bool {
                self.__sig == other.__sig
                    && self.__opaque
                    .iter()
                    .zip(other.__opaque.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for pthread_attr_t {}
        impl ::fmt::Debug for pthread_attr_t {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("pthread_attr_t")
                    .field("__sig", &self.__sig)
                // FIXME: .field("__opaque", &self.__opaque)
                    .finish()
            }
        }
        impl ::hash::Hash for pthread_attr_t {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.__sig.hash(state);
                self.__opaque.hash(state);
            }
        }
    }
}

#[doc(hidden)]
#[deprecated(since = "0.2.55")]
pub const NET_RT_MAXID: ::c_int = 11;

pub const __PTHREAD_MUTEX_SIZE__: usize = 56;
pub const __PTHREAD_COND_SIZE__: usize = 40;
pub const __PTHREAD_CONDATTR_SIZE__: usize = 8;
pub const __PTHREAD_RWLOCK_SIZE__: usize = 192;
pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 16;

pub const TIOCTIMESTAMP: ::c_ulong = 0x40107459;
pub const TIOCDCDTIMESTAMP: ::c_ulong = 0x40107458;

pub const BIOCSETF: ::c_ulong = 0x80104267;
pub const BIOCSRTIMEOUT: ::c_ulong = 0x8010426d;
pub const BIOCGRTIMEOUT: ::c_ulong = 0x4010426e;
pub const BIOCSETFNR: ::c_ulong = 0x8010427e;

extern "C" {
    pub fn exchangedata(
        path1: *const ::c_char,
        path2: *const ::c_char,
        options: ::c_uint,
    ) -> ::c_int;
}

cfg_if! {
    if #[cfg(libc_align)] {
        mod align;
        pub use self::align::*;
    }
}
<|endoftext|>


<commit_before>use std::iter;

use ast::edit::IndentLevel;
use ide_db::base_db::AnchoredPathBuf;
use itertools::Itertools;
use stdx::format_to;
use syntax::{
    ast::{self, edit::AstNodeEdit, HasName},
    AstNode, TextRange,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: move_module_to_file
//
// Moves inline module's contents to a separate file.
//
// ```
// mod $0foo {
//     fn t() {}
// }
// ```
// ->
// ```
// mod foo;
// ```
pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
    let module_items = module_ast.item_list()?;

    let l_curly_offset = module_items.syntax().text_range().start();
    if l_curly_offset <= ctx.offset() {
        cov_mark::hit!(available_before_curly);
        return None;
    }
    let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset);

    let module_name = module_ast.name()?;

    // get to the outermost module syntax so we can grab the module of file we are in
    let outermost_mod_decl =
        iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?;
    let module_def = ctx.sema.to_def(&outermost_mod_decl)?;
    let parent_module = module_def.parent(ctx.db())?;

    acc.add(
        AssistId("move_module_to_file", AssistKind::RefactorExtract),
        "Extract module to file",
        target,
        |builder| {
            let path = {
                let mut buf = String::from("./");
                match parent_module.name(ctx.db()) {
                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
                        format_to!(buf, "{}/", name)
                    }
                    _ => (),
                }
                let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
                    .filter_map(|it| it.name())
                    .collect::<Vec<_>>();
                format_to!(buf, "{}", segments.into_iter().rev().format("/"));
                format_to!(buf, ".rs");
                buf
            };
            let contents = {
                let items = module_items.dedent(IndentLevel(1)).to_string();
                let mut items =
                    items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
                if !items.is_empty() {
                    items.push('\n');
                }
                items
            };

            let buf = format!("mod {};", module_name);

            let replacement_start = match module_ast.mod_token() {
                Some(mod_token) => mod_token.text_range(),
                None => module_ast.syntax().text_range(),
            }
            .start();

            builder.replace(
                TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
                buf,
            );

            let dst = AnchoredPathBuf { anchor: ctx.file_id(), path };
            builder.create_file(dst, contents);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn extract_from_root() {
        check_assist(
            move_module_to_file,
            r#"
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_from_submodule() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submod;
//- /submod.rs
$0mod inner {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submod.rs
mod inner;
fn g() {}
//- /submod/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submodule;
//- /submodule/mod.rs
mod inner$0 {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submodule/mod.rs
mod inner;
fn g() {}
//- /submodule/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_public() {
        check_assist(
            move_module_to_file,
            r#"
pub mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_public_crate() {
        check_assist(
            move_module_to_file,
            r#"
pub(crate) mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub(crate) mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn available_before_curly() {
        cov_mark::check!(available_before_curly);
        check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
    }

    #[test]
    fn keep_outer_comments_and_attributes() {
        check_assist(
            move_module_to_file,
            r#"
/// doc comment
#[attribute]
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
/// doc comment
#[attribute]
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_nested() {
        check_assist(
            move_module_to_file,
            r#"
//- /lib.rs
mod foo;
//- /foo.rs
mod bar {
    mod baz {
        mod qux$0 {}
    }
}
"#,
            r#"
//- /foo.rs
mod bar {
    mod baz {
        mod qux;
    }
}
//- /foo/bar/baz/qux.rs
"#,
        );
    }
}
<commit_msg>fix: handle raw identifiers in move_module_to_file<commit_after>use std::iter;

use ast::edit::IndentLevel;
use ide_db::base_db::AnchoredPathBuf;
use itertools::Itertools;
use stdx::format_to;
use syntax::{
    ast::{self, edit::AstNodeEdit, HasName},
    AstNode, SmolStr, TextRange,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: move_module_to_file
//
// Moves inline module's contents to a separate file.
//
// ```
// mod $0foo {
//     fn t() {}
// }
// ```
// ->
// ```
// mod foo;
// ```
pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
    let module_items = module_ast.item_list()?;

    let l_curly_offset = module_items.syntax().text_range().start();
    if l_curly_offset <= ctx.offset() {
        cov_mark::hit!(available_before_curly);
        return None;
    }
    let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset);

    let module_name = module_ast.name()?;

    // get to the outermost module syntax so we can grab the module of file we are in
    let outermost_mod_decl =
        iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?;
    let module_def = ctx.sema.to_def(&outermost_mod_decl)?;
    let parent_module = module_def.parent(ctx.db())?;

    acc.add(
        AssistId("move_module_to_file", AssistKind::RefactorExtract),
        "Extract module to file",
        target,
        |builder| {
            let path = {
                let mut buf = String::from("./");
                match parent_module.name(ctx.db()) {
                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
                        format_to!(buf, "{}/", name)
                    }
                    _ => (),
                }
                let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
                    .filter_map(|it| it.name())
                    .map(|name| SmolStr::from(name.text().trim_start_matches("r#")))
                    .collect::<Vec<_>>();

                format_to!(buf, "{}", segments.into_iter().rev().format("/"));

                // We need to special case mod named `r#mod` and place the file in a
                // subdirectory as "mod.rs" would be of its parent module otherwise.
                if module_name.text() == "r#mod" {
                    format_to!(buf, "/mod.rs");
                } else {
                    format_to!(buf, ".rs");
                }
                buf
            };
            let contents = {
                let items = module_items.dedent(IndentLevel(1)).to_string();
                let mut items =
                    items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
                if !items.is_empty() {
                    items.push('\n');
                }
                items
            };

            let buf = format!("mod {};", module_name);

            let replacement_start = match module_ast.mod_token() {
                Some(mod_token) => mod_token.text_range(),
                None => module_ast.syntax().text_range(),
            }
            .start();

            builder.replace(
                TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
                buf,
            );

            let dst = AnchoredPathBuf { anchor: ctx.file_id(), path };
            builder.create_file(dst, contents);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn extract_from_root() {
        check_assist(
            move_module_to_file,
            r#"
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_from_submodule() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submod;
//- /submod.rs
$0mod inner {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submod.rs
mod inner;
fn g() {}
//- /submod/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submodule;
//- /submodule/mod.rs
mod inner$0 {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submodule/mod.rs
mod inner;
fn g() {}
//- /submodule/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_public() {
        check_assist(
            move_module_to_file,
            r#"
pub mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_public_crate() {
        check_assist(
            move_module_to_file,
            r#"
pub(crate) mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub(crate) mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn available_before_curly() {
        cov_mark::check!(available_before_curly);
        check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
    }

    #[test]
    fn keep_outer_comments_and_attributes() {
        check_assist(
            move_module_to_file,
            r#"
/// doc comment
#[attribute]
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
/// doc comment
#[attribute]
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_nested() {
        check_assist(
            move_module_to_file,
            r#"
//- /lib.rs
mod foo;
//- /foo.rs
mod bar {
    mod baz {
        mod qux$0 {}
    }
}
"#,
            r#"
//- /foo.rs
mod bar {
    mod baz {
        mod qux;
    }
}
//- /foo/bar/baz/qux.rs
"#,
        );
    }

    #[test]
    fn extract_mod_with_raw_ident() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod $0r#static {}
"#,
            r#"
//- /main.rs
mod r#static;
//- /static.rs
"#,
        )
    }

    #[test]
    fn extract_r_mod() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod $0r#mod {}
"#,
            r#"
//- /main.rs
mod r#mod;
//- /mod/mod.rs
"#,
        )
    }

    #[test]
    fn extract_r_mod_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod foo;
//- /foo/mod.rs
mod $0r#mod {}
"#,
            r#"
//- /foo/mod.rs
mod r#mod;
//- /foo/mod/mod.rs
"#,
        )
    }

    #[test]
    fn extract_nested_r_mod() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod r#mod {
    mod foo {
        mod $0r#mod {}
    }
}
"#,
            r#"
//- /main.rs
mod r#mod {
    mod foo {
        mod r#mod;
    }
}
//- /mod/foo/mod/mod.rs
"#,
        )
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

// FIXME: this modules relies on strings and AST way too much, and it should be
// rewritten (matklad 2020-05-07)
use std::{
    convert::From,
    fmt::{self, Display},
};

use hir::{Docs, Documentation, HasSource, HirDisplay};
use ra_ide_db::RootDatabase;
use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
use stdx::SepBy;

use crate::display::{generic_parameters, where_predicates};

#[derive(Debug)]
pub enum CallableKind {
    Function,
    StructConstructor,
    VariantConstructor,
    Macro,
}

/// Contains information about a function signature
#[derive(Debug)]
pub struct FunctionSignature {
    pub kind: CallableKind,
    /// Optional visibility
    pub visibility: Option<String>,
    /// Qualifiers like `async`, `unsafe`, ...
    pub qualifier: FunctionQualifier,
    /// Name of the function
    pub name: Option<String>,
    /// Documentation for the function
    pub doc: Option<Documentation>,
    /// Generic parameters
    pub generic_parameters: Vec<String>,
    /// Parameters of the function
    pub parameters: Vec<String>,
    /// Parameter names of the function
    pub parameter_names: Vec<String>,
    /// Parameter types of the function
    pub parameter_types: Vec<String>,
    /// Optional return type
    pub ret_type: Option<String>,
    /// Where predicates
    pub where_predicates: Vec<String>,
    /// Self param presence
    pub has_self_param: bool,
}

#[derive(Debug, Default)]
pub struct FunctionQualifier {
    // `async` and `const` are mutually exclusive. Do we need to enforcing it here?
    pub is_async: bool,
    pub is_const: bool,
    pub is_unsafe: bool,
    /// The string `extern ".."`
    pub extern_abi: Option<String>,
}

impl FunctionSignature {
    pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
        self.doc = doc;
        self
    }

    pub(crate) fn from_hir(db: &RootDatabase, function: hir::Function) -> Self {
        let doc = function.docs(db);
        let ast_node = function.source(db).value;
        FunctionSignature::from(&ast_node).with_doc_opt(doc)
    }

    pub(crate) fn from_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> {
        let node: ast::StructDef = st.source(db).value;
        if let ast::StructKind::Record(_) = node.kind() {
            return None;
        };

        let mut params = vec![];
        let mut parameter_types = vec![];
        for field in st.fields(db).into_iter() {
            let ty = field.signature_ty(db);
            let raw_param = format!("{}", ty.display(db));

            if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
                parameter_types.push(param_type.to_string());
            } else {
                // useful when you have tuple struct
                parameter_types.push(raw_param.clone());
            }
            params.push(raw_param);
        }

        Some(
            FunctionSignature {
                kind: CallableKind::StructConstructor,
                visibility: node.visibility().map(|n| n.syntax().text().to_string()),
                // Do we need `const`?
                qualifier: Default::default(),
                name: node.name().map(|n| n.text().to_string()),
                ret_type: node.name().map(|n| n.text().to_string()),
                parameters: params,
                parameter_names: vec![],
                parameter_types,
                generic_parameters: generic_parameters(&node),
                where_predicates: where_predicates(&node),
                doc: None,
                has_self_param: false,
            }
            .with_doc_opt(st.docs(db)),
        )
    }

    pub(crate) fn from_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> {
        let node: ast::EnumVariant = variant.source(db).value;
        match node.kind() {
            ast::StructKind::Record(_) | ast::StructKind::Unit => return None,
            _ => (),
        };

        let parent_name = variant.parent_enum(db).name(db).to_string();

        let name = format!("{}::{}", parent_name, variant.name(db));

        let mut params = vec![];
        let mut parameter_types = vec![];
        for field in variant.fields(db).into_iter() {
            let ty = field.signature_ty(db);
            let raw_param = format!("{}", ty.display(db));
            dbg!(&raw_param);
            if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
                parameter_types.push(param_type.to_string());
            } else {
                // The unwrap_or_else is useful when you have tuple
                parameter_types.push(raw_param);
            }
            let name = field.name(db);

            params.push(format!("{}: {}", name, ty.display(db)));
        }

        Some(
            FunctionSignature {
                kind: CallableKind::VariantConstructor,
                visibility: None,
                // Do we need `const`?
                qualifier: Default::default(),
                name: Some(name),
                ret_type: None,
                parameters: params,
                parameter_names: vec![],
                parameter_types,
                generic_parameters: vec![],
                where_predicates: vec![],
                doc: None,
                has_self_param: false,
            }
            .with_doc_opt(variant.docs(db)),
        )
    }

    pub(crate) fn from_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
        let node: ast::MacroCall = macro_def.source(db).value;

        let params = vec![];

        Some(
            FunctionSignature {
                kind: CallableKind::Macro,
                visibility: None,
                qualifier: Default::default(),
                name: node.name().map(|n| n.text().to_string()),
                ret_type: None,
                parameters: params,
                parameter_names: vec![],
                parameter_types: vec![],
                generic_parameters: vec![],
                where_predicates: vec![],
                doc: None,
                has_self_param: false,
            }
            .with_doc_opt(macro_def.docs(db)),
        )
    }
}

impl From<&'_ ast::FnDef> for FunctionSignature {
    fn from(node: &ast::FnDef) -> FunctionSignature {
        fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) {
            let mut res = vec![];
            let mut res_types = vec![];
            let mut has_self_param = false;
            if let Some(param_list) = node.param_list() {
                if let Some(self_param) = param_list.self_param() {
                    has_self_param = true;
                    let raw_param = self_param.syntax().text().to_string();

                    res_types.push(
                        raw_param
                            .split(':')
                            .nth(1)
                            .and_then(|it| it.get(1..))
                            .unwrap_or_else(|| "Self")
                            .to_string(),
                    );
                    res.push(raw_param);
                }

                res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
                res_types.extend(param_list.params().map(|param| {
                    let param_text = param.syntax().text().to_string();
                    match param_text.split(':').nth(1).and_then(|it| it.get(1..)) {
                        Some(it) => it.to_string(),
                        None => param_text,
                    }
                }));
            }
            (has_self_param, res, res_types)
        }

        fn param_name_list(node: &ast::FnDef) -> Vec<String> {
            let mut res = vec![];
            if let Some(param_list) = node.param_list() {
                if let Some(self_param) = param_list.self_param() {
                    res.push(self_param.syntax().text().to_string())
                }

                res.extend(
                    param_list
                        .params()
                        .map(|param| {
                            Some(
                                param
                                    .pat()?
                                    .syntax()
                                    .descendants()
                                    .find_map(ast::Name::cast)?
                                    .text()
                                    .to_string(),
                            )
                        })
                        .map(|param| param.unwrap_or_default()),
                );
            }
            res
        }

        let (has_self_param, parameters, parameter_types) = param_list(node);

        FunctionSignature {
            kind: CallableKind::Function,
            visibility: node.visibility().map(|n| n.syntax().text().to_string()),
            qualifier: FunctionQualifier {
                is_async: node.async_token().is_some(),
                is_const: node.const_token().is_some(),
                is_unsafe: node.unsafe_token().is_some(),
                extern_abi: node.abi().map(|n| n.to_string()),
            },
            name: node.name().map(|n| n.text().to_string()),
            ret_type: node
                .ret_type()
                .and_then(|r| r.type_ref())
                .map(|n| n.syntax().text().to_string()),
            parameters,
            parameter_names: param_name_list(node),
            parameter_types,
            generic_parameters: generic_parameters(node),
            where_predicates: where_predicates(node),
            // docs are processed separately
            doc: None,
            has_self_param,
        }
    }
}

impl Display for FunctionSignature {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(t) = &self.visibility {
            write!(f, "{} ", t)?;
        }

        if self.qualifier.is_async {
            write!(f, "async ")?;
        }

        if self.qualifier.is_const {
            write!(f, "const ")?;
        }

        if self.qualifier.is_unsafe {
            write!(f, "unsafe ")?;
        }

        if let Some(extern_abi) = &self.qualifier.extern_abi {
            // Keyword `extern` is included in the string.
            write!(f, "{} ", extern_abi)?;
        }

        if let Some(name) = &self.name {
            match self.kind {
                CallableKind::Function => write!(f, "fn {}", name)?,
                CallableKind::StructConstructor => write!(f, "struct {}", name)?,
                CallableKind::VariantConstructor => write!(f, "{}", name)?,
                CallableKind::Macro => write!(f, "{}!", name)?,
            }
        }

        if !self.generic_parameters.is_empty() {
            write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?;
        }

        write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?;

        if let Some(t) = &self.ret_type {
            write!(f, " -> {}", t)?;
        }

        if !self.where_predicates.is_empty() {
            write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n      "))?;
        }

        Ok(())
    }
}
<commit_msg>Remove dbg<commit_after>//! FIXME: write short doc here

// FIXME: this modules relies on strings and AST way too much, and it should be
// rewritten (matklad 2020-05-07)
use std::{
    convert::From,
    fmt::{self, Display},
};

use hir::{Docs, Documentation, HasSource, HirDisplay};
use ra_ide_db::RootDatabase;
use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
use stdx::SepBy;

use crate::display::{generic_parameters, where_predicates};

#[derive(Debug)]
pub enum CallableKind {
    Function,
    StructConstructor,
    VariantConstructor,
    Macro,
}

/// Contains information about a function signature
#[derive(Debug)]
pub struct FunctionSignature {
    pub kind: CallableKind,
    /// Optional visibility
    pub visibility: Option<String>,
    /// Qualifiers like `async`, `unsafe`, ...
    pub qualifier: FunctionQualifier,
    /// Name of the function
    pub name: Option<String>,
    /// Documentation for the function
    pub doc: Option<Documentation>,
    /// Generic parameters
    pub generic_parameters: Vec<String>,
    /// Parameters of the function
    pub parameters: Vec<String>,
    /// Parameter names of the function
    pub parameter_names: Vec<String>,
    /// Parameter types of the function
    pub parameter_types: Vec<String>,
    /// Optional return type
    pub ret_type: Option<String>,
    /// Where predicates
    pub where_predicates: Vec<String>,
    /// Self param presence
    pub has_self_param: bool,
}

#[derive(Debug, Default)]
pub struct FunctionQualifier {
    // `async` and `const` are mutually exclusive. Do we need to enforcing it here?
    pub is_async: bool,
    pub is_const: bool,
    pub is_unsafe: bool,
    /// The string `extern ".."`
    pub extern_abi: Option<String>,
}

impl FunctionSignature {
    pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
        self.doc = doc;
        self
    }

    pub(crate) fn from_hir(db: &RootDatabase, function: hir::Function) -> Self {
        let doc = function.docs(db);
        let ast_node = function.source(db).value;
        FunctionSignature::from(&ast_node).with_doc_opt(doc)
    }

    pub(crate) fn from_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> {
        let node: ast::StructDef = st.source(db).value;
        if let ast::StructKind::Record(_) = node.kind() {
            return None;
        };

        let mut params = vec![];
        let mut parameter_types = vec![];
        for field in st.fields(db).into_iter() {
            let ty = field.signature_ty(db);
            let raw_param = format!("{}", ty.display(db));

            if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
                parameter_types.push(param_type.to_string());
            } else {
                // useful when you have tuple struct
                parameter_types.push(raw_param.clone());
            }
            params.push(raw_param);
        }

        Some(
            FunctionSignature {
                kind: CallableKind::StructConstructor,
                visibility: node.visibility().map(|n| n.syntax().text().to_string()),
                // Do we need `const`?
                qualifier: Default::default(),
                name: node.name().map(|n| n.text().to_string()),
                ret_type: node.name().map(|n| n.text().to_string()),
                parameters: params,
                parameter_names: vec![],
                parameter_types,
                generic_parameters: generic_parameters(&node),
                where_predicates: where_predicates(&node),
                doc: None,
                has_self_param: false,
            }
            .with_doc_opt(st.docs(db)),
        )
    }

    pub(crate) fn from_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> {
        let node: ast::EnumVariant = variant.source(db).value;
        match node.kind() {
            ast::StructKind::Record(_) | ast::StructKind::Unit => return None,
            _ => (),
        };

        let parent_name = variant.parent_enum(db).name(db).to_string();

        let name = format!("{}::{}", parent_name, variant.name(db));

        let mut params = vec![];
        let mut parameter_types = vec![];
        for field in variant.fields(db).into_iter() {
            let ty = field.signature_ty(db);
            let raw_param = format!("{}", ty.display(db));
            if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
                parameter_types.push(param_type.to_string());
            } else {
                // The unwrap_or_else is useful when you have tuple
                parameter_types.push(raw_param);
            }
            let name = field.name(db);

            params.push(format!("{}: {}", name, ty.display(db)));
        }

        Some(
            FunctionSignature {
                kind: CallableKind::VariantConstructor,
                visibility: None,
                // Do we need `const`?
                qualifier: Default::default(),
                name: Some(name),
                ret_type: None,
                parameters: params,
                parameter_names: vec![],
                parameter_types,
                generic_parameters: vec![],
                where_predicates: vec![],
                doc: None,
                has_self_param: false,
            }
            .with_doc_opt(variant.docs(db)),
        )
    }

    pub(crate) fn from_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
        let node: ast::MacroCall = macro_def.source(db).value;

        let params = vec![];

        Some(
            FunctionSignature {
                kind: CallableKind::Macro,
                visibility: None,
                qualifier: Default::default(),
                name: node.name().map(|n| n.text().to_string()),
                ret_type: None,
                parameters: params,
                parameter_names: vec![],
                parameter_types: vec![],
                generic_parameters: vec![],
                where_predicates: vec![],
                doc: None,
                has_self_param: false,
            }
            .with_doc_opt(macro_def.docs(db)),
        )
    }
}

impl From<&'_ ast::FnDef> for FunctionSignature {
    fn from(node: &ast::FnDef) -> FunctionSignature {
        fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) {
            let mut res = vec![];
            let mut res_types = vec![];
            let mut has_self_param = false;
            if let Some(param_list) = node.param_list() {
                if let Some(self_param) = param_list.self_param() {
                    has_self_param = true;
                    let raw_param = self_param.syntax().text().to_string();

                    res_types.push(
                        raw_param
                            .split(':')
                            .nth(1)
                            .and_then(|it| it.get(1..))
                            .unwrap_or_else(|| "Self")
                            .to_string(),
                    );
                    res.push(raw_param);
                }

                res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
                res_types.extend(param_list.params().map(|param| {
                    let param_text = param.syntax().text().to_string();
                    match param_text.split(':').nth(1).and_then(|it| it.get(1..)) {
                        Some(it) => it.to_string(),
                        None => param_text,
                    }
                }));
            }
            (has_self_param, res, res_types)
        }

        fn param_name_list(node: &ast::FnDef) -> Vec<String> {
            let mut res = vec![];
            if let Some(param_list) = node.param_list() {
                if let Some(self_param) = param_list.self_param() {
                    res.push(self_param.syntax().text().to_string())
                }

                res.extend(
                    param_list
                        .params()
                        .map(|param| {
                            Some(
                                param
                                    .pat()?
                                    .syntax()
                                    .descendants()
                                    .find_map(ast::Name::cast)?
                                    .text()
                                    .to_string(),
                            )
                        })
                        .map(|param| param.unwrap_or_default()),
                );
            }
            res
        }

        let (has_self_param, parameters, parameter_types) = param_list(node);

        FunctionSignature {
            kind: CallableKind::Function,
            visibility: node.visibility().map(|n| n.syntax().text().to_string()),
            qualifier: FunctionQualifier {
                is_async: node.async_token().is_some(),
                is_const: node.const_token().is_some(),
                is_unsafe: node.unsafe_token().is_some(),
                extern_abi: node.abi().map(|n| n.to_string()),
            },
            name: node.name().map(|n| n.text().to_string()),
            ret_type: node
                .ret_type()
                .and_then(|r| r.type_ref())
                .map(|n| n.syntax().text().to_string()),
            parameters,
            parameter_names: param_name_list(node),
            parameter_types,
            generic_parameters: generic_parameters(node),
            where_predicates: where_predicates(node),
            // docs are processed separately
            doc: None,
            has_self_param,
        }
    }
}

impl Display for FunctionSignature {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(t) = &self.visibility {
            write!(f, "{} ", t)?;
        }

        if self.qualifier.is_async {
            write!(f, "async ")?;
        }

        if self.qualifier.is_const {
            write!(f, "const ")?;
        }

        if self.qualifier.is_unsafe {
            write!(f, "unsafe ")?;
        }

        if let Some(extern_abi) = &self.qualifier.extern_abi {
            // Keyword `extern` is included in the string.
            write!(f, "{} ", extern_abi)?;
        }

        if let Some(name) = &self.name {
            match self.kind {
                CallableKind::Function => write!(f, "fn {}", name)?,
                CallableKind::StructConstructor => write!(f, "struct {}", name)?,
                CallableKind::VariantConstructor => write!(f, "{}", name)?,
                CallableKind::Macro => write!(f, "{}!", name)?,
            }
        }

        if !self.generic_parameters.is_empty() {
            write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?;
        }

        write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?;

        if let Some(t) = &self.ret_type {
            write!(f, " -> {}", t)?;
        }

        if !self.where_predicates.is_empty() {
            write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n      "))?;
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Translated from C to Rust. The original C code can be found at
// https://github.com/ulfjack/ryu and carries the following license:
//
// Copyright 2018 Ulf Adams
//
// The contents of this file may be used under the terms of the Apache License,
// Version 2.0.
//
//    (See accompanying file LICENSE-Apache or copy at
//     http://www.apache.org/licenses/LICENSE-2.0)
//
// Alternatively, the contents of this file may be used under the terms of
// the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE-Boost or copy at
//     https://www.boost.org/LICENSE_1_0.txt)
//
// Unless required by applicable law or agreed to in writing, this software
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.

#![allow(dead_code)]

#[path = "../src/common.rs"]
mod common;

#[path = "../src/d2s_full_table.rs"]
mod d2s_full_table;

#[path = "../src/d2s_intrinsics.rs"]
mod d2s_intrinsics;

#[path = "../src/d2s_small_table.rs"]
mod d2s_small_table;

use d2s_full_table::*;
use d2s_small_table::*;

#[test]
fn test_compute_pow5() {
    for (i, entry) in DOUBLE_POW5_SPLIT.iter().enumerate() {
        assert_eq!(*entry, unsafe { compute_pow5(i as u32) }, "entry {}", i);
    }
}

#[test]
fn test_compute_inv_pow5() {
    for (i, entry) in DOUBLE_POW5_INV_SPLIT.iter().enumerate() {
        assert_eq!(*entry, unsafe { compute_inv_pow5(i as u32) }, "entry {}", i);
    }
}
<commit_msg>Only test table entries that upstream tests<commit_after>// Translated from C to Rust. The original C code can be found at
// https://github.com/ulfjack/ryu and carries the following license:
//
// Copyright 2018 Ulf Adams
//
// The contents of this file may be used under the terms of the Apache License,
// Version 2.0.
//
//    (See accompanying file LICENSE-Apache or copy at
//     http://www.apache.org/licenses/LICENSE-2.0)
//
// Alternatively, the contents of this file may be used under the terms of
// the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE-Boost or copy at
//     https://www.boost.org/LICENSE_1_0.txt)
//
// Unless required by applicable law or agreed to in writing, this software
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.

#![allow(dead_code)]

#[path = "../src/common.rs"]
mod common;

#[path = "../src/d2s_full_table.rs"]
mod d2s_full_table;

#[path = "../src/d2s_intrinsics.rs"]
mod d2s_intrinsics;

#[path = "../src/d2s_small_table.rs"]
mod d2s_small_table;

use d2s_full_table::*;
use d2s_small_table::*;

#[test]
fn test_compute_pow5() {
    for (i, entry) in DOUBLE_POW5_SPLIT.iter().enumerate() {
        assert_eq!(*entry, unsafe { compute_pow5(i as u32) }, "entry {}", i);
    }
}

#[test]
fn test_compute_inv_pow5() {
    for (i, entry) in DOUBLE_POW5_INV_SPLIT[..292].iter().enumerate() {
        assert_eq!(*entry, unsafe { compute_inv_pow5(i as u32) }, "entry {}", i);
    }
}
<|endoftext|>


<commit_before>//! Activation literal type and helpers.
//!
//! For an explanation of what activation literal are, see
//! [the discussion below][why actlits].
//!
//! **NB**: while `rmst2`'s actlit API declares some constant symbols in the
//! underlying solver, these will not appear in the result of
//! [`get_model`](get_model) queries.
//!
//!
//! # Relevant functions on solvers
//!
//! - [`get_actlit`](../trait.Solver.html#method.get_actlit)
//! - [`get_sactlit`](../trait.Solver.html#method.get_sactlit)
//! - [`de_actlit`](../trait.Solver.html#method.de_actlit)
//! - [`set_actlit`](../trait.Solver.html#method.set_actlit)
//! - [`assert_act`](../trait.Solver.html#method.assert_act)
//! - [`assert_act_with`](../trait.Solver.html#method.assert_act_with)
//! - [`print_check_sat_act`](../trait.Solver.html#method.print_check_sat_act)
//! - [`check_sat_act`](../trait.Solver.html#method.check_sat_act)
//! - [`check_sat_act_or_unk`]
//!   (../trait.Solver.html#method.check_sat_act_or_unk)
//!
//!
//!
//! # Usage
//!
//! First, one can of course create activation literals by hand, and use them
//! in `check-sat`s with [`check_sat_assuming`][check sat ass]:
//!
//! ```
//! use rsmt2::* ;
//!
//! let mut solver = Solver::default(()).unwrap() ;
//! solver.declare_const("x", "Int").unwrap() ;
//!
//! solver.declare_const("actlit", "Bool").unwrap() ;
//! solver.assert("\
//!   (=> actlit \
//!       (and (> x 0) (< x 3) (= (mod x 3) 0))\
//!   )\
//! ").unwrap() ;
//! assert!{
//!   ! solver.check_sat_assuming( Some("actlit") ).unwrap()
//! }
//! solver.assert("(not actlit)").unwrap() ;
//!
//! solver.declare_const("other_actlit", "Bool").unwrap() ;
//! solver.assert("\
//!   (=> other_actlit \
//!       (and (> x 7) (= (mod x 2) 0))\
//!   )\
//! ").unwrap() ;
//! assert!{
//!   solver.check_sat_assuming( Some("other_actlit") ).unwrap()
//! }
//! solver.assert("(not other_actlit)").unwrap() ;
//!
//! solver.kill().unwrap()
//! ```
//!
//! The activation literal API makes this process more straightforward:
//!
//! ```
//! use rsmt2::* ;
//!
//! let mut solver = match Solver::default(()) {
//!   Ok(kid) => kid,
//!   Err(e) => panic!("Could not spawn solver kid: {:?}", e)
//! } ; solver.path_tee("log.smt2").unwrap() ;
//!
//! solver.declare_const("x", "Int").unwrap() ;
//!
//! let actlit = solver.get_actlit().unwrap() ;
//! solver.assert_act(& actlit, "(> x 0)").unwrap() ;
//! solver.assert_act(& actlit, "(< x 3)").unwrap() ;
//! solver.assert_act(& actlit, "(= (mod x 3) 0)").unwrap() ;
//!
//! assert!{
//!   ! solver.check_sat_act( Some(& actlit) ).unwrap()
//! }
//! solver.de_actlit(actlit).unwrap() ;
//! // At this point `actlit` has been consumed. So it's a bit safer than the
//! // version above, since use-after-deactivate is not possible.
//!
//! let actlit = solver.get_actlit().unwrap() ;
//! solver.assert_act(& actlit, "(> x 7)").unwrap() ;
//! solver.assert_act(& actlit, "(= (mod x 2) 0)").unwrap() ;
//! assert!{
//!   solver.check_sat_act( Some(& actlit) ).unwrap()
//! }
//! solver.de_actlit(actlit).unwrap() ;
//!
//! solver.kill().unwrap()
//! ```
//!
//!
//! **NB**: under the hood, `rmst2` declares a constant boolean symbol for each
//! actlit. Hence, there is a (very low) risk of collision with the user's
//! symbol. The internal actlits are named `"|rsmt2 actlit <uid>|"`. Any symbol
//! starting with `"|rsmt2 actlit "` is assumed to be a `rsmt2` actlit. In
//! particular, such symbols will be pruned out of `get_model` queries (if at
//! least one actlit was requested since the last reset).
//!
//! ```
//! use rsmt2::* ;
//! use rsmt2::parse::* ;
//!
//! struct Parser ;
//! impl<'a, 'b> IdentParser<String, String, & 'a str> for & 'b Parser {
//!   fn parse_ident(self, s: & 'a str) -> SmtRes<String> {
//!     Ok(s.to_string())
//!   }
//!   fn parse_type(self, s: & 'a str) -> SmtRes<String> {
//!     Ok(s.to_string())
//!   }
//! }
//! impl<'a, 'b> ModelParser<
//!   String, String, String, & 'a str
//! > for & 'b Parser {
//!   fn parse_value(
//!     self, s: & 'a str,
//!     _: & String, _: & [ (String, String) ], _: & String
//!   ) -> SmtRes<String> {
//!     Ok(s.to_string())
//!   }
//! }
//!
//! let mut solver = match Solver::default(& Parser) {
//!   Ok(kid) => kid,
//!   Err(e) => panic!("Could not spawn solver kid: {:?}", e)
//! } ;
//!
//! solver.declare_const("x", "Int").unwrap() ;
//!
//! let actlit = solver.get_actlit().unwrap() ;
//! let mut buf: Vec<u8> = vec![] ;
//! actlit.write(& mut buf).unwrap() ;
//! assert_eq!{
//!   "|rsmt2 actlit 0|",
//!   ::std::str::from_utf8(& buf).unwrap()
//! }
//!
//! solver.assert_act(& actlit, "(> x 7)").unwrap() ;
//! solver.assert_act(& actlit, "(= (mod x 2) 0)").unwrap() ;
//! assert!{
//!   solver.check_sat_act( Some(& actlit) ).unwrap()
//! }
//!
//! let model = solver.get_model_const().unwrap() ;
//! let mut model = model.into_iter() ;
//! if let Some((x, int, n)) = model.next() {
//!   assert_eq!{ x, "x" }
//!   assert_eq!{ int, "Int" }
//!   use std::str::FromStr ;
//!   let n = i64::from_str(& n).unwrap() ;
//!   println!("{}", n) ;
//!   assert!{ n > 7 }
//!   assert!{ n % 2 == 0 }
//! } else {
//!   panic!("expected the model for `x`")
//! }
//! assert_eq!{
//!   model.next(), None
//! }
//!
//! solver.de_actlit(actlit).unwrap() ;
//!
//! solver.kill().unwrap()
//! ```
//!
//!
//!
//! # Discussion on activation literals
//!
//! The activation literal technique is a much more efficient alternative to
//! the `push`/`pop` SMT-LIB commands. When a `pop` command is issued, solvers
//! usually reset themselves and re-declare/assert whatever was before the last
//! push.
//!
//! Activation literals are boolean nullary symbols controlling the activation
//! of some assertions.
//!
//! For instance
//!
//! ```smt2
//! (declare-fun x () Int)
//!
//! (push 1)
//!   (assert (> x 0))
//!   (assert (< x 3))
//!   (assert (= (mod x 3) 0))
//!   (check-sat)
//!   ; unsat
//! (pop 1)
//!
//! (push 1)
//!   (assert (> x 7))
//!   (assert (= (mod x 2) 0))
//!   (check-sat)
//!   (get-value (x))
//! (pop 1)
//! ```
//!
//! can be encoded with activation literals as
//!
//! ```smt
//! (declare-fun x () Int)
//!
//! (declare-fun actlit_1 () Bool)
//! (declare-fun actlit_2 () Bool)
//!
//! (assert (=> actlit_1 (> x 0)) )
//! (assert (=> actlit_2 (< x 3)) )
//! (assert (=> actlit_2 (= (mod x 3) 0)) )
//! (check-sat actlit_1 actlit_2) ; <--- Conditional check-sat
//!                               ;      usually called "check-sat-assuming"
//! ; unsat
//!
//! (assert (not actlit_2)) ; <--- Actlit deactivation
//!                         ;      all its assertions basically disappear
//!
//! (declare-fun actlit_3 () Bool)
//!
//! (assert (=> actlit_3 (> x 7)) )
//! (assert (=> actlit_3 (= (mod x 2) 0)) )
//! (check-sat actlit_1 actlit_3)
//! ; sat
//! (get-value (x))
//! ```
//!
//! This is much more efficient than `push`/`pop`: the conditional `check-sat`s
//! basically force the activation literals directly in the SAT part of the SMT
//! solver. Long story short, this means everything the solver learns during
//! the checks is still valid afterwards. Conversely, after a `pop` solvers are
//! usually unable to decide what to keep from the checks before the `pop`, and
//! thus drop everything.
//!
//! Actlits are **not** equivalent to `push`/`pop` however. Pushing a scope
//! allows to declare/define function symbols and then discard them, while
//! keeping whatever's outside of the scope. Actlits (mostly) just guard
//! assertions and cannot accomplish this.
//!
//! [why actlits]: #discussion-on-activation-literals
//! (Activation literals, why?)
//! [SActlit]: struct.SActlit.html (SActlit documentation)
//! [Actlit]: struct.Actlit.html (Actlit documentation)
//! [phantom]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html
//! (PhantomData documentation)
//! [check sat ass]: ../trait.Solver.html#method.check_sat_assuming
//! (check_sat_assuming function)
//! [get_model]: ../trait.Solver.html#method.get_model (get_model function)

pub use solver::Actlit;
<commit_msg>rmed stupid debug tee in doc tests<commit_after>//! Activation literal type and helpers.
//!
//! For an explanation of what activation literal are, see
//! [the discussion below][why actlits].
//!
//! **NB**: while `rmst2`'s actlit API declares some constant symbols in the
//! underlying solver, these will not appear in the result of
//! [`get_model`](get_model) queries.
//!
//!
//! # Relevant functions on solvers
//!
//! - [`get_actlit`](../trait.Solver.html#method.get_actlit)
//! - [`get_sactlit`](../trait.Solver.html#method.get_sactlit)
//! - [`de_actlit`](../trait.Solver.html#method.de_actlit)
//! - [`set_actlit`](../trait.Solver.html#method.set_actlit)
//! - [`assert_act`](../trait.Solver.html#method.assert_act)
//! - [`assert_act_with`](../trait.Solver.html#method.assert_act_with)
//! - [`print_check_sat_act`](../trait.Solver.html#method.print_check_sat_act)
//! - [`check_sat_act`](../trait.Solver.html#method.check_sat_act)
//! - [`check_sat_act_or_unk`]
//!   (../trait.Solver.html#method.check_sat_act_or_unk)
//!
//!
//!
//! # Usage
//!
//! First, one can of course create activation literals by hand, and use them
//! in `check-sat`s with [`check_sat_assuming`][check sat ass]:
//!
//! ```
//! use rsmt2::* ;
//!
//! let mut solver = Solver::default(()).unwrap() ;
//! solver.declare_const("x", "Int").unwrap() ;
//!
//! solver.declare_const("actlit", "Bool").unwrap() ;
//! solver.assert("\
//!   (=> actlit \
//!       (and (> x 0) (< x 3) (= (mod x 3) 0))\
//!   )\
//! ").unwrap() ;
//! assert!{
//!   ! solver.check_sat_assuming( Some("actlit") ).unwrap()
//! }
//! solver.assert("(not actlit)").unwrap() ;
//!
//! solver.declare_const("other_actlit", "Bool").unwrap() ;
//! solver.assert("\
//!   (=> other_actlit \
//!       (and (> x 7) (= (mod x 2) 0))\
//!   )\
//! ").unwrap() ;
//! assert!{
//!   solver.check_sat_assuming( Some("other_actlit") ).unwrap()
//! }
//! solver.assert("(not other_actlit)").unwrap() ;
//!
//! solver.kill().unwrap()
//! ```
//!
//! The activation literal API makes this process more straightforward:
//!
//! ```
//! use rsmt2::* ;
//!
//! let mut solver = match Solver::default(()) {
//!   Ok(kid) => kid,
//!   Err(e) => panic!("Could not spawn solver kid: {:?}", e)
//! } ;
//!
//! solver.declare_const("x", "Int").unwrap() ;
//!
//! let actlit = solver.get_actlit().unwrap() ;
//! solver.assert_act(& actlit, "(> x 0)").unwrap() ;
//! solver.assert_act(& actlit, "(< x 3)").unwrap() ;
//! solver.assert_act(& actlit, "(= (mod x 3) 0)").unwrap() ;
//!
//! assert!{
//!   ! solver.check_sat_act( Some(& actlit) ).unwrap()
//! }
//! solver.de_actlit(actlit).unwrap() ;
//! // At this point `actlit` has been consumed. So it's a bit safer than the
//! // version above, since use-after-deactivate is not possible.
//!
//! let actlit = solver.get_actlit().unwrap() ;
//! solver.assert_act(& actlit, "(> x 7)").unwrap() ;
//! solver.assert_act(& actlit, "(= (mod x 2) 0)").unwrap() ;
//! assert!{
//!   solver.check_sat_act( Some(& actlit) ).unwrap()
//! }
//! solver.de_actlit(actlit).unwrap() ;
//!
//! solver.kill().unwrap()
//! ```
//!
//!
//! **NB**: under the hood, `rmst2` declares a constant boolean symbol for each
//! actlit. Hence, there is a (very low) risk of collision with the user's
//! symbol. The internal actlits are named `"|rsmt2 actlit <uid>|"`. Any symbol
//! starting with `"|rsmt2 actlit "` is assumed to be a `rsmt2` actlit. In
//! particular, such symbols will be pruned out of `get_model` queries (if at
//! least one actlit was requested since the last reset).
//!
//! ```
//! use rsmt2::* ;
//! use rsmt2::parse::* ;
//!
//! struct Parser ;
//! impl<'a, 'b> IdentParser<String, String, & 'a str> for & 'b Parser {
//!   fn parse_ident(self, s: & 'a str) -> SmtRes<String> {
//!     Ok(s.to_string())
//!   }
//!   fn parse_type(self, s: & 'a str) -> SmtRes<String> {
//!     Ok(s.to_string())
//!   }
//! }
//! impl<'a, 'b> ModelParser<
//!   String, String, String, & 'a str
//! > for & 'b Parser {
//!   fn parse_value(
//!     self, s: & 'a str,
//!     _: & String, _: & [ (String, String) ], _: & String
//!   ) -> SmtRes<String> {
//!     Ok(s.to_string())
//!   }
//! }
//!
//! let mut solver = match Solver::default(& Parser) {
//!   Ok(kid) => kid,
//!   Err(e) => panic!("Could not spawn solver kid: {:?}", e)
//! } ;
//!
//! solver.declare_const("x", "Int").unwrap() ;
//!
//! let actlit = solver.get_actlit().unwrap() ;
//! let mut buf: Vec<u8> = vec![] ;
//! actlit.write(& mut buf).unwrap() ;
//! assert_eq!{
//!   "|rsmt2 actlit 0|",
//!   ::std::str::from_utf8(& buf).unwrap()
//! }
//!
//! solver.assert_act(& actlit, "(> x 7)").unwrap() ;
//! solver.assert_act(& actlit, "(= (mod x 2) 0)").unwrap() ;
//! assert!{
//!   solver.check_sat_act( Some(& actlit) ).unwrap()
//! }
//!
//! let model = solver.get_model_const().unwrap() ;
//! let mut model = model.into_iter() ;
//! if let Some((x, int, n)) = model.next() {
//!   assert_eq!{ x, "x" }
//!   assert_eq!{ int, "Int" }
//!   use std::str::FromStr ;
//!   let n = i64::from_str(& n).unwrap() ;
//!   println!("{}", n) ;
//!   assert!{ n > 7 }
//!   assert!{ n % 2 == 0 }
//! } else {
//!   panic!("expected the model for `x`")
//! }
//! assert_eq!{
//!   model.next(), None
//! }
//!
//! solver.de_actlit(actlit).unwrap() ;
//!
//! solver.kill().unwrap()
//! ```
//!
//!
//!
//! # Discussion on activation literals
//!
//! The activation literal technique is a much more efficient alternative to
//! the `push`/`pop` SMT-LIB commands. When a `pop` command is issued, solvers
//! usually reset themselves and re-declare/assert whatever was before the last
//! push.
//!
//! Activation literals are boolean nullary symbols controlling the activation
//! of some assertions.
//!
//! For instance
//!
//! ```smt2
//! (declare-fun x () Int)
//!
//! (push 1)
//!   (assert (> x 0))
//!   (assert (< x 3))
//!   (assert (= (mod x 3) 0))
//!   (check-sat)
//!   ; unsat
//! (pop 1)
//!
//! (push 1)
//!   (assert (> x 7))
//!   (assert (= (mod x 2) 0))
//!   (check-sat)
//!   (get-value (x))
//! (pop 1)
//! ```
//!
//! can be encoded with activation literals as
//!
//! ```smt
//! (declare-fun x () Int)
//!
//! (declare-fun actlit_1 () Bool)
//! (declare-fun actlit_2 () Bool)
//!
//! (assert (=> actlit_1 (> x 0)) )
//! (assert (=> actlit_2 (< x 3)) )
//! (assert (=> actlit_2 (= (mod x 3) 0)) )
//! (check-sat actlit_1 actlit_2) ; <--- Conditional check-sat
//!                               ;      usually called "check-sat-assuming"
//! ; unsat
//!
//! (assert (not actlit_2)) ; <--- Actlit deactivation
//!                         ;      all its assertions basically disappear
//!
//! (declare-fun actlit_3 () Bool)
//!
//! (assert (=> actlit_3 (> x 7)) )
//! (assert (=> actlit_3 (= (mod x 2) 0)) )
//! (check-sat actlit_1 actlit_3)
//! ; sat
//! (get-value (x))
//! ```
//!
//! This is much more efficient than `push`/`pop`: the conditional `check-sat`s
//! basically force the activation literals directly in the SAT part of the SMT
//! solver. Long story short, this means everything the solver learns during
//! the checks is still valid afterwards. Conversely, after a `pop` solvers are
//! usually unable to decide what to keep from the checks before the `pop`, and
//! thus drop everything.
//!
//! Actlits are **not** equivalent to `push`/`pop` however. Pushing a scope
//! allows to declare/define function symbols and then discard them, while
//! keeping whatever's outside of the scope. Actlits (mostly) just guard
//! assertions and cannot accomplish this.
//!
//! [why actlits]: #discussion-on-activation-literals
//! (Activation literals, why?)
//! [SActlit]: struct.SActlit.html (SActlit documentation)
//! [Actlit]: struct.Actlit.html (Actlit documentation)
//! [phantom]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html
//! (PhantomData documentation)
//! [check sat ass]: ../trait.Solver.html#method.check_sat_assuming
//! (check_sat_assuming function)
//! [get_model]: ../trait.Solver.html#method.get_model (get_model function)

pub use solver::Actlit;
<|endoftext|>