<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 std::sync::Arc;
use tink::{
    keyset::{insecure, Handle},
    proto::{key_data::KeyMaterialType, KeyData},
    TinkError,
};

#[test]
fn test_new_handle() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = Handle::new(&kt).unwrap();
    let ks = insecure::keyset_material(&kh);
    assert_eq!(1, ks.key.len(), "incorrect number of keys in the keyset");
    let key = ks.key[0].clone();
    assert_eq!(ks.primary_key_id, key.key_id, "incorrect primary key id");
    assert_eq!(
        key.key_data.unwrap().type_url,
        kt.type_url,
        "incorrect type url"
    );
    assert!(
        tink_mac::new(&kh).is_ok(),
        "cannot get primitive from generated keyset handle"
    );
}

#[test]
fn test_new_handle_with_invalid_input() {
    tink_mac::init();
    // template unregistered type_url
    let mut template = tink_mac::hmac_sha256_tag128_key_template();
    template.type_url = "some unknown type_url".to_string();
    assert!(
        Handle::new(&template).is_err(),
        "expect an error when type_url is not registered"
    );
}

#[test]
fn test_read() {
    let main_key = Box::new(tink_aead::subtle::AesGcm::new(&[b'A'; 32]).unwrap());

    // Create a keyset
    let key_data = tink_testutil::new_key_data(
        "some type url",
        &[42, 42, 0x42, 0x42, 0o42, 0o42], // 42 in all possible formats
        KeyMaterialType::Symmetric,
    );
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    // Also check that debug output of handle doesn't include key material.
    let debug_output = format!("{:?}", h);
    assert!(!debug_output.contains("42"));

    let mem_keyset = &mut tink::keyset::MemReaderWriter::default();
    assert!(h.write(mem_keyset, main_key.clone()).is_ok());
    let h2 = Handle::read(mem_keyset, main_key).unwrap();
    assert_eq!(
        insecure::keyset_material(&h),
        insecure::keyset_material(&h2),
        "Decrypt failed: got {:?}, want {:?}",
        h2,
        h
    );
}

#[test]
fn test_read_with_no_secrets() {
    // Create a keyset containing public key material
    let key_data =
        tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::AsymmetricPublic);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    let mem_keyset = &mut tink::keyset::MemReaderWriter::default();
    assert!(h.write_with_no_secrets(mem_keyset).is_ok());
    let h2 = Handle::read_with_no_secrets(mem_keyset).unwrap();

    assert_eq!(
        insecure::keyset_material(&h),
        insecure::keyset_material(&h2),
        "Decrypt failed: got {:?}, want {:?}",
        h2,
        h
    );
}

#[test]
fn test_with_no_secrets_functions_fail_when_handling_secret_key_material() {
    // Create a keyset containing secret key material (symmetric)
    let key_data = tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::Symmetric);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    assert!(
        h.write_with_no_secrets(&mut tink::keyset::MemReaderWriter::default())
            .is_err(),
        "handle.write_with_no_secrets() should fail when exporting secret key material"
    );

    assert!(
        Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter {
            keyset: Some(insecure::keyset_material(&h)),
            ..Default::default()
        })
        .is_err(),
        "keyset.read_with_no_secrets should fail when importing secret key material"
    );
}

#[test]
fn test_with_no_secrets_functions_fail_when_unknown_key_material() {
    // Create a keyset containing secret key material (symmetric)
    let key_data =
        tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::UnknownKeymaterial);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    assert!(
        h.write_with_no_secrets(&mut tink::keyset::MemReaderWriter::default())
            .is_err(),
        "handle.write_with_no_secrets() should fail when exporting secret key material"
    );

    assert!(
        Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter {
            keyset: Some(insecure::keyset_material(&h)),
            ..Default::default()
        })
        .is_err(),
        "keyset.read_with_no_secrets should fail when importing secret key material"
    );
}

#[test]
fn test_with_no_secrets_functions_fail_with_asymmetric_private_key_material() {
    // Create a keyset containing secret key material (asymmetric)
    let key_data =
        tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::AsymmetricPrivate);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    assert!(
        h.write_with_no_secrets(&mut tink::keyset::MemReaderWriter::default())
            .is_err(),
        "handle.write_with_no_secrets() should fail when exporting secret key material"
    );

    assert!(
        Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter {
            keyset: Some(insecure::keyset_material(&h)),
            ..Default::default()
        })
        .is_err(),
        "keyset.read_with_no_secrets should fail when importing secret key material"
    );
}

#[test]
fn test_keyset_info() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = tink::keyset::Handle::new(&kt).unwrap();
    let info = kh.keyset_info();
    assert_eq!(info.primary_key_id, info.key_info[0].key_id);
}

#[test]
fn test_invalid_keyset() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = Handle::new(&kt).unwrap();

    let mut invalid_ks = insecure::keyset_material(&kh);
    invalid_ks.key[0].key_data = None;
    assert!(insecure::new_handle(invalid_ks).is_err());

    let mut invalid_ks = insecure::keyset_material(&kh);
    invalid_ks.key.clear();
    assert!(insecure::new_handle(invalid_ks).is_err());
}

#[test]
fn test_invalid_keyset_from_manager() {
    // Use a key manager that generates invalid `KeyData`.
    pub struct InvalidKeyManager {}

    impl tink::registry::KeyManager for InvalidKeyManager {
        fn primitive(&self, _serialized_key: &[u8]) -> Result<tink::Primitive, TinkError> {
            Err("not implemented".into())
        }

        fn new_key(&self, _serialized_key_format: &[u8]) -> Result<Vec<u8>, TinkError> {
            Err("not implemented".into())
        }

        fn type_url(&self) -> &'static str {
            "InvalidKeyGenerator"
        }

        fn key_material_type(&self) -> KeyMaterialType {
            KeyMaterialType::Symmetric
        }

        fn new_key_data(&self, _serialized_key_format: &[u8]) -> Result<KeyData, TinkError> {
            Ok(KeyData {
                key_material_type: 9999,
                type_url: self.type_url().to_string(),
                value: vec![],
            })
        }
    }
    tink::registry::register_key_manager(Arc::new(InvalidKeyManager {})).unwrap();
    let kt = tink::proto::KeyTemplate {
        output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
        type_url: "InvalidKeyGenerator".to_string(),
        value: vec![],
    };

    assert!(tink::keyset::Handle::new(&kt).is_err());
}

#[test]
fn test_destroyed_key_keyset() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = Handle::new(&kt).unwrap();

    let mut ks = insecure::keyset_material(&kh);
    ks.key[0].key_data = None;
    ks.key[0].status = tink::proto::KeyStatusType::Destroyed as i32;
    let kh = insecure::new_handle(ks).unwrap();
    let info = kh.keyset_info();
    assert_eq!(info.primary_key_id, info.key_info[0].key_id);
    // The type_url for a destroyed key is not available.
    assert_eq!(info.key_info[0].type_url, "");
}

#[test]
fn test_handle_public() {
    tink_signature::init();
    let kh = Handle::new(&tink_signature::ecdsa_p256_key_template()).unwrap();

    let kh_public = kh.public().unwrap();

    let ks = insecure::keyset_material(&kh_public);
    assert_eq!(
        ks.key[0].key_data.as_ref().unwrap().key_material_type,
        KeyMaterialType::AsymmetricPublic as i32
    );

    // handle.public() only works for asymmetric private keys.
    let result = kh_public.public();
    tink_testutil::expect_err(result, "contains a non-private key");
}

#[test]
fn test_handle_public_destroyed_key() {
    tink_signature::init();

    let mut ksm = tink::keyset::Manager::new();
    ksm.rotate(&tink_signature::ecdsa_p256_key_template())
        .unwrap();
    let key_id = ksm
        .add(
            &tink_signature::ecdsa_p256_key_template(),
            /* primary= */ false,
        )
        .unwrap();
    ksm.destroy(key_id).unwrap();
    let kh = ksm.handle().unwrap();

    let result = kh.public();
    tink_testutil::expect_err(result, "invalid keyset");
}

#[test]
fn test_handle_public_wrong_keymanager() {
    tink_mac::init();
    tink_signature::init();
    let kh = Handle::new(&tink_signature::ecdsa_p256_key_template()).unwrap();

    // Manually corrupt the keyset to refer to the wrong key manager.
    let mut ks = insecure::keyset_material(&kh);
    ks.key[0].key_data.as_mut().unwrap().type_url = tink_testutil::HMAC_TYPE_URL.to_string();
    let invalid_kh = insecure::new_handle(ks).unwrap();

    let result = invalid_kh.public();
    tink_testutil::expect_err(result, "handles private keys");
}

#[test]
fn test_mem_read_with_no_secrets_empty() {
    let result = Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter::default());
    tink_testutil::expect_err(result, "no keyset available");
}

