<commit_before>use proc_macro2::TokenStream;
use quote::quote;
use std::env;
use std::fs::File;
use std::io::{prelude::*, BufReader, BufWriter};
use std::path::Path;

fn get_data_file(path_fragment: &str) -> BufReader<File> {
    println!("cargo:rerun-if-changed=../data/{}", path_fragment);

    let path = Path::new("../data").join(path_fragment);

    BufReader::new(File::open(path).expect("Something went wrong reading the file"))
}

fn ivd_sequences() -> TokenStream {
    let ivd_seqs_file = get_data_file("Unicode/IVD/IVD_Sequences.txt");

    let lines: Vec<_> = ivd_seqs_file
        .lines()
        .map(Result::unwrap)
        .filter(|line| line.len() > 0 && !line.starts_with('#'))
        .collect();
    let array_size = lines.len();

    let structs: TokenStream = lines
        .iter()
        .map(|line| {
            let parts: Vec<_> = line.split(';').map(|s| s.trim()).collect();
            let codepoint_parts: Vec<_> = parts[0].split(' ').collect();
            let base_codepoint = u32::from_str_radix(codepoint_parts[0].trim(), 16).unwrap();
            let variation_selector = u32::from_str_radix(codepoint_parts[1].trim(), 16).unwrap();
            let collection = parts[1].trim();
            let item = parts[2].trim();

            quote! {
                IdeographicVariationSequence {
                    base_codepoint: #base_codepoint,
                    variation_selector: #variation_selector,
                    collection: #collection,
                    item: #item
                },
            }
        })
        .collect();

    quote! {
        const IVD_SEQUENCES: [IdeographicVariationSequence; #array_size] = [
            #structs
        ];
    }
}

