<commit_before>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{
    File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename,
};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_file_create_new();
    test_seek();
    test_metadata();
    test_file_set_len();
    test_file_sync();
    test_symlink();
    test_errors();
    test_rename();
    test_directory();
}

fn tmp() -> PathBuf {
    std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir())
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let path = tmp().join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

/// Prepare directory: compute directory name and make sure it does not exist.
fn prepare_dir(dirname: &str) -> PathBuf {
    let path = tmp().join(&dirname);
    // Clean the directory for robustness.
    remove_dir_all(&path).ok();
    path
}

/// Prepare like above, and also write some initial content to the file.
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
    let path = prepare(filename);
    let mut file = File::create(&path).unwrap();
    file.write(content).unwrap();
    path
}

fn test_file() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_file.txt");

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_create_new() {
    let path = prepare("miri_test_fs_file_create_new.txt");

    // Creating a new file that doesn't yet exist should succeed.
    OpenOptions::new().write(true).create_new(true).open(&path).unwrap();
    // Creating a new file that already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind());
    // Optionally creating a new file that already exists should succeed.
    OpenOptions::new().write(true).create(true).open(&path).unwrap();

    // Clean up
    remove_file(&path).unwrap();
}

fn test_seek() {
    let bytes = b"Hello, entire World!\n";
    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let bytes = b"Hello, meta-World!\n";
    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_set_len() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_set_len.txt", bytes);

    // Test extending the file
    let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
    let bytes_extended = b"Hello, World!\n\x00\x00\x00\x00\x00\x00";
    file.set_len(20).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes_extended, contents.as_slice());

    // Test truncating the file
    file.seek(SeekFrom::Start(0)).unwrap();
    file.set_len(10).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[..10], contents.as_slice());

    // Can't use set_len on a file not opened for writing
    let file = OpenOptions::new().read(true).open(&path).unwrap();
    assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind());

    remove_file(&path).unwrap();
}

fn test_file_sync() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_sync.txt", bytes);

    // Test that we can call sync_data and sync_all (can't readily test effects of this operation)
    let file = File::open(&path).unwrap();
    file.sync_data().unwrap();
    file.sync_all().unwrap();

    remove_file(&path).unwrap();
}

fn test_symlink() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
    let symlink_path = prepare("miri_test_fs_symlink.txt");

    // Creating a symbolic link should succeed.
    #[cfg(unix)]
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    #[cfg(windows)]
    std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_errors.txt");

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);

    // Renaming should succeed
    rename(&path1, &path2).unwrap();
    // Check that the old file path isn't present
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    // Check that the file has moved successfully
    assert!(path2.metadata().unwrap().is_file());

    // Renaming a nonexistent file should fail
    assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind());

    remove_file(&path2).unwrap();
}

fn test_directory() {
    let dir_path = prepare_dir("miri_test_fs_dir");
    // Creating a directory should succeed.
    create_dir(&dir_path).unwrap();
    // Test that the metadata of a directory is correct.
    assert!(dir_path.metadata().unwrap().is_dir());
    // Creating a directory when it already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, create_dir(&dir_path).unwrap_err().kind());

    // Create some files inside the directory
    let path_1 = dir_path.join("test_file_1");
    drop(File::create(&path_1).unwrap());
    let path_2 = dir_path.join("test_file_2");
    drop(File::create(&path_2).unwrap());
    // Test that the files are present inside the directory
    let dir_iter = read_dir(&dir_path).unwrap();
    let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    file_names.sort_unstable();
    assert_eq!(file_names, vec!["test_file_1", "test_file_2"]);
    // Clean up the files in the directory
    remove_file(&path_1).unwrap();
    remove_file(&path_2).unwrap();
    // Now there should be nothing left in the directory.
    let dir_iter = read_dir(&dir_path).unwrap();
    let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    assert!(file_names.is_empty());

    // Deleting the directory should succeed.
    remove_dir(&dir_path).unwrap();
    // Reading the metadata of a non-existent directory should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind());
}
<commit_msg>Fix test on Windows hosts<commit_after>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{
    File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename,
};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_file_create_new();
    test_seek();
    test_metadata();
    test_file_set_len();
    test_file_sync();
    test_symlink();
    test_errors();
    test_rename();
    test_directory();
}

fn tmp() -> PathBuf {
    std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir())
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let path = tmp().join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

/// Prepare directory: compute directory name and make sure it does not exist.
fn prepare_dir(dirname: &str) -> PathBuf {
    let path = tmp().join(&dirname);
    // Clean the directory for robustness.
    remove_dir_all(&path).ok();
    path
}

/// Prepare like above, and also write some initial content to the file.
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
    let path = prepare(filename);
    let mut file = File::create(&path).unwrap();
    file.write(content).unwrap();
    path
}

fn test_file() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_file.txt");

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_create_new() {
    let path = prepare("miri_test_fs_file_create_new.txt");

    // Creating a new file that doesn't yet exist should succeed.
    OpenOptions::new().write(true).create_new(true).open(&path).unwrap();
    // Creating a new file that already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind());
    // Optionally creating a new file that already exists should succeed.
    OpenOptions::new().write(true).create(true).open(&path).unwrap();

    // Clean up
    remove_file(&path).unwrap();
}

fn test_seek() {
    let bytes = b"Hello, entire World!\n";
    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let bytes = b"Hello, meta-World!\n";
    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_set_len() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_set_len.txt", bytes);

    // Test extending the file
    let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
    let bytes_extended = b"Hello, World!\n\x00\x00\x00\x00\x00\x00";
    file.set_len(20).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes_extended, contents.as_slice());

    // Test truncating the file
    file.seek(SeekFrom::Start(0)).unwrap();
    file.set_len(10).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[..10], contents.as_slice());

    // Can't use set_len on a file not opened for writing
    let file = OpenOptions::new().read(true).open(&path).unwrap();
    assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind());

    remove_file(&path).unwrap();
}

fn test_file_sync() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_sync.txt", bytes);

    // Test that we can call sync_data and sync_all (can't readily test effects of this operation)
    let file = OpenOptions::new().write(true).open(&path).unwrap();
    file.sync_data().unwrap();
    file.sync_all().unwrap();

    remove_file(&path).unwrap();
}

fn test_symlink() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
    let symlink_path = prepare("miri_test_fs_symlink.txt");

    // Creating a symbolic link should succeed.
    #[cfg(unix)]
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    #[cfg(windows)]
    std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_errors.txt");

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);

    // Renaming should succeed
    rename(&path1, &path2).unwrap();
    // Check that the old file path isn't present
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    // Check that the file has moved successfully
    assert!(path2.metadata().unwrap().is_file());

    // Renaming a nonexistent file should fail
    assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind());

    remove_file(&path2).unwrap();
}

fn test_directory() {
    let dir_path = prepare_dir("miri_test_fs_dir");
    // Creating a directory should succeed.
    create_dir(&dir_path).unwrap();
    // Test that the metadata of a directory is correct.
    assert!(dir_path.metadata().unwrap().is_dir());
    // Creating a directory when it already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, create_dir(&dir_path).unwrap_err().kind());

    // Create some files inside the directory
    let path_1 = dir_path.join("test_file_1");
    drop(File::create(&path_1).unwrap());
    let path_2 = dir_path.join("test_file_2");
    drop(File::create(&path_2).unwrap());
    // Test that the files are present inside the directory
    let dir_iter = read_dir(&dir_path).unwrap();
    let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    file_names.sort_unstable();
    assert_eq!(file_names, vec!["test_file_1", "test_file_2"]);
    // Clean up the files in the directory
    remove_file(&path_1).unwrap();
    remove_file(&path_2).unwrap();
    // Now there should be nothing left in the directory.
    let dir_iter = read_dir(&dir_path).unwrap();
    let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    assert!(file_names.is_empty());

    // Deleting the directory should succeed.
    remove_dir(&dir_path).unwrap();
    // Reading the metadata of a non-existent directory should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind());
}
<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_void, c_uint, c_ulong};

use gobject_ffi::{self, GCallback};
use ffi::{gboolean, GQuark};
use object::{IsA, Object};
use source::CallbackGuard;
use translate::{from_glib, FromGlib, ToGlib, ToGlibPtr};

/// The id of a signal that is returned by `connect`.
#[derive(Debug, Eq, PartialEq)]
pub struct SignalHandlerId(c_ulong);

impl ToGlib for SignalHandlerId {
    type GlibType = c_ulong;

    #[inline]
    fn to_glib(&self) -> c_ulong {
        self.0
    }
}

impl FromGlib<c_ulong> for SignalHandlerId {
    #[inline]
    fn from_glib(val: c_ulong) -> SignalHandlerId {
        SignalHandlerId(val)
    }
}