#[test]
fn test_mem_read_empty() {
    let main_key = Box::new(tink_aead::subtle::AesGcm::new(&[b'A'; 32]).unwrap());
    let result = Handle::read(&mut tink::keyset::MemReaderWriter::default(), main_key);
    tink_testutil::expect_err(result, "no keyset available");
}
<commit_msg>tink::keyset: more insecure tests<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 std::sync::Arc;
use tink::{
    keyset::{insecure, Handle},
    proto::{key_data::KeyMaterialType, KeyData},
    TinkError,
};

#[test]
fn test_new_handle() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = Handle::new(&kt).unwrap();
    let ks = insecure::keyset_material(&kh);
    assert_eq!(1, ks.key.len(), "incorrect number of keys in the keyset");
    let key = ks.key[0].clone();
    assert_eq!(ks.primary_key_id, key.key_id, "incorrect primary key id");
    assert_eq!(
        key.key_data.unwrap().type_url,
        kt.type_url,
        "incorrect type url"
    );
    assert!(
        tink_mac::new(&kh).is_ok(),
        "cannot get primitive from generated keyset handle"
    );
}

#[test]
fn test_new_handle_with_invalid_input() {
    tink_mac::init();
    // template unregistered type_url
    let mut template = tink_mac::hmac_sha256_tag128_key_template();
    template.type_url = "some unknown type_url".to_string();
    assert!(
        Handle::new(&template).is_err(),
        "expect an error when type_url is not registered"
    );
}

#[test]
fn test_read() {
    let main_key = Box::new(tink_aead::subtle::AesGcm::new(&[b'A'; 32]).unwrap());

    // Create a keyset
    let key_data = tink_testutil::new_key_data(
        "some type url",
        &[42, 42, 0x42, 0x42, 0o42, 0o42], // 42 in all possible formats
        KeyMaterialType::Symmetric,
    );
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    // Also check that debug output of handle doesn't include key material.
    let debug_output = format!("{:?}", h);
    assert!(!debug_output.contains("42"));

    let mem_keyset = &mut tink::keyset::MemReaderWriter::default();
    assert!(h.write(mem_keyset, main_key.clone()).is_ok());
    let h2 = Handle::read(mem_keyset, main_key).unwrap();
    assert_eq!(
        insecure::keyset_material(&h),
        insecure::keyset_material(&h2),
        "Decrypt failed: got {:?}, want {:?}",
        h2,
        h
    );
}

#[test]
fn test_read_with_no_secrets() {
    // Create a keyset containing public key material
    let key_data =
        tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::AsymmetricPublic);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    let mem_keyset = &mut tink::keyset::MemReaderWriter::default();
    assert!(h.write_with_no_secrets(mem_keyset).is_ok());
    let h2 = Handle::read_with_no_secrets(mem_keyset).unwrap();

    assert_eq!(
        insecure::keyset_material(&h),
        insecure::keyset_material(&h2),
        "Decrypt failed: got {:?}, want {:?}",
        h2,
        h
    );
}

#[test]
fn test_with_no_secrets_functions_fail_when_handling_secret_key_material() {
    // Create a keyset containing secret key material (symmetric)
    let key_data = tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::Symmetric);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    assert!(
        h.write_with_no_secrets(&mut tink::keyset::MemReaderWriter::default())
            .is_err(),
        "handle.write_with_no_secrets() should fail when exporting secret key material"
    );

    assert!(
        Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter {
            keyset: Some(insecure::keyset_material(&h)),
            ..Default::default()
        })
        .is_err(),
        "keyset.read_with_no_secrets should fail when importing secret key material"
    );
}

#[test]
fn test_with_no_secrets_functions_fail_when_unknown_key_material() {
    // Create a keyset containing secret key material (symmetric)
    let key_data =
        tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::UnknownKeymaterial);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    assert!(
        h.write_with_no_secrets(&mut tink::keyset::MemReaderWriter::default())
            .is_err(),
        "handle.write_with_no_secrets() should fail when exporting secret key material"
    );

    assert!(
        Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter {
            keyset: Some(insecure::keyset_material(&h)),
            ..Default::default()
        })
        .is_err(),
        "keyset.read_with_no_secrets should fail when importing secret key material"
    );
}

#[test]
fn test_with_no_secrets_functions_fail_with_asymmetric_private_key_material() {
    // Create a keyset containing secret key material (asymmetric)
    let key_data =
        tink_testutil::new_key_data("some type url", &[0], KeyMaterialType::AsymmetricPrivate);
    let key = tink_testutil::new_key(
        &key_data,
        tink::proto::KeyStatusType::Enabled,
        1,
        tink::proto::OutputPrefixType::Tink,
    );
    let ks = tink_testutil::new_keyset(1, vec![key]);
    let h = insecure::new_handle(ks).unwrap();

    assert!(
        h.write_with_no_secrets(&mut tink::keyset::MemReaderWriter::default())
            .is_err(),
        "handle.write_with_no_secrets() should fail when exporting secret key material"
    );

    assert!(
        Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter {
            keyset: Some(insecure::keyset_material(&h)),
            ..Default::default()
        })
        .is_err(),
        "keyset.read_with_no_secrets should fail when importing secret key material"
    );
}

#[test]
fn test_keyset_info() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = tink::keyset::Handle::new(&kt).unwrap();
    let info = kh.keyset_info();
    assert_eq!(info.primary_key_id, info.key_info[0].key_id);
}

#[test]
fn test_invalid_keyset() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = Handle::new(&kt).unwrap();

    let mut invalid_ks = insecure::keyset_material(&kh);
    invalid_ks.key[0].key_data = None;
    assert!(insecure::new_handle(invalid_ks).is_err());

    let mut invalid_ks = insecure::keyset_material(&kh);
    invalid_ks.key.clear();
    assert!(insecure::new_handle(invalid_ks).is_err());
}

#[test]
fn test_invalid_keyset_from_manager() {
    // Use a key manager that generates invalid `KeyData`.
    pub struct InvalidKeyManager {}

    impl tink::registry::KeyManager for InvalidKeyManager {
        fn primitive(&self, _serialized_key: &[u8]) -> Result<tink::Primitive, TinkError> {
            Err("not implemented".into())
        }

        fn new_key(&self, _serialized_key_format: &[u8]) -> Result<Vec<u8>, TinkError> {
            Err("not implemented".into())
        }

        fn type_url(&self) -> &'static str {
            "InvalidKeyGenerator"
        }

        fn key_material_type(&self) -> KeyMaterialType {
            KeyMaterialType::Symmetric
        }

        fn new_key_data(&self, _serialized_key_format: &[u8]) -> Result<KeyData, TinkError> {
            Ok(KeyData {
                key_material_type: 9999,
                type_url: self.type_url().to_string(),
                value: vec![],
            })
        }
    }
    tink::registry::register_key_manager(Arc::new(InvalidKeyManager {})).unwrap();
    let kt = tink::proto::KeyTemplate {
        output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
        type_url: "InvalidKeyGenerator".to_string(),
        value: vec![],
    };

    assert!(tink::keyset::Handle::new(&kt).is_err());
}

#[test]
fn test_destroyed_key_keyset() {
    tink_mac::init();
    let kt = tink_mac::hmac_sha256_tag128_key_template();
    let kh = Handle::new(&kt).unwrap();

    let mut ks = insecure::keyset_material(&kh);
    ks.key[0].key_data = None;
    ks.key[0].status = tink::proto::KeyStatusType::Destroyed as i32;
    let kh = insecure::new_handle(ks).unwrap();
    let info = kh.keyset_info();
    assert_eq!(info.primary_key_id, info.key_info[0].key_id);
    // The type_url for a destroyed key is not available.
    assert_eq!(info.key_info[0].type_url, "");
}

#[test]
fn test_handle_public() {
    tink_signature::init();
    let kh = Handle::new(&tink_signature::ecdsa_p256_key_template()).unwrap();

    let kh_public = kh.public().unwrap();

    let ks = insecure::keyset_material(&kh_public);
    assert_eq!(
        ks.key[0].key_data.as_ref().unwrap().key_material_type,
        KeyMaterialType::AsymmetricPublic as i32
    );

    // handle.public() only works for asymmetric private keys.
    let result = kh_public.public();
    tink_testutil::expect_err(result, "contains a non-private key");
}

#[test]
fn test_handle_public_destroyed_key() {
    tink_signature::init();

    let mut ksm = tink::keyset::Manager::new();
    ksm.rotate(&tink_signature::ecdsa_p256_key_template())
        .unwrap();
    let key_id = ksm
        .add(
            &tink_signature::ecdsa_p256_key_template(),
            /* primary= */ false,
        )
        .unwrap();
    ksm.destroy(key_id).unwrap();
    let kh = ksm.handle().unwrap();

    let result = kh.public();
    tink_testutil::expect_err(result, "invalid keyset");
}

#[test]
fn test_handle_public_wrong_keymanager() {
    tink_mac::init();
    tink_signature::init();
    let kh = Handle::new(&tink_signature::ecdsa_p256_key_template()).unwrap();

    // Manually corrupt the keyset to refer to the wrong key manager.
    let mut ks = insecure::keyset_material(&kh);
    ks.key[0].key_data.as_mut().unwrap().type_url = tink_testutil::HMAC_TYPE_URL.to_string();
    let invalid_kh = insecure::new_handle(ks).unwrap();

    let result = invalid_kh.public();
    tink_testutil::expect_err(result, "handles private keys");
}