fn build_encoding_table(name: &str, data_file: &str) -> TokenStream {
    let encoding_table_file = get_data_file(data_file);

    let lines: Vec<_> = encoding_table_file
        .lines()
        .map(Result::unwrap)
        // remove text after first '#'
        .map(|line| line.split('#').nth(0).unwrap().to_string())
        .filter(|line| line.len() > 0)
        // weird format found in CP857 (and others)
        .filter(|line| !(line.len() == 1 && line.chars().nth(0).unwrap() == '\x1a'))
        .collect();

    let mappings: TokenStream = lines
        .iter()
        .map(|line| line.split('\t').collect::<Vec<_>>())
        .filter(|components| components[1].trim().len() != 0)
        .map(|components| {
            let coded_byte = u32::from_str_radix(&components[0][2..], 16).unwrap();
            let codepoint = u32::from_str_radix(&components[1][2..], 16).unwrap();

            quote! {
                (#codepoint, #coded_byte),
            }
        })
        .collect();

    quote! {
        encoding_table.insert(#name, [#mappings].iter().cloned().collect());
    }
}

fn build_encodings() -> TokenStream {
    let tables: TokenStream = [
        build_encoding_table("ASCII", "ascii.txt"),
        build_encoding_table(
            "ASCII with typographical quotes",
            "Unicode/Mappings/VENDORS/MISC/US-ASCII-QUOTES.TXT",
        ),
        build_encoding_table(
            "ISO-8859-1 (Latin-1 Western European)",
            "Unicode/Mappings/ISO8859/8859-1.TXT",
        ),
        build_encoding_table(
            "ISO-8859-2 (Latin-2 Central European)",
            "Unicode/Mappings/ISO8859/8859-2.TXT",
        ),
        build_encoding_table(
            "ISO-8859-3 (Latin-3 South European)",
            "Unicode/Mappings/ISO8859/8859-3.TXT",
        ),
        build_encoding_table(
            "ISO-8859-4 (Latin-4 North European)",
            "Unicode/Mappings/ISO8859/8859-4.TXT",
        ),
        build_encoding_table(
            "ISO-8859-5 (Latin/Cyrillic)",
            "Unicode/Mappings/ISO8859/8859-5.TXT",
        ),
        build_encoding_table(
            "ISO-8859-6 (Latin/Arabic)",
            "Unicode/Mappings/ISO8859/8859-6.TXT",
        ),
        build_encoding_table(
            "ISO-8859-7 (Latin/Greek)",
            "Unicode/Mappings/ISO8859/8859-7.TXT",
        ),
        build_encoding_table(
            "ISO-8859-8 (Latin/Hebrew)",
            "Unicode/Mappings/ISO8859/8859-8.TXT",
        ),
        build_encoding_table(
            "ISO-8859-9 (Latin-5 Turkish)",
            "Unicode/Mappings/ISO8859/8859-9.TXT",
        ),
        build_encoding_table(
            "ISO-8859-10 (Latin-6 Nordic)",
            "Unicode/Mappings/ISO8859/8859-10.TXT",
        ),
        build_encoding_table(
            "ISO-8859-11 (Latin/Thai)",
            "Unicode/Mappings/ISO8859/8859-11.TXT",
        ),
        build_encoding_table(
            "ISO-8859-13 (Latin-7 Baltic Rim)",
            "Unicode/Mappings/ISO8859/8859-13.TXT",
        ),
        build_encoding_table(
            "ISO-8859-14 (Latin-8 Celtic)",
            "Unicode/Mappings/ISO8859/8859-14.TXT",
        ),
        build_encoding_table(
            "ISO-8859-15 (Latin-9)",
            "Unicode/Mappings/ISO8859/8859-15.TXT",
        ),
        build_encoding_table(
            "ISO-8859-16 (Latin-10 South-Eastern European)",
            "Unicode/Mappings/ISO8859/8859-16.TXT",
        ),
        build_encoding_table(
            "Code page 437 (MS-DOS Latin US)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP437.TXT",
        ),
        build_encoding_table(
            "Code page 737 (MS-DOS Greek)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP737.TXT",
        ),
        build_encoding_table(
            "Code page 775 (MS-DOS Baltic Rim)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP775.TXT",
        ),
        build_encoding_table(
            "Code page 850 (MS-DOS Latin 1)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP850.TXT",
        ),
        build_encoding_table(
            "Code page 852 (MS-DOS Latin 2)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP852.TXT",
        ),
        build_encoding_table(
            "Code page 855 (MS-DOS Cyrillic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP855.TXT",
        ),
        build_encoding_table(
            "Code page 857 (MS-DOS Turkish)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP857.TXT",
        ),
        build_encoding_table(
            "Code page 860 (MS-DOS Portuguese)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP860.TXT",
        ),
        build_encoding_table(
            "Code page 861 (MS-DOS Icelandic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP861.TXT",
        ),
        build_encoding_table(
            "Code page 862 (MS-DOS Hebrew)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP862.TXT",
        ),
        build_encoding_table(
            "Code page 863 (MS-DOS French Canada)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP863.TXT",
        ),
        build_encoding_table(
            "Code page 864 (MS-DOS Arabic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP864.TXT",
        ),
        build_encoding_table(
            "Code page 865 (MS-DOS Nordic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP865.TXT",
        ),
        build_encoding_table(
            "Code page 866 (MS-DOS Cyrillic CIS 1)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP866.TXT",
        ),
        build_encoding_table(
            "Code page 869 (MS-DOS Greek 2)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP869.TXT",
        ),
        build_encoding_table(
            "Code page 874 (Thai)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP874.TXT",
        ),
        build_encoding_table(
            "Code page 932 (Japanese; Shift-JIS extension)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP932.TXT",
        ),
        build_encoding_table(
            "Code page 936 (Simplified Chinese)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP936.TXT",
        ),
        build_encoding_table(
            "Code page 949 (Korean)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP949.TXT",
        ),
        build_encoding_table(
            "Code page 950 (Traditional Chinese)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP950.TXT",
        ),
        build_encoding_table(
            "Code page 1250 (Windows Latin 2 (Central Europe))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1250.TXT",
        ),
        build_encoding_table(
            "Code page 1251 (Windows Cyrillic (Slavic))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1251.TXT",
        ),
        build_encoding_table(
            "Code page 1252 (Windows Latin 1 (ANSI))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1252.TXT",
        ),
        build_encoding_table(
            "Code page 1253 (Windows Greek)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1253.TXT",
        ),
        build_encoding_table(
            "Code page 1254 (Windows Latin 5 (Turkish))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1254.TXT",
        ),
        build_encoding_table(
            "Code page 1255 (Windows Hebrew)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1255.TXT",
        ),
        build_encoding_table(
            "Code page 1256 (Windows Arabic)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1256.TXT",
        ),
        build_encoding_table(
            "Code page 1257 (Windows Baltic Rim)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1257.TXT",
        ),
        build_encoding_table(
            "Code page 1258 (Windows Vietnamese)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1258.TXT",
        ),
        build_encoding_table(
            "Code page 10000 (Macintosh Roman)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/ROMAN.TXT",
        ),
        build_encoding_table(
            "Code page 10006 (Macintosh Greek)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/GREEK.TXT",
        ),
        build_encoding_table(
            "Code page 10007 (Macintosh Cyrillic)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/CYRILLIC.TXT",
        ),
        build_encoding_table(
            "Code page 10029 (Macintosh Latin 2)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/LATIN2.TXT",
        ),
        build_encoding_table(
            "Code page 10079 (Macintosh Iceland)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/ICELAND.TXT",
        ),
        build_encoding_table(
            "Code page 10081 (Macintosh Turkish)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/TURKISH.TXT",
        ),
        build_encoding_table(
            "Code page 37 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP037.TXT",
        ),
        build_encoding_table(
            "Code page 500 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP500.TXT",
        ),
        build_encoding_table(
            "Code page 875 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP875.TXT",
        ),
        build_encoding_table(
            "Code page 1026 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP1026.TXT",
        ),
    ]
    .iter()
    .cloned()
    .collect();

    quote! {
        lazy_static! {
            static ref ENCODING_TABLES: HashMap<&'static str, EncodingTable> = {
                let mut encoding_table = HashMap::new();
                #tables
                encoding_table
            };
        }
    }
}

fn main() {
    let out_dir = env::var_os("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("compiled-data.rs");

    write!(
        BufWriter::new(File::create(dest_path).unwrap()),
        "{}{}",
        ivd_sequences(),
        build_encodings()
    )
    .unwrap();
}
<commit_msg>Minor code cleanup<commit_after>use proc_macro2::TokenStream;
use quote::quote;
use std::env;
use std::fs::File;
use std::io::{prelude::*, BufReader, BufWriter};
use std::path::Path;

fn get_data_file(path_fragment: &str) -> BufReader<File> {
    println!("cargo:rerun-if-changed=../data/{}", path_fragment);

    let path = Path::new("../data").join(path_fragment);

    BufReader::new(File::open(path).expect("Something went wrong reading the file"))
}

fn ivd_sequences() -> TokenStream {
    let ivd_seqs_file = get_data_file("Unicode/IVD/IVD_Sequences.txt");

    let lines: Vec<_> = ivd_seqs_file
        .lines()
        .map(Result::unwrap)
        .filter(|line| line.len() > 0 && !line.starts_with('#'))
        .collect();
    let array_size = lines.len();

    let structs: TokenStream = lines
        .iter()
        .map(|line| {
            let parts: Vec<_> = line.split(';').map(|s| s.trim()).collect();
            let codepoint_parts: Vec<_> = parts[0].split(' ').collect();
            let base_codepoint = u32::from_str_radix(codepoint_parts[0].trim(), 16).unwrap();
            let variation_selector = u32::from_str_radix(codepoint_parts[1].trim(), 16).unwrap();
            let collection = parts[1].trim();
            let item = parts[2].trim();

            quote! {
                IdeographicVariationSequence {
                    base_codepoint: #base_codepoint,
                    variation_selector: #variation_selector,
                    collection: #collection,
                    item: #item
                },
            }
        })
        .collect();

    quote! {
        const IVD_SEQUENCES: [IdeographicVariationSequence; #array_size] = [
            #structs
        ];
    }
}

fn build_encoding_table(name: &str, data_file: &str) -> TokenStream {
    let encoding_table_file = get_data_file(data_file);

    let lines: Vec<_> = encoding_table_file
        .lines()
        .map(Result::unwrap)
        // remove text after first '#'
        .map(|line| line.split('#').nth(0).unwrap().to_string())
        .filter(|line| line.len() > 0)
        // weird format found in CP857 (and others)
        .filter(|line| line != "\x1a")
        .collect();

    let mappings: TokenStream = lines
        .iter()
        .map(|line| line.split('\t').collect::<Vec<_>>())
        .filter(|components| components[1].trim().len() != 0)
        .map(|components| {
            let coded_byte = u32::from_str_radix(&components[0][2..], 16).unwrap();
            let codepoint = u32::from_str_radix(&components[1][2..], 16).unwrap();

            quote! {
                (#codepoint, #coded_byte),
            }
        })
        .collect();

    quote! {
        encoding_table.insert(#name, [#mappings].iter().cloned().collect());
    }
}

fn build_encodings() -> TokenStream {
    let tables: TokenStream = [
        build_encoding_table("ASCII", "ascii.txt"),
        build_encoding_table(
            "ASCII with typographical quotes",
            "Unicode/Mappings/VENDORS/MISC/US-ASCII-QUOTES.TXT",
        ),
        build_encoding_table(
            "ISO-8859-1 (Latin-1 Western European)",
            "Unicode/Mappings/ISO8859/8859-1.TXT",
        ),
        build_encoding_table(
            "ISO-8859-2 (Latin-2 Central European)",
            "Unicode/Mappings/ISO8859/8859-2.TXT",
        ),
        build_encoding_table(
            "ISO-8859-3 (Latin-3 South European)",
            "Unicode/Mappings/ISO8859/8859-3.TXT",
        ),
        build_encoding_table(
            "ISO-8859-4 (Latin-4 North European)",
            "Unicode/Mappings/ISO8859/8859-4.TXT",
        ),
        build_encoding_table(
            "ISO-8859-5 (Latin/Cyrillic)",
            "Unicode/Mappings/ISO8859/8859-5.TXT",
        ),
        build_encoding_table(
            "ISO-8859-6 (Latin/Arabic)",
            "Unicode/Mappings/ISO8859/8859-6.TXT",
        ),
        build_encoding_table(
            "ISO-8859-7 (Latin/Greek)",
            "Unicode/Mappings/ISO8859/8859-7.TXT",
        ),
        build_encoding_table(
            "ISO-8859-8 (Latin/Hebrew)",
            "Unicode/Mappings/ISO8859/8859-8.TXT",
        ),
        build_encoding_table(
            "ISO-8859-9 (Latin-5 Turkish)",
            "Unicode/Mappings/ISO8859/8859-9.TXT",
        ),
        build_encoding_table(
            "ISO-8859-10 (Latin-6 Nordic)",
            "Unicode/Mappings/ISO8859/8859-10.TXT",
        ),
        build_encoding_table(
            "ISO-8859-11 (Latin/Thai)",
            "Unicode/Mappings/ISO8859/8859-11.TXT",
        ),
        build_encoding_table(
            "ISO-8859-13 (Latin-7 Baltic Rim)",
            "Unicode/Mappings/ISO8859/8859-13.TXT",
        ),
        build_encoding_table(
            "ISO-8859-14 (Latin-8 Celtic)",
            "Unicode/Mappings/ISO8859/8859-14.TXT",
        ),
        build_encoding_table(
            "ISO-8859-15 (Latin-9)",
            "Unicode/Mappings/ISO8859/8859-15.TXT",
        ),
        build_encoding_table(
            "ISO-8859-16 (Latin-10 South-Eastern European)",
            "Unicode/Mappings/ISO8859/8859-16.TXT",
        ),
        build_encoding_table(
            "Code page 437 (MS-DOS Latin US)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP437.TXT",
        ),
        build_encoding_table(
            "Code page 737 (MS-DOS Greek)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP737.TXT",
        ),
        build_encoding_table(
            "Code page 775 (MS-DOS Baltic Rim)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP775.TXT",
        ),
        build_encoding_table(
            "Code page 850 (MS-DOS Latin 1)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP850.TXT",
        ),
        build_encoding_table(
            "Code page 852 (MS-DOS Latin 2)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP852.TXT",
        ),
        build_encoding_table(
            "Code page 855 (MS-DOS Cyrillic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP855.TXT",
        ),
        build_encoding_table(
            "Code page 857 (MS-DOS Turkish)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP857.TXT",
        ),
        build_encoding_table(
            "Code page 860 (MS-DOS Portuguese)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP860.TXT",
        ),
        build_encoding_table(
            "Code page 861 (MS-DOS Icelandic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP861.TXT",
        ),
        build_encoding_table(
            "Code page 862 (MS-DOS Hebrew)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP862.TXT",
        ),
        build_encoding_table(
            "Code page 863 (MS-DOS French Canada)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP863.TXT",
        ),
        build_encoding_table(
            "Code page 864 (MS-DOS Arabic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP864.TXT",
        ),
        build_encoding_table(
            "Code page 865 (MS-DOS Nordic)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP865.TXT",
        ),
        build_encoding_table(
            "Code page 866 (MS-DOS Cyrillic CIS 1)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP866.TXT",
        ),
        build_encoding_table(
            "Code page 869 (MS-DOS Greek 2)",
            "Unicode/Mappings/VENDORS/MICSFT/PC/CP869.TXT",
        ),
        build_encoding_table(
            "Code page 874 (Thai)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP874.TXT",
        ),
        build_encoding_table(
            "Code page 932 (Japanese; Shift-JIS extension)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP932.TXT",
        ),
        build_encoding_table(
            "Code page 936 (Simplified Chinese)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP936.TXT",
        ),
        build_encoding_table(
            "Code page 949 (Korean)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP949.TXT",
        ),
        build_encoding_table(
            "Code page 950 (Traditional Chinese)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP950.TXT",
        ),
        build_encoding_table(
            "Code page 1250 (Windows Latin 2 (Central Europe))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1250.TXT",
        ),
        build_encoding_table(
            "Code page 1251 (Windows Cyrillic (Slavic))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1251.TXT",
        ),
        build_encoding_table(
            "Code page 1252 (Windows Latin 1 (ANSI))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1252.TXT",
        ),
        build_encoding_table(
            "Code page 1253 (Windows Greek)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1253.TXT",
        ),
        build_encoding_table(
            "Code page 1254 (Windows Latin 5 (Turkish))",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1254.TXT",
        ),
        build_encoding_table(
            "Code page 1255 (Windows Hebrew)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1255.TXT",
        ),
        build_encoding_table(
            "Code page 1256 (Windows Arabic)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1256.TXT",
        ),
        build_encoding_table(
            "Code page 1257 (Windows Baltic Rim)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1257.TXT",
        ),
        build_encoding_table(
            "Code page 1258 (Windows Vietnamese)",
            "Unicode/Mappings/VENDORS/MICSFT/WINDOWS/CP1258.TXT",
        ),
        build_encoding_table(
            "Code page 10000 (Macintosh Roman)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/ROMAN.TXT",
        ),
        build_encoding_table(
            "Code page 10006 (Macintosh Greek)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/GREEK.TXT",
        ),
        build_encoding_table(
            "Code page 10007 (Macintosh Cyrillic)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/CYRILLIC.TXT",
        ),
        build_encoding_table(
            "Code page 10029 (Macintosh Latin 2)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/LATIN2.TXT",
        ),
        build_encoding_table(
            "Code page 10079 (Macintosh Iceland)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/ICELAND.TXT",
        ),
        build_encoding_table(
            "Code page 10081 (Macintosh Turkish)",
            "Unicode/Mappings/VENDORS/MICSFT/MAC/TURKISH.TXT",
        ),
        build_encoding_table(
            "Code page 37 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP037.TXT",
        ),
        build_encoding_table(
            "Code page 500 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP500.TXT",
        ),
        build_encoding_table(
            "Code page 875 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP875.TXT",
        ),
        build_encoding_table(
            "Code page 1026 (Microsoft EBCDIC)",
            "Unicode/Mappings/VENDORS/MICSFT/EBCDIC/CP1026.TXT",
        ),
    ]
    .iter()
    .cloned()
    .collect();

    quote! {
        lazy_static! {
            static ref ENCODING_TABLES: HashMap<&'static str, EncodingTable> = {
                let mut encoding_table = HashMap::new();
                #tables
                encoding_table
            };
        }
    }
}

fn main() {
    let out_dir = env::var_os("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("compiled-data.rs");

    write!(
        BufWriter::new(File::create(dest_path).unwrap()),
        "{}{}",
        ivd_sequences(),
        build_encodings()
    )
    .unwrap();
}
<|endoftext|>


<commit_before>use analysis::rust_type::Result;
use env::Env;
use gobjects::GStatus;
use library;
use library::*;
use nameutil::crate_name;
use traits::*;

// FIXME: This module needs redundant allocations audit
// TODO: ffi_type computations should be cached

pub fn ffi_type(env: &Env, tid: library::TypeId, c_type: &str) -> Result {
    let (ptr, inner) = rustify_pointers(c_type);
    let res = if ptr.is_empty() {
        if let Some(c_tid) = env.library.find_type(0, c_type) {
            // Fast track plain fundamental types avoiding some checks
            if env.library.type_(c_tid).maybe_ref_as::<Fundamental>().is_some() {
                if let &library::Type::FixedArray(_, size) = env.library.type_(tid) {
                    ffi_inner(env, c_tid, c_type.into())
                        .map_any(|s| format!("[{}; {}]", s, size))
                }
                else {
                    ffi_inner(env, c_tid, c_type.into())
                }
            }
            else { // c_type isn't fundamental
                ffi_inner(env, tid, inner)
            }
        }
        else { // c_type doesn't match any type in the library by name
            ffi_inner(env, tid, inner)
        }
    }
    else { // ptr not empty
        ffi_inner(env, tid, inner)
            .map_any(|s| format!("{} {}", ptr, s))
    };
    trace!("ffi_type({:?}, {}) -> {:?}", tid, c_type, res);
    res
}

fn ffi_inner(env: &Env, tid: library::TypeId, mut inner: String) -> Result {
    let volatile = inner.starts_with("volatile ");
    if volatile {
        inner = inner["volatile ".len()..].into();
    }

    let typ = env.library.type_(tid);
    let res = match *typ {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            let inner = match fund {
                None => "c_void",
                Boolean => "gboolean",
                Int8 => "i8",
                UInt8 => "u8",
                Int16 => "i16",
                UInt16 => "u16",
                Int32 => "i32",
                UInt32 => "u32",
                Int64 => "i64",
                UInt64 => "u64",
                Char => "c_char",
                UChar => "c_char",
                Short => "c_short",
                UShort => "c_ushort",
                Int => "c_int",
                UInt => "c_uint",
                Long => "c_long",
                ULong => "c_ulong",
                Size => "size_t",
                SSize => "ssize_t",
                Float => "c_float",
                Double => "c_double",
                UniChar => "u32",
                Utf8 => "c_char",
                Filename => "c_char",
                Type => "GType",
                Pointer => match &inner[..]  {
                    "void" => "c_void",
                    _ => &*inner,
                },
                Unsupported => return Err(format!("[Unsupported type {}]", inner)),
                VarArgs => panic!("Should not reach here"),
            };
            Ok(inner.into())
        }
        Type::Record(..) | Type::Alias(..) | Type::Function(..) => {
            if let Some(declared_c_type) = typ.get_glib_name() {
                if declared_c_type != inner {
                    let msg = format!("[c:type mismatch `{}` != `{}` of `{}`]",
                                      inner, declared_c_type, typ.get_name());
                    warn!("{}", msg);
                    return Err(msg);
                }
            }
            else {
                warn!("Type `{}` missing c_type", typ.get_name());
            }
            fix_name(env, tid, &inner)
        }
        Type::CArray(inner_tid) => ffi_inner(env, inner_tid, inner),
        Type::FixedArray(inner_tid, size) => {
            match ffi_inner(env, inner_tid, inner) {
                Ok(s) => Ok(format!("[{}; {}]", s, size)),
                Err(s) => Err(format!("[{}; {}]", s, size)),
            }
        }
        Type::Array(..) | Type::PtrArray(..)
                | Type::List(..) | Type::SList(..) | Type::HashTable(..) => {
            fix_name(env, tid, &inner)
        }
        _ => {
            if let Some(glib_name) = env.library.type_(tid).get_glib_name() {
                if inner != glib_name && !implements_c_type(&env.library, tid, &inner) {
                    let msg = format!("[c:type mismatch {} != {} of {}]", inner, glib_name,
                      env.library.type_(tid).get_name());
                    warn!("{}", msg);
                    Err(msg)
                }
                else {
                    fix_name(env, tid, &inner)
                }
            }
            else {
                let msg = format!("[Missing glib_name of {}, can't match != {}]",
                                  env.library.type_(tid).get_name(), inner);
                warn!("{}", msg);
                Err(msg)
            }
        }
    };

    if volatile {
        res.map(|s| format!("Volatile<{}>", s))
    }
    else {
        res
    }
}

fn fix_name(env: &Env, type_id: library::TypeId, name: &str) -> Result {
    if type_id.ns_id == library::INTERNAL_NAMESPACE {
        match *env.library.type_(type_id) {
            Type::Array(..) | Type::PtrArray(..)
                    | Type::List(..) | Type::SList(..) | Type::HashTable(..) => {
                if Some(MAIN_NAMESPACE) == env.library.find_namespace("GLib") {
                    Ok(name.into())
                }
                else {
                    Ok(format!("{}_ffi::{}", crate_name("GLib"), name))
                }
            }
            _ => Ok(name.into())
        }
    } else {
        let name_with_prefix = if type_id.ns_id == library::MAIN_NAMESPACE {
            name.into()
        } else {
            format!("{}_ffi::{}", fix_namespace(env, type_id), name)
        };
        if env.type_status_sys(&type_id.full_name(&env.library)) == GStatus::Ignore {
            Err(name_with_prefix)
        } else {
            Ok(name_with_prefix)
        }
    }
}

//TODO: check if need to use in non sys codegen
fn fix_namespace(env: &Env, type_id: library::TypeId) -> String {
    crate_name(&env.library.namespace(type_id.ns_id).name)
}

fn implements_c_type(library: &library::Library, tid: TypeId, c_type: &str) -> bool {
    if let Some(ref klass) = library.type_(tid).maybe_ref_as::<library::Class>() {
        klass.implements.iter().chain(klass.parents.iter())
            .any(|&super_tid| library.type_(super_tid).get_glib_name() == Some(c_type))
    }
    else if let Some(ref iface) = library.type_(tid).maybe_ref_as::<library::Interface>() {
        iface.prereq_parents.iter()
            .any(|&super_tid| library.type_(super_tid).get_glib_name() == Some(c_type))
    }
    else {
        false
    }
}

fn rustify_pointers(c_type: &str) -> (String, String) {
    let mut input = c_type.trim();
    let leading_const = input.starts_with("const ");
    if leading_const {
        input = &input[6..];
    }
    let end = [
        input.find(" const"),
        input.find("*const"),
        input.find("*"),
        Some(input.len()),
    ].iter().filter_map(|&x| x).min().unwrap();
    let inner = input[..end].trim().into();

    let mut ptrs: Vec<_> = input[end..].rsplit('*').skip(1)
        .map(|s| if s.contains("const") { "*const" } else { "*mut" }).collect();
    if let (true, Some(p)) = (leading_const, ptrs.last_mut()) {
        *p = "*const";
    }

    let res = (ptrs.connect(" "), inner);
    trace!("rustify `{}` -> `{}` `{}`", c_type, res.0, res.1);
    res
}

#[cfg(test)]
mod tests {
    use super::rustify_pointers as rustify_ptr;

    fn s(x: &str, y: &str) -> (String, String) {
        (x.into(), y.into())
    }

    #[test]
    fn rustify_pointers() {
        assert_eq!(rustify_ptr("char"), s("", "char"));
        assert_eq!(rustify_ptr("char*"), s("*mut", "char"));
        assert_eq!(rustify_ptr("const char*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const *"), s("*const", "char"));
        assert_eq!(rustify_ptr(" char * * "), s("*mut *mut", "char"));
        assert_eq!(rustify_ptr("const char**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("char const**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("const char* const*"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char const * const *"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char* const*"), s("*const *mut", "char"));
    }
}
<commit_msg>Comment tm*<commit_after>use analysis::rust_type::Result;
use env::Env;
use gobjects::GStatus;
use library;
use library::*;
use nameutil::crate_name;
use traits::*;

// FIXME: This module needs redundant allocations audit
// TODO: ffi_type computations should be cached

pub fn ffi_type(env: &Env, tid: library::TypeId, c_type: &str) -> Result {
    let (ptr, inner) = rustify_pointers(c_type);
    let res = if ptr.is_empty() {
        if let Some(c_tid) = env.library.find_type(0, c_type) {
            // Fast track plain fundamental types avoiding some checks
            if env.library.type_(c_tid).maybe_ref_as::<Fundamental>().is_some() {
                if let &library::Type::FixedArray(_, size) = env.library.type_(tid) {
                    ffi_inner(env, c_tid, c_type.into())
                        .map_any(|s| format!("[{}; {}]", s, size))
                }
                else {
                    ffi_inner(env, c_tid, c_type.into())
                }
            }
            else { // c_type isn't fundamental
                ffi_inner(env, tid, inner)
            }
        }
        else { // c_type doesn't match any type in the library by name
            ffi_inner(env, tid, inner)
        }
    }
    else { // ptr not empty
        ffi_inner(env, tid, inner)
            .map_any(|s| format!("{} {}", ptr, s))
    };
    trace!("ffi_type({:?}, {}) -> {:?}", tid, c_type, res);
    res
}

fn ffi_inner(env: &Env, tid: library::TypeId, mut inner: String) -> Result {
    let volatile = inner.starts_with("volatile ");
    if volatile {
        inner = inner["volatile ".len()..].into();
    }

    let typ = env.library.type_(tid);
    let res = match *typ {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            let inner = match fund {
                None => "c_void",
                Boolean => "gboolean",
                Int8 => "i8",
                UInt8 => "u8",
                Int16 => "i16",
                UInt16 => "u16",
                Int32 => "i32",
                UInt32 => "u32",
                Int64 => "i64",
                UInt64 => "u64",
                Char => "c_char",
                UChar => "c_char",
                Short => "c_short",
                UShort => "c_ushort",
                Int => "c_int",
                UInt => "c_uint",
                Long => "c_long",
                ULong => "c_ulong",
                Size => "size_t",
                SSize => "ssize_t",
                Float => "c_float",
                Double => "c_double",
                UniChar => "u32",
                Utf8 => "c_char",
                Filename => "c_char",
                Type => "GType",
                Pointer => match &inner[..]  {
                    "void" => "c_void",
                    "tm" => return Err(inner),  //TODO: try use time:Tm
                    _ => &*inner,
                },
                Unsupported => return Err(format!("[Unsupported type {}]", inner)),
                VarArgs => panic!("Should not reach here"),
            };
            Ok(inner.into())
        }
        Type::Record(..) | Type::Alias(..) | Type::Function(..) => {
            if let Some(declared_c_type) = typ.get_glib_name() {
                if declared_c_type != inner {
                    let msg = format!("[c:type mismatch `{}` != `{}` of `{}`]",
                                      inner, declared_c_type, typ.get_name());
                    warn!("{}", msg);
                    return Err(msg);
                }
            }
            else {
                warn!("Type `{}` missing c_type", typ.get_name());
            }
            fix_name(env, tid, &inner)
        }
        Type::CArray(inner_tid) => ffi_inner(env, inner_tid, inner),
        Type::FixedArray(inner_tid, size) => {
            match ffi_inner(env, inner_tid, inner) {
                Ok(s) => Ok(format!("[{}; {}]", s, size)),
                Err(s) => Err(format!("[{}; {}]", s, size)),
            }
        }
        Type::Array(..) | Type::PtrArray(..)
                | Type::List(..) | Type::SList(..) | Type::HashTable(..) => {
            fix_name(env, tid, &inner)
        }
        _ => {
            if let Some(glib_name) = env.library.type_(tid).get_glib_name() {
                if inner != glib_name && !implements_c_type(&env.library, tid, &inner) {
                    let msg = format!("[c:type mismatch {} != {} of {}]", inner, glib_name,
                      env.library.type_(tid).get_name());
                    warn!("{}", msg);
                    Err(msg)
                }
                else {
                    fix_name(env, tid, &inner)
                }
            }
            else {
                let msg = format!("[Missing glib_name of {}, can't match != {}]",
                                  env.library.type_(tid).get_name(), inner);
                warn!("{}", msg);
                Err(msg)
            }
        }
    };

    if volatile {
        res.map(|s| format!("Volatile<{}>", s))
    }
    else {
        res
    }
}

fn fix_name(env: &Env, type_id: library::TypeId, name: &str) -> Result {
    if type_id.ns_id == library::INTERNAL_NAMESPACE {
        match *env.library.type_(type_id) {
            Type::Array(..) | Type::PtrArray(..)
                    | Type::List(..) | Type::SList(..) | Type::HashTable(..) => {
                if Some(MAIN_NAMESPACE) == env.library.find_namespace("GLib") {
                    Ok(name.into())
                }
                else {
                    Ok(format!("{}_ffi::{}", crate_name("GLib"), name))
                }
            }
            _ => Ok(name.into())
        }
    } else {
        let name_with_prefix = if type_id.ns_id == library::MAIN_NAMESPACE {
            name.into()
        } else {
            format!("{}_ffi::{}", fix_namespace(env, type_id), name)
        };
        if env.type_status_sys(&type_id.full_name(&env.library)) == GStatus::Ignore {
            Err(name_with_prefix)
        } else {
            Ok(name_with_prefix)
        }
    }
}

//TODO: check if need to use in non sys codegen
fn fix_namespace(env: &Env, type_id: library::TypeId) -> String {
    crate_name(&env.library.namespace(type_id.ns_id).name)
}

fn implements_c_type(library: &library::Library, tid: TypeId, c_type: &str) -> bool {
    if let Some(ref klass) = library.type_(tid).maybe_ref_as::<library::Class>() {
        klass.implements.iter().chain(klass.parents.iter())
            .any(|&super_tid| library.type_(super_tid).get_glib_name() == Some(c_type))
    }
    else if let Some(ref iface) = library.type_(tid).maybe_ref_as::<library::Interface>() {
        iface.prereq_parents.iter()
            .any(|&super_tid| library.type_(super_tid).get_glib_name() == Some(c_type))
    }
    else {
        false
    }
}

fn rustify_pointers(c_type: &str) -> (String, String) {
    let mut input = c_type.trim();
    let leading_const = input.starts_with("const ");
    if leading_const {
        input = &input[6..];
    }
    let end = [
        input.find(" const"),
        input.find("*const"),
        input.find("*"),
        Some(input.len()),
    ].iter().filter_map(|&x| x).min().unwrap();
    let inner = input[..end].trim().into();

    let mut ptrs: Vec<_> = input[end..].rsplit('*').skip(1)
        .map(|s| if s.contains("const") { "*const" } else { "*mut" }).collect();
    if let (true, Some(p)) = (leading_const, ptrs.last_mut()) {
        *p = "*const";
    }

    let res = (ptrs.connect(" "), inner);
    trace!("rustify `{}` -> `{}` `{}`", c_type, res.0, res.1);
    res
}

#[cfg(test)]
mod tests {
    use super::rustify_pointers as rustify_ptr;

    fn s(x: &str, y: &str) -> (String, String) {
        (x.into(), y.into())
    }

    #[test]
    fn rustify_pointers() {
        assert_eq!(rustify_ptr("char"), s("", "char"));
        assert_eq!(rustify_ptr("char*"), s("*mut", "char"));
        assert_eq!(rustify_ptr("const char*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const *"), s("*const", "char"));
        assert_eq!(rustify_ptr(" char * * "), s("*mut *mut", "char"));
        assert_eq!(rustify_ptr("const char**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("char const**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("const char* const*"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char const * const *"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char* const*"), s("*const *mut", "char"));
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::fs::File;
use std::ffi::OsString;
use std::io::Write;

use app::parser::Parser;
use shell::Shell;
use args::{ArgSettings, OptBuilder};

macro_rules! w {
    ($_self:ident, $f:ident, $to_w:expr) => {
        match $f.write_all($to_w) {
            Ok(..) => (),
            Err(..) => panic!(format!("Failed to write to file completions file")),
        }
    };
}

pub struct ComplGen<'a, 'b> where 'a: 'b {
    p: &'b Parser<'a, 'b>,
    out_dir: OsString,
}

impl<'a, 'b> ComplGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>, od: OsString) -> Self {
        ComplGen {
            p: p,
            out_dir: od,
        }
    }

    pub fn generate(&self, for_shell: Shell) {
        match for_shell {
            Shell::Bash => self.gen_bash(),
        }
    }

    fn gen_bash(&self) {
        use std::error::Error;
        let out_dir = PathBuf::from(&self.out_dir);

        let mut file = match File::create(out_dir.join("bash.sh")) {
            Err(why) => panic!("couldn't create bash completion file: {}",
                why.description()),
            Ok(file) => file,
        };
        w!(self, file, format!(
"_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} {name}
",
            name=self.p.meta.bin_name.as_ref().unwrap(),
            name_opts=self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            name_opts_details=self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            subcmds=self.all_subcommands(),
            subcmd_details=self.subcommand_details()
        ).as_bytes());
    }

    fn all_subcommands(&self) -> String {
        let mut subcmds = String::new();
        let mut scs = get_all_subcommands(self.p);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmds = format!(
                "{}
            {name})
                cmd+=\"_{name}\"
                ;;",
                subcmds,
                name=sc.replace("-", "_"));
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        let mut subcmd_dets = String::new();
        let mut scs = get_all_subcommand_paths(self.p, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!(
                "{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            ;;",
                subcmd_dets,
                subcmd=sc.replace("-", "_"),
                sc_opts=self.all_options_for_path(&*sc),
                level=sc.split("_").map(|_|1).fold(0, |acc, n| acc + n),
                opts_details=self.option_details_for_path(&*sc)
            );
        }

        subcmd_dets
    }

    fn all_options_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc).next().unwrap().p;
        }
        let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
        opts = format!("{} {}", opts, p.long_list.iter()
                                                 .fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
        opts = format!("{} {}", opts, p.positionals.values()
                                                   .fold(String::new(), |acc, p| format!("{} {}", acc, p)));
        opts = format!("{} {}", opts, p.subcommands.iter()
                                                   .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
        opts
    }

    fn option_details_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc).next().unwrap().p;
        }
        let mut opts = String::new();
        for o in &p.opts {
            if let Some(l) = o.long {
                opts = format!("{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, l, vals_for(o));
            }
            if let Some(s) = o.short {
                opts = format!("{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, s, vals_for(o));
            }
        }
        opts
    }
}

pub fn get_all_subcommands(p: &Parser) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        return vec![p.meta.name.clone()]
    }
    for sc in p.subcommands.iter().map(|ref s| s.p.meta.name.clone()) {
        subcmds.push(sc);
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommands(&s.p)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        if !first {
            return vec![p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_")]
        }
        return vec![];
    }
    for sc in p.subcommands.iter()
                           .map(|ref s| s.p.meta.bin_name.as_ref()
                                                         .unwrap()
                                                         .clone()
                                                         .replace(" ", "_")) {
        subcmds.push(sc);
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommand_paths(&s.p, false)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

fn vals_for(o: &OptBuilder) -> String {
    use args::AnyArg;
    let mut ret = String::new();
    let mut needs_quotes = true;
    if let Some(ref vals) = o.possible_vals() {
        needs_quotes = false;
        ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
    } else if let Some(ref vec) = o.val_names() {
        let mut it = vec.iter().peekable();
        while let Some((_, val)) = it.next() {
            ret = format!("{}<{}>{}", ret, val,
                if it.peek().is_some() {
                    " "
                } else {
                    ""
                });
        }
        let num = vec.len();
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else if let Some(num) = o.num_vals() {
        let mut it = (0..num).peekable();
        while let Some(_) = it.next() {
            ret = format!("{}<{}>{}", ret, o.name(),
            if it.peek().is_some() {
                " "
            } else {
                ""
            });
        }
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else {
        ret = format!("<{}>", o.name());
        if o.is_set(ArgSettings::Multiple) {
            ret = format!("{}...", ret);
        }
    }
    if needs_quotes {
        ret = format!("\"{}\"", ret);
    }
    ret
}
<commit_msg>imp(Completions): completions now continue completing even after first completion<commit_after>use std::path::PathBuf;
use std::fs::File;
use std::ffi::OsString;
use std::io::Write;

use app::parser::Parser;
use shell::Shell;
use args::{ArgSettings, OptBuilder};

macro_rules! w {
    ($_self:ident, $f:ident, $to_w:expr) => {
        match $f.write_all($to_w) {
            Ok(..) => (),
            Err(..) => panic!(format!("Failed to write to file completions file")),
        }
    };
}

pub struct ComplGen<'a, 'b> where 'a: 'b {
    p: &'b Parser<'a, 'b>,
    out_dir: OsString,
}

impl<'a, 'b> ComplGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>, od: OsString) -> Self {
        ComplGen {
            p: p,
            out_dir: od,
        }
    }

    pub fn generate(&self, for_shell: Shell) {
        match for_shell {
            Shell::Bash => self.gen_bash(),
        }
    }

    fn gen_bash(&self) {
        use std::error::Error;
        let out_dir = PathBuf::from(&self.out_dir);

        let mut file = match File::create(out_dir.join("bash.sh")) {
            Err(why) => panic!("couldn't create bash completion file: {}",
                why.description()),
            Ok(file) => file,
        };
        w!(self, file, format!(
"_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} {name}
",
            name=self.p.meta.bin_name.as_ref().unwrap(),
            name_opts=self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            name_opts_details=self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            subcmds=self.all_subcommands(),
            subcmd_details=self.subcommand_details()
        ).as_bytes());
    }

    fn all_subcommands(&self) -> String {
        let mut subcmds = String::new();
        let mut scs = get_all_subcommands(self.p);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmds = format!(
                "{}
            {name})
                cmd+=\"_{name}\"
                ;;",
                subcmds,
                name=sc.replace("-", "_"));
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        let mut subcmd_dets = String::new();
        let mut scs = get_all_subcommand_paths(self.p, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!(
                "{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;",
                subcmd_dets,
                subcmd=sc.replace("-", "_"),
                sc_opts=self.all_options_for_path(&*sc),
                level=sc.split("_").map(|_|1).fold(0, |acc, n| acc + n),
                opts_details=self.option_details_for_path(&*sc)
            );
        }

        subcmd_dets
    }

    fn all_options_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc).next().unwrap().p;
        }
        let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
        opts = format!("{} {}", opts, p.long_list.iter()
                                                 .fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
        opts = format!("{} {}", opts, p.positionals.values()
                                                   .fold(String::new(), |acc, p| format!("{} {}", acc, p)));
        opts = format!("{} {}", opts, p.subcommands.iter()
                                                   .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
        opts
    }

    fn option_details_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc).next().unwrap().p;
        }
        let mut opts = String::new();
        for o in &p.opts {
            if let Some(l) = o.long {
                opts = format!("{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, l, vals_for(o));
            }
            if let Some(s) = o.short {
                opts = format!("{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, s, vals_for(o));
            }
        }
        opts
    }
}