/// Whether to propagate the signal to the default handler.
///
/// Don't inhibit default handlers without a reason, they're usually helpful.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Inhibit(pub bool);

#[doc(hidden)]
impl ToGlib for Inhibit {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> SignalHandlerId {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure),
        gobject_ffi::GConnectFlags::empty());
    assert!(handle > 0);
    from_glib(handle)
}

pub fn signal_handler_block<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_block(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_unblock<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_unblock(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_disconnect<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_disconnect(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_stop_emission<T: IsA<Object>>(instance: &T, signal_id: u32, detail: GQuark) {
    unsafe {
        gobject_ffi::g_signal_stop_emission(instance.to_glib_none().0, signal_id as c_uint, detail);
    }
}

pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &str) {
    unsafe {
        gobject_ffi::g_signal_stop_emission_by_name(instance.to_glib_none().0, signal_name.to_glib_none().0);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<commit_msg>signal: Require a &SignalHandlerId to block/unblock the emission<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_void, c_uint, c_ulong};

use gobject_ffi::{self, GCallback};
use ffi::{gboolean, GQuark};
use object::{IsA, Object};
use source::CallbackGuard;
use translate::{from_glib, FromGlib, ToGlib, ToGlibPtr};

/// The id of a signal that is returned by `connect`.
#[derive(Debug, Eq, PartialEq)]
pub struct SignalHandlerId(c_ulong);

impl ToGlib for SignalHandlerId {
    type GlibType = c_ulong;

    #[inline]
    fn to_glib(&self) -> c_ulong {
        self.0
    }
}

impl FromGlib<c_ulong> for SignalHandlerId {
    #[inline]
    fn from_glib(val: c_ulong) -> SignalHandlerId {
        SignalHandlerId(val)
    }
}

/// Whether to propagate the signal to the default handler.
///
/// Don't inhibit default handlers without a reason, they're usually helpful.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Inhibit(pub bool);

#[doc(hidden)]
impl ToGlib for Inhibit {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> SignalHandlerId {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure),
        gobject_ffi::GConnectFlags::empty());
    assert!(handle > 0);
    from_glib(handle)
}

pub fn signal_handler_block<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_block(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_unblock<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_unblock(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_disconnect<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_disconnect(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_stop_emission<T: IsA<Object>>(instance: &T, signal_id: u32, detail: GQuark) {
    unsafe {
        gobject_ffi::g_signal_stop_emission(instance.to_glib_none().0, signal_id as c_uint, detail);
    }
}

pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &str) {
    unsafe {
        gobject_ffi::g_signal_stop_emission_by_name(instance.to_glib_none().0, signal_name.to_glib_none().0);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<|endoftext|>


<commit_before>use std::fmt;
use std::sync::Arc;
use std::time::Duration;

use futures::{Future, Stream};
use futures::sync::{mpsc, oneshot};

use request::{self, Request, RequestBuilder};
use response::{self, Response};
use {async_impl, Certificate, Method, IntoUrl, Proxy, RedirectPolicy, wait};

/// A `Client` to make Requests with.
///
/// The Client has various configuration values to tweak, but the defaults
/// are set to what is usually the most commonly desired value.
///
/// The `Client` holds a connection pool internally, so it is advised that
/// you create one and reuse it.
///
/// # Examples
///
/// ```rust
/// # use reqwest::{Error, Client};
/// #
/// # fn run() -> Result<(), Error> {
/// let client = Client::new()?;
/// let resp = client.get("http://httpbin.org/")?.send()?;
/// #   drop(resp);
/// #   Ok(())
/// # }
///
/// ```
#[derive(Clone)]
pub struct Client {
    inner: ClientHandle,
}

/// A `ClientBuilder` can be used to create a `Client` with  custom configuration.
///
/// # Example
///
/// ```
/// # fn run() -> Result<(), Error> {
/// use std::time::Duration;
///
/// let client = reqwest::Client::builder()?
///     .gzip(true)
///     .timeout(Duration::from_secs(10))
///     .build()?;
/// # }
/// ```
pub struct ClientBuilder {
    gzip: bool,
    inner: async_impl::ClientBuilder,
    timeout: Option<Duration>,
}

impl ClientBuilder {
    /// Constructs a new `ClientBuilder`
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    pub fn new() -> ::Result<ClientBuilder> {
        async_impl::ClientBuilder::new().map(|builder| ClientBuilder {
            inner: builder,
            gzip: true,
            timeout: None,
        })
    }

    /// Returns a `Client` that uses this `ClientBuilder` configuration.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be initialized.
    ///
    /// # Panics
    ///
    /// This method consumes the internal state of the builder.
    /// Trying to use this builder again after calling `build` will panic.
    pub fn build(&mut self) -> ::Result<Client> {
        ClientHandle::new(self).map(|handle| Client {
            inner: handle,
        })
    }

    /// Add a custom root certificate.
    ///
    /// This can be used to connect to a server that has a self-signed
    /// certificate for example.
    ///
    /// # Example
    /// ```
    /// # use std::fs::File;
    /// # use std::io::Read;
    /// # fn build_client() -> Result<(), Box<std::error::Error>> {
    /// // read a local binary DER encoded certificate
    /// let mut buf = Vec::new();
    /// File::open("my-cert.der")?.read_to_end(&mut buf)?;
    ///
    /// // create a certificate
    /// let cert = reqwest::Certificate::from_der(&buf)?;
    ///
    /// // get a client builder
    /// let client = reqwest::ClientBuilder::new()?
    ///     .add_root_certificate(cert)?
    ///     .build()?;
    /// # drop(client);
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// This method fails if adding root certificate was unsuccessful.
    pub fn add_root_certificate(&mut self, cert: Certificate) -> ::Result<&mut ClientBuilder> {
        self.inner.add_root_certificate(cert)?;
        Ok(self)
    }

    /// Disable hostname verification.
    ///
    /// # Warning
    ///
    /// You should think very carefully before you use this method. If
    /// hostname verification is not used, any valid certificate for any
    /// site will be trusted for use from any other. This introduces a
    /// significant vulnerability to man-in-the-middle attacks.
    #[inline]
    pub fn danger_disable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.inner.danger_disable_hostname_verification();
        self
    }

    /// Enable hostname verification.
    ///
    /// Default is enabled.
    #[inline]
    pub fn enable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.inner.enable_hostname_verification();
        self
    }

    /// Enable auto gzip decompression by checking the ContentEncoding response header.
    ///
    /// Default is enabled.
    #[inline]
    pub fn gzip(&mut self, enable: bool) -> &mut ClientBuilder {
        self.inner.gzip(enable);
        self.gzip = enable;
        self
    }

    /// Add a `Proxy` to the list of proxies the `Client` will use.
    #[inline]
    pub fn proxy(&mut self, proxy: Proxy) -> &mut ClientBuilder {
        self.inner.proxy(proxy);
        self
    }

    /// Set a `RedirectPolicy` for this client.
    ///
    /// Default will follow redirects up to a maximum of 10.
    #[inline]
    pub fn redirect(&mut self, policy: RedirectPolicy) -> &mut ClientBuilder {
        self.inner.redirect(policy);
        self
    }

    /// Enable or disable automatic setting of the `Referer` header.
    ///
    /// Default is `true`.
    #[inline]
    pub fn referer(&mut self, enable: bool) -> &mut ClientBuilder {
        self.inner.referer(enable);
        self
    }

    /// Set a timeout for connect, read and write operations of a `Client`.
    #[inline]
    pub fn timeout(&mut self, timeout: Duration) -> &mut ClientBuilder {
        self.timeout = Some(timeout);
        self
    }
}

impl Client {
    /// Constructs a new `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created or initialized.
    #[inline]
    pub fn new() -> ::Result<Client> {
        ClientBuilder::new()?.build()
    }

    /// Creates a `ClientBuilder` to configure a `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    #[inline]
    pub fn builder() -> ::Result<ClientBuilder> {
        ClientBuilder::new()
    }

    /// Convenience method to make a `GET` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn get<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Get, url)
    }

    /// Convenience method to make a `POST` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn post<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Post, url)
    }

    /// Convenience method to make a `PUT` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn put<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Put, url)
    }

    /// Convenience method to make a `PATCH` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn patch<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Patch, url)
    }

    /// Convenience method to make a `DELETE` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn delete<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Delete, url)
    }

    /// Convenience method to make a `HEAD` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn head<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Head, url)
    }

    /// Start building a `Request` with the `Method` and `Url`.
    ///
    /// Returns a `RequestBuilder`, which will allow setting headers and
    /// request body before sending.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> ::Result<RequestBuilder> {
        let url = try_!(url.into_url());
        Ok(request::builder(self.clone(), Request::new(method, url)))
    }

    /// Executes a `Request`.
    ///
    /// A `Request` can be built manually with `Request::new()` or obtained
    /// from a RequestBuilder with `RequestBuilder::build()`.
    ///
    /// You should prefer to use the `RequestBuilder` and
    /// `RequestBuilder::send()`.
    ///
    /// # Errors
    ///
    /// This method fails if there was an error while sending request,
    /// redirect loop was detected or redirect limit was exhausted.
    pub fn execute(&self, request: Request) -> ::Result<Response> {
        self.inner.execute_request(request)
    }
}