#[test]
fn test_mem_read_with_no_secrets_empty() {
    let result = Handle::read_with_no_secrets(&mut tink::keyset::MemReaderWriter::default());
    tink_testutil::expect_err(result, "no keyset available");
}

#[test]
fn test_mem_read_empty() {
    let main_key = Box::new(tink_aead::subtle::AesGcm::new(&[b'A'; 32]).unwrap());
    let result = Handle::read(&mut tink::keyset::MemReaderWriter::default(), main_key);
    tink_testutil::expect_err(result, "no keyset available");
}

#[test]
fn test_insecure_read_write() {
    tink_signature::init();
    let kh = Handle::new(&tink_signature::ecdsa_p256_key_template()).unwrap();
    let mut mem_keyset = tink::keyset::MemReaderWriter::default();
    insecure::write(&kh, &mut mem_keyset).unwrap();

    let kh2 = insecure::read(&mut mem_keyset).unwrap();
    let ks = insecure::keyset_material(&kh);
    let ks2 = insecure::keyset_material(&kh2);
    assert_eq!(ks, ks2);
}

#[test]
fn test_insecure_read_empty() {
    let mut mem_keyset = tink::keyset::MemReaderWriter {
        keyset: Some(tink::proto::Keyset {
            key: vec![],
            primary_key_id: 1,
        }),
        ..Default::default()
    };
    let result = insecure::read(&mut mem_keyset);
    tink_testutil::expect_err(result, "insecure: invalid keyset");
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt::Write;
use std::rc::Rc;

use ::forktable::ForkTable;

pub mod ast;
pub mod types;
pub mod annotations;

use ast::*;
use self::annotations::*;
use self::types::Type;

/// A symbol table is a `ForkTable` mapping `String`s to `Type` annotations.
///
/// This table should be forked upon entering a new scope.
pub type SymbolTable<'a>
    = ForkTable<'a, String, SymbolAnnotation<'a>>;

macro_rules! indent {
    ($to:expr) => ( iter::repeat('\t')
                        .take($to)
                        .collect::<String>() )
}

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait ASTNode: Sized {

    /// Pretty-print the AST node as an S-expression at the desired
    /// indentation level.]
    ///
    /// Note that this prints the desugared form and may not be a perfect
    /// match for the original source code.
    fn to_sexpr(&self, level: usize) -> String;

}

pub trait AnnotateTypes<'a>: Sized {

    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl<'a, S> ASTNode for Form<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Form::Define(ref form)  => form.to_sexpr(level)
          , Form::Let(ref form)     => form.to_sexpr(level)
          , Form::If { .. }         => unimplemented!()
          , Form::Call { .. }       => unimplemented!()
          , Form::Lambda(ref fun)   => fun.to_sexpr(level)
          , Form::Logical(ref form) => form.to_sexpr(level)
        }
    }

}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, Form<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}

impl<'a, S> ASTNode for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot.to_sexpr(level)
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> ASTNode for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                                 })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                              write!(s, "{}", expr.to_sexpr(level + 1))
                                .expect("Could not write to string!");
                              s
                          })
                       )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1))
                                    .expect("Could not write to string!");
                                s
                            })
                          )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> ASTNode for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> ASTNode for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> ASTNode for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, DefForm<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self>{
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

#[derive(Clone,Debug,PartialEq)]
pub struct SymbolAnnotation<'a> {
    /// The type of the symbol
    pub ty: Type,
    /// An optional proven value for the symbol.
    ///
    /// This should be defined iff the symbol signifies a constant value
    /// or a constant expression, or if we were able to prove that the value
    /// remains constant within the current scope.
    pub proven_value: Option<Rc<Expr<'a, ScopedState>>>
}
<commit_msg>Add changes to core/semantic/mod.rs I forgot to commit This should fix the build on CI, whoops!<commit_after>use std::iter;
use std::fmt::Write;
use std::rc::Rc;

use ::forktable::ForkTable;

pub mod ast;
pub mod types;
pub mod annotations;

use ast::*;
use self::annotations::*;
use self::types::Type;

/// A symbol table is a `ForkTable` mapping `String`s to `Type` annotations.
///
/// This table should be forked upon entering a new scope.
pub type SymbolTable<'a>
    = ForkTable<'a, String, SymbolAnnotation<'a>>;

macro_rules! indent {
    ($to:expr) => ( iter::repeat('\t')
                        .take($to)
                        .collect::<String>() )
}

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait ASTNode: Sized {

    /// Pretty-print the AST node as an S-expression at the desired
    /// indentation level.]
    ///
    /// Note that this prints the desugared form and may not be a perfect
    /// match for the original source code.
    fn to_sexpr(&self, level: usize) -> String;

}

pub trait AnnotateTypes<'a>: Sized {

    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl<'a, S> ASTNode for Form<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Form::Define(ref form)  => form.to_sexpr(level)
          , Form::Let(ref form)     => form.to_sexpr(level)
          , Form::If { .. }         => unimplemented!()
          , Form::Call { .. }       => unimplemented!()
          , Form::Lambda(ref fun)   => fun.to_sexpr(level)
          , Form::Logical(ref form) => form.to_sexpr(level)
        }
    }

}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, Form<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}

impl<'a, S> ASTNode for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> ASTNode for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                                 })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                              write!(s, "{}", expr.to_sexpr(level + 1))
                                .expect("Could not write to string!");
                              s
                          })
                       )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1))
                                    .expect("Could not write to string!");
                                s
                            })
                          )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> ASTNode for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> ASTNode for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> ASTNode for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a> AnnotateTypes<'a> for Unscoped<'a, DefForm<'a, UnscopedState>> {
    #[allow(unused_variables)]
    fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self>{
        unimplemented!() //TODO: implement
    }
}

impl ASTNode for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

#[derive(Clone,Debug,PartialEq)]
pub struct SymbolAnnotation<'a> {
    /// The type of the symbol
    pub ty: Type,
    /// An optional proven value for the symbol.
    ///
    /// This should be defined iff the symbol signifies a constant value
    /// or a constant expression, or if we were able to prove that the value
    /// remains constant within the current scope.
    pub proven_value: Option<Rc<Expr<'a, ScopedState>>>
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::path::PathBuf;

use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
use log::{self, error, LevelFilter};

use alacritty_terminal::config::Program;
use alacritty_terminal::index::{Column, Line};

use crate::config::ui_config::Delta;
use crate::config::window::{Dimensions, DEFAULT_NAME};
use crate::config::Config;

#[cfg(not(any(target_os = "macos", windows)))]
const CONFIG_PATH: &str = "$XDG_CONFIG_HOME/alacritty/alacritty.yml";
#[cfg(windows)]
const CONFIG_PATH: &str = "%APPDATA%\\alacritty\\alacritty.yml";
#[cfg(target_os = "macos")]
const CONFIG_PATH: &str = "$HOME/.config/alacritty/alacritty.yml";

/// Options specified on the command line.
pub struct Options {
    pub live_config_reload: Option<bool>,
    pub print_events: bool,
    pub ref_test: bool,
    pub dimensions: Option<Dimensions>,
    pub position: Option<Delta<i32>>,
    pub title: Option<String>,
    pub class_instance: Option<String>,
    pub class_general: Option<String>,
    pub embed: Option<String>,
    pub log_level: LevelFilter,
    pub command: Option<Program>,
    pub hold: bool,
    pub working_dir: Option<PathBuf>,
    pub config: Option<PathBuf>,
    pub persistent_logging: bool,
}

impl Default for Options {
    fn default() -> Options {
        Options {
            live_config_reload: None,
            print_events: false,
            ref_test: false,
            dimensions: None,
            position: None,
            title: None,
            class_instance: None,
            class_general: None,
            embed: None,
            log_level: LevelFilter::Warn,
            command: None,
            hold: false,
            working_dir: None,
            config: None,
            persistent_logging: false,
        }
    }
}