pub fn get_all_subcommands(p: &Parser) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        return vec![p.meta.name.clone()]
    }
    for sc in p.subcommands.iter().map(|ref s| s.p.meta.name.clone()) {
        subcmds.push(sc);
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommands(&s.p)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        if !first {
            return vec![p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_")]
        }
        return vec![];
    }
    for sc in p.subcommands.iter()
                           .map(|ref s| s.p.meta.bin_name.as_ref()
                                                         .unwrap()
                                                         .clone()
                                                         .replace(" ", "_")) {
        subcmds.push(sc);
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommand_paths(&s.p, false)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

fn vals_for(o: &OptBuilder) -> String {
    use args::AnyArg;
    let mut ret = String::new();
    let mut needs_quotes = true;
    if let Some(ref vals) = o.possible_vals() {
        needs_quotes = false;
        ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
    } else if let Some(ref vec) = o.val_names() {
        let mut it = vec.iter().peekable();
        while let Some((_, val)) = it.next() {
            ret = format!("{}<{}>{}", ret, val,
                if it.peek().is_some() {
                    " "
                } else {
                    ""
                });
        }
        let num = vec.len();
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else if let Some(num) = o.num_vals() {
        let mut it = (0..num).peekable();
        while let Some(_) = it.next() {
            ret = format!("{}<{}>{}", ret, o.name(),
            if it.peek().is_some() {
                " "
            } else {
                ""
            });
        }
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else {
        ret = format!("<{}>", o.name());
        if o.is_set(ArgSettings::Multiple) {
            ret = format!("{}...", ret);
        }
    }
    if needs_quotes {
        ret = format!("\"{}\"", ret);
    }
    ret
}
<|endoftext|>


<commit_before>use super::{ffi, safe};
use std::{fmt, cmp};
use std::ffi::CStr;
use std::error::Error;

pub const MAX_DIAGNOSTIC_MESSAGE_SIZE: usize = 1024;

/// ODBC Diagnostic Record
///
/// The `description` method of the `std::error::Error` trait only returns the message. Use
/// `std::fmt::Display` to retrive status code and other information.
pub struct DiagnosticRecord {
    // All elements but the last one, may not be nul. The last one must be nul.
    state: [ffi::SQLCHAR; ffi::SQL_SQLSTATE_SIZE + 1],
    // Must at least contain one nul
    message: [ffi::SQLCHAR; MAX_DIAGNOSTIC_MESSAGE_SIZE],
    // The numbers of characters in message not nul
    message_length: ffi::SQLSMALLINT,
    native_error: ffi::SQLINTEGER,
}

impl DiagnosticRecord {
    /// get raw state string data.
    pub fn get_raw_state(&self) -> &[u8] {
        &self.state
    }
    /// get raw diagnostics message for avoiding encoding error.
    pub fn get_raw_message(&self) -> &[u8] {
        &self.message[0..self.message_length as usize]
    }
    /// get native odbc error number
    pub fn get_native_error(&self) -> i32 {
        self.native_error
    }
}

impl fmt::Display for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Todo: replace unwrap with `?` in Rust 1.17
        let state = CStr::from_bytes_with_nul(&self.state).unwrap();
        let message = CStr::from_bytes_with_nul(
            &self.message[0..(self.message_length as usize + 1)],
        ).unwrap();

        write!(
            f,
            "State: {}, Native error: {}, Message: {}",
            state.to_str().unwrap(),
            self.native_error,
            message.to_str().unwrap()
        )
    }
}

impl fmt::Debug for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for DiagnosticRecord {
    fn description(&self) -> &str {
        CStr::from_bytes_with_nul(&self.message[0..(self.message_length as usize + 1)])
            .unwrap()
            .to_str()
            .unwrap()
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

/// Allows retriving a diagnostic record, describing errors (or lack thereof) during the last
/// operation.
pub trait GetDiagRec {
    /// Retrieves a diagnostic record
    ///
    /// `record_number` - Record numbers start at one. If you pass an number < 1 the function will
    /// panic. If no record is available for the number specified none is returned.
    fn get_diag_rec(&self, record_number: i16) -> Option<DiagnosticRecord>;
}

impl<D> GetDiagRec for D
where
    D: safe::Diagnostics,
{
    fn get_diag_rec(&self, record_number: i16) -> Option<(DiagnosticRecord)> {
        use safe::ReturnOption::*;
        let mut message = [0; MAX_DIAGNOSTIC_MESSAGE_SIZE];
        match self.diagnostics(record_number, &mut message) {
            Success(result) | Info(result) => {
                let message_length = cmp::min(result.text_length, MAX_DIAGNOSTIC_MESSAGE_SIZE as ffi::SQLSMALLINT - 1);
                Some(DiagnosticRecord {
                    state: result.state,
                    native_error: result.native_error,
                    message_length,
                    message,
                })
            }
            NoData(()) => None,
            Error(()) => panic!("Diagnostics returned error for record number {}. Record numbers have to be at least 1.", record_number),
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;

    impl DiagnosticRecord {
        fn new() -> DiagnosticRecord {
            DiagnosticRecord {
                state: [0u8; ffi::SQL_SQLSTATE_SIZE + 1],
                message: [0u8; MAX_DIAGNOSTIC_MESSAGE_SIZE],
                native_error: 0,
                message_length: 0,
            }
        }
    }

    #[test]
    fn formatting() {

        // build diagnostic record
        let message = b"[Microsoft][ODBC Driver Manager] Function sequence error\0";
        let mut rec = DiagnosticRecord::new();
        rec.state = b"HY010\0".clone();
        rec.message_length = 56;
        for i in 0..(rec.message_length as usize) {
            rec.message[i] = message[i];
        }

        // test formatting
        assert_eq!(
            format!("{}", rec),
            "State: HY010, Native error: 0, Message: [Microsoft][ODBC Driver Manager] \
             Function sequence error"
        );
    }
}
<commit_msg>Remove null-char padding from diagnostic messages.<commit_after>use super::{ffi, safe};
use std::{fmt, cmp};
use std::ffi::CStr;
use std::error::Error;

pub const MAX_DIAGNOSTIC_MESSAGE_SIZE: usize = 1024;

/// ODBC Diagnostic Record
///
/// The `description` method of the `std::error::Error` trait only returns the message. Use
/// `std::fmt::Display` to retrive status code and other information.
pub struct DiagnosticRecord {
    // All elements but the last one, may not be nul. The last one must be nul.
    state: [ffi::SQLCHAR; ffi::SQL_SQLSTATE_SIZE + 1],
    // Must at least contain one nul
    message: [ffi::SQLCHAR; MAX_DIAGNOSTIC_MESSAGE_SIZE],
    // The numbers of characters in message not nul
    message_length: ffi::SQLSMALLINT,
    native_error: ffi::SQLINTEGER,
}

impl DiagnosticRecord {
    /// get raw state string data.
    pub fn get_raw_state(&self) -> &[u8] {
        &self.state
    }
    /// get raw diagnostics message for avoiding encoding error.
    pub fn get_raw_message(&self) -> &[u8] {
        &self.message[0..self.message_length as usize]
    }
    /// get native odbc error number
    pub fn get_native_error(&self) -> i32 {
        self.native_error
    }
}

impl fmt::Display for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Todo: replace unwrap with `?` in Rust 1.17
        let state = CStr::from_bytes_with_nul(&self.state).unwrap();
        let message = CStr::from_bytes_with_nul(
            &self.message[0..(self.message_length as usize + 1)],
        ).unwrap();

        write!(
            f,
            "State: {}, Native error: {}, Message: {}",
            state.to_str().unwrap(),
            self.native_error,
            message.to_str().unwrap()
        )
    }
}

impl fmt::Debug for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for DiagnosticRecord {
    fn description(&self) -> &str {
        CStr::from_bytes_with_nul(&self.message[0..(self.message_length as usize + 1)])
            .unwrap()
            .to_str()
            .unwrap()
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

/// Allows retriving a diagnostic record, describing errors (or lack thereof) during the last
/// operation.
pub trait GetDiagRec {
    /// Retrieves a diagnostic record
    ///
    /// `record_number` - Record numbers start at one. If you pass an number < 1 the function will
    /// panic. If no record is available for the number specified none is returned.
    fn get_diag_rec(&self, record_number: i16) -> Option<DiagnosticRecord>;
}

impl<D> GetDiagRec for D
where
    D: safe::Diagnostics,
{
    fn get_diag_rec(&self, record_number: i16) -> Option<(DiagnosticRecord)> {
        use safe::ReturnOption::*;
        let mut message = [0; MAX_DIAGNOSTIC_MESSAGE_SIZE];
        match self.diagnostics(record_number, &mut message) {
            Success(result) | Info(result) => {
                // The message could be larger than the supplied buffer, so we need to limit the message length to the buffer size.
                let mut message_length = cmp::min(result.text_length, MAX_DIAGNOSTIC_MESSAGE_SIZE as ffi::SQLSMALLINT - 1);
                // Some drivers pad the message with null-chars (which is still a valid C string, but not a valid Rust string).
                while message_length > 0 && message[(message_length - 1) as usize] == 0 {
                    message_length = message_length - 1;
                }
                Some(DiagnosticRecord {
                    state: result.state,
                    native_error: result.native_error,
                    message_length,
                    message,
                })
            }
            NoData(()) => None,
            Error(()) => panic!("Diagnostics returned error for record number {}. Record numbers have to be at least 1.", record_number),
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;

    impl DiagnosticRecord {
        fn new() -> DiagnosticRecord {
            DiagnosticRecord {
                state: [0u8; ffi::SQL_SQLSTATE_SIZE + 1],
                message: [0u8; MAX_DIAGNOSTIC_MESSAGE_SIZE],
                native_error: 0,
                message_length: 0,
            }
        }
    }

    #[test]
    fn formatting() {

        // build diagnostic record
        let message = b"[Microsoft][ODBC Driver Manager] Function sequence error\0";
        let mut rec = DiagnosticRecord::new();
        rec.state = b"HY010\0".clone();
        rec.message_length = 56;
        for i in 0..(rec.message_length as usize) {
            rec.message[i] = message[i];
        }

        // test formatting
        assert_eq!(
            format!("{}", rec),
            "State: HY010, Native error: 0, Message: [Microsoft][ODBC Driver Manager] \
             Function sequence error"
        );
    }
}
<|endoftext|>


<commit_before>use orbtk::*;

use std::{cell::Cell, rc::Rc};

#[derive(Default)]
struct MainViewState {
    counter: Cell<i32>,
}

impl MainViewState {
    pub fn increment(&self) {
        self.counter.set(self.counter.get() + 1)
    }
}

impl State for MainViewState {
    fn update(&self, context: &mut Context<'_>) {
        if let Ok(button_count_text) = context.widget().borrow_mut_property::<Text>() {
            button_count_text.0 = format!("Button count: {}", self.counter.get());
        }
    }
}

fn create_header(text: &str, grid: usize, column: usize) -> Template {
    TextBlock::create()
        .text(text)
        .selector(Selector::from("textblock").class("h1"))
        .attach_property(GridColumn(grid))
        .attach_property(GridRow(column))
        .into()
}

struct MainView;

impl Widget for MainView {
    type Template = Template;

    fn create() -> Self::Template {
        let state = Rc::new(MainViewState::default());
        let button_count_text = SharedProperty::new(Text::from("Button count: 0"));

        Template::new()
            .state(state.clone())
            .child(
                Grid::create()
                    .margin(8.0)
                    .columns(
                        Columns::create()
                            .column("Auto")
                            .column(32.0)
                            .column("Auto")
                            .column("*")
                            .build(),
                    )
                    .rows(
                        Rows::create()
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .build(),
                    )
                    // Column 0
                    .child(create_header("Button", 0, 0))
                    .child(
                        Button::create()
                            .text("Button")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .font_icon(material_font_icons::CHECK_FONT_ICON)
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(1)),
                    )
                    .child(
                        Button::create()
                            .text("Primary")
                            .selector(Selector::from("button").class("primary"))
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .font_icon(material_font_icons::CHECK_FONT_ICON)
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(2)),
                    )
                    .child(
                        ToggleButton::create()
                            .text("ToggleButton")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(3)),
                    )
                    .child(
                        CheckBox::create()
                            .text("CheckBox")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(4)),
                    )
                    .child(
                        Switch::create()
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(5)),
                    )
                    // Column 2
                    .child(create_header("Text", 2, 0))
                    .child(
                        TextBlock::create()
                            .shared_text(button_count_text.clone())
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(2))
                            .attach_property(GridRow(1)),
                    )
                    .child(
                        TextBox::create()
                            .water_mark("TextBox...")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(2))
                            .attach_property(GridRow(2)),
                    ),
            )
            .shared_property(button_count_text)
            .debug_name("MainView")
    }
}

fn main() {
    let mut application = Application::default();
    application
        .create_window()
        .bounds(Bounds::new(100.0, 100.0, 420.0, 730.0))
        .title("OrbTk - light theme example")
        .root(MainView::create())
        .debug_flag(false)
        .theme(Theme::default_light())
        .build();
    application.run();
}
<commit_msg>[update] light theme example.<commit_after>use orbtk::*;

use std::{cell::Cell, rc::Rc};

#[derive(Default)]
struct MainViewState {
    counter: Cell<i32>,
}

impl MainViewState {
    pub fn increment(&self) {
        self.counter.set(self.counter.get() + 1)
    }
}

impl State for MainViewState {
    fn update(&self, context: &mut Context<'_>) {
        if let Ok(button_count_text) = context.widget().borrow_mut_property::<Text>() {
            button_count_text.0 = format!("Button count: {}", self.counter.get());
        }
    }
}

fn create_header(text: &str, grid: usize, column: usize) -> Template {
    TextBlock::create()
        .text(text)
        .selector(Selector::from("textblock").class("h1"))
        .attach_property(GridColumn(grid))
        .attach_property(GridRow(column))
        .into()
}

struct MainView;

impl Widget for MainView {
    type Template = Template;

    fn create() -> Self::Template {
        let state = Rc::new(MainViewState::default());
        let button_count_text = SharedProperty::new(Text::from("Button count: 0"));

        Template::new()
            .state(state.clone())
            .child(
                Grid::create()
                    .margin(8.0)
                    .columns(
                        Columns::create()
                            .column("Auto")
                            .column(32.0)
                            .column("Auto")
                            .column("*")
                            .build(),
                    )
                    .rows(
                        Rows::create()
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .row("Auto")
                            .build(),
                    )
                    // Column 0
                    .child(create_header("Button", 0, 0))
                    .child(
                        Button::create()
                            .text("Button")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .font_icon(material_font_icons::CHECK_FONT_ICON)
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(1))
                            .on_click(move |_| {
                                state.increment();
                                true
                            }),
                    )
                    .child(
                        Button::create()
                            .text("Primary")
                            .selector(Selector::from("button").class("primary"))
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .font_icon(material_font_icons::CHECK_FONT_ICON)
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(2)),
                    )
                    .child(
                        ToggleButton::create()
                            .text("ToggleButton")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(3)),
                    )
                    .child(
                        CheckBox::create()
                            .text("CheckBox")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(4)),
                    )
                    .child(
                        Switch::create()
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(0))
                            .attach_property(GridRow(5)),
                    )
                    // Column 2
                    .child(create_header("Text", 2, 0))
                    .child(
                        TextBlock::create()
                            .shared_text(button_count_text.clone())
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(2))
                            .attach_property(GridRow(1)),
                    )
                    .child(
                        TextBox::create()
                            .water_mark("TextBox...")
                            .margin((0.0, 8.0, 0.0, 0.0))
                            .attach_property(GridColumn(2))
                            .attach_property(GridRow(2)),
                    ),
            )
            .shared_property(button_count_text)
            .debug_name("MainView")
    }
}