impl fmt::Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Client")
            //.field("gzip", &self.inner.gzip)
            //.field("redirect_policy", &self.inner.redirect_policy)
            //.field("referer", &self.inner.referer)
            .finish()
    }
}

impl fmt::Debug for ClientBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ClientBuilder")
            .finish()
    }
}

#[derive(Clone)]
struct ClientHandle {
    gzip: bool,
    timeout: Option<Duration>,
    tx: Arc<ThreadSender>
}

type ThreadSender = mpsc::UnboundedSender<(async_impl::Request, oneshot::Sender<::Result<async_impl::Response>>)>;

impl ClientHandle {
    fn new(builder: &mut ClientBuilder) -> ::Result<ClientHandle> {
        use std::thread;

        let gzip = builder.gzip;
        let timeout = builder.timeout;
        let mut builder = async_impl::client::take_builder(&mut builder.inner);
        let (tx, rx) = mpsc::unbounded();
        let (spawn_tx, spawn_rx) = oneshot::channel::<::Result<()>>();
        try_!(thread::Builder::new().name("reqwest-internal-sync-core".into()).spawn(move || {
            use tokio_core::reactor::Core;

            let built = (|| {
                let core = try_!(Core::new());
                let handle = core.handle();
                let client = builder.build(&handle)?;
                Ok((core, handle, client))
            })();

            let (mut core, handle, client) = match built {
                Ok((a, b, c)) => {
                    if let Err(_) = spawn_tx.send(Ok(())) {
                        return;
                    }
                    (a, b, c)
                },
                Err(e) => {
                    let _ = spawn_tx.send(Err(e));
                    return;
                }
            };

            let work = rx.for_each(|(req, tx)| {
                let tx: oneshot::Sender<::Result<async_impl::Response>> = tx;
                let task = client.execute(req)
                    .then(move |x| tx.send(x).map_err(|_| ()));
                handle.spawn(task);
                Ok(())
            });

            // work is Future<(), ()>, and our closure will never return Err
            let _ = core.run(work);
        }));

        wait::timeout(spawn_rx, timeout).expect("core thread cancelled")?;

        Ok(ClientHandle {
            gzip: gzip,
            timeout: timeout,
            tx: Arc::new(tx),
        })
    }

    fn execute_request(&self, req: Request) -> ::Result<Response> {
        let (tx, rx) = oneshot::channel();
        let (req, body) = request::async(req);
        let url = req.url().clone();
        self.tx.send((req, tx)).expect("core thread panicked");

        if let Some(body) = body {
            try_!(body.send(), &url);
        }

        let res = match wait::timeout(rx, self.timeout) {
            Ok(res) => res,
            Err(wait::Waited::TimedOut) => return Err(::error::timedout(Some(url))),
            Err(wait::Waited::Err(_canceled)) => {
                // The only possible reason there would be a Cancelled error
                // is if the thread running the Core panicked. We could return
                // an Err here, like a BrokenPipe, but the Client is not
                // recoverable. Additionally, the panic in the other thread
                // is not normal, and should likely be propagated.
                panic!("core thread panicked");
            }
        };
        res.map(|res| {
            response::new(res, self.gzip, self.timeout, KeepCoreThreadAlive(self.tx.clone()))
        })
    }
}

// pub(crate)

pub struct KeepCoreThreadAlive(Arc<ThreadSender>);
<commit_msg>fix doc test on clientbuilder<commit_after>use std::fmt;
use std::sync::Arc;
use std::time::Duration;

use futures::{Future, Stream};
use futures::sync::{mpsc, oneshot};

use request::{self, Request, RequestBuilder};
use response::{self, Response};
use {async_impl, Certificate, Method, IntoUrl, Proxy, RedirectPolicy, wait};

/// A `Client` to make Requests with.
///
/// The Client has various configuration values to tweak, but the defaults
/// are set to what is usually the most commonly desired value.
///
/// The `Client` holds a connection pool internally, so it is advised that
/// you create one and reuse it.
///
/// # Examples
///
/// ```rust
/// # use reqwest::{Error, Client};
/// #
/// # fn run() -> Result<(), Error> {
/// let client = Client::new()?;
/// let resp = client.get("http://httpbin.org/")?.send()?;
/// #   drop(resp);
/// #   Ok(())
/// # }
///
/// ```
#[derive(Clone)]
pub struct Client {
    inner: ClientHandle,
}

/// A `ClientBuilder` can be used to create a `Client` with  custom configuration.
///
/// # Example
///
/// ```
/// # fn run() -> Result<(), reqwest::Error> {
/// use std::time::Duration;
///
/// let client = reqwest::Client::builder()?
///     .gzip(true)
///     .timeout(Duration::from_secs(10))
///     .build()?;
/// # }
/// ```
pub struct ClientBuilder {
    gzip: bool,
    inner: async_impl::ClientBuilder,
    timeout: Option<Duration>,
}

impl ClientBuilder {
    /// Constructs a new `ClientBuilder`
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    pub fn new() -> ::Result<ClientBuilder> {
        async_impl::ClientBuilder::new().map(|builder| ClientBuilder {
            inner: builder,
            gzip: true,
            timeout: None,
        })
    }

    /// Returns a `Client` that uses this `ClientBuilder` configuration.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be initialized.
    ///
    /// # Panics
    ///
    /// This method consumes the internal state of the builder.
    /// Trying to use this builder again after calling `build` will panic.
    pub fn build(&mut self) -> ::Result<Client> {
        ClientHandle::new(self).map(|handle| Client {
            inner: handle,
        })
    }

    /// Add a custom root certificate.
    ///
    /// This can be used to connect to a server that has a self-signed
    /// certificate for example.
    ///
    /// # Example
    /// ```
    /// # use std::fs::File;
    /// # use std::io::Read;
    /// # fn build_client() -> Result<(), Box<std::error::Error>> {
    /// // read a local binary DER encoded certificate
    /// let mut buf = Vec::new();
    /// File::open("my-cert.der")?.read_to_end(&mut buf)?;
    ///
    /// // create a certificate
    /// let cert = reqwest::Certificate::from_der(&buf)?;
    ///
    /// // get a client builder
    /// let client = reqwest::ClientBuilder::new()?
    ///     .add_root_certificate(cert)?
    ///     .build()?;
    /// # drop(client);
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// This method fails if adding root certificate was unsuccessful.
    pub fn add_root_certificate(&mut self, cert: Certificate) -> ::Result<&mut ClientBuilder> {
        self.inner.add_root_certificate(cert)?;
        Ok(self)
    }

    /// Disable hostname verification.
    ///
    /// # Warning
    ///
    /// You should think very carefully before you use this method. If
    /// hostname verification is not used, any valid certificate for any
    /// site will be trusted for use from any other. This introduces a
    /// significant vulnerability to man-in-the-middle attacks.
    #[inline]
    pub fn danger_disable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.inner.danger_disable_hostname_verification();
        self
    }

    /// Enable hostname verification.
    ///
    /// Default is enabled.
    #[inline]
    pub fn enable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.inner.enable_hostname_verification();
        self
    }

    /// Enable auto gzip decompression by checking the ContentEncoding response header.
    ///
    /// Default is enabled.
    #[inline]
    pub fn gzip(&mut self, enable: bool) -> &mut ClientBuilder {
        self.inner.gzip(enable);
        self.gzip = enable;
        self
    }

    /// Add a `Proxy` to the list of proxies the `Client` will use.
    #[inline]
    pub fn proxy(&mut self, proxy: Proxy) -> &mut ClientBuilder {
        self.inner.proxy(proxy);
        self
    }

    /// Set a `RedirectPolicy` for this client.
    ///
    /// Default will follow redirects up to a maximum of 10.
    #[inline]
    pub fn redirect(&mut self, policy: RedirectPolicy) -> &mut ClientBuilder {
        self.inner.redirect(policy);
        self
    }

    /// Enable or disable automatic setting of the `Referer` header.
    ///
    /// Default is `true`.
    #[inline]
    pub fn referer(&mut self, enable: bool) -> &mut ClientBuilder {
        self.inner.referer(enable);
        self
    }

    /// Set a timeout for connect, read and write operations of a `Client`.
    #[inline]
    pub fn timeout(&mut self, timeout: Duration) -> &mut ClientBuilder {
        self.timeout = Some(timeout);
        self
    }
}