impl Options {
    /// Build `Options` from command line arguments.
    pub fn new() -> Self {
        let mut version = crate_version!().to_owned();
        let commit_hash = env!("GIT_HASH");
        if !commit_hash.is_empty() {
            version = format!("{} ({})", version, commit_hash);
        }

        let mut options = Options::default();

        let matches = App::new(crate_name!())
            .version(version.as_str())
            .author(crate_authors!("\n"))
            .about(crate_description!())
            .arg(Arg::with_name("ref-test").long("ref-test").help("Generates ref test"))
            .arg(
                Arg::with_name("live-config-reload")
                    .long("live-config-reload")
                    .help("Enable automatic config reloading"),
            )
            .arg(
                Arg::with_name("no-live-config-reload")
                    .long("no-live-config-reload")
                    .help("Disable automatic config reloading")
                    .conflicts_with("live-config-reload"),
            )
            .arg(
                Arg::with_name("print-events")
                    .long("print-events")
                    .help("Print all events to stdout"),
            )
            .arg(
                Arg::with_name("persistent-logging")
                    .long("persistent-logging")
                    .help("Keep the log file after quitting Alacritty"),
            )
            .arg(
                Arg::with_name("dimensions")
                    .long("dimensions")
                    .short("d")
                    .value_names(&["columns", "lines"])
                    .help(
                        "Defines the window dimensions. Falls back to size specified by window \
                         manager if set to 0x0 [default: 0x0]",
                    ),
            )
            .arg(
                Arg::with_name("position")
                    .long("position")
                    .allow_hyphen_values(true)
                    .value_names(&["x-pos", "y-pos"])
                    .help(
                        "Defines the window position. Falls back to position specified by window \
                         manager if unset [default: unset]",
                    ),
            )
            .arg(
                Arg::with_name("title")
                    .long("title")
                    .short("t")
                    .takes_value(true)
                    .help(&format!("Defines the window title [default: {}]", DEFAULT_NAME)),
            )
            .arg(
                Arg::with_name("class")
                    .long("class")
                    .value_name("instance> | <instance>,<general")
                    .takes_value(true)
                    .use_delimiter(true)
                    .help(&format!(
                        "Defines window class or `app_id` on Linux [default: {}]",
                        DEFAULT_NAME
                    )),
            )
            .arg(
                Arg::with_name("embed").long("embed").takes_value(true).help(
                    "Defines the X11 window ID (as a decimal integer) to embed Alacritty within",
                ),
            )
            .arg(
                Arg::with_name("q")
                    .short("q")
                    .multiple(true)
                    .conflicts_with("v")
                    .help("Reduces the level of verbosity (the min level is -qq)"),
            )
            .arg(
                Arg::with_name("v")
                    .short("v")
                    .multiple(true)
                    .conflicts_with("q")
                    .help("Increases the level of verbosity (the max level is -vvv)"),
            )
            .arg(
                Arg::with_name("working-directory")
                    .long("working-directory")
                    .takes_value(true)
                    .help("Start the shell in the specified working directory"),
            )
            .arg(Arg::with_name("config-file").long("config-file").takes_value(true).help(
                &format!("Specify alternative configuration file [default: {}]", CONFIG_PATH),
            ))
            .arg(
                Arg::with_name("command")
                    .long("command")
                    .short("e")
                    .multiple(true)
                    .takes_value(true)
                    .min_values(1)
                    .allow_hyphen_values(true)
                    .help("Command and args to execute (must be last argument)"),
            )
            .arg(Arg::with_name("hold").long("hold").help("Remain open after child process exits"))
            .get_matches();

        if matches.is_present("ref-test") {
            options.ref_test = true;
        }

        if matches.is_present("print-events") {
            options.print_events = true;
        }

        if matches.is_present("live-config-reload") {
            options.live_config_reload = Some(true);
        } else if matches.is_present("no-live-config-reload") {
            options.live_config_reload = Some(false);
        }

        if matches.is_present("persistent-logging") {
            options.persistent_logging = true;
        }

        if let Some(mut dimensions) = matches.values_of("dimensions") {
            let width = dimensions.next().map(|w| w.parse().map(Column));
            let height = dimensions.next().map(|h| h.parse().map(Line));
            if let (Some(Ok(width)), Some(Ok(height))) = (width, height) {
                options.dimensions = Some(Dimensions::new(width, height));
            }
        }

        if let Some(mut position) = matches.values_of("position") {
            let x = position.next().map(str::parse);
            let y = position.next().map(str::parse);
            if let (Some(Ok(x)), Some(Ok(y))) = (x, y) {
                options.position = Some(Delta { x, y });
            }
        }

        if let Some(mut class) = matches.values_of("class") {
            options.class_instance = class.next().map(|instance| instance.to_owned());
            options.class_general = class.next().map(|general| general.to_owned());
        }

        options.title = matches.value_of("title").map(ToOwned::to_owned);
        options.embed = matches.value_of("embed").map(ToOwned::to_owned);

        match matches.occurrences_of("q") {
            0 => (),
            1 => options.log_level = LevelFilter::Error,
            _ => options.log_level = LevelFilter::Off,
        }

        match matches.occurrences_of("v") {
            0 if !options.print_events => options.log_level = LevelFilter::Warn,
            0 | 1 => options.log_level = LevelFilter::Info,
            2 => options.log_level = LevelFilter::Debug,
            _ => options.log_level = LevelFilter::Trace,
        }

        if let Some(dir) = matches.value_of("working-directory") {
            options.working_dir = Some(PathBuf::from(dir.to_string()));
        }

        if let Some(path) = matches.value_of("config-file") {
            options.config = Some(PathBuf::from(path.to_string()));
        }

        if let Some(mut args) = matches.values_of("command") {
            // The following unwrap is guaranteed to succeed.
            // If `command` exists it must also have a first item since
            // `Arg::min_values(1)` is set.
            let program = String::from(args.next().unwrap());
            let args = args.map(String::from).collect();
            options.command = Some(Program::WithArgs { program, args });
        }

        if matches.is_present("hold") {
            options.hold = true;
        }

        options
    }

    pub fn config_path(&self) -> Option<PathBuf> {
        self.config.clone()
    }

    pub fn into_config(self, mut config: Config) -> Config {
        match self.working_dir.or_else(|| config.working_directory.take()) {
            Some(ref wd) if !wd.is_dir() => error!("Unable to set working directory to {:?}", wd),
            wd => config.working_directory = wd,
        }

        if let Some(lcr) = self.live_config_reload {
            config.ui_config.set_live_config_reload(lcr);
        }
        config.shell = self.command.or(config.shell);

        config.hold = self.hold;

        let dynamic_title = config.ui_config.dynamic_title() && self.title.is_none();
        config.ui_config.set_dynamic_title(dynamic_title);

        replace_if_some(&mut config.ui_config.window.dimensions, self.dimensions);
        replace_if_some(&mut config.ui_config.window.title, self.title);
        config.ui_config.window.position = self.position.or(config.ui_config.window.position);
        config.ui_config.window.embed = self.embed.and_then(|embed| embed.parse().ok());
        replace_if_some(&mut config.ui_config.window.class.instance, self.class_instance);
        replace_if_some(&mut config.ui_config.window.class.general, self.class_general);

        config.ui_config.debug.print_events |= self.print_events;
        config.ui_config.debug.log_level = max(config.ui_config.debug.log_level, self.log_level);
        config.ui_config.debug.ref_test |= self.ref_test;
        config.ui_config.debug.persistent_logging |= self.persistent_logging;

        if config.ui_config.debug.print_events {
            config.ui_config.debug.log_level =
                max(config.ui_config.debug.log_level, LevelFilter::Info);
        }

        config
    }
}

fn replace_if_some<T>(option: &mut T, value: Option<T>) {
    if let Some(value) = value {
        *option = value;
    }
}

#[cfg(test)]
mod tests {
    use crate::cli::Options;
    use crate::config::Config;

    #[test]
    fn dynamic_title_ignoring_options_by_default() {
        let config = Config::default();
        let old_dynamic_title = config.ui_config.dynamic_title();

        let config = Options::default().into_config(config);

        assert_eq!(old_dynamic_title, config.ui_config.dynamic_title());
    }

    #[test]
    fn dynamic_title_overridden_by_options() {
        let config = Config::default();

        let mut options = Options::default();
        options.title = Some("foo".to_owned());
        let config = options.into_config(config);

        assert!(!config.ui_config.dynamic_title());
    }

    #[test]
    fn dynamic_title_not_overridden_by_config() {
        let mut config = Config::default();

        config.ui_config.window.title = "foo".to_owned();
        let config = Options::default().into_config(config);

        assert!(config.ui_config.dynamic_title());
    }
}
<commit_msg>Remove markdownish markup from `--help` output<commit_after>use std::cmp::max;
use std::path::PathBuf;

use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
use log::{self, error, LevelFilter};

use alacritty_terminal::config::Program;
use alacritty_terminal::index::{Column, Line};

use crate::config::ui_config::Delta;
use crate::config::window::{Dimensions, DEFAULT_NAME};
use crate::config::Config;

#[cfg(not(any(target_os = "macos", windows)))]
const CONFIG_PATH: &str = "$XDG_CONFIG_HOME/alacritty/alacritty.yml";
#[cfg(windows)]
const CONFIG_PATH: &str = "%APPDATA%\\alacritty\\alacritty.yml";
#[cfg(target_os = "macos")]
const CONFIG_PATH: &str = "$HOME/.config/alacritty/alacritty.yml";

/// Options specified on the command line.
pub struct Options {
    pub live_config_reload: Option<bool>,
    pub print_events: bool,
    pub ref_test: bool,
    pub dimensions: Option<Dimensions>,
    pub position: Option<Delta<i32>>,
    pub title: Option<String>,
    pub class_instance: Option<String>,
    pub class_general: Option<String>,
    pub embed: Option<String>,
    pub log_level: LevelFilter,
    pub command: Option<Program>,
    pub hold: bool,
    pub working_dir: Option<PathBuf>,
    pub config: Option<PathBuf>,
    pub persistent_logging: bool,
}