fn main() {
    let mut application = Application::default();
    application
        .create_window()
        .bounds(Bounds::new(100.0, 100.0, 420.0, 730.0))
        .title("OrbTk - light theme example")
        .root(MainView::create())
        .debug_flag(false)
        .theme(Theme::default_light())
        .build();
    application.run();
}
<|endoftext|>


<commit_before>static NTASKS: int = 10;

fn main() {
    for i in range(0, NTASKS) {
        // spin up a task
        spawn(proc() {
            println!("this is task number {}", i)
        });
    }
}
<commit_msg>tasks: fix style<commit_after>static NTASKS: int = 10;

fn main() {
    for i in range(0, NTASKS) {
        // Spin up a task
        spawn(proc() {
            println!("this is task number {}", i)
        });
    }
}
<|endoftext|>


<commit_before>// aux-build:rustdoc-extern-default-method.rs
// ignore-cross-compile

extern crate rustdoc_extern_default_method as ext;

// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
pub use ext::Struct;
<commit_msg>add assertions on existing tests with missing doc source<commit_after>// aux-build:rustdoc-extern-default-method.rs
// ignore-cross-compile

extern crate rustdoc_extern_default_method as ext;

// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
// @has extern_default_method/struct.Struct.html '//div[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided
// @has extern_default_method/struct.Struct.html '//div[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
pub use ext::Struct;
<|endoftext|>