impl Client {
    /// Constructs a new `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created or initialized.
    #[inline]
    pub fn new() -> ::Result<Client> {
        ClientBuilder::new()?.build()
    }

    /// Creates a `ClientBuilder` to configure a `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    #[inline]
    pub fn builder() -> ::Result<ClientBuilder> {
        ClientBuilder::new()
    }

    /// Convenience method to make a `GET` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn get<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Get, url)
    }

    /// Convenience method to make a `POST` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn post<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Post, url)
    }

    /// Convenience method to make a `PUT` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn put<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Put, url)
    }

    /// Convenience method to make a `PATCH` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn patch<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Patch, url)
    }

    /// Convenience method to make a `DELETE` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn delete<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Delete, url)
    }

    /// Convenience method to make a `HEAD` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn head<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Head, url)
    }

    /// Start building a `Request` with the `Method` and `Url`.
    ///
    /// Returns a `RequestBuilder`, which will allow setting headers and
    /// request body before sending.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> ::Result<RequestBuilder> {
        let url = try_!(url.into_url());
        Ok(request::builder(self.clone(), Request::new(method, url)))
    }

    /// Executes a `Request`.
    ///
    /// A `Request` can be built manually with `Request::new()` or obtained
    /// from a RequestBuilder with `RequestBuilder::build()`.
    ///
    /// You should prefer to use the `RequestBuilder` and
    /// `RequestBuilder::send()`.
    ///
    /// # Errors
    ///
    /// This method fails if there was an error while sending request,
    /// redirect loop was detected or redirect limit was exhausted.
    pub fn execute(&self, request: Request) -> ::Result<Response> {
        self.inner.execute_request(request)
    }
}

impl fmt::Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Client")
            //.field("gzip", &self.inner.gzip)
            //.field("redirect_policy", &self.inner.redirect_policy)
            //.field("referer", &self.inner.referer)
            .finish()
    }
}

impl fmt::Debug for ClientBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ClientBuilder")
            .finish()
    }
}

#[derive(Clone)]
struct ClientHandle {
    gzip: bool,
    timeout: Option<Duration>,
    tx: Arc<ThreadSender>
}

type ThreadSender = mpsc::UnboundedSender<(async_impl::Request, oneshot::Sender<::Result<async_impl::Response>>)>;

impl ClientHandle {
    fn new(builder: &mut ClientBuilder) -> ::Result<ClientHandle> {
        use std::thread;

        let gzip = builder.gzip;
        let timeout = builder.timeout;
        let mut builder = async_impl::client::take_builder(&mut builder.inner);
        let (tx, rx) = mpsc::unbounded();
        let (spawn_tx, spawn_rx) = oneshot::channel::<::Result<()>>();
        try_!(thread::Builder::new().name("reqwest-internal-sync-core".into()).spawn(move || {
            use tokio_core::reactor::Core;

            let built = (|| {
                let core = try_!(Core::new());
                let handle = core.handle();
                let client = builder.build(&handle)?;
                Ok((core, handle, client))
            })();

            let (mut core, handle, client) = match built {
                Ok((a, b, c)) => {
                    if let Err(_) = spawn_tx.send(Ok(())) {
                        return;
                    }
                    (a, b, c)
                },
                Err(e) => {
                    let _ = spawn_tx.send(Err(e));
                    return;
                }
            };

            let work = rx.for_each(|(req, tx)| {
                let tx: oneshot::Sender<::Result<async_impl::Response>> = tx;
                let task = client.execute(req)
                    .then(move |x| tx.send(x).map_err(|_| ()));
                handle.spawn(task);
                Ok(())
            });

            // work is Future<(), ()>, and our closure will never return Err
            let _ = core.run(work);
        }));

        wait::timeout(spawn_rx, timeout).expect("core thread cancelled")?;

        Ok(ClientHandle {
            gzip: gzip,
            timeout: timeout,
            tx: Arc::new(tx),
        })
    }

    fn execute_request(&self, req: Request) -> ::Result<Response> {
        let (tx, rx) = oneshot::channel();
        let (req, body) = request::async(req);
        let url = req.url().clone();
        self.tx.send((req, tx)).expect("core thread panicked");

        if let Some(body) = body {
            try_!(body.send(), &url);
        }

        let res = match wait::timeout(rx, self.timeout) {
            Ok(res) => res,
            Err(wait::Waited::TimedOut) => return Err(::error::timedout(Some(url))),
            Err(wait::Waited::Err(_canceled)) => {
                // The only possible reason there would be a Cancelled error
                // is if the thread running the Core panicked. We could return
                // an Err here, like a BrokenPipe, but the Client is not
                // recoverable. Additionally, the panic in the other thread
                // is not normal, and should likely be propagated.
                panic!("core thread panicked");
            }
        };
        res.map(|res| {
            response::new(res, self.gzip, self.timeout, KeepCoreThreadAlive(self.tx.clone()))
        })
    }
}

// pub(crate)

pub struct KeepCoreThreadAlive(Arc<ThreadSender>);
<|endoftext|>


<commit_before>// mod client

use std::fmt;
use std::cmp;
use std::ops::Deref;
use std::str::FromStr;
use map::*;

/// Client contains information about a TeamSpeak 3 client.
/// # Example
/// ```
/// use sqlib;
///
/// let client = sqlib::Client {
///     clid: 1,
///     cid: 1,
///     client_database_id: 1,
///     client_nickname: "John Doe".to_string(),
///     client_type: 0,
///     connection_connected_time: 0
/// };
///
/// assert!(client.is_client());
///
/// let client_print = format!("{}", client);
///
/// assert_eq!("John Doe (0)".to_string(), client_print);
/// ```
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Client {
    /// client id
    pub clid: i64,
    /// channel id
    pub cid: i64,
    /// client database id
    pub client_database_id: i64,
    /// client nickname
    pub client_nickname: String,
    /// client type: 0 is client and 1 is query client
    pub client_type: i64,
    /// connection time in milliseconds
    pub connection_connected_time: i64,
}

impl Default for Client {
    fn default() -> Client {
        Client {
            clid: 0,
            cid: 0,
            client_database_id: 0,
            client_nickname: String::new(),
            client_type: 0,
            connection_connected_time: 0,
        }
    }
}

impl Client {
    /// creates a new client from a client id and a nickname
    pub fn new(client_id: i64, nickname: String) -> Client {
        let mut client = Client::default();
        client.clid = client_id;
        client.client_nickname = nickname;
        client
    }
    /// checks if it is a real client
    pub fn is_client(&self) -> bool {
        self.client_type == 0
    }

    pub fn from_map(map: &StringMap) -> Client {
        let mut client = Client::default();
        client.mut_from_map(map);
        client
    }

    pub fn update_from_map(client: Client, map: &StringMap) -> Client {
        let mut client = client.clone();
        client.mut_from_map(map);
        client
    }

    pub fn mut_from_map(&mut self, map: &StringMap) {
        update_from_map(map, "clid", &mut self.clid);
        update_from_map(map, "cid", &mut self.cid);
        update_from_map(map, "client_database_id", &mut self.client_database_id);
        update_from_map(map, "client_nickname", &mut self.client_nickname);
        update_from_map(map, "client_type", &mut self.client_type);
        update_from_map(map,
                        "connection_connected_time",
                        &mut self.connection_connected_time);
    }
}

impl FromStr for Client {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let map = to_map(s);
        Ok(Client::from_map(&map))
    }
}

impl fmt::Display for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({})",
               &self.client_nickname,
               self.connection_connected_time / 1000 / 60) // TODO: generate exact time string
    }
}

impl PartialEq for Client {
    fn eq(&self, other: &Client) -> bool {
        self.clid.eq(&other.clid)
    }
}

impl Eq for Client {}

impl PartialOrd for Client {
    fn partial_cmp(&self, other: &Client) -> Option<cmp::Ordering> {
        self.clid.partial_cmp(&other.clid)
    }
}

impl Ord for Client {
    fn cmp(&self, other: &Client) -> cmp::Ordering {
        self.clid.cmp(&other.clid)
    }
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, RustcDecodable, RustcEncodable)]
pub struct ClientList(Vec<Client>);

impl ClientList {
    pub fn vec(&self) -> &Vec<Client> {
        let &ClientList(ref v) = self;
        v
    }

    pub fn get_mut(&mut self) -> &mut Vec<Client> {
        let &mut ClientList(ref mut v) = self;
        v
    }