impl Default for Options {
    fn default() -> Options {
        Options {
            live_config_reload: None,
            print_events: false,
            ref_test: false,
            dimensions: None,
            position: None,
            title: None,
            class_instance: None,
            class_general: None,
            embed: None,
            log_level: LevelFilter::Warn,
            command: None,
            hold: false,
            working_dir: None,
            config: None,
            persistent_logging: false,
        }
    }
}

impl Options {
    /// Build `Options` from command line arguments.
    pub fn new() -> Self {
        let mut version = crate_version!().to_owned();
        let commit_hash = env!("GIT_HASH");
        if !commit_hash.is_empty() {
            version = format!("{} ({})", version, commit_hash);
        }

        let mut options = Options::default();

        let matches = App::new(crate_name!())
            .version(version.as_str())
            .author(crate_authors!("\n"))
            .about(crate_description!())
            .arg(Arg::with_name("ref-test").long("ref-test").help("Generates ref test"))
            .arg(
                Arg::with_name("live-config-reload")
                    .long("live-config-reload")
                    .help("Enable automatic config reloading"),
            )
            .arg(
                Arg::with_name("no-live-config-reload")
                    .long("no-live-config-reload")
                    .help("Disable automatic config reloading")
                    .conflicts_with("live-config-reload"),
            )
            .arg(
                Arg::with_name("print-events")
                    .long("print-events")
                    .help("Print all events to stdout"),
            )
            .arg(
                Arg::with_name("persistent-logging")
                    .long("persistent-logging")
                    .help("Keep the log file after quitting Alacritty"),
            )
            .arg(
                Arg::with_name("dimensions")
                    .long("dimensions")
                    .short("d")
                    .value_names(&["columns", "lines"])
                    .help(
                        "Defines the window dimensions. Falls back to size specified by window \
                         manager if set to 0x0 [default: 0x0]",
                    ),
            )
            .arg(
                Arg::with_name("position")
                    .long("position")
                    .allow_hyphen_values(true)
                    .value_names(&["x-pos", "y-pos"])
                    .help(
                        "Defines the window position. Falls back to position specified by window \
                         manager if unset [default: unset]",
                    ),
            )
            .arg(
                Arg::with_name("title")
                    .long("title")
                    .short("t")
                    .takes_value(true)
                    .help(&format!("Defines the window title [default: {}]", DEFAULT_NAME)),
            )
            .arg(
                Arg::with_name("class")
                    .long("class")
                    .value_name("instance> | <instance>,<general")
                    .takes_value(true)
                    .use_delimiter(true)
                    .help(&format!(
                        "Defines window class/app_id on X11/Wayland [default: {}]",
                        DEFAULT_NAME
                    )),
            )
            .arg(
                Arg::with_name("embed").long("embed").takes_value(true).help(
                    "Defines the X11 window ID (as a decimal integer) to embed Alacritty within",
                ),
            )
            .arg(
                Arg::with_name("q")
                    .short("q")
                    .multiple(true)
                    .conflicts_with("v")
                    .help("Reduces the level of verbosity (the min level is -qq)"),
            )
            .arg(
                Arg::with_name("v")
                    .short("v")
                    .multiple(true)
                    .conflicts_with("q")
                    .help("Increases the level of verbosity (the max level is -vvv)"),
            )
            .arg(
                Arg::with_name("working-directory")
                    .long("working-directory")
                    .takes_value(true)
                    .help("Start the shell in the specified working directory"),
            )
            .arg(Arg::with_name("config-file").long("config-file").takes_value(true).help(
                &format!("Specify alternative configuration file [default: {}]", CONFIG_PATH),
            ))
            .arg(
                Arg::with_name("command")
                    .long("command")
                    .short("e")
                    .multiple(true)
                    .takes_value(true)
                    .min_values(1)
                    .allow_hyphen_values(true)
                    .help("Command and args to execute (must be last argument)"),
            )
            .arg(Arg::with_name("hold").long("hold").help("Remain open after child process exits"))
            .get_matches();

        if matches.is_present("ref-test") {
            options.ref_test = true;
        }

        if matches.is_present("print-events") {
            options.print_events = true;
        }

        if matches.is_present("live-config-reload") {
            options.live_config_reload = Some(true);
        } else if matches.is_present("no-live-config-reload") {
            options.live_config_reload = Some(false);
        }

        if matches.is_present("persistent-logging") {
            options.persistent_logging = true;
        }

        if let Some(mut dimensions) = matches.values_of("dimensions") {
            let width = dimensions.next().map(|w| w.parse().map(Column));
            let height = dimensions.next().map(|h| h.parse().map(Line));
            if let (Some(Ok(width)), Some(Ok(height))) = (width, height) {
                options.dimensions = Some(Dimensions::new(width, height));
            }
        }

        if let Some(mut position) = matches.values_of("position") {
            let x = position.next().map(str::parse);
            let y = position.next().map(str::parse);
            if let (Some(Ok(x)), Some(Ok(y))) = (x, y) {
                options.position = Some(Delta { x, y });
            }
        }

        if let Some(mut class) = matches.values_of("class") {
            options.class_instance = class.next().map(|instance| instance.to_owned());
            options.class_general = class.next().map(|general| general.to_owned());
        }

        options.title = matches.value_of("title").map(ToOwned::to_owned);
        options.embed = matches.value_of("embed").map(ToOwned::to_owned);

        match matches.occurrences_of("q") {
            0 => (),
            1 => options.log_level = LevelFilter::Error,
            _ => options.log_level = LevelFilter::Off,
        }

        match matches.occurrences_of("v") {
            0 if !options.print_events => options.log_level = LevelFilter::Warn,
            0 | 1 => options.log_level = LevelFilter::Info,
            2 => options.log_level = LevelFilter::Debug,
            _ => options.log_level = LevelFilter::Trace,
        }

        if let Some(dir) = matches.value_of("working-directory") {
            options.working_dir = Some(PathBuf::from(dir.to_string()));
        }

        if let Some(path) = matches.value_of("config-file") {
            options.config = Some(PathBuf::from(path.to_string()));
        }

        if let Some(mut args) = matches.values_of("command") {
            // The following unwrap is guaranteed to succeed.
            // If `command` exists it must also have a first item since
            // `Arg::min_values(1)` is set.
            let program = String::from(args.next().unwrap());
            let args = args.map(String::from).collect();
            options.command = Some(Program::WithArgs { program, args });
        }

        if matches.is_present("hold") {
            options.hold = true;
        }

        options
    }

    pub fn config_path(&self) -> Option<PathBuf> {
        self.config.clone()
    }

    pub fn into_config(self, mut config: Config) -> Config {
        match self.working_dir.or_else(|| config.working_directory.take()) {
            Some(ref wd) if !wd.is_dir() => error!("Unable to set working directory to {:?}", wd),
            wd => config.working_directory = wd,
        }

        if let Some(lcr) = self.live_config_reload {
            config.ui_config.set_live_config_reload(lcr);
        }
        config.shell = self.command.or(config.shell);

        config.hold = self.hold;

        let dynamic_title = config.ui_config.dynamic_title() && self.title.is_none();
        config.ui_config.set_dynamic_title(dynamic_title);

        replace_if_some(&mut config.ui_config.window.dimensions, self.dimensions);
        replace_if_some(&mut config.ui_config.window.title, self.title);
        config.ui_config.window.position = self.position.or(config.ui_config.window.position);
        config.ui_config.window.embed = self.embed.and_then(|embed| embed.parse().ok());
        replace_if_some(&mut config.ui_config.window.class.instance, self.class_instance);
        replace_if_some(&mut config.ui_config.window.class.general, self.class_general);

        config.ui_config.debug.print_events |= self.print_events;
        config.ui_config.debug.log_level = max(config.ui_config.debug.log_level, self.log_level);
        config.ui_config.debug.ref_test |= self.ref_test;
        config.ui_config.debug.persistent_logging |= self.persistent_logging;

        if config.ui_config.debug.print_events {
            config.ui_config.debug.log_level =
                max(config.ui_config.debug.log_level, LevelFilter::Info);
        }

        config
    }
}

fn replace_if_some<T>(option: &mut T, value: Option<T>) {
    if let Some(value) = value {
        *option = value;
    }
}

#[cfg(test)]
mod tests {
    use crate::cli::Options;
    use crate::config::Config;

    #[test]
    fn dynamic_title_ignoring_options_by_default() {
        let config = Config::default();
        let old_dynamic_title = config.ui_config.dynamic_title();

        let config = Options::default().into_config(config);

        assert_eq!(old_dynamic_title, config.ui_config.dynamic_title());
    }

    #[test]
    fn dynamic_title_overridden_by_options() {
        let config = Config::default();

        let mut options = Options::default();
        options.title = Some("foo".to_owned());
        let config = options.into_config(config);

        assert!(!config.ui_config.dynamic_title());
    }