<commit_before><commit_msg>docs(lex): Provide examples<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::ir::*;
use crate::program::Program;

pub trait Visitor {
    const NAME: &'static str;
    const VISIT_ARGUMENTS: bool;
    const VISIT_DIRECTIVES: bool;

    fn visit_program(&mut self, program: &Program) {
        self.default_visit_program(program)
    }

    fn default_visit_program(&mut self, program: &Program) {
        for operation in program.operations() {
            self.visit_operation(operation);
        }
        for fragment in program.fragments() {
            self.visit_fragment(fragment);
        }
    }

    // Fragment Definition
    fn visit_fragment(&mut self, fragment: &FragmentDefinition) {
        self.default_visit_fragment(fragment)
    }

    fn default_visit_fragment(&mut self, fragment: &FragmentDefinition) {
        self.visit_selections(&fragment.selections);
        self.visit_directives(&fragment.directives);
    }

    // Operation Definition
    fn visit_operation(&mut self, operation: &OperationDefinition) {
        self.default_visit_operation(operation)
    }

    fn default_visit_operation(&mut self, operation: &OperationDefinition) {
        self.visit_directives(&operation.directives);
        self.visit_selections(&operation.selections);
    }

    // Selection
    fn visit_selections(&mut self, selections: &[Selection]) {
        self.visit_list(selections, Self::visit_selection)
    }