    pub fn get_vec(self) -> Vec<Client> {
        let ClientList(v) = self;
        v
    }

    pub fn from_maps(maps: &Vec<StringMap>) -> ClientList {
        let mut vec = Vec::new();
        for map in maps.iter() {
            let client = Client::from_map(map);
            vec.push(client);
        }
        ClientList(vec)
    }
}

impl FromStr for ClientList {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let maps = s.split('|').map(to_map).collect();
        Ok(ClientList::from_maps(&maps))
    }
}

impl Deref for ClientList {
    type Target = Vec<Client>;
    fn deref(&self) -> &Vec<Client> {
        self.vec()
    }
}

impl fmt::Display for ClientList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[ "));
        let mut cls = self.vec().iter();
        if cls.len() > 0 {
            try!(write!(f, "{}", cls.next().unwrap()));
        }
        for client in cls {
            try!(write!(f, ", {}", client));
        }
        write!(f, " ]")
    }
}
<commit_msg>adding some functions to Client and ClientList<commit_after>// mod client

use std::fmt;
use std::cmp;
use std::ops::Deref;
use std::str::FromStr;
use map::*;
use escaping::*;

/// Client contains information about a TeamSpeak 3 client.
/// # Example
/// ```
/// use sqlib;
///
/// let client = sqlib::Client {
///     clid: 1,
///     cid: 1,
///     client_database_id: 1,
///     client_nickname: "John Doe".to_string(),
///     client_type: 0,
///     connection_connected_time: 0
/// };
///
/// assert!(client.is_client());
///
/// let client_print = format!("{}", client);
///
/// assert_eq!("John Doe (0)".to_string(), client_print);
/// ```
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Client {
    /// client id
    pub clid: i64,
    /// channel id
    pub cid: i64,
    /// client database id
    pub client_database_id: i64,
    /// client nickname
    pub client_nickname: String,
    /// client type: 0 is client and 1 is query client
    pub client_type: i64,
    /// connection time in milliseconds
    pub connection_connected_time: i64,
}

impl Default for Client {
    fn default() -> Client {
        Client {
            clid: 0,
            cid: 0,
            client_database_id: 0,
            client_nickname: String::new(),
            client_type: 0,
            connection_connected_time: 0,
        }
    }
}

impl Client {
    /// creates a new client from a client id and a nickname
    pub fn new(client_id: i64, nickname: String) -> Client {
        let mut client = Client::default();
        client.clid = client_id;
        client.client_nickname = nickname;
        client.unescape();
        client
    }
    /// checks if it is a real client
    pub fn is_client(&self) -> bool {
        self.client_type == 0
    }

    fn unescape(&mut self) {
        self.client_nickname = unescape(&self.client_nickname);
    }

    pub fn from_map(map: &StringMap) -> Client {
        let mut client = Client::default();
        client.mut_from_map(map);
        client
    }

    pub fn update_from_map(client: Client, map: &StringMap) -> Client {
        let mut client = client.clone();
        client.mut_from_map(map);
        client
    }

    pub fn mut_from_map(&mut self, map: &StringMap) {
        update_from_map(map, "clid", &mut self.clid);
        update_from_map(map, "cid", &mut self.cid);
        update_from_map(map, "client_database_id", &mut self.client_database_id);
        update_from_map(map, "client_nickname", &mut self.client_nickname);
        update_from_map(map, "client_type", &mut self.client_type);
        update_from_map(map,
                        "connection_connected_time",
                        &mut self.connection_connected_time);
        self.unescape();
    }

    fn connection_connected_time_string(&self) -> String {
        let mut raw_seconds = self.connection_connected_time / 1000;
        let hours = raw_seconds / 3600;
        raw_seconds = raw_seconds % 3600;
        let minutes = raw_seconds / 60;
        let seconds = raw_seconds % 60;
        if hours > 0 {
            format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
        } else if minutes > 0 {
            format!("{:02}:{:02}", minutes, seconds)
        } else {
            format!("{}", seconds)
        }
    }
}

impl FromStr for Client {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let map = to_map(s);
        Ok(Client::from_map(&map))
    }
}

impl fmt::Display for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({})",
               &self.client_nickname,
               self.connection_connected_time_string())
    }
}

impl PartialEq for Client {
    fn eq(&self, other: &Client) -> bool {
        self.clid.eq(&other.clid)
    }
}

impl Eq for Client {}

impl PartialOrd for Client {
    fn partial_cmp(&self, other: &Client) -> Option<cmp::Ordering> {
        self.clid.partial_cmp(&other.clid)
    }
}

impl Ord for Client {
    fn cmp(&self, other: &Client) -> cmp::Ordering {
        self.clid.cmp(&other.clid)
    }
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, RustcDecodable, RustcEncodable)]
pub struct ClientList(Vec<Client>);

impl ClientList {
    pub fn vec(&self) -> &Vec<Client> {
        let &ClientList(ref v) = self;
        v
    }

    pub fn get_mut(&mut self) -> &mut Vec<Client> {
        let &mut ClientList(ref mut v) = self;
        v
    }

    pub fn get_vec(self) -> Vec<Client> {
        let ClientList(v) = self;
        v
    }

    pub fn filter_clients(&self) -> ClientList {
        let new_vec = self.iter().map(Clone::clone).filter(|c| c.is_client()).collect();
        ClientList(new_vec)
    }

    pub fn from_maps(maps: &Vec<StringMap>) -> ClientList {
        let mut vec = Vec::new();
        for map in maps.iter() {
            let client = Client::from_map(map);
            vec.push(client);
        }
        ClientList(vec)
    }
}

impl FromStr for ClientList {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let maps = s.split('|').map(to_map).collect();
        Ok(ClientList::from_maps(&maps))
    }
}

impl Deref for ClientList {
    type Target = Vec<Client>;
    fn deref(&self) -> &Vec<Client> {
        self.vec()
    }
}

