<commit_before>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use super::wycheproof;
use std::collections::HashSet;
use tink::{subtle::random::get_random_bytes, Aead};
use tink_aead::subtle;
use tink_tests::WycheproofResult;

const KEY_SIZES: &[usize] = &[16, 32];

// Check that the tag size is always 128 bit.
#[test]
fn test_aes_gcm_tag_length() {
    for key_size in KEY_SIZES {
        let key = get_random_bytes(*key_size);
        let a = subtle::AesGcm::new(&key).unwrap();
        let ad = get_random_bytes(32);
        let pt = get_random_bytes(32);
        let ct = a.encrypt(&pt, &ad).unwrap();
        let actual_tag_size = ct.len() - subtle::AES_GCM_IV_SIZE - pt.len();
        assert_eq!(
            actual_tag_size,
            subtle::AES_GCM_TAG_SIZE,
            "tag size is not 128 bit, it is {} bit",
            actual_tag_size * 8
        );
    }
}

#[test]
fn test_aes_gcm_key_size() {
    for key_size in KEY_SIZES {
        subtle::AesGcm::new(&vec![0; *key_size])
            .unwrap_or_else(|_| panic!("unexpected error when key size is {} bytes", *key_size));
        assert!(
            subtle::AesGcm::new(&vec![0; *key_size + 1]).is_err(),
            "expect an error when key size is not supported {}",
            *key_size
        );
    }
}

#[test]
fn test_aes_gcm_encrypt_decrypt() {
    for key_size in KEY_SIZES {
        let key = get_random_bytes(*key_size);
        let a = subtle::AesGcm::new(&key).expect("unexpected error when creating new cipher");
        let ad = get_random_bytes(5);
        for pt_size in 0..75 {
            let pt = get_random_bytes(pt_size);
            let ct = a.encrypt(&pt, &ad).unwrap_or_else(|_| {
                panic!(
                    "unexpected error in encryption: key_size {}, pt_size {}",
                    key_size, pt_size
                )
            });
            let decrypted = a.decrypt(&ct, &ad).unwrap_or_else(|_| {
                panic!(
                    "unexpected error in decryption: keySize {}, ptSize {}",
                    key_size, pt_size
                )
            });
            assert_eq!(
                pt, decrypted,
                "decrypted text and plaintext don't match: key_size {}, pt_size {}",
                key_size, pt_size
            );
        }
    }
}

#[test]
fn test_aes_gcm_long_messages() {
    let mut pt_size = 16;
    while pt_size <= 1 << 24 {
        let pt = get_random_bytes(pt_size);
        let ad = get_random_bytes(pt_size / 3);
        for key_size in KEY_SIZES {
            let key = get_random_bytes(*key_size);
            let a = subtle::AesGcm::new(&key).unwrap();
            let ct = a.encrypt(&pt, &ad).unwrap();
            let decrypted = a.decrypt(&ct, &ad).unwrap();
            assert_eq!(
                pt, decrypted,
                "decrypted text and plaintext don't match: key_size {}, pt_size {}",
                key_size, pt_size
            );
        }
        pt_size += 9 * pt_size / 11
    }
}

#[test]
fn test_aes_gcm_modify_ciphertext() {
    let mut ad = get_random_bytes(33);
    let key = get_random_bytes(16);
    let pt = get_random_bytes(32);
    let a = subtle::AesGcm::new(&key).unwrap();
    let mut ct = a.encrypt(&pt, &ad).unwrap();
    // flipping bits
    for i in 0..ct.len() {
        let tmp = ct[i];
        for j in 0..8 {
            ct[i] ^= 1 << j;
            a.decrypt(&ct, &ad).expect_err(&format!(
                "expect an error when flipping bit of ciphertext: byte {}, bit {}",
                i, j
            ));
        }
        ct[i] = tmp;
    }
    // truncated ciphertext
    for i in 1..ct.len() {
        a.decrypt(&ct[..i], &ad).expect_err(&format!(
            "expect an error ciphertext is truncated until byte {}",
            i
        ));
    }
    // modify additional authenticated data
    for i in 0..ad.len() {
        let tmp = ad[i];
        for j in 0..8 {
            ad[i] ^= 1 << j;
            a.decrypt(&ct, &ad).expect_err(&format!(
                "expect an error when flipping bit of ad: byte {}, bit {}",
                i, j
            ));
            ad[i] = tmp;
        }
    }
}

// This is a very simple test for the randomness of the nonce. The test simply checks that the
// multiple ciphertexts of the same message are distinct.
#[test]
fn test_aes_gcm_random_nonce() {
    let n_sample = 1 << 17;
    let key = get_random_bytes(16);
    let pt = &[];
    let ad = &[];
    let a = subtle::AesGcm::new(&key).unwrap();
    let mut ct_set = HashSet::new();
    for i in 0..n_sample {
        let ct = a.encrypt(pt, ad).unwrap();
        let ct_hex = hex::encode(&ct);
        assert!(
            !ct_set.contains(&ct_hex),
            "nonce is repeated after {} samples",
            i
        );
        ct_set.insert(ct_hex);
    }
}

#[test]
fn test_aes_gcm_vectors() {
    let filename = "testvectors/aes_gcm_test.json";
    println!("wycheproof file '{}'", filename);
    let bytes = tink_tests::wycheproof_data(filename);
    let data: wycheproof::TestData = serde_json::from_slice(&bytes).unwrap();
    assert_eq!("AES-GCM", data.suite.algorithm);

    for g in &data.test_groups {
        if subtle::validate_aes_key_size(g.key_size as usize / 8).is_err() {
            println!("   skipping tests for key_size={}", g.key_size);
            continue;
        }
        if g.iv_size as usize != subtle::AES_GCM_IV_SIZE * 8 {
            println!("   skipping tests for iv_size={}", g.iv_size);
            continue;
        }
        for tc in &g.tests {
            println!(
                "     case {} [{}] {}",
                tc.case.case_id, tc.case.result, tc.case.comment
            );
            let mut combined_ct = Vec::new();
            combined_ct.extend_from_slice(&tc.iv);
            combined_ct.extend_from_slice(&tc.ct);
            combined_ct.extend_from_slice(&tc.tag);

            // create cipher and do decryption
            let cipher = match subtle::AesGcm::new(&tc.key) {
                Ok(c) => c,
                Err(e) => panic!(
                    "cannot create new instance of AesGcm in test case {}: {:?}",
                    tc.case.case_id, e
                ),
            };
            let result = cipher.decrypt(&combined_ct, &tc.aad);
            match result {
                Err(e) => {
                    assert_ne!(
                        tc.case.result,
                        WycheproofResult::Valid,
                        "unexpected error in test case {}: {}",
                        tc.case.case_id,
                        e
                    );
                }
                Ok(decrypted) => {
                    assert_ne!(
                        tc.case.result,
                        WycheproofResult::Invalid,
                        "decrypted invalid test case {}",
                        tc.case.case_id
                    );
                    assert_eq!(
                        decrypted, tc.msg,
                        "incorrect decryption in test case {}",
                        tc.case.case_id,
                    );
                }
            }
        }
    }
}
<commit_msg>tink-aead: fix ciphertext modification test<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use super::wycheproof;
use std::collections::HashSet;
use tink::{subtle::random::get_random_bytes, Aead};
use tink_aead::subtle;
use tink_tests::WycheproofResult;

const KEY_SIZES: &[usize] = &[16, 32];

// Check that the tag size is always 128 bit.
#[test]
fn test_aes_gcm_tag_length() {
    for key_size in KEY_SIZES {
        let key = get_random_bytes(*key_size);
        let a = subtle::AesGcm::new(&key).unwrap();
        let ad = get_random_bytes(32);
        let pt = get_random_bytes(32);
        let ct = a.encrypt(&pt, &ad).unwrap();
        let actual_tag_size = ct.len() - subtle::AES_GCM_IV_SIZE - pt.len();
        assert_eq!(
            actual_tag_size,
            subtle::AES_GCM_TAG_SIZE,
            "tag size is not 128 bit, it is {} bit",
            actual_tag_size * 8
        );
    }
}