    #[test]
    fn dynamic_title_not_overridden_by_config() {
        let mut config = Config::default();

        config.ui_config.window.title = "foo".to_owned();
        let config = Options::default().into_config(config);

        assert!(config.ui_config.dynamic_title());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor_set::DescriptorsCount;
use device::Device;

/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
///
/// Despite its name, this type is technically not unsafe. However it serves the same purpose
/// in the API as other types whose names start with `Unsafe`. Using the same naming scheme avoids
/// confusions.
pub struct UnsafeDescriptorSetLayout {
    // The layout.
    layout: vk::DescriptorSetLayout,
    // The device this layout belongs to.
    device: Arc<Device>,
    // Number of descriptors.
    descriptors_count: DescriptorsCount,
}

impl UnsafeDescriptorSetLayout {
    /// Builds a new `UnsafeDescriptorSetLayout` with the given descriptors.
    ///
    /// The descriptors must be passed in the order of the bindings. In order words, descriptor
    /// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
    /// empty, you can make the iterator yield `None` for an element.
    pub fn new<I>(device: Arc<Device>, descriptors: I)
                  -> Result<UnsafeDescriptorSetLayout, OomError>
        where I: IntoIterator<Item = Option<DescriptorDesc>>
    {
        let mut descriptors_count = DescriptorsCount::zero();

        let bindings = descriptors.into_iter().enumerate().filter_map(|(binding, desc)| {
            let desc = match desc {
                Some(d) => d,
                None => return None
            };

            // FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
            //        doesn't have tess shaders enabled

            let ty = desc.ty.ty().unwrap();     // TODO: shouldn't panic
            descriptors_count.add_one(ty);

            Some(vk::DescriptorSetLayoutBinding {
                binding: binding as u32,
                descriptorType: ty as u32,
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            })
        }).collect::<SmallVec<[_; 32]>>();

        // Note that it seems legal to have no descriptor at all in the set.

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            let vk = device.pointers();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(UnsafeDescriptorSetLayout {
            layout: layout,
            device: device,
            descriptors_count: descriptors_count,
        })
    }

    /// Returns the device used to create this layout.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }

    /// Returns the number of descriptors of each type.
    #[inline]
    pub fn descriptors_count(&self) -> &DescriptorsCount {
        &self.descriptors_count
    }
}

unsafe impl VulkanObject for UnsafeDescriptorSetLayout {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl Drop for UnsafeDescriptorSetLayout {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout,
                                          ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use std::iter;
    use descriptor::descriptor_set::unsafe_layout::UnsafeDescriptorSetLayout;

    #[test]
    fn empty() {
        let (device, _) = gfx_dev_and_queue!();
        let _layout = UnsafeDescriptorSetLayout::new(device, iter::empty());
    }
}
<commit_msg>Some tweaks to UnsafeDescriptorSetLayout<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor_set::DescriptorsCount;
use device::Device;
use device::DeviceOwned;

/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
///
/// Despite its name, this type is technically not unsafe. However it serves the same purpose
/// in the API as other types whose names start with `Unsafe`. Using the same naming scheme avoids
/// confusions.
pub struct UnsafeDescriptorSetLayout {
    // The layout.
    layout: vk::DescriptorSetLayout,
    // The device this layout belongs to.
    device: Arc<Device>,
    // Number of descriptors.
    descriptors_count: DescriptorsCount,
}

impl UnsafeDescriptorSetLayout {
    /// Builds a new `UnsafeDescriptorSetLayout` with the given descriptors.
    ///
    /// The descriptors must be passed in the order of the bindings. In order words, descriptor
    /// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
    /// empty, you can make the iterator yield `None` for an element.
    pub fn new<I>(device: Arc<Device>, descriptors: I)
                  -> Result<UnsafeDescriptorSetLayout, OomError>
        where I: IntoIterator<Item = Option<DescriptorDesc>>
    {
        let mut descriptors_count = DescriptorsCount::zero();

        let bindings = descriptors.into_iter().enumerate().filter_map(|(binding, desc)| {
            let desc = match desc {
                Some(d) => d,
                None => return None
            };

            // FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
            //        doesn't have tess shaders enabled

            let ty = desc.ty.ty().unwrap();     // TODO: shouldn't panic
            descriptors_count.add_one(ty);

            Some(vk::DescriptorSetLayoutBinding {
                binding: binding as u32,
                descriptorType: ty as u32,
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            })
        }).collect::<SmallVec<[_; 32]>>();

        // Note that it seems legal to have no descriptor at all in the set.

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            let vk = device.pointers();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(UnsafeDescriptorSetLayout {
            layout: layout,
            device: device,
            descriptors_count: descriptors_count,
        })
    }

    /// Returns the number of descriptors of each type.
    #[inline]
    pub fn descriptors_count(&self) -> &DescriptorsCount {
        &self.descriptors_count
    }
}

unsafe impl DeviceOwned for UnsafeDescriptorSetLayout {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl VulkanObject for UnsafeDescriptorSetLayout {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl Drop for UnsafeDescriptorSetLayout {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout,
                                          ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use std::iter;
    use descriptor::descriptor::DescriptorDesc;
    use descriptor::descriptor::DescriptorDescTy;
    use descriptor::descriptor::DescriptorBufferDesc;
    use descriptor::descriptor::DescriptorBufferContentDesc;
    use descriptor::descriptor::ShaderStages;
    use descriptor::descriptor_set::DescriptorsCount;
    use descriptor::descriptor_set::UnsafeDescriptorSetLayout;

    #[test]
    fn empty() {
        let (device, _) = gfx_dev_and_queue!();
        let _layout = UnsafeDescriptorSetLayout::new(device, iter::empty());
    }

    #[test]
    fn basic_create() {
        let (device, _) = gfx_dev_and_queue!();

        let layout = DescriptorDesc {
            ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
                dynamic: Some(false),
                storage: false,
                content: DescriptorBufferContentDesc::F32,
            }),
            array_count: 1,
            stages: ShaderStages::all_graphics(),
            readonly: true,
        };

        let sl = UnsafeDescriptorSetLayout::new(device.clone(), iter::once(Some(layout))).unwrap();

        assert_eq!(sl.descriptors_count(), &DescriptorsCount {
            uniform_buffer: 1,
            .. DescriptorsCount::zero()
        });
    }
}
<|endoftext|>


<commit_before>#![crate_type= "lib"]
#![cfg_attr(feature = "nightly", feature(plugin))]

#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![cfg_attr(not(any(feature = "lints", feature = "nightly")), deny())]
#![deny(
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unused_import_braces,
    unused_qualifications
)]

//! ![uml](ml.svg)

extern crate syntex_syntax;
extern crate syntex_errors;
extern crate itertools;
extern crate walkdir;
extern crate dot;

pub mod prelude;
pub mod syntax;

use std::process::{Command, Stdio};
use std::io::{Write, Read};
use std::path::Path;
use std::fs::{self, File};
use std::ffi::OsStr;
use std::rc::Rc;

use syntex_errors::emitter::ColorConfig;
use syntex_errors::Handler;

use syntex_syntax::codemap::CodeMap;
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::{ast, ptr};

use walkdir::WalkDir;
use syntax::ListItem;

/// The default name of *graph/dot* file.
pub const DEFAULT_NAME_DOT: &'static str = "ml.dot";
/// The default name of *image/svg* file.
pub const DEFAULT_NAME_PNG: &'static str = "ml.svg";

/// The function `file2crate` returns a syntex module.
fn file2crate<P: AsRef<Path>>(path: P) -> Option<ast::Crate> {
    let codemap = Rc::new(CodeMap::new());
    let tty_handler =
        Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
    let parse_session: ParseSess = ParseSess::with_span_handler(tty_handler, codemap.clone());
    let parse = parse::parse_crate_from_file(path.as_ref(), &parse_session);

    parse.ok()
}

/// The function `items2chars` returns a graph formated for *Graphiz/Dot*.
fn items2chars(list: Vec<ptr::P<ast::Item>>) -> Option<Vec<u8>> {
    let mut f: Vec<u8> = Vec::new();
    let it: ListItem = ListItem::from(list.iter().peekable());

    dot::render(&it, &mut f).ok().and_then(|()| Some(f))
}

/// The function `rs2dot` returns graphed file module.
pub fn rs2dot<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    file2crate(path).and_then(|parse: ast::Crate| items2chars(parse.module.items))
}

/// The function `src2dot` returns graphed repository of modules.
pub fn src2dot<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    items2chars(WalkDir::new(path).into_iter()
                                 .filter_map(|entry: Result<walkdir::DirEntry, _>| entry.ok())
                                 .filter(|entry| entry.file_type().is_file())
                                 .filter_map(|entry: walkdir::DirEntry| {
                                     let path: &Path = entry.path();

                                     if path.extension().eq(&Some(OsStr::new("rs"))) {
                                         file2crate(path).and_then(|parse| Some(parse.module.items))
                                     } else {
                                         None
                                     }
                                 })
                                 .collect::<Vec<Vec<ptr::P<ast::Item>>>>()
                                 .concat())
}