impl fmt::Display for ClientList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[ "));
        let mut cls = self.vec().iter();
        if cls.len() > 0 {
            try!(write!(f, "{}", cls.next().unwrap()));
        }
        for client in cls {
            try!(write!(f, ", {}", client));
        }
        write!(f, " ]")
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rustastic SMTP Developers
//
// 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::io::{Reader, Writer, IoError};
use std::vec::{Vec};
#[allow(unused_imports)]
use std::io::{Truncate, Open, Read, Write};
#[allow(unused_imports)]
use std::io::fs::{File};

/// The maximum line size as specified by RFC 5321.
static MAX_LINE_SIZE: uint = 512;

#[test]
fn test_static_vars() {
    assert_eq!(512, MAX_LINE_SIZE);
}

/// A stream specially made for reading SMTP commands.
///
/// It reads lines of input delimited by the <CRLF> sequence and with a maximum
/// size of 512 bytes, including the command word and the <CRLF> sequence. If
/// the input is not UTF8, non-UTF8 characters are replaced with `U+FFFD
/// REPLACEMENT CHARACTER` but no error is returned.
///
/// Returns `InvalidInput` if no line is found within 512 bytes of input.
///
/// # Example
/// ```no_run
/// use std::io::TcpStream;
/// use rsmtp::stream::SmtpStream;
///
/// let mut smtp = SmtpStream::new(TcpStream::connect("127.0.0.1", 2525).unwrap(), 65536);
///
/// println!("{}", smtp.read_line().unwrap());
/// ```
pub struct SmtpStream<S> {
    stream: S,
    /// The maximum message size, including headers and ending sequence.
    max_message_size: uint
}

#[deriving(Show, Eq, PartialEq)]
pub enum SmtpStreamError {
    ReadFailed(IoError),
    WriteFailed(IoError),
    LineTooLong,
    TooMuchData
}

impl<S> SmtpStream<S> {
    /// Create a new `SmtpStream` from another stream.
    pub fn new(inner: S, max_message_size: uint) -> SmtpStream<S> {
        SmtpStream {
            stream: inner,
            max_message_size: max_message_size
        }
    }
}

impl<R: Reader> SmtpStream<R> {
    /// Read the data section of an email. Ends with "<CRLF>.<CRLF>".
    pub fn read_data(&mut self) -> Result<Vec<u8>, SmtpStreamError> {
        let mut data: Vec<u8> = Vec::with_capacity(512);
        let end = [13u8, 10u8, 46u8, 13u8, 10u8]; // CRLF.CRLF
        let mut too_long = false;
        let mut last_5: Vec<u8> = vec!(0u8, 0u8, 0u8, 0u8, 0u8);

        loop {
            // If we have previously read as much data as possible and still are not finished
            // reading, stop here.
            if data.len() >= self.max_message_size && !too_long {
                too_long = true;
            }

            // Try to get more data and see if we have got it all.
            let byte_res = self.stream.read_byte();
            match byte_res {
                Ok(b) => {
                    // Only keep remaining data if we are allowed too. Otherwise, discard it too
                    // avoid out of memory errors.
                    if data.len() < self.max_message_size {
                        data.push(b);
                    }
                    // Since we always have 5 bytes in here, this should never fail.
                    last_5.remove(0).unwrap();
                    last_5.push(b);

                    // Let's see if we have read all the data.
                    if last_5.as_slice() == end {
                        if !too_long {
                            let data_len = data.len();
                            data.truncate(data_len - end.len());
                        }
                        break;
                    }
                },
                Err(err) => {
                    return Err(ReadFailed(err))
                }
            }
        }
        if too_long {
            Err(TooMuchData)
        } else {
            Ok(data)
        }
    }

    /// Read one line of input.
    pub fn read_line(&mut self) -> Result<Vec<u8>, SmtpStreamError> {
        let mut data: Vec<u8> = Vec::with_capacity(MAX_LINE_SIZE);
        let end = [13u8, 10u8]; // CRLF
        let mut too_long = false;
        let mut last_2: Vec<u8> = vec!(0u8, 0u8);

        loop {
            // If we have previously read as much data as possible and still are not finished
            // reading, stop here.
            if data.len() >= MAX_LINE_SIZE && !too_long {
                too_long = true;
            }

            // Try to get more data and see if we have got it all.
            let byte_res = self.stream.read_byte();
            match byte_res {
                Ok(b) => {
                    // Only keep remaining data if we are allowed too. Otherwise, discard it too
                    // avoid out of memory errors.
                    if data.len() < self.max_message_size {
                        data.push(b);
                    }
                    // Since we always have 2 bytes in here, this should never fail.
                    last_2.remove(0).unwrap();
                    last_2.push(b);

                    // Let's see if we have read all the line
                    if last_2.as_slice() == end {
                        if !too_long {
                            let data_len = data.len();
                            data.truncate(data_len - end.len());
                        }
                        break;
                    }
                },
                Err(err) => return Err(ReadFailed(err))
            }
        }
        if too_long {
            Err(LineTooLong)
        } else {
            Ok(data)
        }
    }

}

impl<W: Writer> SmtpStream<W> {
    /// Write a line ended with <CRLF>.
    pub fn write_line(&mut self, s: &str) -> Result<(), SmtpStreamError> {
        match self.stream.write_str(format!("{}\r\n", s).as_slice()) {
            Ok(_) => Ok(()),
            Err(err) => Err(WriteFailed(err))
        }
    }
}

#[test]
fn test_new() {
    // Testing via `test_read_line()`.
}

#[test]
fn test_read_data() {
    let mut path: Path;
    let mut file: File;
    let mut stream: SmtpStream<File>;
    let mut expected: String;

    path = Path::new("tests/stream/data_ok");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    expected = String::from_utf8_lossy(stream.read_data().unwrap().as_slice()).into_string();
    assert_eq!("Hello world!\nBlabla\n", expected.as_slice());
}

#[test]
fn test_write_line() {
    // Use a block so the file gets closed at the end of it.
    {
        let mut path_write: Path;
        let mut file_write: File;
        let mut stream: SmtpStream<File>;

        path_write = Path::new("tests/stream/write_line");
        file_write = File::open_mode(&path_write, Truncate, Write).unwrap();
        stream = SmtpStream::new(file_write, 65536);
        stream.write_line("HelloWorld").unwrap();
        stream.write_line("ByeBye").unwrap();
    }
    let mut path_read: Path;
    let mut file_read: File;
    let mut expected: String;

    path_read = Path::new("tests/stream/write_line");
    file_read = File::open_mode(&path_read, Open, Read).unwrap();
    expected = file_read.read_to_string().unwrap();
    assert_eq!("HelloWorld\r\nByeBye\r\n", expected.as_slice());
}

#[test]
fn test_read_line() {
    let mut path: Path;
    let mut file: File;
    let mut stream: SmtpStream<File>;
    let mut expected: String;

    path = Path::new("tests/stream/0line1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line2");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line3");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line2");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/2lines1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "hello world!");
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "bye bye world!");
    assert!(!stream.read_line().is_ok());

    expected = String::from_char(62, 'x');
    path = Path::new("tests/stream/xlines1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert!(!stream.read_line().is_ok());
}
<commit_msg>fix reader and make more maintainable<commit_after>// Copyright 2014 The Rustastic SMTP Developers
//
// 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::io::{Reader, Writer, IoError};
use std::vec::{Vec};
#[allow(unused_imports)]
use std::io::{Truncate, Append, Open, Read, Write};
#[allow(unused_imports)]
use std::io::fs::{File};

/// The maximum line size as specified by RFC 5321.
static MAX_LINE_SIZE: uint = 512;

#[test]
fn test_static_vars() {
    assert_eq!(512, MAX_LINE_SIZE);
}

/// A stream specially made for reading SMTP commands.
///
/// It reads lines of input delimited by the <CRLF> sequence and with a maximum
/// size of 512 bytes, including the command word and the <CRLF> sequence. If
/// the input is not UTF8, non-UTF8 characters are replaced with `U+FFFD
/// REPLACEMENT CHARACTER` but no error is returned.
///
/// Returns `InvalidInput` if no line is found within 512 bytes of input.
///
/// # Example
/// ```no_run
/// use std::io::TcpStream;
/// use rsmtp::stream::SmtpStream;
///
/// let mut smtp = SmtpStream::new(TcpStream::connect("127.0.0.1", 2525).unwrap(), 65536);
///
/// println!("{}", smtp.read_line().unwrap());
/// ```
pub struct SmtpStream<S> {
    stream: S,
    /// The maximum message size, including headers and ending sequence.
    max_message_size: uint
}

#[deriving(Show, Eq, PartialEq)]
pub enum SmtpStreamError {
    ReadFailed(IoError),
    WriteFailed(IoError),
    LineTooLong,
    TooMuchData
}

#[deriving(Show, Eq, PartialEq)]
enum SmtpStreamPrivateError {
    PrivateReadFailed(IoError),
    TooLong
}

impl<S> SmtpStream<S> {
    /// Create a new `SmtpStream` from another stream.
    pub fn new(inner: S, max_message_size: uint) -> SmtpStream<S> {
        SmtpStream {
            stream: inner,
            max_message_size: max_message_size
        }
    }
}

impl<R: Reader> SmtpStream<R> {
    fn read_until(&mut self, end: &[u8], limit: uint) -> Result<Vec<u8>, SmtpStreamPrivateError> {
        let mut data: Vec<u8> = Vec::with_capacity(512);
        let mut last: Vec<u8> = Vec::with_capacity(end.len());
        let mut too_long = false;

        loop {
            // If we have previously read as much data as possible and still are not finished
            // reading, stop here.
            if data.len() >= limit && !too_long {
                too_long = true;
            }

            // Try to get more data and see if we have got it all.
            let byte_res = self.stream.read_byte();
            match byte_res {
                Ok(b) => {
                    // Only keep remaining data if we are allowed too. Otherwise, discard it too
                    // avoid out of memory errors.
                    if !too_long {
                        data.push(b);
                    }

                    // Update our last bytes for later comparison.
                    if last.len() == end.len() {
                        last.remove(0).unwrap();
                    }
                    last.push(b);

                    // Let's see if we have read all the data.
                    if last.as_slice() == end {
                        // If we didn't have too much data, we'll remove the end form it to clean up.
                        if !too_long {
                            let data_len = data.len();
                            data.truncate(data_len - end.len());
                        }
                        break;
                    }
                },
                Err(err) => {
                    return Err(PrivateReadFailed(err))
                }
            }
        }
        if too_long {
            Err(TooLong)
        } else {
            Ok(data)
        }
    }

    /// Read the data section of an email. Ends with "<CRLF>.<CRLF>".
    pub fn read_data(&mut self) -> Result<Vec<u8>, SmtpStreamError> {
        let max_data = self.max_message_size;
        match self.read_until(&[13, 10, 46, 13, 10], max_data) {
            Ok(data) => Ok(data),
            Err(err) => {
                match err {
                    TooLong => Err(TooMuchData),
                    PrivateReadFailed(err) => Err(ReadFailed(err))
                }
            }
        }
    }

    /// Read one line of input.
    pub fn read_line(&mut self) -> Result<Vec<u8>, SmtpStreamError> {
        match self.read_until(&[13, 10], MAX_LINE_SIZE) {
            Ok(data) => Ok(data),
            Err(err) => {
                match err {
                    TooLong => Err(LineTooLong),
                    PrivateReadFailed(err) => Err(ReadFailed(err))
                }
            }
        }
    }

}