    fn visit_selection(&mut self, selection: &Selection) {
        self.default_visit_selection(selection)
    }

    fn default_visit_selection(&mut self, selection: &Selection) {
        match selection {
            Selection::FragmentSpread(selection) => self.visit_fragment_spread(selection),
            Selection::InlineFragment(selection) => self.visit_inline_fragment(selection),
            Selection::LinkedField(selection) => self.visit_linked_field(selection),
            Selection::ScalarField(selection) => self.visit_scalar_field(selection),
            Selection::Condition(selection) => self.visit_condition(selection),
        }
    }

    // Selection Kinds
    fn visit_scalar_field(&mut self, field: &ScalarField) {
        self.default_visit_scalar_field(field)
    }

    fn default_visit_scalar_field(&mut self, field: &ScalarField) {
        self.visit_arguments(&field.arguments);
        self.visit_directives(&field.directives);
    }

    fn visit_linked_field(&mut self, field: &LinkedField) {
        self.default_visit_linked_field(field)
    }

    fn default_visit_linked_field(&mut self, field: &LinkedField) {
        self.visit_arguments(&field.arguments);
        self.visit_directives(&field.directives);
        self.visit_selections(&field.selections);
    }

    fn visit_inline_fragment(&mut self, fragment: &InlineFragment) {
        self.default_visit_inline_fragment(fragment)
    }