/// The function `content2svg` returns structured vector graphics content of modules.
fn content2svg(buf: Vec<u8>) -> Option<Vec<u8>> {
        Command::new("dot").arg("-Tsvg")
                           .stdin(Stdio::piped()).stdout(Stdio::piped())
                           .spawn()
                           .ok()
                           .and_then(|child| {
                                let mut ret = vec![];

                                child.stdin.unwrap().write_all(buf.as_slice()).unwrap();
                                child.stdout.unwrap().read_to_end(&mut ret).unwrap();
                                Some(ret)
                           })
}

/// The function `rs2svg` returns structured vector graphics file modules.
pub fn rs2svg<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    rs2dot(path).and_then(|buf| content2svg(buf))
}

/// The function `src2svg` returns structured vector graphics repository of modules.
pub fn src2svg<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    src2dot(path).and_then(|buf| content2svg(buf))
}

/// The function `src2both` creates two files formated like a graph/dot and a structured vector graphics.
pub fn src2both<P: AsRef<Path>>(src: P, dest: P) -> Option<()> {
    let _ = fs::create_dir_all(dest.as_ref()).unwrap();
    let mut file_dot = File::create(dest.as_ref().join(DEFAULT_NAME_DOT)).unwrap();
    let mut file_svg = File::create(dest.as_ref().join(DEFAULT_NAME_PNG)).unwrap();

    src2dot(src).and_then(|content_dot: Vec<u8>| {
        let _ = file_dot.write_all(content_dot.as_slice()).unwrap();

        content2svg(content_dot).and_then(|content_svg: Vec<u8>| {
            let _ = file_svg.write_all(content_svg.as_slice()).unwrap();
            Some(())
        })
    })
}
<commit_msg>add example for documentation<commit_after>#![crate_type= "lib"]
#![cfg_attr(feature = "nightly", feature(plugin))]

#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![cfg_attr(not(any(feature = "lints", feature = "nightly")), deny())]
#![deny(
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unused_import_braces,
    unused_qualifications
)]

//! ![uml](ml.svg)

extern crate syntex_syntax;
extern crate syntex_errors;
extern crate itertools;
extern crate walkdir;
extern crate dot;

pub mod prelude;
pub mod syntax;

use std::process::{Command, Stdio};
use std::io::{Write, Read};
use std::path::Path;
use std::fs::{self, File};
use std::ffi::OsStr;
use std::rc::Rc;

use syntex_errors::emitter::ColorConfig;
use syntex_errors::Handler;

use syntex_syntax::codemap::CodeMap;
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::{ast, ptr};

use walkdir::WalkDir;
use syntax::ListItem;

/// The default name of *graph/dot* file.
pub const DEFAULT_NAME_DOT: &'static str = "ml.dot";
/// The default name of *image/svg* file.
pub const DEFAULT_NAME_PNG: &'static str = "ml.svg";

/// The function `file2crate` returns a syntex module.
fn file2crate<P: AsRef<Path>>(path: P) -> Option<ast::Crate> {
    let codemap = Rc::new(CodeMap::new());
    let tty_handler =
        Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
    let parse_session: ParseSess = ParseSess::with_span_handler(tty_handler, codemap.clone());
    let parse = parse::parse_crate_from_file(path.as_ref(), &parse_session);

    parse.ok()
}

/// The function `items2chars` returns a graph formated for *Graphiz/Dot*.
fn items2chars(list: Vec<ptr::P<ast::Item>>) -> Option<Vec<u8>> {
    let mut f: Vec<u8> = Vec::new();
    let it: ListItem = ListItem::from(list.iter().peekable());

    dot::render(&it, &mut f).ok().and_then(|()| Some(f))
}

/// The function `rs2dot` returns graphed file module.
pub fn rs2dot<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    file2crate(path).and_then(|parse: ast::Crate| items2chars(parse.module.items))
}

/// The function `src2dot` returns graphed repository of modules.
pub fn src2dot<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    items2chars(WalkDir::new(path).into_iter()
                                 .filter_map(|entry: Result<walkdir::DirEntry, _>| entry.ok())
                                 .filter(|entry| entry.file_type().is_file())
                                 .filter_map(|entry: walkdir::DirEntry| {
                                     let path: &Path = entry.path();

                                     if path.extension().eq(&Some(OsStr::new("rs"))) {
                                         file2crate(path).and_then(|parse| Some(parse.module.items))
                                     } else {
                                         None
                                     }
                                 })
                                 .collect::<Vec<Vec<ptr::P<ast::Item>>>>()
                                 .concat())
}

/// The function `content2svg` returns structured vector graphics content of modules.
fn content2svg(buf: Vec<u8>) -> Option<Vec<u8>> {
        Command::new("dot").arg("-Tsvg")
                           .stdin(Stdio::piped()).stdout(Stdio::piped())
                           .spawn()
                           .ok()
                           .and_then(|child| {
                                let mut ret = vec![];

                                child.stdin.unwrap().write_all(buf.as_slice()).unwrap();
                                child.stdout.unwrap().read_to_end(&mut ret).unwrap();
                                Some(ret)
                           })
}

/// The function `rs2svg` returns structured vector graphics file modules.
pub fn rs2svg<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    rs2dot(path).and_then(|buf| content2svg(buf))
}

/// The function `src2svg` returns structured vector graphics repository of modules.
pub fn src2svg<P: AsRef<Path>>(path: P) -> Option<Vec<u8>> {
    src2dot(path).and_then(|buf| content2svg(buf))
}

/// The function `src2both` creates two files formated like a graph/dot and a structured vector graphics.
///
/// # Examples
/// ```
/// extern crate ml;
///
/// use std::path::PathBuf;
///
/// fn main() {
///     ml::src2both(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src"),
///                  PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("target")
///                                                           .join("doc")
///                                                           .join(env!("CARGO_PKG_NAME")));
/// }
/// ```
pub fn src2both<P: AsRef<Path>>(src: P, dest: P) -> Option<()> {
    let _ = fs::create_dir_all(dest.as_ref()).unwrap();
    let mut file_dot = File::create(dest.as_ref().join(DEFAULT_NAME_DOT)).unwrap();
    let mut file_svg = File::create(dest.as_ref().join(DEFAULT_NAME_PNG)).unwrap();

    src2dot(src).and_then(|content_dot: Vec<u8>| {
        let _ = file_dot.write_all(content_dot.as_slice()).unwrap();

        content2svg(content_dot).and_then(|content_svg: Vec<u8>| {
            let _ = file_svg.write_all(content_svg.as_slice()).unwrap();
            Some(())
        })
    })
}
<|endoftext|>


<commit_before>/*!
This is a binary memcached protocol implemented only in rust with support of traits to send
and receive `T` and consistent hashing to select connections from a pool to distribute data.
# Example
```rust
extern crate bmemcached;

use std::sync::Arc;
use std::thread;

use bmemcached::MemcachedClient;

fn main() {
    // Use arc for threading support
    let client = Arc::new(MemcachedClient::new(vec!["127.0.0.1:11211"], 5).unwrap());

    // Traits examples
    let value = "value";
    client.set("string", value, 1000);
    let rv: String = client.get("string").unwrap();
    assert_eq!(rv, "value");

    client.set("integer", 10 as u8, 1000);
    let rv: u8 = client.get("integer").unwrap();
    assert_eq!(rv, 10 as u8);

    // Threads example
    let mut threads = vec![];
    for i in 0..4 {
        let client = client.clone();
        threads.push(thread::spawn(move || {
            let data = format!("data_n{}", i);
            client.set(&data, &data, 100).unwrap();
            let val: String = client.get(&data).unwrap();
            client.delete(&data).unwrap();
            val
        }));
    }
    for (i, thread) in threads.into_iter().enumerate() {
        let result = thread.join();
        assert_eq!(result.unwrap(), format!("data_n{}", i));
    }
}
```
*/
#![forbid(unsafe_code)]
#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate conhash;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate log;
extern crate num;

mod client;
pub mod errors;
mod protocol;
pub mod constants;

pub use protocol::{FromMemcached, Status, ToMemcached};
#[macro_use] extern crate error_chain;

pub use client::MemcachedClient;
pub use constants::StoredType;
<commit_msg>feat: Make protocol public to allow client to choose how to use it<commit_after>/*!
This is a binary memcached protocol implemented only in rust with support of traits to send
and receive `T` and consistent hashing to select connections from a pool to distribute data.
# Example
```rust
extern crate bmemcached;

use std::sync::Arc;
use std::thread;

use bmemcached::MemcachedClient;

fn main() {
    // Use arc for threading support
    let client = Arc::new(MemcachedClient::new(vec!["127.0.0.1:11211"], 5).unwrap());

    // Traits examples
    let value = "value";
    client.set("string", value, 1000);
    let rv: String = client.get("string").unwrap();
    assert_eq!(rv, "value");

    client.set("integer", 10 as u8, 1000);
    let rv: u8 = client.get("integer").unwrap();
    assert_eq!(rv, 10 as u8);

    // Threads example
    let mut threads = vec![];
    for i in 0..4 {
        let client = client.clone();
        threads.push(thread::spawn(move || {
            let data = format!("data_n{}", i);
            client.set(&data, &data, 100).unwrap();
            let val: String = client.get(&data).unwrap();
            client.delete(&data).unwrap();
            val
        }));
    }
    for (i, thread) in threads.into_iter().enumerate() {
        let result = thread.join();
        assert_eq!(result.unwrap(), format!("data_n{}", i));
    }
}
```
*/
#![forbid(unsafe_code)]
#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate conhash;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate log;
extern crate num;