#[test]
fn test_aes_gcm_key_size() {
    for key_size in KEY_SIZES {
        subtle::AesGcm::new(&vec![0; *key_size])
            .unwrap_or_else(|_| panic!("unexpected error when key size is {} bytes", *key_size));
        assert!(
            subtle::AesGcm::new(&vec![0; *key_size + 1]).is_err(),
            "expect an error when key size is not supported {}",
            *key_size
        );
    }
}

#[test]
fn test_aes_gcm_encrypt_decrypt() {
    for key_size in KEY_SIZES {
        let key = get_random_bytes(*key_size);
        let a = subtle::AesGcm::new(&key).expect("unexpected error when creating new cipher");
        let ad = get_random_bytes(5);
        for pt_size in 0..75 {
            let pt = get_random_bytes(pt_size);
            let ct = a.encrypt(&pt, &ad).unwrap_or_else(|_| {
                panic!(
                    "unexpected error in encryption: key_size {}, pt_size {}",
                    key_size, pt_size
                )
            });
            let decrypted = a.decrypt(&ct, &ad).unwrap_or_else(|_| {
                panic!(
                    "unexpected error in decryption: keySize {}, ptSize {}",
                    key_size, pt_size
                )
            });
            assert_eq!(
                pt, decrypted,
                "decrypted text and plaintext don't match: key_size {}, pt_size {}",
                key_size, pt_size
            );
        }
    }
}

#[test]
fn test_aes_gcm_long_messages() {
    let mut pt_size = 16;
    while pt_size <= 1 << 24 {
        let pt = get_random_bytes(pt_size);
        let ad = get_random_bytes(pt_size / 3);
        for key_size in KEY_SIZES {
            let key = get_random_bytes(*key_size);
            let a = subtle::AesGcm::new(&key).unwrap();
            let ct = a.encrypt(&pt, &ad).unwrap();
            let decrypted = a.decrypt(&ct, &ad).unwrap();
            assert_eq!(
                pt, decrypted,
                "decrypted text and plaintext don't match: key_size {}, pt_size {}",
                key_size, pt_size
            );
        }
        pt_size += 9 * pt_size / 11
    }
}

#[test]
fn test_aes_gcm_modify_ciphertext() {
    let mut ad = get_random_bytes(33);
    let key = get_random_bytes(16);
    let pt = get_random_bytes(32);
    let a = subtle::AesGcm::new(&key).unwrap();
    let mut ct = a.encrypt(&pt, &ad).unwrap();
    // flipping bits
    for i in 0..ct.len() {
        let tmp = ct[i];
        for j in 0..8 {
            ct[i] ^= 1 << j;
            a.decrypt(&ct, &ad).expect_err(&format!(
                "expect an error when flipping bit of ciphertext: byte {}, bit {}",
                i, j
            ));
            ct[i] = tmp;
        }
    }
    // truncated ciphertext
    for i in 1..ct.len() {
        a.decrypt(&ct[..i], &ad).expect_err(&format!(
            "expect an error ciphertext is truncated until byte {}",
            i
        ));
    }
    // modify additional authenticated data
    for i in 0..ad.len() {
        let tmp = ad[i];
        for j in 0..8 {
            ad[i] ^= 1 << j;
            a.decrypt(&ct, &ad).expect_err(&format!(
                "expect an error when flipping bit of ad: byte {}, bit {}",
                i, j
            ));
            ad[i] = tmp;
        }
    }
}

// This is a very simple test for the randomness of the nonce. The test simply checks that the
// multiple ciphertexts of the same message are distinct.
#[test]
fn test_aes_gcm_random_nonce() {
    let n_sample = 1 << 17;
    let key = get_random_bytes(16);
    let pt = &[];
    let ad = &[];
    let a = subtle::AesGcm::new(&key).unwrap();
    let mut ct_set = HashSet::new();
    for i in 0..n_sample {
        let ct = a.encrypt(pt, ad).unwrap();
        let ct_hex = hex::encode(&ct);
        assert!(
            !ct_set.contains(&ct_hex),
            "nonce is repeated after {} samples",
            i
        );
        ct_set.insert(ct_hex);
    }
}