impl<W: Writer> SmtpStream<W> {
    /// Write a line ended with <CRLF>.
    pub fn write_line(&mut self, s: &str) -> Result<(), SmtpStreamError> {
        match self.stream.write_str(format!("{}\r\n", s).as_slice()) {
            Ok(_) => Ok(()),
            Err(err) => Err(WriteFailed(err))
        }
    }
}

#[test]
fn test_new() {
    // Testing via `test_read_line()`.
}

#[test]
fn test_read_data() {
    let mut path: Path;
    let mut file: File;
    let mut stream: SmtpStream<File>;
    let mut expected: String;

    path = Path::new("tests/stream/data_ok");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    expected = String::from_utf8_lossy(stream.read_data().unwrap().as_slice()).into_string();
    assert_eq!("Hello world!\nBlabla\n", expected.as_slice());
}

#[test]
fn test_write_line() {
    // Use a block so the file gets closed at the end of it.
    {
        let mut path_write: Path;
        let mut file_write: File;
        let mut stream: SmtpStream<File>;

        path_write = Path::new("tests/stream/write_line");
        file_write = File::open_mode(&path_write, Truncate, Write).unwrap();
        stream = SmtpStream::new(file_write, 65536);
        stream.write_line("HelloWorld").unwrap();
        stream.write_line("ByeBye").unwrap();
    }
    let mut path_read: Path;
    let mut file_read: File;
    let mut expected: String;

    path_read = Path::new("tests/stream/write_line");
    file_read = File::open_mode(&path_read, Open, Read).unwrap();
    expected = file_read.read_to_string().unwrap();
    assert_eq!("HelloWorld\r\nByeBye\r\n", expected.as_slice());
}

#[test]
fn test_read_line() {
    let mut path: Path;
    let mut file: File;
    let mut stream: SmtpStream<File>;
    let mut expected: String;

    path = Path::new("tests/stream/0line1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line2");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/0line3");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/1line2");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "hello world!");
    assert!(!stream.read_line().is_ok());

    path = Path::new("tests/stream/2lines1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "hello world!");
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string().as_slice(), "bye bye world!");
    assert!(!stream.read_line().is_ok());

    expected = String::from_char(62, 'x');
    path = Path::new("tests/stream/xlines1");
    file = File::open(&path).unwrap();
    stream = SmtpStream::new(file, 65536);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert_eq!(String::from_utf8_lossy(stream.read_line().unwrap().as_slice()).into_string(), expected);
    assert!(!stream.read_line().is_ok());
}
<|endoftext|>


<commit_before>use std::net::{UdpSocket, SocketAddr};
use std::io::{Error};

/// Client socket for statsd servers.
///
/// After creating a metric you can use `Client`
/// to send metrics to the configured statsd server
///
/// # Example
///
/// Creating a client and sending metrics is easy.
///
/// ```ignore
/// use statsd::client::Client;
///
/// let client = Client::new("127.0.0.1:8125", "myapp.");
/// client.incr("some.metric.completed");
/// ```
pub struct Client {
    socket: UdpSocket,
    server_addr: SocketAddr,
    prefix: String
}

impl Client {
    /// Construct a new statsd client given an host/port & prefix
    pub fn new(host: &str, prefix: &str) -> Result<Client, Error> {
        let addr = SocketAddr.from_str(host);
        let mut socket = try!(UdpSocket::bind(addr));
        Ok(Client {socket: socket, prefix: prefix.to_string(), server_addr: addr})
    }

    /// Increment a metric by 1
    ///
    /// ```ignore
    /// # Increment a given metric by 1.
    /// client.incr("metric.completed");
    /// ```
    ///
    /// This modifies a counter with an effective sampling
    /// rate of 1.0.
    pub fn incr(&mut self, metric: &str) {
        self.count(metric, 1.0);
    }

    /// Decrement a metric by -1
    ///
    /// ```ignore
    /// # Decrement a given metric by 1
    /// client.decr("metric.completed");
    /// ```
    ///
    /// This modifies a counter with an effective sampling
    /// rate of 1.0.
    pub fn decr(&mut self, metric: &str) {
        self.count(metric, -1.0);
    }

    /// Modify a counter by `value`.
    ///
    /// Will increment or decrement a counter by `value` with
    /// a sampling rate of 1.0.
    ///
    /// ```ignore
    /// # Increment by 12
    /// client.count("metric.completed", 12);
    /// ```
    pub fn count(&mut self, metric: &str, value: usize) {
        let data = format!("{}.{}:{}|c", self.prefix, metric, value);
        self.send(data);
    }

    /// Data goes in, data comes out.
    fn send(&mut self, data: &str) {
        let _ = self.socket.send_to(data.as_bytes(), self.dest);
    }
}
<commit_msg>Add commented out functions for a few things.<commit_after>use std::net::{UdpSocket, SocketAddr};
use std::io::Error;
use std::str::FromStr;
// use std::time::Duration;

/// Client socket for statsd servers.
///
/// After creating a metric you can use `Client`
/// to send metrics to the configured statsd server
///
/// # Example
///
/// Creating a client and sending metrics is easy.
///
/// ```ignore
/// use statsd::client::Client;
///
/// let client = Client::new("127.0.0.1:8125", "myapp.");
/// client.incr("some.metric.completed");
/// ```
pub struct Client {
    socket: UdpSocket,
    server_addr: SocketAddr,
    prefix: String
}

impl Client {
    /// Construct a new statsd client given an host/port & prefix
    pub fn new(host: &str, prefix: &str) -> Result<Client, Error> {
        let addr = SocketAddr::from_str(host).ok().unwrap();
        let mut socket = try!(UdpSocket::bind(addr));
        Ok(Client {socket: socket, prefix: prefix.to_string(), server_addr: addr})
    }

    /// Increment a metric by 1
    ///
    /// ```ignore
    /// # Increment a given metric by 1.
    /// client.incr("metric.completed");
    /// ```
    ///
    /// This modifies a counter with an effective sampling
    /// rate of 1.0.
    pub fn incr(&mut self, metric: &str) {
        self.count(metric, 1.0);
    }

    /// Decrement a metric by -1
    ///
    /// ```ignore
    /// # Decrement a given metric by 1
    /// client.decr("metric.completed");
    /// ```
    ///
    /// This modifies a counter with an effective sampling
    /// rate of 1.0.
    pub fn decr(&mut self, metric: &str) {
        self.count(metric, -1.0);
    }

    /// Modify a counter by `value`.
    ///
    /// Will increment or decrement a counter by `value` with
    /// a sampling rate of 1.0.
    ///
    /// ```ignore
    /// # Increment by 12
    /// client.count("metric.completed", 12);
    /// ```
    pub fn count(&mut self, metric: &str, value: f64) {
        let data = format!("{}.{}:{}|c", self.prefix, metric, value);
        self.send(data);
    }

    /// Modify a counter by `value` only x% of the time.
    ///
    /// Will increment or decrement a counter by `value` with
    /// a custom sampling rate.
    ///
    ///
    /// ```ignore
    /// # Increment by 4 50% of the time.
    /// client.sampled_count("metric.completed", 4, 0.5);
    /// ```
    pub fn sampled_count(&mut self, metric: &str, value: f64, rate: f64) {
        /* TODO figure out how to generate random numbers properly.
        if f64::rand() < rate {
            return
        }
        let data = format!("{}.{}:{}|c", self.prefix, metric, value);
        self.send(data);
        */
    }

    /// Set a gauge value.
    ///
    /// ```ignore
    /// # set a gauge to 9001
    /// client.gauge("power_level.observed", 9001);
    /// ```
    pub fn gauge(&mut self, metric: &str, value: f64) {
        let data = format!("{}.{}:{}|g", self.prefix, metric, value);
        self.send(data);
    }

    /// Send a timer value.
    ///
    /// The value is expected to be in ms.
    ///
    /// ```ignore
    /// # pass a duration value
    /// client.timer("response.duration", 10.123);
    /// ```
    pub fn timer(&mut self, metric: &str, value: f64) {
        let data = format!("{}.{}:{}|ms", self.prefix, metric, value);
        self.send(data);
    }

    /*
     TODO this relies on unstable API's - figure out how to disable the warnings.
    /// Time a block of code.
    ///
    /// The passed closure will be timed and executed. The block's
    /// duration will be sent as a metric.
    ///
    /// ```ignore
    /// # pass a duration value
    /// client.time("response.duration", || {
    ///   # Your code here.
    /// });
    /// ```
    pub fn time<F>(&mut self, metric: &str, callable: F) where F : Fn() {
        let duration = {
            Duration::span(callable)
        };
        let data = format!("{}.{}:{}|ms", self.prefix, metric, duration.num_seconds());
        self.send(data);
    }
    */