    fn default_visit_inline_fragment(&mut self, fragment: &InlineFragment) {
        self.visit_directives(&fragment.directives);
        self.visit_selections(&fragment.selections);
    }

    fn visit_fragment_spread(&mut self, spread: &FragmentSpread) {
        self.default_visit_fragment_spread(spread)
    }
    fn default_visit_fragment_spread(&mut self, spread: &FragmentSpread) {
        self.visit_arguments(&spread.arguments);
        self.visit_directives(&spread.directives);
    }

    fn visit_condition(&mut self, condition: &Condition) {
        self.default_visit_condition(condition)
    }
    fn default_visit_condition(&mut self, condition: &Condition) {
        self.visit_condition_value(&condition.value);
        self.visit_selections(&condition.selections);
    }

    fn visit_condition_value(&mut self, condition_value: &ConditionValue) {
        self.default_visit_condition_value(condition_value);
    }
    fn default_visit_condition_value(&mut self, condition_value: &ConditionValue) {
        if Self::VISIT_ARGUMENTS {
            match condition_value {
                ConditionValue::Variable(variable) => self.visit_variable(variable),
                ConditionValue::Constant(_) => {}
            }
        }
    }

    // Directives
    fn visit_directives(&mut self, directives: &[Directive]) {
        if Self::VISIT_DIRECTIVES {
            self.visit_list(directives, Self::visit_directive)
        }
    }