mod client;
pub mod constants;
pub mod errors;
pub mod protocol;

pub use protocol::{FromMemcached, Status, ToMemcached};
#[macro_use]
extern crate error_chain;

pub use client::MemcachedClient;
pub use constants::StoredType;
<|endoftext|>


<commit_before>#![crate_name = "hash_ring"]
#![crate_type = "lib"]

extern crate twox_hash;
mod hash_ring;
pub use hash_ring::NodeInfo;
pub use hash_ring::HashRing;<commit_msg>rustfmt lib.rs<commit_after>#![crate_name = "hash_ring"]
#![crate_type = "lib"]

extern crate twox_hash;
mod hash_ring;
pub use hash_ring::HashRing;
pub use hash_ring::NodeInfo;
<|endoftext|>


<commit_before>#![feature(core)]
#![cfg_attr(test, deny(warnings))]

#[macro_use] extern crate log;

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use std::error::Error;

use conduit::{Request, Response};
use middleware::Middleware;

pub struct LogRequests(pub log::LogLevel);

struct LogStart(u64);

impl Middleware for LogRequests {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
        req.mut_extensions().insert(LogStart(time::precise_time_ns()));
        Ok(())
    }

    fn after(&self, req: &mut Request, resp: Result<Response, Box<Error+Send>>)
             -> Result<Response, Box<Error+Send>> {
        let LogStart(start) = *req.mut_extensions().find::<LogStart>().unwrap();

        match resp {
            Ok(ref resp) => self.log_message(req, start, resp.status.0, None),
            Err(ref e) => {
                let msg: &Error = &**e;
                self.log_message(req, start, 500, Some(msg))
            }
        }
        resp
    }

}

impl LogRequests {
    fn log_message(&self, req: &mut Request, start: u64, status: u32,
                   msg: Option<&Error>) {
        let LogRequests(level) = *self;
        let level = if msg.is_some() {log::LogLevel::Error} else {level};
        log!(level, "{} [{}] {:?} {} - {}ms {}{}",
             req.remote_addr(),
             time::now().rfc3339(),
             req.method(),
             req.path(),
             (time::precise_time_ns() - start) / 1000000,
             status,
             match msg {
                 None => String::new(),
                 Some(s) => format!(": {} {}", s.description(), s),
             })
    }
}

#[cfg(all(test, foo))] // FIXME: needs a thread-local logger
mod tests {
    extern crate "conduit-test" as test;

    use {LogRequests};

    use conduit::{Request, Response, Handler, Method};
    use log::{Log, LogRecord};
    use log;
    use middleware;
    use std::error::Error;
    use std::old_io::{ChanWriter, ChanReader};
    use std::sync::Mutex;
    use std::sync::mpsc::{channel, Sender};
    use std::thread::Thread;
    use std;

    struct MyWriter(Mutex<ChanWriter>);

    impl Log for MyWriter {
        fn enabled(&self, _: log::LogLevel, _: &str) -> bool { true }
        fn log(&self, record: &LogRecord) {
            let MyWriter(ref inner) = *self;
            (write!(inner.lock(), "{}", record.args)).unwrap();
        }
    }

    #[test]
    fn test_log() {
        let (sender, receiver) = channel();
        let mut reader = ChanReader::new(receiver);

        let mut builder = middleware::MiddlewareBuilder::new(handler);
        builder.add(LogRequests(log::LogLevel::Error));

        task(builder, sender);

        let result = reader.read_to_string().ok().expect("No response");
        let parts = result.as_slice().split(' ').map(|s| s.to_string()).collect::<Vec<String>>();

        assert_eq!(parts[0].as_slice(), "127.0.0.1");
        // Failing on travis?! bug in libtime?!
        // assert!(parts.get(1).as_slice().len() == "[2014-07-01T22:34:06-07:00]".len(),
        //         "bad length for {}", parts.get(1));
        assert_eq!(parts[2].as_slice(), "Get");
        assert_eq!(parts[3].as_slice(), "/foo");
    }

    fn task<H: Handler + 'static + Send>(handler: H, sender: Sender<Vec<u8>>) {
        Thread::spawn(move|| {
            log::set_logger(Box::new(MyWriter(Mutex::new(ChanWriter::new(sender)))));
            let mut request = test::MockRequest::new(Method::Get, "/foo");
            let _ = handler.call(&mut request);
        });
    }

    fn handler(_: &mut Request) -> Result<Response, Box<Error+Send>> {
        Ok(Response {
            status: (200, "OK"),
            headers: std::collections::HashMap::new(),
            body: Box::new(std::old_io::util::NullReader)
        })
    }
}
<commit_msg>Update to rust master<commit_after>#![cfg_attr(test, deny(warnings))]

#[macro_use] extern crate log;

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use std::error::Error;

use conduit::{Request, Response};
use middleware::Middleware;

pub struct LogRequests(pub log::LogLevel);

struct LogStart(u64);

impl Middleware for LogRequests {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
        req.mut_extensions().insert(LogStart(time::precise_time_ns()));
        Ok(())
    }

    fn after(&self, req: &mut Request, resp: Result<Response, Box<Error+Send>>)
             -> Result<Response, Box<Error+Send>> {
        let LogStart(start) = *req.mut_extensions().find::<LogStart>().unwrap();

        match resp {
            Ok(ref resp) => self.log_message(req, start, resp.status.0, None),
            Err(ref e) => {
                let msg: &Error = &**e;
                self.log_message(req, start, 500, Some(msg))
            }
        }
        resp
    }

}

impl LogRequests {
    fn log_message(&self, req: &mut Request, start: u64, status: u32,
                   msg: Option<&Error>) {
        let LogRequests(level) = *self;
        let level = if msg.is_some() {log::LogLevel::Error} else {level};
        log!(level, "{} [{}] {:?} {} - {}ms {}{}",
             req.remote_addr(),
             time::now().rfc3339(),
             req.method(),
             req.path(),
             (time::precise_time_ns() - start) / 1000000,
             status,
             match msg {
                 None => String::new(),
                 Some(s) => format!(": {} {}", s.description(), s),
             })
    }
}

#[cfg(all(test, foo))] // FIXME: needs a thread-local logger
mod tests {
    extern crate "conduit-test" as test;

    use {LogRequests};

    use conduit::{Request, Response, Handler, Method};
    use log::{Log, LogRecord};
    use log;
    use middleware;
    use std::error::Error;
    use std::old_io::{ChanWriter, ChanReader};
    use std::sync::Mutex;
    use std::sync::mpsc::{channel, Sender};
    use std::thread::Thread;
    use std;

    struct MyWriter(Mutex<ChanWriter>);

    impl Log for MyWriter {
        fn enabled(&self, _: log::LogLevel, _: &str) -> bool { true }
        fn log(&self, record: &LogRecord) {
            let MyWriter(ref inner) = *self;
            (write!(inner.lock(), "{}", record.args)).unwrap();
        }
    }

    #[test]
    fn test_log() {
        let (sender, receiver) = channel();
        let mut reader = ChanReader::new(receiver);

        let mut builder = middleware::MiddlewareBuilder::new(handler);
        builder.add(LogRequests(log::LogLevel::Error));

        task(builder, sender);

        let result = reader.read_to_string().ok().expect("No response");
        let parts = result.as_slice().split(' ').map(|s| s.to_string()).collect::<Vec<String>>();

        assert_eq!(parts[0].as_slice(), "127.0.0.1");
        // Failing on travis?! bug in libtime?!
        // assert!(parts.get(1).as_slice().len() == "[2014-07-01T22:34:06-07:00]".len(),
        //         "bad length for {}", parts.get(1));
        assert_eq!(parts[2].as_slice(), "Get");
        assert_eq!(parts[3].as_slice(), "/foo");
    }

    fn task<H: Handler + 'static + Send>(handler: H, sender: Sender<Vec<u8>>) {
        Thread::spawn(move|| {
            log::set_logger(Box::new(MyWriter(Mutex::new(ChanWriter::new(sender)))));
            let mut request = test::MockRequest::new(Method::Get, "/foo");
            let _ = handler.call(&mut request);
        });
    }

    fn handler(_: &mut Request) -> Result<Response, Box<Error+Send>> {
        Ok(Response {
            status: (200, "OK"),
            headers: std::collections::HashMap::new(),
            body: Box::new(std::old_io::util::NullReader)
        })
    }
}
<|endoftext|>