#[test]
fn test_aes_gcm_vectors() {
    let filename = "testvectors/aes_gcm_test.json";
    println!("wycheproof file '{}'", filename);
    let bytes = tink_tests::wycheproof_data(filename);
    let data: wycheproof::TestData = serde_json::from_slice(&bytes).unwrap();
    assert_eq!("AES-GCM", data.suite.algorithm);

    for g in &data.test_groups {
        if subtle::validate_aes_key_size(g.key_size as usize / 8).is_err() {
            println!("   skipping tests for key_size={}", g.key_size);
            continue;
        }
        if g.iv_size as usize != subtle::AES_GCM_IV_SIZE * 8 {
            println!("   skipping tests for iv_size={}", g.iv_size);
            continue;
        }
        for tc in &g.tests {
            println!(
                "     case {} [{}] {}",
                tc.case.case_id, tc.case.result, tc.case.comment
            );
            let mut combined_ct = Vec::new();
            combined_ct.extend_from_slice(&tc.iv);
            combined_ct.extend_from_slice(&tc.ct);
            combined_ct.extend_from_slice(&tc.tag);

            // create cipher and do decryption
            let cipher = match subtle::AesGcm::new(&tc.key) {
                Ok(c) => c,
                Err(e) => panic!(
                    "cannot create new instance of AesGcm in test case {}: {:?}",
                    tc.case.case_id, e
                ),
            };
            let result = cipher.decrypt(&combined_ct, &tc.aad);
            match result {
                Err(e) => {
                    assert_ne!(
                        tc.case.result,
                        WycheproofResult::Valid,
                        "unexpected error in test case {}: {}",
                        tc.case.case_id,
                        e
                    );
                }
                Ok(decrypted) => {
                    assert_ne!(
                        tc.case.result,
                        WycheproofResult::Invalid,
                        "decrypted invalid test case {}",
                        tc.case.case_id
                    );
                    assert_eq!(
                        decrypted, tc.msg,
                        "incorrect decryption in test case {}",
                        tc.case.case_id,
                    );
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::str;

use webidl::{self, ast};

/// Helper method for inserting into a BTreeMap-based multi-map
pub fn multimap_insert<K: Ord, V: PartialEq>(m: &mut BTreeMap<K, Vec<V>>, key: K, value: V) {
    let v = m.entry(key).or_insert_with(Vec::new);
    if !v.contains(&value) {
        v.push(value);
    }
}

/// Helper method for appending to a BTreeMap-based multi-map
pub fn multimap_append<K: Ord + Clone, V: PartialEq>(
    m: &mut BTreeMap<K, Vec<V>>,
    other: BTreeMap<K, Vec<V>>,
) {
    for (k, v) in other {
        for value in v {
            multimap_insert(m, k.clone(), value);
        }
    }
}

/// Best-effort attempt to render HTML into a doc-comment which can
/// be placed in the generated code.
pub fn convert_html_to_doc_comment(html: &str) -> String {
    use regex::RegexBuilder;

    // Create doc comments
    let doc_comment_regex = RegexBuilder::new("^").multi_line(true).build().unwrap();

    let md = html2runes::markdown::convert_string(html);
    let mut doc = doc_comment_regex
        .replace_all(md.trim_right(), "/// ")
        .into();
    doc += "\n";
    doc
}

/// Appends an underscore to a name if it conflicts with a reserved word.
pub fn unreserve<S: Into<String>>(name: S) -> String {
    const RESERVED_WORDS: &'static [&'static str] = &[
        "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn",
        "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
        "return", "Self", "self", "static", "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while", "abstract", "alignof", "become", "box", "do", "final", "macro",
        "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof", "unsized", "virtual",
        "yield",
    ];

    let mut s = name.into();
    if RESERVED_WORDS.contains(&&*s) {
        s += "_";
    }
    s
}

/// Converts to lower snake-case
pub fn snake(name: &str) -> String {
    use heck::SnakeCase;
    name.to_snake_case()
}

/// Converts to upper snake-case
pub fn shouty_snake(name: &str) -> String {
    use heck::ShoutySnakeCase;
    name.to_shouty_snake_case()
}

/// Converts to upper camel case
pub fn camel(name: &str) -> String {
    use heck::CamelCase;
    name.to_camel_case()
}

/// Parse WebIDL content into an AST
pub fn parse_defs(src: &[u8]) -> Vec<ast::Definition> {
    let src = str::from_utf8(src).expect("IDL contained invalid UTF-8");

    webidl::parse_string(src).expect("Failed to parse IDL")
}
<commit_msg>Fix deprecated use of `trim_right` warning.<commit_after>use std::collections::BTreeMap;
use std::str;

use webidl::{self, ast};

/// Helper method for inserting into a BTreeMap-based multi-map
pub fn multimap_insert<K: Ord, V: PartialEq>(m: &mut BTreeMap<K, Vec<V>>, key: K, value: V) {
    let v = m.entry(key).or_insert_with(Vec::new);
    if !v.contains(&value) {
        v.push(value);
    }
}

/// Helper method for appending to a BTreeMap-based multi-map
pub fn multimap_append<K: Ord + Clone, V: PartialEq>(
    m: &mut BTreeMap<K, Vec<V>>,
    other: BTreeMap<K, Vec<V>>,
) {
    for (k, v) in other {
        for value in v {
            multimap_insert(m, k.clone(), value);
        }
    }
}

/// Best-effort attempt to render HTML into a doc-comment which can
/// be placed in the generated code.
pub fn convert_html_to_doc_comment(html: &str) -> String {
    use regex::RegexBuilder;

    // Create doc comments
    let doc_comment_regex = RegexBuilder::new("^").multi_line(true).build().unwrap();

    let md = html2runes::markdown::convert_string(html);
    let mut doc = doc_comment_regex.replace_all(md.trim_end(), "/// ").into();
    doc += "\n";
    doc
}

/// Appends an underscore to a name if it conflicts with a reserved word.
pub fn unreserve<S: Into<String>>(name: S) -> String {
    const RESERVED_WORDS: &'static [&'static str] = &[
        "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn",
        "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
        "return", "Self", "self", "static", "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while", "abstract", "alignof", "become", "box", "do", "final", "macro",
        "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof", "unsized", "virtual",
        "yield",
    ];

    let mut s = name.into();
    if RESERVED_WORDS.contains(&&*s) {
        s += "_";
    }
    s
}

/// Converts to lower snake-case
pub fn snake(name: &str) -> String {
    use heck::SnakeCase;
    name.to_snake_case()
}

/// Converts to upper snake-case
pub fn shouty_snake(name: &str) -> String {
    use heck::ShoutySnakeCase;
    name.to_shouty_snake_case()
}

/// Converts to upper camel case
pub fn camel(name: &str) -> String {
    use heck::CamelCase;
    name.to_camel_case()
}

/// Parse WebIDL content into an AST
pub fn parse_defs(src: &[u8]) -> Vec<ast::Definition> {
    let src = str::from_utf8(src).expect("IDL contained invalid UTF-8");

    webidl::parse_string(src).expect("Failed to parse IDL")
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::mem;

use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMBuilderRef,
  LLVMValueRef
};
use libc::{c_char, c_uint};

use types::Ty;
use block::BasicBlock;
use value::{PhiNode, Value};

static NULL_NAME:[c_char; 1] = [0];

pub struct Builder(pub LLVMBuilderRef);
impl_dispose!(Builder, core::LLVMDisposeBuilder);

impl Builder {

  pub fn get_insert_block(&self) -> BasicBlock
  {
    BasicBlock(unsafe { core::LLVMGetInsertBlock(self.0)})
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value)
  {
    unsafe { core::LLVMPositionBuilder(self.0, block.0, instr.0) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.0, block.0) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> Value
  {
    Value(unsafe {core::LLVMBuildRetVoid(self.0)})
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildRet(self.0, value.0)})
  }

  /// Build an instruction that allocates an array with the element type `elem` and
  /// the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Ty, size: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildArrayAlloca(self.0,
    														 elem.0,
    														 size.0,
    														 NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this
  /// pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Ty) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildAlloca(self.0,
    												ty.0,
    												NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildFree(self.0, val.0) })
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildStore(self.0, val.0, ptr.0) })
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> Value
  {
    Value(unsafe { core::LLVMBuildBr(self.0, dest.0)})
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and
  /// `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildCondBr(self.0,
    		                    cond.0,
    		                    if_block.0,
    		                    mem::transmute(else_block))
    })
  }

  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val`
  /// otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildSelect(self.0,
    		                    cond.0,
    		                    true_val.0,
    		                    false_val.0,
    		                    NULL_NAME.as_ptr()) })
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Ty) -> Value
  {
    Value(unsafe { core::LLVMBuildBitCast(
    		self.0,
    		value.0,
    		dest.0,
    		NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildInsertValue(self.0,
    		                         agg.0,
    		                         elem.0,
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that extracts a value from an aggregate type.
	pub fn create_extract_value(&self, agg: &Value, index: usize) -> Value {
    Value(unsafe {
    	core::LLVMBuildExtractValue(self.0,
    		                          agg.0,
    		                          index as c_uint,
    		                          NULL_NAME.as_ptr())
   	})
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data
  /// structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> Value
  {
    let ref_array = to_llvmref_array!(indices, LLVMValueRef);

    Value(unsafe {
    	core::LLVMBuildInBoundsGEP(self.0,
    	                           pointer.0,
    	                           ref_array.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Ty, name: &str) -> PhiNode
  {
	  PhiNode(unsafe {
	  	core::LLVMBuildPhi(self.0, ty.0, ::util::chars::from_str(name))
  	})
  }

  /// Build an instruction that runs whichever block matches the value, or `default` if none of
  /// them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> Value {
    Value(unsafe {
      let switch = core::LLVMBuildSwitch(self.0,
      	                                 value.0,
      	                                 default.0,
      	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, (case.0).0, (case.1).0);
      }

      switch
    })
  }
}<commit_msg>Add create_call() create_tail_call() in builder module.<commit_after>#![allow(dead_code)]

use std::mem;

use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMBuilderRef,
  LLVMValueRef
};
use libc::{c_char, c_uint};

use types::Ty;
use block::BasicBlock;
use value::{Function, Value, PhiNode};

static NULL_NAME:[c_char; 1] = [0];

pub struct Builder(pub LLVMBuilderRef);
impl_dispose!(Builder, core::LLVMDisposeBuilder);

impl Builder {

  pub fn get_insert_block(&self) -> BasicBlock
  {
    BasicBlock(unsafe { core::LLVMGetInsertBlock(self.0)})
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value)
  {
    unsafe { core::LLVMPositionBuilder(self.0, block.0, instr.0) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.0, block.0) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> Value
  {
    Value(unsafe {core::LLVMBuildRetVoid(self.0)})
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildRet(self.0, value.0)})
  }

  /// Build an instruction that allocates an array with the element type `elem` and
  /// the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Ty, size: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildArrayAlloca(self.0,
    														 elem.0,
    														 size.0,
    														 NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this
  /// pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Ty) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildAlloca(self.0,
    												ty.0,
    												NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildFree(self.0, val.0) })
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildStore(self.0, val.0, ptr.0) })
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> Value
  {
    Value(unsafe { core::LLVMBuildBr(self.0, dest.0)})
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and
  /// `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildCondBr(self.0,
    		                    cond.0,
    		                    if_block.0,
    		                    mem::transmute(else_block))
    })
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  fn create_call_internal(&self, func: &Function, args: &[&Value], tail_call: bool) -> Value
  {
    let ref_array = to_llvmref_array!(args, LLVMValueRef);

    Value(unsafe {
        let call = core::LLVMBuildCall(self.0,
        	                             func.0,
                                       ref_array.as_ptr() as *mut LLVMValueRef,
        	                             args.len() as c_uint,
        	                             NULL_NAME.as_ptr());
        core::LLVMSetTailCall(call, if tail_call {1} else {0});
        call.into()
    })
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_call(&self, func: &Function, args: &[&Value]) -> Value
  {
    self.create_call_internal(func, args, false)
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_tail_call(&self, func: &Function, args: &[&Value]) -> Value
  {
    self.create_call_internal(func, args, true)
  }

  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val`
  /// otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildSelect(self.0,
    		                    cond.0,
    		                    true_val.0,
    		                    false_val.0,
    		                    NULL_NAME.as_ptr()) })
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Ty) -> Value
  {
    Value(unsafe { core::LLVMBuildBitCast(
    		self.0,
    		value.0,
    		dest.0,
    		NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildInsertValue(self.0,
    		                         agg.0,
    		                         elem.0,
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that extracts a value from an aggregate type.
	pub fn create_extract_value(&self, agg: &Value, index: usize) -> Value {
    Value(unsafe {
    	core::LLVMBuildExtractValue(self.0,
    		                          agg.0,
    		                          index as c_uint,
    		                          NULL_NAME.as_ptr())
   	})
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data
  /// structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> Value
  {
    let ref_array = to_llvmref_array!(indices, LLVMValueRef);

    Value(unsafe {
    	core::LLVMBuildInBoundsGEP(self.0,
    	                           pointer.0,
    	                           ref_array.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Ty, name: &str) -> PhiNode
  {
	  PhiNode(unsafe {
	  	core::LLVMBuildPhi(self.0, ty.0, ::util::chars::from_str(name))
  	})
  }

  /// Build an instruction that runs whichever block matches the value, or `default` if none of
  /// them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> Value {
    Value(unsafe {
      let switch = core::LLVMBuildSwitch(self.0,
      	                                 value.0,
      	                                 default.0,
      	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, (case.0).0, (case.1).0);
      }

      switch
    })
  }
}<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::io::{Result, Write};

use analysis;
use analysis::namespaces::MAIN;
use case::CaseExt;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use self::format::reformat_doc;
use stripper_lib::Type as SType;
use stripper_lib::{write_file_name, write_item_doc, TypeStruct};
use traits::*;

mod format;

trait ToStripperType {
    fn to_stripper_type(&self) -> TypeStruct;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn to_stripper_type(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }
        }
    }
}

impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Class, Struct);

pub fn generate(env: &Env) {
    let path = env.config.target_path.join("vendor.md");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup, |w| generate_doc(w, env));
}

fn generate_doc(w: &mut Write, env: &Env) -> Result<()> {
    try!(write_file_name(w, None));
    let mut generators: Vec<(&str, Box<Fn(&mut Write, &Env) -> Result<()>>)> = Vec::new();

    for info in env.analysis.objects.values() {
        if info.type_id.ns_id == MAIN {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_object_doc(w, e, info)),
            ));
        }
    }

    for info in env.analysis.records.values() {
        if info.type_id.ns_id == MAIN {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_record_doc(w, e, info)),
            ));
        }
    }

    for (tid, type_) in env.library.namespace_types(MAIN) {
        if let LType::Enumeration(ref enum_) = *type_ {
            if !env.config
                .objects
                .get(&tid.full_name(&env.library))
                .map_or(true, |obj| obj.status.ignored())
            {
                generators.push((
                    &enum_.name[..],
                    Box::new(move |w, e| create_enum_doc(w, e, enum_)),
                ));
            }
        }
    }

    generators.sort_by_key(|&(name, _)| name);
    for (_, f) in generators {
        try!(f(w, env));
    }

    Ok(())
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &info.trait_name);
    let has_trait = info.generate_trait;
    let doc;
    let functions: &[Function];

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            doc = cl.doc.as_ref();
            functions = &cl.functions;
        }
        Type::Interface(ref iface) => {
            doc = iface.doc.as_ref();
            functions = &iface.functions;
        }
        _ => unreachable!(),
    }

    try!(write_item_doc(w, &ty, |w| {
        if let Some(ver) = info.deprecated_version {
            try!(write!(w, "`[Deprecated since {}]` ", ver));
        }
        if let Some(doc) = doc {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        } else {
            try!(writeln!(w, ""));
        }
        if let Some(version) = info.version {
            try!(writeln!(w, "\nFeature: `{}`", version.to_feature()));
        }

        let impl_self = if has_trait { Some(info.type_id) } else { None };
        let implements = impl_self
            .iter()
            .chain(env.class_hierarchy.supertypes(info.type_id))
            .filter(|&tid| {
                !env.type_status(&tid.full_name(&env.library)).ignored()
            })
            .map(|&tid| {
                format!(
                    "[`{name}Ext`](trait.{name}Ext.html)",
                    name = env.library.type_(tid).get_name()
                )
            })
            .collect::<Vec<_>>();
        if !implements.is_empty() {
            try!(writeln!(w, "\n# Implements\n"));
            try!(writeln!(w, "{}", &implements.join(", ")));
        }
        Ok(())
    }));

    if has_trait {
        try!(write_item_doc(w, &ty_ext, |w| {
            if let Some(ver) = info.deprecated_version {
                try!(write!(w, "`[Deprecated since {}]` ", ver));
            }
            try!(writeln!(w, "Trait containing all `{}` methods.", ty.name));

            if let Some(version) = info.version {
                try!(writeln!(w, "\nFeature: `{}`", version.to_feature()));
            }

            let mut implementors = Some(info.type_id)
                .into_iter()
                .chain(env.class_hierarchy.subtypes(info.type_id))
                .filter(|&tid| {
                    !env.type_status(&tid.full_name(&env.library)).ignored()
                })
                .map(|tid| {
                    format!(
                        "[`{name}`](struct.{name}.html)",
                        name = env.library.type_(tid).get_name()
                    )
                })
                .collect::<Vec<_>>();
            implementors.sort();

            try!(writeln!(w, "\n# Implementors\n"));
            try!(writeln!(w, "{}", implementors.join(", ")));
            Ok(())
        }));
    }

    let ty = TypeStruct {
        ty: SType::Impl,
        ..ty
    };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        } else {
            ty.clone()
        };
        try!(create_fn_doc(w, env, function, Some(Box::new(ty))));
    }
    Ok(())
}

fn create_record_doc(w: &mut Write, env: &Env, info: &analysis::record::Info) -> Result<()> {
    let record: &Record = env.library.type_(info.type_id).to_ref_as();
    let ty = record.to_stripper_type();
    let symbols = env.symbols.borrow();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(ref doc) = record.doc {
            if let Some(ver) = info.deprecated_version {
                try!(write!(w, "`[Deprecated since {}]` ", ver));
            }
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        if let Some(ver) = info.deprecated_version {
            try!(writeln!(w, "\n# Deprecated since {}\n", ver));
        } else if record.doc_deprecated.is_some() {
            try!(writeln!(w, "\n# Deprecated\n"));
        }
        if let Some(ref doc) = record.doc_deprecated {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        if let Some(version) = info.version {
            try!(writeln!(w, "\nFeature: `{}`", version.to_feature()));
        }
        Ok(())
    }));

    let ty = TypeStruct {
        ty: SType::Impl,
        ..ty
    };
    for function in &record.functions {
        try!(create_fn_doc(w, env, function, Some(Box::new(ty.clone()))));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, env: &Env, enum_: &Enumeration) -> Result<()> {
    let ty = enum_.to_stripper_type();
    let symbols = env.symbols.borrow();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(ref doc) = enum_.doc {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        if let Some(ver) = enum_.deprecated_version {
            try!(writeln!(w, "\n# Deprecated since {}\n", ver));
        } else if enum_.doc_deprecated.is_some() {
            try!(writeln!(w, "\n# Deprecated\n"));
        }
        if let Some(ref doc) = enum_.doc_deprecated {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        Ok(())
    }));

    for member in &enum_.members {
        let mut sub_ty = TypeStruct {
            name: member.name.to_camel(),
            ..member.to_stripper_type()
        };

        if member.doc.is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(write_item_doc(w, &sub_ty, |w| {
                if let Some(ref doc) = member.doc {
                    try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
                }
                Ok(())
            }));
        }
    }

    if let Some(version) = enum_.version {
        if version > env.config.min_cfg_version {
            try!(writeln!(w, "\nFeature: `{}`\n", version.to_feature()));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names<'a>(doc: &'a str, self_name: &Option<String>) -> Cow<'a, str> {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into();
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc(
    w: &mut Write,
    env: &Env,
    fn_: &Function,
    parent: Option<Box<TypeStruct>>,
) -> Result<()> {
    if fn_.doc.is_none() && fn_.doc_deprecated.is_none() && fn_.ret.doc.is_none() &&
        fn_.parameters.iter().all(|p| p.doc.is_none())
    {
        return Ok(());
    }

    let symbols = env.symbols.borrow();
    let ty = TypeStruct {
        parent: parent,
        ..fn_.to_stripper_type()
    };

    let self_name: Option<String> = fn_.parameters
        .iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    write_item_doc(w, &ty, |w| {
        if let Some(ref doc) = fn_.doc {
            try!(writeln!(
                w,
                "{}",
                reformat_doc(&fix_param_names(doc, &self_name), &symbols)
            ));
        }
        if let Some(version) = fn_.version {
            if version > env.config.min_cfg_version {
                try!(writeln!(w, "\nFeature: `{}`\n", version.to_feature()));
            }
        }
        if let Some(ver) = fn_.deprecated_version {
            try!(writeln!(w, "\n# Deprecated since {}\n", ver));
        } else if fn_.doc_deprecated.is_some() {
            try!(writeln!(w, "\n# Deprecated\n"));
        }
        if let Some(ref doc) = fn_.doc_deprecated {
            try!(writeln!(
                w,
                "{}",
                reformat_doc(&fix_param_names(doc, &self_name), &symbols)
            ));
        }

        for parameter in &fn_.parameters {
            if parameter.instance_parameter || parameter.name.is_empty() {
                continue;
            }
            if let Some(ref doc) = parameter.doc {
                try!(writeln!(
                    w,
                    "## `{}`",
                    nameutil::mangle_keywords(&parameter.name[..])
                ));
                try!(writeln!(
                    w,
                    "{}",
                    reformat_doc(&fix_param_names(doc, &self_name), &symbols)
                ));
            }
        }

        if let Some(ref doc) = fn_.ret.doc {
            try!(writeln!(w, "\n# Returns\n"));
            try!(writeln!(
                w,
                "{}",
                reformat_doc(&fix_param_names(doc, &self_name), &symbols)
            ));
        }
        Ok(())
    })
}
<commit_msg>Add doc for signals<commit_after>use std::borrow::Cow;
use std::io::{Result, Write};

use analysis;
use analysis::namespaces::MAIN;
use case::CaseExt;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use self::format::reformat_doc;
use stripper_lib::Type as SType;
use stripper_lib::{write_file_name, write_item_doc, TypeStruct};
use traits::*;
use version::Version;

mod format;

trait ToStripperType {
    fn to_stripper_type(&self) -> TypeStruct;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident, $useless:expr) => {
        impl ToStripperType for $ty {
            fn to_stripper_type(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var,
                                &format!("connect_{}", self.name.replace('-', "_")))
            }
        }
    };
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn to_stripper_type(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }
        }
    }
}

trait FunctionLikeType {
    fn doc(&self) -> &Option<String>;
    fn doc_deprecated(&self) -> &Option<String>;
    fn ret(&self) -> &Parameter;
    fn parameters(&self) -> &[Parameter];
    fn version(&self) -> &Option<Version>;
    fn deprecated_version(&self) -> &Option<Version>;
}

macro_rules! impl_function_like_type {
    ($ty:ident) => {
        impl FunctionLikeType for $ty {
            fn doc(&self) -> &Option<String> {
                &self.doc
            }
            fn doc_deprecated(&self) -> &Option<String> {
                &self.doc_deprecated
            }
            fn ret(&self) -> &Parameter {
                &self.ret
            }
            fn parameters(&self) -> &[Parameter] {
                &self.parameters
            }
            fn version(&self) -> &Option<Version> {
                &self.version
            }
            fn deprecated_version(&self) -> &Option<Version> {
                &self.deprecated_version
            }
        }
    }
}

impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Struct);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Signal, Fn, false);
impl_to_stripper_type!(Property, Fn);

impl_function_like_type!(Function);
impl_function_like_type!(Signal);

pub fn generate(env: &Env) {
    let path = env.config.target_path.join("vendor.md");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup, |w| generate_doc(w, env));
}

fn generate_doc(w: &mut Write, env: &Env) -> Result<()> {
    try!(write_file_name(w, None));
    let mut generators: Vec<(&str, Box<Fn(&mut Write, &Env) -> Result<()>>)> = Vec::new();

    for info in env.analysis.objects.values() {
        if info.type_id.ns_id == MAIN {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_object_doc(w, e, info)),
            ));
        }
    }

    for info in env.analysis.records.values() {
        if info.type_id.ns_id == MAIN {
            generators.push((
                &info.name,
                Box::new(move |w, e| create_record_doc(w, e, info)),
            ));
        }
    }

    for (tid, type_) in env.library.namespace_types(MAIN) {
        if let LType::Enumeration(ref enum_) = *type_ {
            if !env.config
                .objects
                .get(&tid.full_name(&env.library))
                .map_or(true, |obj| obj.status.ignored())
            {
                generators.push((
                    &enum_.name[..],
                    Box::new(move |w, e| create_enum_doc(w, e, enum_)),
                ));
            }
        }
    }

    generators.sort_by_key(|&(name, _)| name);
    for (_, f) in generators {
        try!(f(w, env));
    }

    Ok(())
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &info.trait_name);
    let has_trait = info.generate_trait;
    let doc;
    let functions: &[Function];
    let signals: &[Signal];

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            doc = cl.doc.as_ref();
            functions = &cl.functions;
            signals = &cl.signals;
        }
        Type::Interface(ref iface) => {
            doc = iface.doc.as_ref();
            functions = &iface.functions;
            signals = &iface.signals;
        }
        _ => unreachable!(),
    }

    try!(write_item_doc(w, &ty, |w| {
        if let Some(ver) = info.deprecated_version {
            try!(write!(w, "`[Deprecated since {}]` ", ver));
        }
        if let Some(doc) = doc {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        } else {
            try!(writeln!(w, ""));
        }
        if let Some(version) = info.version {
            try!(writeln!(w, "\nFeature: `{}`", version.to_feature()));
        }

        let impl_self = if has_trait { Some(info.type_id) } else { None };
        let implements = impl_self
            .iter()
            .chain(env.class_hierarchy.supertypes(info.type_id))
            .filter(|&tid| {
                !env.type_status(&tid.full_name(&env.library)).ignored()
            })
            .map(|&tid| {
                format!(
                    "[`{name}Ext`](trait.{name}Ext.html)",
                    name = env.library.type_(tid).get_name()
                )
            })
            .collect::<Vec<_>>();
        if !implements.is_empty() {
            try!(writeln!(w, "\n# Implements\n"));
            try!(writeln!(w, "{}", &implements.join(", ")));
        }
        Ok(())
    }));

    if has_trait {
        try!(write_item_doc(w, &ty_ext, |w| {
            if let Some(ver) = info.deprecated_version {
                try!(write!(w, "`[Deprecated since {}]` ", ver));
            }
            try!(writeln!(w, "Trait containing all `{}` methods.", ty.name));

            if let Some(version) = info.version {
                try!(writeln!(w, "\nFeature: `{}`", version.to_feature()));
            }

            let mut implementors = Some(info.type_id)
                .into_iter()
                .chain(env.class_hierarchy.subtypes(info.type_id))
                .filter(|&tid| {
                    !env.type_status(&tid.full_name(&env.library)).ignored()
                })
                .map(|tid| {
                    format!(
                        "[`{name}`](struct.{name}.html)",
                        name = env.library.type_(tid).get_name()
                    )
                })
                .collect::<Vec<_>>();
            implementors.sort();

            try!(writeln!(w, "\n# Implementors\n"));
            try!(writeln!(w, "{}", implementors.join(", ")));
            Ok(())
        }));
    }

    let ty = TypeStruct {
        ty: SType::Impl,
        ..ty
    };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        } else {
            ty.clone()
        };
        try!(create_fn_doc(w, env, function, Some(Box::new(ty))));
    }
    for signal in signals {
        try!(create_fn_doc(w, env, signal, Some(Box::new(ty_ext.clone()))));
    }
    Ok(())
}

fn create_record_doc(w: &mut Write, env: &Env, info: &analysis::record::Info) -> Result<()> {
    let record: &Record = env.library.type_(info.type_id).to_ref_as();
    let ty = record.to_stripper_type();
    let symbols = env.symbols.borrow();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(ref doc) = record.doc {
            if let Some(ver) = info.deprecated_version {
                try!(write!(w, "`[Deprecated since {}]` ", ver));
            }
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        if let Some(ver) = info.deprecated_version {
            try!(writeln!(w, "\n# Deprecated since {}\n", ver));
        } else if record.doc_deprecated.is_some() {
            try!(writeln!(w, "\n# Deprecated\n"));
        }
        if let Some(ref doc) = record.doc_deprecated {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        if let Some(version) = info.version {
            try!(writeln!(w, "\nFeature: `{}`", version.to_feature()));
        }
        Ok(())
    }));

    let ty = TypeStruct {
        ty: SType::Impl,
        ..ty
    };
    for function in &record.functions {
        try!(create_fn_doc(w, env, function, Some(Box::new(ty.clone()))));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, env: &Env, enum_: &Enumeration) -> Result<()> {
    let ty = enum_.to_stripper_type();
    let symbols = env.symbols.borrow();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(ref doc) = enum_.doc {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        if let Some(ver) = enum_.deprecated_version {
            try!(writeln!(w, "\n# Deprecated since {}\n", ver));
        } else if enum_.doc_deprecated.is_some() {
            try!(writeln!(w, "\n# Deprecated\n"));
        }
        if let Some(ref doc) = enum_.doc_deprecated {
            try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
        }
        Ok(())
    }));

    for member in &enum_.members {
        let mut sub_ty = TypeStruct {
            name: member.name.to_camel(),
            ..member.to_stripper_type()
        };

        if member.doc.is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(write_item_doc(w, &sub_ty, |w| {
                if let Some(ref doc) = member.doc {
                    try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
                }
                Ok(())
            }));
        }
    }

    if let Some(version) = enum_.version {
        if version > env.config.min_cfg_version {
            try!(writeln!(w, "\nFeature: `{}`\n", version.to_feature()));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names<'a>(doc: &'a str, self_name: &Option<String>) -> Cow<'a, str> {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into();
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc<T>(
    w: &mut Write,
    env: &Env,
    fn_: &T,
    parent: Option<Box<TypeStruct>>,
) -> Result<()>
where T: FunctionLikeType + ToStripperType {
    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret().doc.is_none() &&
        fn_.parameters().iter().all(|p| p.doc.is_none()) {
        return Ok(());
    }

    let symbols = env.symbols.borrow();
    let ty = TypeStruct {
        parent: parent,
        ..fn_.to_stripper_type()
    };

    let self_name: Option<String> = fn_.parameters()
        .iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    write_item_doc(w, &ty, |w| {
        if let &Some(ref doc) = fn_.doc() {
            try!(writeln!(
                w,
                "{}",
                reformat_doc(&fix_param_names(doc, &self_name), &symbols)
            ));
        }
        if let &Some(version) = fn_.version() {
            if version > env.config.min_cfg_version {
                try!(writeln!(w, "\nFeature: `{}`\n", version.to_feature()));
            }
        }
        if let &Some(ver) = fn_.deprecated_version() {
            try!(writeln!(w, "\n# Deprecated since {}\n", ver));
        } else if fn_.doc_deprecated().is_some() {
            try!(writeln!(w, "\n# Deprecated\n"));
        }
        if let &Some(ref doc) = fn_.doc_deprecated() {
            try!(writeln!(
                w,
                "{}",
                reformat_doc(&fix_param_names(doc, &self_name), &symbols)
            ));
        }

        for parameter in fn_.parameters() {
            if parameter.instance_parameter || parameter.name.is_empty() {
                continue;
            }
            if let Some(ref doc) = parameter.doc {
                try!(writeln!(
                    w,
                    "## `{}`",
                    nameutil::mangle_keywords(&parameter.name[..])
                ));
                try!(writeln!(
                    w,
                    "{}",
                    reformat_doc(&fix_param_names(doc, &self_name), &symbols)
                ));
            }
        }

        if let Some(ref doc) = fn_.ret().doc {
            try!(writeln!(w, "\n# Returns\n"));
            try!(writeln!(
                w,
                "{}",
                reformat_doc(&fix_param_names(doc, &self_name), &symbols)
            ));
        }
        Ok(())
    })
}
<|endoftext|>


<commit_before>use std::{env, path::Path};

use rust_swig::{CppConfig, LanguageConfig};

fn main() {
    env_logger::init();

    let out_dir = env::var("OUT_DIR").unwrap();

    let cpp_gen_path = Path::new("c++").join("rust_interface");
    println!("cargo:rerun-if-changed={}", cpp_gen_path.display());
    let cpp_cfg = if cfg!(feature = "boost") {
        CppConfig::new(cpp_gen_path, "rust".into()).use_boost()
    } else {
        CppConfig::new(cpp_gen_path, "rust".into())
    };

    let swig_gen = rust_swig::Generator::new(LanguageConfig::CppConfig(cpp_cfg));
    swig_gen.expand(
        "rust_swig_test_c++",
        Path::new("src/cpp_glue.rs.in"),
        &Path::new(&out_dir).join("cpp_glue.rs"),
    );
    println!(
        "cargo:rerun-if-changed={}",
        Path::new("src").join("cpp_glue.rs.in").display()
    );
}
<commit_msg>c++_tests/fix: cargo doesn't support rerun-if-changed for directory<commit_after>use std::{env, path::Path};

use rust_swig::{CppConfig, LanguageConfig};

fn main() {
    env_logger::init();

    let out_dir = env::var("OUT_DIR").unwrap();

    let cpp_gen_path = Path::new("c++").join("rust_interface");
    let cpp_cfg = if cfg!(feature = "boost") {
        CppConfig::new(cpp_gen_path, "rust".into()).use_boost()
    } else {
        CppConfig::new(cpp_gen_path, "rust".into())
    };

    let swig_gen = rust_swig::Generator::new(LanguageConfig::CppConfig(cpp_cfg));
    swig_gen.expand(
        "rust_swig_test_c++",
        Path::new("src/cpp_glue.rs.in"),
        &Path::new(&out_dir).join("cpp_glue.rs"),
    );
    println!(
        "cargo:rerun-if-changed={}",
        Path::new("src").join("cpp_glue.rs.in").display()
    );
}
<|endoftext|>


<commit_before>use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use lazy_static::lazy_static;
use rand::{rngs::ThreadRng, Rng, RngCore};
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

#[derive(Debug, Clone)]
enum Action {
    AddProgressBar(usize),
    IncProgressBar(usize),
}

#[derive(Clone, Debug)]
struct Elem {
    key: String,
    index: usize,
    indent: usize,
    progress_bar: ProgressBar,
}

lazy_static! {
    static ref ELEMENTS: [Elem; 9] = [
        Elem {
            indent: 1,
            index: 0,
            progress_bar: ProgressBar::new(32),
            key: "jumps".to_string()
        },
        Elem {
            indent: 2,
            index: 1,
            progress_bar: ProgressBar::new(32),
            key: "lazy".to_string()
        },
        Elem {
            indent: 0,
            index: 0,
            progress_bar: ProgressBar::new(32),
            key: "the".to_string()
        },
        Elem {
            indent: 3,
            index: 3,
            progress_bar: ProgressBar::new(32),
            key: "dog".to_string()
        },
        Elem {
            indent: 2,
            index: 2,
            progress_bar: ProgressBar::new(32),
            key: "over".to_string()
        },
        Elem {
            indent: 2,
            index: 1,
            progress_bar: ProgressBar::new(32),
            key: "brown".to_string()
        },
        Elem {
            indent: 1,
            index: 1,
            progress_bar: ProgressBar::new(32),
            key: "quick".to_string()
        },
        Elem {
            indent: 3,
            index: 5,
            progress_bar: ProgressBar::new(32),
            key: "a".to_string()
        },
        Elem {
            indent: 3,
            index: 3,
            progress_bar: ProgressBar::new(32),
            key: "fox".to_string()
        },
    ];
}

fn main() {
    let mp = Arc::new(MultiProgress::new());
    let sty_main = ProgressStyle::default_bar().template("{bar:40.green/yellow} {pos:>4}/{len:4}");
    let sty_aux = ProgressStyle::default_bar().template("{spinner:.green} {msg} {pos:>4}/{len:4}");

    let pb_main = mp.add(ProgressBar::new(
        ELEMENTS.iter().map(|e| e.progress_bar.length()).sum(),
    ));
    pb_main.set_style(sty_main);
    for elem in ELEMENTS.iter() {
        elem.progress_bar.set_style(sty_aux.clone());
    }

    let tree: Arc<Mutex<Vec<&Elem>>> = Arc::new(Mutex::new(Vec::with_capacity(ELEMENTS.len())));
    let tree2 = Arc::clone(&tree);

    let mp2 = Arc::clone(&mp);
    let _ = thread::spawn(move || {
        let mut rng = ThreadRng::default();
        pb_main.tick();
        loop {
            match get_action(&mut rng, &tree) {
                None => {
                    // all elements were exhausted
                    pb_main.finish();
                    return;
                }
                Some(Action::AddProgressBar(el_idx)) => {
                    let elem = &ELEMENTS[el_idx];
                    let pb = mp2.insert(elem.index + 1, elem.progress_bar.clone());
                    pb.set_message(&format!("{}  {}", "  ".repeat(elem.indent), elem.key));
                    tree.lock().unwrap().insert(elem.index, &elem);
                }
                Some(Action::IncProgressBar(el_idx)) => {
                    let elem = &tree.lock().unwrap()[el_idx];
                    elem.progress_bar.inc(1);
                    let pos = elem.progress_bar.position();
                    let len = elem.progress_bar.length();
                    if pos >= len {
                        elem.progress_bar.finish_with_message(&format!(
                            "{}{} {}",
                            "  ".repeat(elem.indent),
                            "✔",
                            elem.key
                        ));
                    }
                    pb_main.inc(1);
                }
            }
            thread::sleep(Duration::from_millis(15));
        }
    });

    mp.join().unwrap();

    println!("===============================");
    println!("the tree should be the same as:");
    for elem in tree2.lock().unwrap().iter() {
        println!("{}  {}", "  ".repeat(elem.indent), elem.key);
    }
}

fn get_action<'a>(rng: &'a mut dyn RngCore, tree: &Mutex<Vec<&Elem>>) -> Option<Action> {
    let elem_len = ELEMENTS.len() as u64;
    let list_len = tree.lock().unwrap().len() as u64;
    let sum_free = tree
        .lock()
        .unwrap()
        .iter()
        .map(|e| {
            let pos = e.progress_bar.position();
            let len = e.progress_bar.length();
            len - pos
        })
        .sum::<u64>();
    if sum_free == 0 && list_len == elem_len {
        // nothing to do more
        return None;
    } else if sum_free == 0 && list_len < elem_len {
        // there is no place to make an increment
        return Some(Action::AddProgressBar(tree.lock().unwrap().len()));
    } else {
        loop {
            let list = tree.lock().unwrap();
            let k = rng.gen_range(0..17);
            if k == 0 && list_len < elem_len {
                return Some(Action::AddProgressBar(list.len()));
            } else {
                let l = (k % list_len) as usize;
                let pos = list[l].progress_bar.position();
                let len = list[l].progress_bar.length();
                if pos < len {
                    return Some(Action::IncProgressBar(l));
                }
            }
        }
    }
}
<commit_msg>Remove unnecessary return statements<commit_after>use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use lazy_static::lazy_static;
use rand::{rngs::ThreadRng, Rng, RngCore};
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

#[derive(Debug, Clone)]
enum Action {
    AddProgressBar(usize),
    IncProgressBar(usize),
}

#[derive(Clone, Debug)]
struct Elem {
    key: String,
    index: usize,
    indent: usize,
    progress_bar: ProgressBar,
}

lazy_static! {
    static ref ELEMENTS: [Elem; 9] = [
        Elem {
            indent: 1,
            index: 0,
            progress_bar: ProgressBar::new(32),
            key: "jumps".to_string()
        },
        Elem {
            indent: 2,
            index: 1,
            progress_bar: ProgressBar::new(32),
            key: "lazy".to_string()
        },
        Elem {
            indent: 0,
            index: 0,
            progress_bar: ProgressBar::new(32),
            key: "the".to_string()
        },
        Elem {
            indent: 3,
            index: 3,
            progress_bar: ProgressBar::new(32),
            key: "dog".to_string()
        },
        Elem {
            indent: 2,
            index: 2,
            progress_bar: ProgressBar::new(32),
            key: "over".to_string()
        },
        Elem {
            indent: 2,
            index: 1,
            progress_bar: ProgressBar::new(32),
            key: "brown".to_string()
        },
        Elem {
            indent: 1,
            index: 1,
            progress_bar: ProgressBar::new(32),
            key: "quick".to_string()
        },
        Elem {
            indent: 3,
            index: 5,
            progress_bar: ProgressBar::new(32),
            key: "a".to_string()
        },
        Elem {
            indent: 3,
            index: 3,
            progress_bar: ProgressBar::new(32),
            key: "fox".to_string()
        },
    ];
}

fn main() {
    let mp = Arc::new(MultiProgress::new());
    let sty_main = ProgressStyle::default_bar().template("{bar:40.green/yellow} {pos:>4}/{len:4}");
    let sty_aux = ProgressStyle::default_bar().template("{spinner:.green} {msg} {pos:>4}/{len:4}");

    let pb_main = mp.add(ProgressBar::new(
        ELEMENTS.iter().map(|e| e.progress_bar.length()).sum(),
    ));
    pb_main.set_style(sty_main);
    for elem in ELEMENTS.iter() {
        elem.progress_bar.set_style(sty_aux.clone());
    }

    let tree: Arc<Mutex<Vec<&Elem>>> = Arc::new(Mutex::new(Vec::with_capacity(ELEMENTS.len())));
    let tree2 = Arc::clone(&tree);

    let mp2 = Arc::clone(&mp);
    let _ = thread::spawn(move || {
        let mut rng = ThreadRng::default();
        pb_main.tick();
        loop {
            match get_action(&mut rng, &tree) {
                None => {
                    // all elements were exhausted
                    pb_main.finish();
                    return;
                }
                Some(Action::AddProgressBar(el_idx)) => {
                    let elem = &ELEMENTS[el_idx];
                    let pb = mp2.insert(elem.index + 1, elem.progress_bar.clone());
                    pb.set_message(&format!("{}  {}", "  ".repeat(elem.indent), elem.key));
                    tree.lock().unwrap().insert(elem.index, &elem);
                }
                Some(Action::IncProgressBar(el_idx)) => {
                    let elem = &tree.lock().unwrap()[el_idx];
                    elem.progress_bar.inc(1);
                    let pos = elem.progress_bar.position();
                    let len = elem.progress_bar.length();
                    if pos >= len {
                        elem.progress_bar.finish_with_message(&format!(
                            "{}{} {}",
                            "  ".repeat(elem.indent),
                            "✔",
                            elem.key
                        ));
                    }
                    pb_main.inc(1);
                }
            }
            thread::sleep(Duration::from_millis(15));
        }
    });

    mp.join().unwrap();

    println!("===============================");
    println!("the tree should be the same as:");
    for elem in tree2.lock().unwrap().iter() {
        println!("{}  {}", "  ".repeat(elem.indent), elem.key);
    }
}

fn get_action<'a>(rng: &'a mut dyn RngCore, tree: &Mutex<Vec<&Elem>>) -> Option<Action> {
    let elem_len = ELEMENTS.len() as u64;
    let list_len = tree.lock().unwrap().len() as u64;
    let sum_free = tree
        .lock()
        .unwrap()
        .iter()
        .map(|e| {
            let pos = e.progress_bar.position();
            let len = e.progress_bar.length();
            len - pos
        })
        .sum::<u64>();

    if sum_free == 0 && list_len == elem_len {
        // nothing to do more
        None
    } else if sum_free == 0 && list_len < elem_len {
        // there is no place to make an increment
        Some(Action::AddProgressBar(tree.lock().unwrap().len()))
    } else {
        loop {
            let list = tree.lock().unwrap();
            let k = rng.gen_range(0..17);
            if k == 0 && list_len < elem_len {
                return Some(Action::AddProgressBar(list.len()));
            } else {
                let l = (k % list_len) as usize;
                let pos = list[l].progress_bar.position();
                let len = list[l].progress_bar.length();
                if pos < len {
                    return Some(Action::IncProgressBar(l));
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{self, Read, Write};
use std::str::from_utf8;

use mio::event::Event;
use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interests, Poll, Registry, Token};

// Setup some tokens to allow us to identify which event is for which socket.
const SERVER: Token = Token(0);

// Some data we'll send over the connection.
const DATA: &[u8] = b"Hello world!\n";

fn main() -> io::Result<()> {
    // Create a poll instance.
    let mut poll = Poll::new()?;
    // Create storage for events.
    let mut events = Events::with_capacity(128);

    // Setup the TCP server socket.
    let addr = "127.0.0.1:13265".parse().unwrap();
    let server = TcpListener::bind(addr)?;

    // Register the server with poll we can receive events for it.
    poll.registry()
        .register(&server, SERVER, Interests::READABLE)?;

    // Map of `Token` -> `TcpStream`.
    let mut connections = HashMap::new();
    // Unique token for each incoming connection.
    let mut unique_token = Token(SERVER.0 + 1);

    println!("You can connect to the server using `nc`:");
    println!(" $ nc 127.0.0.1 13265");
    println!("You'll see our welcome message and anything you type we'll be printed here.");

    loop {
        poll.poll(&mut events, None)?;

        for event in events.iter() {
            match event.token() {
                SERVER => {
                    // Received an event for the TCP server socket.
                    // Accept an connection.
                    let (connection, address) = server.accept()?;
                    println!("Accepted connection from: {}", address);

                    let token = next(&mut unique_token);
                    poll.registry().register(
                        &connection,
                        token,
                        Interests::READABLE.add(Interests::WRITABLE),
                    )?;

                    connections.insert(token, connection);
                }
                token => {
                    // (maybe) received an event for a TCP connection.
                    let done = if let Some(connection) = connections.get_mut(&token) {
                        handle_connection_event(poll.registry(), connection, event)?
                    } else {
                        // Sporadic events happen.
                        false
                    };
                    if done {
                        connections.remove(&token);
                    }
                }
            }
        }
    }
}

fn next(current: &mut Token) -> Token {
    let next = current.0;
    current.0 += 1;
    Token(next)
}

/// Returns `true` if the connection is done.
fn handle_connection_event(
    registry: &Registry,
    connection: &mut TcpStream,
    event: &Event,
) -> io::Result<bool> {
    if event.is_writable() {
        // We can (maybe) write to the connection.
        match connection.write(DATA) {
            // We want to write the entire `DATA` buffer in a single go. If we
            // write less we'll return a short write error (same as
            // `io::Write::write_all` does).
            Ok(n) if n < DATA.len() => return Err(io::ErrorKind::WriteZero.into()),
            Ok(_) => {
                // After we've written something we'll reregister the connection
                // to only respond to readable events.
                registry
                    .reregister(&connection, event.token(), Interests::READABLE)?
            }
            // Would block "errors" are the OS's way of saying that the
            // connection is not actually ready to perform this I/O operation.
            Err(ref err) if would_block(err) => {}
            // Got interrupted (how rude!), we'll try again.
            Err(ref err) if interrupted(err) => {
                return handle_connection_event(registry, connection, event)
            }
            // Other errors we'll consider fatal.
            Err(err) => return Err(err),
        }
    }

    if event.is_readable() {
        let mut connection_closed = false;
        let mut received_data = Vec::with_capacity(4096);
        // We can (maybe) read from the connection.
        loop {
            let mut buf = [0; 256];
            match connection.read(&mut buf) {
                Ok(0) => {
                    // Reading 0 bytes means the other side has closed the
                    // connection or is done writing, then so are we.
                    connection_closed = true;
                    break;
                }
                Ok(n) => received_data.extend_from_slice(&buf[..n]),
                // Would block "errors" are the OS's way of saying that the
                // connection is not actually ready to perform this I/O operation.
                Err(ref err) if would_block(err) => break,
                Err(ref err) if interrupted(err) => continue,
                // Other errors we'll consider fatal.
                Err(err) => return Err(err),
            }
        }

        if let Ok(str_buf) = from_utf8(&received_data) {
            println!("Received data: {}", str_buf.trim_end());
        } else {
            println!("Received (none UTF-8) data: {:?}", &received_data);
        }

        if connection_closed {
            println!("Connection closed");
            return Ok(true);
        }
    }

    Ok(false)
}

fn would_block(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::WouldBlock
}

fn interrupted(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::Interrupted
}
<commit_msg>Run rustfmt and put back unused `env_logger::init` call<commit_after>use std::collections::HashMap;
use std::io::{self, Read, Write};
use std::str::from_utf8;

use mio::event::Event;
use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interests, Poll, Registry, Token};

// Setup some tokens to allow us to identify which event is for which socket.
const SERVER: Token = Token(0);

// Some data we'll send over the connection.
const DATA: &[u8] = b"Hello world!\n";

fn main() -> io::Result<()> {
    env_logger::init();

    // Create a poll instance.
    let mut poll = Poll::new()?;
    // Create storage for events.
    let mut events = Events::with_capacity(128);

    // Setup the TCP server socket.
    let addr = "127.0.0.1:13265".parse().unwrap();
    let server = TcpListener::bind(addr)?;

    // Register the server with poll we can receive events for it.
    poll.registry()
        .register(&server, SERVER, Interests::READABLE)?;

    // Map of `Token` -> `TcpStream`.
    let mut connections = HashMap::new();
    // Unique token for each incoming connection.
    let mut unique_token = Token(SERVER.0 + 1);

    println!("You can connect to the server using `nc`:");
    println!(" $ nc 127.0.0.1 13265");
    println!("You'll see our welcome message and anything you type we'll be printed here.");

    loop {
        poll.poll(&mut events, None)?;

        for event in events.iter() {
            match event.token() {
                SERVER => {
                    // Received an event for the TCP server socket.
                    // Accept an connection.
                    let (connection, address) = server.accept()?;
                    println!("Accepted connection from: {}", address);

                    let token = next(&mut unique_token);
                    poll.registry().register(
                        &connection,
                        token,
                        Interests::READABLE.add(Interests::WRITABLE),
                    )?;

                    connections.insert(token, connection);
                }
                token => {
                    // (maybe) received an event for a TCP connection.
                    let done = if let Some(connection) = connections.get_mut(&token) {
                        handle_connection_event(poll.registry(), connection, event)?
                    } else {
                        // Sporadic events happen.
                        false
                    };
                    if done {
                        connections.remove(&token);
                    }
                }
            }
        }
    }
}

fn next(current: &mut Token) -> Token {
    let next = current.0;
    current.0 += 1;
    Token(next)
}

/// Returns `true` if the connection is done.
fn handle_connection_event(
    registry: &Registry,
    connection: &mut TcpStream,
    event: &Event,
) -> io::Result<bool> {
    if event.is_writable() {
        // We can (maybe) write to the connection.
        match connection.write(DATA) {
            // We want to write the entire `DATA` buffer in a single go. If we
            // write less we'll return a short write error (same as
            // `io::Write::write_all` does).
            Ok(n) if n < DATA.len() => return Err(io::ErrorKind::WriteZero.into()),
            Ok(_) => {
                // After we've written something we'll reregister the connection
                // to only respond to readable events.
                registry.reregister(&connection, event.token(), Interests::READABLE)?
            }
            // Would block "errors" are the OS's way of saying that the
            // connection is not actually ready to perform this I/O operation.
            Err(ref err) if would_block(err) => {}
            // Got interrupted (how rude!), we'll try again.
            Err(ref err) if interrupted(err) => {
                return handle_connection_event(registry, connection, event)
            }
            // Other errors we'll consider fatal.
            Err(err) => return Err(err),
        }
    }

    if event.is_readable() {
        let mut connection_closed = false;
        let mut received_data = Vec::with_capacity(4096);
        // We can (maybe) read from the connection.
        loop {
            let mut buf = [0; 256];
            match connection.read(&mut buf) {
                Ok(0) => {
                    // Reading 0 bytes means the other side has closed the
                    // connection or is done writing, then so are we.
                    connection_closed = true;
                    break;
                }
                Ok(n) => received_data.extend_from_slice(&buf[..n]),
                // Would block "errors" are the OS's way of saying that the
                // connection is not actually ready to perform this I/O operation.
                Err(ref err) if would_block(err) => break,
                Err(ref err) if interrupted(err) => continue,
                // Other errors we'll consider fatal.
                Err(err) => return Err(err),
            }
        }

        if let Ok(str_buf) = from_utf8(&received_data) {
            println!("Received data: {}", str_buf.trim_end());
        } else {
            println!("Received (none UTF-8) data: {:?}", &received_data);
        }

        if connection_closed {
            println!("Connection closed");
            return Ok(true);
        }
    }

    Ok(false)
}

fn would_block(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::WouldBlock
}

fn interrupted(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::Interrupted
}
<|endoftext|>