    fn visit_directive(&mut self, directive: &Directive) {
        self.default_visit_directive(directive)
    }

    fn default_visit_directive(&mut self, directive: &Directive) {
        self.visit_arguments(&directive.arguments)
    }

    // Arguments
    fn visit_arguments(&mut self, arguments: &[Argument]) {
        if Self::VISIT_ARGUMENTS {
            self.visit_list(arguments, Self::visit_argument)
        }
    }

    fn visit_argument(&mut self, argument: &Argument) {
        self.default_visit_argument(argument)
    }

    fn default_visit_argument(&mut self, argument: &Argument) {
        self.visit_value(&argument.value.item)
    }

    // Values
    fn visit_value(&mut self, value: &Value) {
        self.default_visit_value(value)
    }

    fn default_visit_value(&mut self, value: &Value) {
        match value {
            Value::Variable(variable) => self.visit_variable(variable),
            Value::Constant(_) => {}
            Value::List(items) => self.visit_list(items, Self::visit_value),
            Value::Object(arguments) => self.visit_arguments(arguments),
        }
    }

    fn visit_variable(&mut self, value: &Variable) {
        let _ = value;
    }

    // Helpers
    fn visit_list<F, T>(&mut self, list: &[T], f: F)
    where
        F: Fn(&mut Self, &T) -> (),
        T: Clone,
    {
        for prev_item in list {
            f(self, prev_item)
        }
    }
}
<commit_msg>Add VariableDefinition Visitor to graphql-ir<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::ir::*;
use crate::program::Program;

pub trait Visitor {
    const NAME: &'static str;
    const VISIT_ARGUMENTS: bool;
    const VISIT_DIRECTIVES: bool;

    fn visit_program(&mut self, program: &Program) {
        self.default_visit_program(program)
    }

    fn default_visit_program(&mut self, program: &Program) {
        for operation in program.operations() {
            self.visit_operation(operation);
        }
        for fragment in program.fragments() {
            self.visit_fragment(fragment);
        }
    }

    // Fragment Definition
    fn visit_fragment(&mut self, fragment: &FragmentDefinition) {
        self.default_visit_fragment(fragment)
    }

    fn default_visit_fragment(&mut self, fragment: &FragmentDefinition) {
        self.visit_selections(&fragment.selections);
        self.visit_directives(&fragment.directives);
        self.visit_variable_definitions(&fragment.variable_definitions);
        self.visit_variable_definitions(&fragment.used_global_variables);
    }

    // Operation Definition
    fn visit_operation(&mut self, operation: &OperationDefinition) {
        self.default_visit_operation(operation)
    }

    fn default_visit_operation(&mut self, operation: &OperationDefinition) {
        self.visit_directives(&operation.directives);
        self.visit_selections(&operation.selections);
        self.visit_variable_definitions(&operation.variable_definitions);
    }

    // Selection
    fn visit_selections(&mut self, selections: &[Selection]) {
        self.visit_list(selections, Self::visit_selection)
    }

    fn visit_selection(&mut self, selection: &Selection) {
        self.default_visit_selection(selection)
    }

    fn default_visit_selection(&mut self, selection: &Selection) {
        match selection {
            Selection::FragmentSpread(selection) => self.visit_fragment_spread(selection),
            Selection::InlineFragment(selection) => self.visit_inline_fragment(selection),
            Selection::LinkedField(selection) => self.visit_linked_field(selection),
            Selection::ScalarField(selection) => self.visit_scalar_field(selection),
            Selection::Condition(selection) => self.visit_condition(selection),
        }
    }

    // Selection Kinds
    fn visit_scalar_field(&mut self, field: &ScalarField) {
        self.default_visit_scalar_field(field)
    }

    fn default_visit_scalar_field(&mut self, field: &ScalarField) {
        self.visit_arguments(&field.arguments);
        self.visit_directives(&field.directives);
    }

    fn visit_linked_field(&mut self, field: &LinkedField) {
        self.default_visit_linked_field(field)
    }

    fn default_visit_linked_field(&mut self, field: &LinkedField) {
        self.visit_arguments(&field.arguments);
        self.visit_directives(&field.directives);
        self.visit_selections(&field.selections);
    }

    fn visit_inline_fragment(&mut self, fragment: &InlineFragment) {
        self.default_visit_inline_fragment(fragment)
    }

    fn default_visit_inline_fragment(&mut self, fragment: &InlineFragment) {
        self.visit_directives(&fragment.directives);
        self.visit_selections(&fragment.selections);
    }

    fn visit_fragment_spread(&mut self, spread: &FragmentSpread) {
        self.default_visit_fragment_spread(spread)
    }
    fn default_visit_fragment_spread(&mut self, spread: &FragmentSpread) {
        self.visit_arguments(&spread.arguments);
        self.visit_directives(&spread.directives);
    }

    fn visit_condition(&mut self, condition: &Condition) {
        self.default_visit_condition(condition)
    }
    fn default_visit_condition(&mut self, condition: &Condition) {
        self.visit_condition_value(&condition.value);
        self.visit_selections(&condition.selections);
    }

    fn visit_condition_value(&mut self, condition_value: &ConditionValue) {
        self.default_visit_condition_value(condition_value);
    }
    fn default_visit_condition_value(&mut self, condition_value: &ConditionValue) {
        if Self::VISIT_ARGUMENTS {
            match condition_value {
                ConditionValue::Variable(variable) => self.visit_variable(variable),
                ConditionValue::Constant(_) => {}
            }
        }
    }

    // Directives
    fn visit_directives(&mut self, directives: &[Directive]) {
        if Self::VISIT_DIRECTIVES {
            self.visit_list(directives, Self::visit_directive)
        }
    }

    fn visit_directive(&mut self, directive: &Directive) {
        self.default_visit_directive(directive)
    }

    fn default_visit_directive(&mut self, directive: &Directive) {
        self.visit_arguments(&directive.arguments)
    }

    // Arguments
    fn visit_arguments(&mut self, arguments: &[Argument]) {
        if Self::VISIT_ARGUMENTS {
            self.visit_list(arguments, Self::visit_argument)
        }
    }

    fn visit_argument(&mut self, argument: &Argument) {
        self.default_visit_argument(argument)
    }

    fn default_visit_argument(&mut self, argument: &Argument) {
        self.visit_value(&argument.value.item)
    }

    // Values
    fn visit_value(&mut self, value: &Value) {
        self.default_visit_value(value)
    }

    fn default_visit_value(&mut self, value: &Value) {
        match value {
            Value::Variable(variable) => self.visit_variable(variable),
            Value::Constant(_) => {}
            Value::List(items) => self.visit_list(items, Self::visit_value),
            Value::Object(arguments) => self.visit_arguments(arguments),
        }
    }

    fn visit_variable(&mut self, value: &Variable) {
        let _ = value;
    }

    // Variable Definitions
    fn visit_variable_definitions(&mut self, variable_definitions: &[VariableDefinition]) {
        self.visit_list(variable_definitions, Self::visit_variable_definition)
    }

    fn visit_variable_definition(&mut self, variable_definition: &VariableDefinition) {
        self.default_visit_variable_definition(variable_definition)
    }

    fn default_visit_variable_definition(&mut self, variable_definition: &VariableDefinition) {
        self.visit_directives(&variable_definition.directives)
    }

    // Helpers
    fn visit_list<F, T>(&mut self, list: &[T], f: F)
    where
        F: Fn(&mut Self, &T) -> (),
        T: Clone,
    {
        for prev_item in list {
            f(self, prev_item)
        }
    }
}
<|endoftext|>