    /// Send data along the UDP socket.
    fn send(&mut self, data: String) {
        let _ = self.socket.send_to(data.as_bytes(), self.server_addr);
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Debug};
use std::net::SocketAddr;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use std::collections::VecDeque;

use futures::sync::mpsc::Sender;
use futures::{Future, Sink};

use mqtt3::*;

pub struct ClientState {
    pub last_pkid: PacketIdentifier,
    /// For QoS 1. Stores outgoing publishes
    pub outgoing_pub: VecDeque<Box<Message>>,
    /// For QoS 2. Stores outgoing publishes
    pub outgoing_rec: VecDeque<Box<Message>>,
    /// For QoS 2. Stores outgoing release
    pub outgoing_rel: VecDeque<PacketIdentifier>,
    /// For QoS 2. Stores outgoing comp
    pub outgoing_comp: VecDeque<PacketIdentifier>,
}

impl ClientState {
    pub fn new() -> Self {
        ClientState {
            last_pkid: PacketIdentifier(0),
            outgoing_pub: VecDeque::new(),
            outgoing_rec: VecDeque::new(),
            outgoing_rel: VecDeque::new(),
            outgoing_comp: VecDeque::new(),
        }
    }
}

#[derive(Clone)]
pub struct Client {
    pub id: String,
    pub addr: SocketAddr,
    pub tx: Sender<Packet>,

    pub state: Rc<RefCell<ClientState>>,
}

impl Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, " [  id = {:?}, address = {:?}  ]", self.id, self.addr)
    }
}

impl Client {
    pub fn new(id: &str, addr: SocketAddr, tx: Sender<Packet>) -> Client {
        let state = ClientState::new();
        Client {
            addr: addr,
            id: id.to_string(),
            tx: tx,

            state: Rc::new(RefCell::new(state)),
        }
    }

    pub fn next_pkid(&mut self) -> PacketIdentifier {
        let mut state = self.state.borrow_mut();
        let PacketIdentifier(mut pkid) = state.last_pkid;
        if pkid == 65535 {
            pkid = 0;
        }
        state.last_pkid = PacketIdentifier(pkid + 1);
        state.last_pkid
    }

    pub fn send(&self, packet: Packet) {
        let _ = self.tx.clone().send(packet).wait();
    }

    pub fn suback_packet(&self, pkid: PacketIdentifier, return_codes: Vec<SubscribeReturnCodes>) -> Packet {

        Packet::Suback(Box::new(Suback {
                                    pid: pkid,
                                    return_codes: return_codes,
                                }))
    }

    pub fn publish_packet(&mut self, topic: &str, qos: QoS, payload: Arc<Vec<u8>>, dup: bool, retain: bool) -> Packet {

        let pkid = if qos == QoS::AtMostOnce {
            None
        } else {
            Some(self.next_pkid())
        };

        Packet::Publish(Box::new(Publish {
                                     dup: dup,
                                     qos: qos,
                                     retain: retain,
                                     pid: pkid,
                                     topic_name: topic.to_owned(),
                                     payload: payload.clone(),
                                 }))

    }
}
<commit_msg>queue methods & unit tests for client<commit_after>use std::fmt::{self, Debug};
use std::net::SocketAddr;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use std::collections::VecDeque;

use futures::sync::mpsc::Sender;
use futures::{Future, Sink};

use mqtt3::*;

pub struct ClientState {
    pub last_pkid: PacketIdentifier,
    /// For QoS 1. Stores outgoing publishes
    pub outgoing_pub: VecDeque<Box<Publish>>,
    /// For QoS 2. Stores outgoing publishes
    pub outgoing_rec: VecDeque<Box<Message>>,
    /// For QoS 2. Stores outgoing release
    pub outgoing_rel: VecDeque<PacketIdentifier>,
    /// For QoS 2. Stores outgoing comp
    pub outgoing_comp: VecDeque<PacketIdentifier>,
}

impl ClientState {
    pub fn new() -> Self {
        ClientState {
            last_pkid: PacketIdentifier(0),
            outgoing_pub: VecDeque::new(),
            outgoing_rec: VecDeque::new(),
            outgoing_rel: VecDeque::new(),
            outgoing_comp: VecDeque::new(),
        }
    }
}

#[derive(Clone)]
pub struct Client {
    pub id: String,
    pub addr: SocketAddr,
    pub tx: Sender<Packet>,

    pub state: Rc<RefCell<ClientState>>,
}

impl Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, " [  id = {:?}, address = {:?}  ]", self.id, self.addr)
    }
}

impl Client {
    pub fn new(id: &str, addr: SocketAddr, tx: Sender<Packet>) -> Client {
        let state = ClientState::new();
        Client {
            addr: addr,
            id: id.to_string(),
            tx: tx,

            state: Rc::new(RefCell::new(state)),
        }
    }

    pub fn next_pkid(&self) -> PacketIdentifier {
        let mut state = self.state.borrow_mut();
        let PacketIdentifier(mut pkid) = state.last_pkid;
        if pkid == 65535 {
            pkid = 0;
        }
        state.last_pkid = PacketIdentifier(pkid + 1);
        state.last_pkid
    }

    // TODO: Find out if broker should drop message if a new massage with existing
    // pkid is received
    pub fn store_publish(&self, publish: Box<Publish>) {
        let mut state = self.state.borrow_mut();
        state.outgoing_pub.push_back(publish.clone());
    }

    pub fn remove_publish(&self, pkid: PacketIdentifier) {
        let mut state = self.state.borrow_mut();

        match state
                  .outgoing_pub
                  .iter()
                  .position(|x| x.pid == Some(pkid)) {
            Some(i) => state.outgoing_pub.remove(i),
            None => {
                // error!("Oopssss..unsolicited ack --> {:?}\n", puback);
                None
            }
        };
    }

    pub fn send(&self, packet: Packet) {
        let _ = self.tx.clone().send(packet).wait();
    }

    pub fn suback_packet(&self, pkid: PacketIdentifier, return_codes: Vec<SubscribeReturnCodes>) -> Packet {

        Packet::Suback(Box::new(Suback {
                                    pid: pkid,
                                    return_codes: return_codes,
                                }))
    }

    pub fn publish_packet(&mut self, topic: &str, qos: QoS, payload: Arc<Vec<u8>>, dup: bool, retain: bool) -> Packet {

        let pkid = if qos == QoS::AtMostOnce {
            None
        } else {
            Some(self.next_pkid())
        };

        Packet::Publish(Box::new(Publish {
                                     dup: dup,
                                     qos: qos,
                                     retain: retain,
                                     pid: pkid,
                                     topic_name: topic.to_owned(),
                                     payload: payload.clone(),
                                 }))

    }
}

#[cfg(test)]
mod test {
    use std::sync::Arc;
    use futures::sync::mpsc::{self, Receiver};
    use super::Client;
    use mqtt3::*;

    fn mock_client() -> (Client, Receiver<Packet>) {
        let (tx, rx) = mpsc::channel::<Packet>(8);
        (Client::new("mock-client", "127.0.0.1:80".parse().unwrap(), tx), rx)
    }

    #[test]
    fn next_pkid_roll() {
        let (client, ..) = mock_client();
        let mut pkid = PacketIdentifier(0);
        for _ in 0..65536 {
            pkid = client.next_pkid();
        }
        assert_eq!(PacketIdentifier(1), pkid);
    }

    #[test]
    fn add_and_remove_of_message_from_publish_queue() {
        let (client, ..) = mock_client();

        for i in 0..100 {
            let publish = Box::new(Publish {
                                       dup: false,
                                       qos: QoS::AtLeastOnce,
                                       retain: false,
                                       pid: Some(PacketIdentifier(i)),
                                       topic_name: "hello/world".to_owned(),
                                       payload: Arc::new(vec![1, 2, 3]),
                                   });

            client.store_publish(publish);
        }

        // sequential remove
        for i in 0..10 {
            client.remove_publish(PacketIdentifier(i));
        }

        let state = client.state.borrow_mut();

        for i in 0..10 {
            let index = state.outgoing_pub.iter().position(|x| x.pid == Some(PacketIdentifier(i)));
            assert_eq!(index, None);
        }

        // big sequential remove
        for i in 10..90 {
            client.remove_publish(PacketIdentifier(i));
        }

        for i in 10..90 {
            let index = state.outgoing_pub.iter().position(|x| x.pid == Some(PacketIdentifier(i)));
            assert_eq!(index, None);
        }
    }
}
<|endoftext|>