<commit_before>//! This module contains paths to types and functions Clippy needs to know
//! about.
//!
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.

pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"];
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"];
pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"];
pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];
pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"];
pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"];
pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 2] = ["f32", "EPSILON"];
pub const F64_EPSILON: [&str; 2] = ["f64", "EPSILON"];
pub const FILE: [&str; 3] = ["std", "fs", "File"];
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FN: [&str; 3] = ["core", "ops", "Fn"];
pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
pub const HASH: [&str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INTO: [&str; 3] = ["core", "convert", "Into"];
pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
pub const LATE_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "LateContext"];
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"];
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"];
pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"];
pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"];
pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
pub const OPTION: [&str; 3] = ["core", "option", "Option"];
pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
pub const PATH: [&str; 3] = ["std", "path", "Path"];
pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
pub const RESULT: [&str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"];
pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
pub const STRING: [&str; 3] = ["alloc", "string", "String"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
<commit_msg>Appease the almightly lord clippy, hallowed be thy name<commit_after>//! This module contains paths to types and functions Clippy needs to know
//! about.
//!
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.

pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"];
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"];
pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"];
pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];
pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"];
pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"];
pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 2] = ["f32", "EPSILON"];
pub const F64_EPSILON: [&str; 2] = ["f64", "EPSILON"];
pub const FILE: [&str; 3] = ["std", "fs", "File"];
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FN: [&str; 3] = ["core", "ops", "Fn"];
pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
pub const HASH: [&str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INTO: [&str; 3] = ["core", "convert", "Into"];
pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
pub const LATE_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "LateContext"];
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"];
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"];
pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"];
pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"];
pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
pub const OPTION: [&str; 3] = ["core", "option", "Option"];
pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
pub const PATH: [&str; 3] = ["std", "path", "Path"];
pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
pub const RESULT: [&str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"];
pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
pub const STRING: [&str; 3] = ["alloc", "string", "String"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
<|endoftext|>


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

use dispatcher::request::Request;
use dispatcher::response::ResponseSender;
use config::ContextConfig;

pub use self::linear::LinearContext;
pub use self::map::MapContext;
pub use self::base::BaseContext;
pub use self::base::BaseContextBuilder;
pub use self::context_map::ContextMap;

pub mod base;
pub mod context_map;
pub mod linear;
pub mod map;
#[cfg(test)]
mod test;

pub enum Context {
    Linear(LinearContext),
    Map(MapContext),
}

impl Context {
    pub fn on_event(&mut self, event: Request, responder: &mut ResponseSender) {
        match *self {
            Context::Linear(ref mut context) => context.on_event(event, responder),
            Context::Map(ref mut context) => context.on_event(event, responder),
        }
    }

    pub fn patterns(&self) -> &[String] {
        match *self {
            Context::Linear(ref context) => context.patterns(),
            Context::Map(ref context) => context.patterns(),
        }
    }
}

impl From<ContextConfig> for Context {
    fn from(config: ContextConfig) -> Context {
        let ContextConfig {name, uuid, conditions, context_id, actions, patterns} = config;

        let base = BaseContextBuilder::new(uuid, conditions);
        let base = base.name(name);
        let base = base.actions(actions);
        let base = base.build();

        if let Some(context_id) = context_id {
            Context::Map(MapContext::new(base, context_id))
        } else {
            Context::Linear(LinearContext::new(base))
        }
    }
}
<commit_msg>Context: use patters to construct BaseContext<commit_after>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use dispatcher::request::Request;
use dispatcher::response::ResponseSender;
use config::ContextConfig;

pub use self::linear::LinearContext;
pub use self::map::MapContext;
pub use self::base::BaseContext;
pub use self::base::BaseContextBuilder;
pub use self::context_map::ContextMap;

pub mod base;
pub mod context_map;
pub mod linear;
pub mod map;
#[cfg(test)]
mod test;

pub enum Context {
    Linear(LinearContext),
    Map(MapContext),
}

impl Context {
    pub fn on_event(&mut self, event: Request, responder: &mut ResponseSender) {
        match *self {
            Context::Linear(ref mut context) => context.on_event(event, responder),
            Context::Map(ref mut context) => context.on_event(event, responder),
        }
    }

    pub fn patterns(&self) -> &[String] {
        match *self {
            Context::Linear(ref context) => context.patterns(),
            Context::Map(ref context) => context.patterns(),
        }
    }
}

impl From<ContextConfig> for Context {
    fn from(config: ContextConfig) -> Context {
        let ContextConfig {name, uuid, conditions, context_id, actions, patterns} = config;

        let base = BaseContextBuilder::new(uuid, conditions);
        let base = base.name(name);
        let base = base.patterns(patterns);
        let base = base.actions(actions);
        let base = base.build();

        if let Some(context_id) = context_id {
            Context::Map(MapContext::new(base, context_id))
        } else {
            Context::Linear(LinearContext::new(base))
        }
    }
}
<|endoftext|>


<commit_before>use math::{Point, Vector};

#[derive(Copy, Clone)]
pub struct Ray {
    pub origin: Point,
    pub direction: Vector,
}

impl Ray {
    pub fn evaluate(&self, distance: f32) -> Point {
        self.origin + self.direction * distance
    }
}
<commit_msg>Add a `Ray::new()` method that ensures the direction is normalized<commit_after>use math::{Point, Vector};

use cgmath::prelude::*;
use cgmath::ApproxEq;

#[derive(Copy, Clone)]
pub struct Ray {
    pub origin: Point,
    pub direction: Vector,
}

impl Ray {
    pub fn new(origin: Point, direction: Vector) -> Ray {
        debug_assert!(direction.magnitude().approx_eq(&1.0),
                      "Ray direction is not normalized. (|{:?}| == {:?} != 1.0)",
                      direction,
                      direction.magnitude());

        Ray {
            origin: origin,
            direction: direction,
        }
    }

    pub fn evaluate(&self, distance: f32) -> Point {
        self.origin + self.direction * distance
    }
}
<|endoftext|>


<commit_before>use error::Error;
use edit::{EditCtx, EditResult, edit};
use builder::Builder;
use parser::{parse_cursor_pos, ParseError, ParseSuccess};

pub trait RunIO {

    fn write(&mut self, Vec<u8>) -> Result<(), Error>;
    fn read_byte(&mut self) -> Result<u8, Error>;
    fn read_seq(&mut self) -> Result<Vec<u8>, Error>;

    fn prompt(&mut self, w: Vec<u8>) -> Result<Vec<u8>, Error> {
        try!(self.write(w));
        self.read_seq()
    }

}

fn query_cursor_pos(io: &mut RunIO) -> Result<(u64, u64), Error> {
    let mut line = Builder::new();
    line.ask_cursor_pos();
    try!(io.write(line.build()));
    let mut seq = vec![];
    loop {
        match parse_cursor_pos(&seq) {
            Ok(ParseSuccess(pos, _)) => {
                return Ok(pos);
            },
            Err(ParseError::Error(_)) => {
                return Err(Error::ParseError);
            },
            Err(ParseError::Incomplete) => {
                let byte = try!(io.read_byte());
                seq.push(byte);
            }
        }
    }
}

fn protect_newline(io: &mut RunIO) -> Result<(), Error> {
    let (x, _) = try!(query_cursor_pos(io));
    if x > 1 {
        let mut line = Builder::new();
        line.invert_color();
        line.append("%\n");
        line.reset_color();
        try!(io.write(line.build()));
    }
    Ok(())
}

fn run_edit<'a>(mut ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    loop {
        match edit(&mut ctx) {
            EditResult::Cont(line) => {
                let bytes = try!(io.prompt(line));
                for byte in bytes.iter() {
                    ctx.fill(*byte);
                }
            },
            EditResult::Halt(res) => { return res; }
        }
    }
}

pub fn run<'a>(ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    try!(protect_newline(io));
    run_edit(ctx, io)
}

#[cfg(test)]
mod test {
    use encoding::all::ASCII;
    use super::super::error::Error;
    use super::super::edit::EditCtx;
    use super::super::history::History;
    use super::{RunIO, run_edit};
    use edit::EditMode;

    pub struct TestIO {
        input: Vec<u8>,
        output: Vec<u8>
    }

    impl RunIO for TestIO {
        fn write(&mut self, w: Vec<u8>) -> Result<(), Error> {
            self.output.extend(w);
            Ok(())
        }
        fn read_byte(&mut self) -> Result<u8, Error> {
            if self.input.len() > 0 {
                Ok(self.input.remove(0))
            } else {
                Err(Error::EndOfFile)
            }
        }

        fn read_seq(&mut self) -> Result<Vec<u8>, Error> {
            // XXX return more than one byte
            if self.input.len() > 0 {
                Ok(vec![self.input.remove(0)])
            } else {
                Err(Error::EndOfFile)
            }
        }
    }

    #[test]
    fn error_eof_on_empty_input() {
        let mut io = TestIO { input: vec![], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Err(Error::EndOfFile));
    }

    #[test]
    fn ok_empty_after_return() {
        let mut io = TestIO { input: vec![13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("".to_string()));
    }

    #[test]
    fn ok_ascii_after_return() {
        let mut io = TestIO { input: vec![65, 66, 67, 13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("ABC".to_string()));
    }

    /// Make sure integers don't overflow in vi mode when using large command counts.
    #[test]
    fn no_integer_overflow() {
        let mut input_vec = vec![27];
        for _ in 0..50 {
            input_vec.push('9' as u8);
        }
        input_vec.push(13);
        let mut io = TestIO { input: input_vec, output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Vi);
        assert_eq!(run_edit(ctx, &mut io), Ok("".to_string()));
    }
}
<commit_msg>add tests for vi mode commands<commit_after>use error::Error;
use edit::{EditCtx, EditResult, edit};
use builder::Builder;
use parser::{parse_cursor_pos, ParseError, ParseSuccess};

pub trait RunIO {

    fn write(&mut self, Vec<u8>) -> Result<(), Error>;
    fn read_byte(&mut self) -> Result<u8, Error>;
    fn read_seq(&mut self) -> Result<Vec<u8>, Error>;

    fn prompt(&mut self, w: Vec<u8>) -> Result<Vec<u8>, Error> {
        try!(self.write(w));
        self.read_seq()
    }

}

fn query_cursor_pos(io: &mut RunIO) -> Result<(u64, u64), Error> {
    let mut line = Builder::new();
    line.ask_cursor_pos();
    try!(io.write(line.build()));
    let mut seq = vec![];
    loop {
        match parse_cursor_pos(&seq) {
            Ok(ParseSuccess(pos, _)) => {
                return Ok(pos);
            },
            Err(ParseError::Error(_)) => {
                return Err(Error::ParseError);
            },
            Err(ParseError::Incomplete) => {
                let byte = try!(io.read_byte());
                seq.push(byte);
            }
        }
    }
}

fn protect_newline(io: &mut RunIO) -> Result<(), Error> {
    let (x, _) = try!(query_cursor_pos(io));
    if x > 1 {
        let mut line = Builder::new();
        line.invert_color();
        line.append("%\n");
        line.reset_color();
        try!(io.write(line.build()));
    }
    Ok(())
}

fn run_edit<'a>(mut ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    loop {
        match edit(&mut ctx) {
            EditResult::Cont(line) => {
                let bytes = try!(io.prompt(line));
                for byte in bytes.iter() {
                    ctx.fill(*byte);
                }
            },
            EditResult::Halt(res) => { return res; }
        }
    }
}

pub fn run<'a>(ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    try!(protect_newline(io));
    run_edit(ctx, io)
}

#[cfg(test)]
mod test {
    use encoding::all::ASCII;
    use super::super::error::Error;
    use super::super::edit::EditCtx;
    use super::super::history::History;
    use super::{RunIO, run_edit};
    use edit::EditMode;

    pub struct TestIO {
        input: Vec<u8>,
        output: Vec<u8>
    }

    impl RunIO for TestIO {
        fn write(&mut self, w: Vec<u8>) -> Result<(), Error> {
            self.output.extend(w);
            Ok(())
        }
        fn read_byte(&mut self) -> Result<u8, Error> {
            if self.input.len() > 0 {
                Ok(self.input.remove(0))
            } else {
                Err(Error::EndOfFile)
            }
        }

        fn read_seq(&mut self) -> Result<Vec<u8>, Error> {
            // XXX return more than one byte
            if self.input.len() > 0 {
                Ok(vec![self.input.remove(0)])
            } else {
                Err(Error::EndOfFile)
            }
        }
    }

    #[test]
    fn error_eof_on_empty_input() {
        let mut io = TestIO { input: vec![], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Err(Error::EndOfFile));
    }

    #[test]
    fn ok_empty_after_return() {
        let mut io = TestIO { input: vec![13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("".to_string()));
    }

    #[test]
    fn ok_ascii_after_return() {
        let mut io = TestIO { input: vec![65, 66, 67, 13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("ABC".to_string()));
    }

    /// Make sure integers don't overflow in vi mode when using large command counts.
    #[test]
    fn no_integer_overflow() {
        let mut input_vec = vec![27];
        for _ in 0..50 {
            input_vec.push('9' as u8);
        }
        input_vec.push(13);
        let mut io = TestIO { input: input_vec, output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Vi);
        assert_eq!(run_edit(ctx, &mut io), Ok("".to_string()));
    }

    macro_rules! vi_cmd_vec {
        ($str:expr) => {{
            let input_str = $str;
            let mut input_vec = Vec::with_capacity(input_str.len());
            input_vec.extend(input_str.as_bytes());
            input_vec
        }}
    }

    macro_rules! test_vi_cmds {
        ($cmd_str:expr, $result:expr) => {{
            let mut io = TestIO { input: vi_cmd_vec!($cmd_str), output: vec![] };
            let h = History::new();
            let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Vi);
            assert_eq!(run_edit(ctx, &mut io), Ok($result.to_owned()));
        }}
    }

    /// Test some vi commands.
    #[test]
    fn vi_commands() {
        test_vi_cmds!("abc 123\x1bbdw\x0d", "abc ");
        test_vi_cmds!("Everything except the last char will be deleted.\x1bd0\x0d", ".");
        test_vi_cmds!("delete everything\x1b0d$\x0d", "");
        test_vi_cmds!("abc\x1b03r \x0d", "   ");
        test_vi_cmds!("this is test\x1b02ea a\x0d", "this is a test");
        test_vi_cmds!("this is a\x1b0A test\x0d", "this is a test");
        test_vi_cmds!("this is test\x1b02wia \x0d", "this is a test");
        test_vi_cmds!("this is test\x1b3hia \x0d", "this is a test");
        test_vi_cmds!("this is test\x1bhhhia \x0d", "this is a test");
        test_vi_cmds!("this is a test\x1b0ftx\x0d", "this is a est");
        test_vi_cmds!("this is a test\x1b0ttx\x0d", "this is atest");
        test_vi_cmds!("this is a test\x1b10x\x0d", "this is a tes");
        test_vi_cmds!("is a test\x1bIthis \x0d", "this is a test");
        test_vi_cmds!("this is a test\x1b0d2ti\x0d", "is a test");
        test_vi_cmds!("this is a test\x1b0d2fi\x0d", "s a test");
        test_vi_cmds!("this is a test\x1bdT \x0d", "this is a t");
        test_vi_cmds!("this is a test\x1bdF \x0d", "this is at");
        test_vi_cmds!("this is a test\x1bbbD\x0d", "this is ");
        test_vi_cmds!("delete everything\x1bdd\x0d", "");
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;

use connection::PortRange;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use rustc_serialize::hex::FromHex;

pub struct Connection {
    hostname: String,
    path: PathBuf,
    port_range: PortRange,
}

pub struct Response {
    pub version: usize,
    pub addr: SocketAddr,
    pub key: Vec<u8>,
}

pub struct Error {
    pub error_type: ErrorType,
    pub msg: String,
}

pub enum ErrorType {
    SshMissing,
    SshError,
    Server(usize),
    BadServerResponse
}

impl Error {
    fn new<S: Into<String>>(error_type: ErrorType, msg: S) -> Error {
        Error {
            error_type: error_type,
            msg: msg.into(),
        }
    }
}

impl Connection {
    pub fn new<S: Into<String>>(hostname: S, path: PathBuf, port_range: &PortRange) -> Connection {
        Connection {
            hostname: hostname.into(),
            path: path,
            port_range: port_range.to_owned(),
        }
    }

    fn command_exists(command: &str) -> bool {
        match Command::new("which").arg(command).output() {
            Ok(output) => output.status.success(),
            Err(_) => false,
        }
    }

    pub fn connect(&self) -> Result<Response, Error> {
        if !Connection::command_exists("ssh") {
            return Err(Error::new(ErrorType::SshMissing, "`ssh` is required!"));
        }

        let cmd = format!("shoop -s '{}' -p {}",
                          self.path.to_string_lossy(),
                          self.port_range);
        debug!("👉  ssh {} {}", &self.hostname, cmd);
        let output = try!(Command::new("ssh")
            .arg(&self.hostname)
            .arg(cmd)
            .output()
            .map_err(|e| {
                Error::new(ErrorType::SshError,
                           format!("failed to execute process: {}", e))
            }));

        let raw_response = try!(String::from_utf8(output.stdout).map_err(|e| {
            Error::new(ErrorType::BadServerResponse,
                       format!("couldn't decode server response: {}", e))
        }));

        let response = raw_response.trim();

        if response.starts_with("shooperr ") {
            let errblock = &response["shooperr ".len()..];
            let (code, msg) = errblock.split_at(errblock.find(' ').unwrap());
            let code_int = try!(code.parse::<usize>().map_err(|_| {
                Error::new(ErrorType::BadServerResponse,
                           format!("server gave bad error code: {}", code))
            }));

            return Err(Error::new(ErrorType::Server(code_int), msg));
        }

        let info: Vec<&str> = response.split(' ').collect();
        if info.len() != 5 {
            return Err(Error::new(ErrorType::BadServerResponse,
                                  format!("{}\n{}: {}",
                                          "unexpected response length from server",
                                          "server said",
                                          response)));
        }

        let (magic, version, ip, port, keyhex) = (info[0], info[1], info[2], info[3], info[4]);
        if magic != "shoop" {
            return Err(Error::new(ErrorType::BadServerResponse,
                                  "unexpected response start from server"));
        }

        let version_code = try!(version.parse::<usize>().map_err(|_| {
            Error::new(ErrorType::BadServerResponse,
                       "unparseable version")
        }));

        if version_code != 0 {
            return Err(Error::new(ErrorType::BadServerResponse,
                                  "unsupported protocol version"));
        }

        let mut keybytes = Vec::with_capacity(32);
        keybytes.extend_from_slice(&keyhex.from_hex().unwrap()[..]);
        let addr: SocketAddr = try!(SocketAddr::from_str(&format!("{}:{}", ip, port)[..])
            .map_err(|_| {
                Error::new(ErrorType::BadServerResponse,
                           "ip/port server sent aren't nice looking")
            }));

        Ok(Response {
            version: version_code,
            addr: addr,
            key: keybytes,
        })
    }
}
<commit_msg>warn on weak SSH cipher choices<commit_after>extern crate rustc_serialize;

use connection::PortRange;
use std::collections::HashMap;
use std::io;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::process::{Command, Output};
use std::str::FromStr;
use rustc_serialize::hex::FromHex;

lazy_static! {
    static ref SECURE_OPTS_MAP: HashMap<&'static str, &'static str> = {
        let mut m = HashMap::new();
        m.insert("Protocol", "2");
        m.insert("Ciphers", "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr");
        m.insert("KexAlgorithms", "curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256");
        m.insert("MACs", "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com");
        m
    };

    static ref SECURE_OPTS: Vec<String> = ssh_args_for_config(&SECURE_OPTS_MAP);
}

fn ssh_args_for_config(map: &HashMap<&'static str, &'static str>) -> Vec<String> {
    let mut args: Vec<String> = Vec::new();
    for (key, val) in map {
        args.push("-o".into());
        args.push(format!("{}={}", key, val));
    }
    args
}

pub struct Connection {
    hostname: String,
    path: PathBuf,
    port_range: PortRange,
}

pub struct Response {
    pub version: usize,
    pub addr: SocketAddr,
    pub key: Vec<u8>,
}

pub struct Error {
    pub error_type: ErrorType,
    pub msg: String,
}

pub enum ErrorType {
    SshMissing,
    SshError,
    Server(usize),
    BadServerResponse
}

impl Error {
    fn new<S: Into<String>>(error_type: ErrorType, msg: S) -> Error {
        Error {
            error_type: error_type,
            msg: msg.into(),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::new(ErrorType::SshError,
                   format!("failed to execute ssh: {}", e))
    }
}

impl Connection {
    pub fn new<S: Into<String>>(hostname: S, path: PathBuf, port_range: &PortRange) -> Connection {
        Connection {
            hostname: hostname.into(),
            path: path,
            port_range: port_range.to_owned(),
        }
    }

    fn verify_command_exists(command: &str) -> Result<(), Error> {
        match Command::new("which").arg(command).output() {
            Ok(output) => {
                if output.status.success() {
                    return Ok(());
                }
            }, _ => {},
        }
        Err(Error::new(ErrorType::SshMissing, "`ssh` is required!"))
    }

    fn exec(&self, extra_args: &Vec<String>) -> Result<Output, Error> {
        try!(Self::verify_command_exists("ssh"));

        let cmd = format!("shoop -s '{}' -p {}",
                          self.path.to_string_lossy(),
                          self.port_range);
        debug!("👉  ssh {} {}", &self.hostname, cmd);
        let mut command = Command::new("ssh");
        for arg in extra_args {
            command.arg(&arg);
        }
        let output = try!(command.arg(&self.hostname)
               .arg(cmd)
               .output());

        if !output.status.success() {
            Err(Error::new(ErrorType::SshError, "ssh returned failure exit code"))
        } else {
            Ok(output)
        }
    }

    pub fn connect(&self) -> Result<Response, Error> {

        let output = match self.exec(&SECURE_OPTS) {
            Ok(output) => output,
            _ => {
                println!("\n");
                error!("strong SSH crypto appears to be unavailable.");
                error!("this session is sketch, and shoop may simply refuse to work in the future.\n");
                try!(self.exec(&Vec::new()))
            }
        };

        let raw_response = try!(String::from_utf8(output.stdout).map_err(|e| {
            Error::new(ErrorType::BadServerResponse,
                       format!("couldn't decode server response: {}", e))
        }));

        let response = raw_response.trim();

        if response.starts_with("shooperr ") {
            let errblock = &response["shooperr ".len()..];
            let (code, msg) = errblock.split_at(errblock.find(' ').unwrap());
            let code_int = try!(code.parse::<usize>().map_err(|_| {
                Error::new(ErrorType::BadServerResponse,
                           format!("server gave bad error code: {}", code))
            }));

            return Err(Error::new(ErrorType::Server(code_int), msg));
        }

        let info: Vec<&str> = response.split(' ').collect();
        if info.len() != 5 {
            return Err(Error::new(ErrorType::BadServerResponse,
                                  format!("{}\n{}: {}",
                                          "unexpected response length from server",
                                          "server said",
                                          response)));
        }

        let (magic, version, ip, port, keyhex) = (info[0], info[1], info[2], info[3], info[4]);
        if magic != "shoop" {
            return Err(Error::new(ErrorType::BadServerResponse,
                                  "unexpected response start from server"));
        }

        let version_code = try!(version.parse::<usize>().map_err(|_| {
            Error::new(ErrorType::BadServerResponse,
                       "unparseable version")
        }));

        if version_code != 0 {
            return Err(Error::new(ErrorType::BadServerResponse,
                                  "unsupported protocol version"));
        }

        let mut keybytes = Vec::with_capacity(32);
        keybytes.extend_from_slice(&keyhex.from_hex().unwrap()[..]);
        let addr: SocketAddr = try!(SocketAddr::from_str(&format!("{}:{}", ip, port)[..])
            .map_err(|_| {
                Error::new(ErrorType::BadServerResponse,
                           "ip/port server sent aren't nice looking")
            }));

        Ok(Response {
            version: version_code,
            addr: addr,
            key: keybytes,
        })
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use rand::OsRng;
use num::traits::FromPrimitive;

use tls_result::{TlsResult, TlsError, TlsErrorKind};
use tls_result::TlsErrorKind::{UnexpectedMessage, RecordOverflow, BadRecordMac, AlertReceived};
use alert::{self, Alert};
use handshake::{Handshake, HandshakeBuffer};
use util::u64_be_array;
use util::{ReadExt, WriteExt};
use cipher::{Encryptor, Decryptor};
use tls_item::TlsItem;

use self::ContentType::{ChangeCipherSpecTy, AlertTy, HandshakeTy, ApplicationDataTy};
use self::Message::{HandshakeMessage, ChangeCipherSpecMessage, AlertMessage,
                    ApplicationDataMessage};

pub static TLS_VERSION: (u8, u8) = (3, 3);

enum_from_primitive! {
    #[repr(u8)]
    #[derive(Copy, Clone, PartialEq, Debug)]
    pub enum ContentType {
        ChangeCipherSpecTy = 20,
        AlertTy = 21,
        HandshakeTy = 22,
        ApplicationDataTy = 23,
        // HeartBeat = 24, RFC 6520 extension :-)
    }
}

/// maximum length of Record (excluding content_type, version, length fields)
pub const RECORD_MAX_LEN: usize = 1 << 14;

/// maximum length of EncryptedRecord (excluding content_type, version, length fields)
pub const ENC_RECORD_MAX_LEN: usize = (1 << 14) + 2048;

/// corresponds to `TLSPlaintext` in Section 6.2.1.
pub struct Record {
    pub content_type: ContentType,
    pub ver_major: u8,
    pub ver_minor: u8,
    // fragment length < 2^14
    pub fragment: Vec<u8>,
}

impl Record {
    pub fn new(content_type: ContentType, ver_major: u8, ver_minor: u8, fragment: Vec<u8>) -> Record {
        let len = fragment.len();
        if len > RECORD_MAX_LEN {
            panic!("record too long: {} > 2^14", len);
        }

        Record {
            content_type: content_type,
            ver_major: ver_major,
            ver_minor: ver_minor,
            fragment: fragment,
        }
    }
}

/// corresponds to `TLSCiphertext` in Section 6.2.3.
pub struct EncryptedRecord {
    pub content_type: ContentType,
    pub ver_major: u8,
    pub ver_minor: u8,
    // fragment length < 2^14 + 2048
    pub fragment: Vec<u8>,
}

impl EncryptedRecord {
    pub fn new(content_type: ContentType, ver_major: u8, ver_minor: u8, fragment: Vec<u8>) -> EncryptedRecord {
        let len = fragment.len();
        if len > ENC_RECORD_MAX_LEN {
            panic!("record too long: {} > 2^14 + 2048", len);
        }

        EncryptedRecord {
            content_type: content_type,
            ver_major: ver_major,
            ver_minor: ver_minor,
            fragment: fragment,
        }
    }
}

pub struct RecordWriter<W: Write> {
    writer: W,
    // if encryptor is None, handshake is not done yet.
    encryptor: Option<Box<Encryptor + Send + 'static>>,
    write_count: u64,
}

impl<W: Write> RecordWriter<W> {
    pub fn new(writer: W) -> RecordWriter<W> {
        RecordWriter {
            writer: writer,
            encryptor: None,
            write_count: 0,
        }
    }

    #[inline]
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    pub fn set_encryptor(&mut self, encryptor: Box<Encryptor + Send + 'static>) {
        self.encryptor = Some(encryptor);
        self.write_count = 0;
    }

    pub fn write_record(&mut self, record: Record) -> TlsResult<()> {
        let enc_record = match self.encryptor {
            None => EncryptedRecord::new(record.content_type,
                                         record.ver_major,
                                         record.ver_minor,
                                         record.fragment),
            Some(ref mut encryptor) => {
                let seq_num = u64_be_array(self.write_count);

                let mut ad = Vec::new();
                ad.extend(&seq_num);
                ad.push(record.content_type as u8);
                ad.push(record.ver_major);
                ad.push(record.ver_minor);
                let frag_len = record.fragment.len() as u16;
                ad.push((frag_len >> 8) as u8);
                ad.push(frag_len as u8);

                let encrypted_fragment = encryptor.encrypt(&seq_num,
                                                           &record.fragment,
                                                           &ad);
                EncryptedRecord::new(record.content_type,
                                     record.ver_major,
                                     record.ver_minor,
                                     encrypted_fragment)
            }
        };
        let fragment_len = enc_record.fragment.len() as u16;

        try!(self.writer.write_u8(enc_record.content_type as u8));

        let (major, minor) = TLS_VERSION;
        try!(self.writer.write_u8(major));
        try!(self.writer.write_u8(minor));

        try!(self.writer.write_be_u16(fragment_len));
        try!(self.writer.write_all(&enc_record.fragment));

        self.write_count += 1;

        Ok(())
    }

    pub fn write_data(&mut self, ty: ContentType, data: &[u8]) -> TlsResult<()> {
        let (major, minor) = TLS_VERSION;
        // TODO: configurable maxlen
        for fragment in data.chunks(RECORD_MAX_LEN) {
            let fragment = fragment.to_vec();
            let record = Record::new(ty, major, minor, fragment);
            try!(self.write_record(record));
        }

        Ok(())
    }

    pub fn write_handshake(&mut self, handshake: &Handshake) -> TlsResult<()> {
        let mut data = Vec::new();
        try!(handshake.tls_write(&mut data));
        self.write_data(HandshakeTy, &data)
    }

    pub fn write_alert(&mut self, alert: &Alert) -> TlsResult<()> {
        let mut data = Vec::new();
        try!(alert.tls_write(&mut data));
        self.write_data(AlertTy, &data)
    }

    pub fn write_change_cipher_spec(&mut self) -> TlsResult<()> {
        self.write_data(ChangeCipherSpecTy, &[1u8])
    }

    pub fn write_application_data(&mut self, data: &[u8]) -> TlsResult<()> {
        if self.encryptor.is_none() {
            panic!("attempted to write ApplicationData before handshake");
        }
        self.write_data(ApplicationDataTy, data)
    }
}

pub enum Message {
    HandshakeMessage(Handshake),
    ChangeCipherSpecMessage,
    AlertMessage(Alert),
    ApplicationDataMessage(Vec<u8>),
}

pub struct RecordReader<R: ReadExt> {
    reader: R,
    // if decryptor is none, handshake is not done yet.
    decryptor: Option<Box<Decryptor + Send + 'static>>,
    read_count: u64,
    handshake_buffer: HandshakeBuffer,
}

impl<R: ReadExt> RecordReader<R> {
    pub fn new(reader: R) -> RecordReader<R> {
        RecordReader {
            reader: reader,
            decryptor: None,
            read_count: 0,
            handshake_buffer: HandshakeBuffer::new(),
        }
    }

    #[inline]
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.reader
    }

    pub fn set_decryptor(&mut self, decryptor: Box<Decryptor + Send + 'static>) {
        self.decryptor = Some(decryptor);
        self.read_count = 0;
    }

    fn read_record(&mut self) -> TlsResult<Record> {
        let ty = try!(self.reader.read_u8());
        let ty = {
            let ct: Option<ContentType> = FromPrimitive::from_u8(ty);
            match ct {
                Some(ty) => ty,
                None => return tls_err!(UnexpectedMessage, "unexpected ContentType: {}", ty),
            }
        };

        let major = try!(self.reader.read_u8());
        let minor = try!(self.reader.read_u8());

        let len = {
            let len = try!(self.reader.read_be_u16()) as usize;
            if len > ENC_RECORD_MAX_LEN {
                return tls_err!(RecordOverflow, "TLSEncryptedText too long: {}", len);
            }
            len
        };

        let fragment = try!(self.reader.read_exact(len as usize));
        let enc_record = EncryptedRecord::new(ty, major, minor, fragment);

        let record = match self.decryptor {
            None => Record::new(enc_record.content_type,
                                enc_record.ver_major,
                                enc_record.ver_minor,
                                enc_record.fragment),
            Some(ref mut decryptor) => {
                let seq_num = u64_be_array(self.read_count);

                let mut ad = Vec::new();
                ad.extend(&seq_num);
                ad.push(enc_record.content_type as u8); // TLSCompressed.type
                ad.push(enc_record.ver_major);
                ad.push(enc_record.ver_minor);

                let mac_len = decryptor.mac_len();
                let total_len = enc_record.fragment.len();
                if total_len < mac_len {
                    return tls_err!(BadRecordMac, "encrypted message too short: {}", total_len);
                }
                let frag_len = (total_len - mac_len) as u16;
                ad.push((frag_len >> 8) as u8);
                ad.push(frag_len as u8);

                // TODO: "seq_num as nonce" is chacha20poly1305-specific
                let data = try!(decryptor.decrypt(&seq_num,
                                                  &enc_record.fragment,
                                                  &ad));

                Record::new(enc_record.content_type,
                            enc_record.ver_major,
                            enc_record.ver_minor,
                            data)
            }
        };

        self.read_count += 1;

        Ok(record)
    }

    /// read records until a "complete" message is found, and return the message.
    /// if invalid ChangeCipherSpec/Alert/Handshake message is found, return Err.
    /// (application record is always considered "complete" and "valid"
    /// since it is opaque to TLS layer.)
    pub fn read_message(&mut self) -> TlsResult<Message> {
        match try!(self.handshake_buffer.get_message()) {
            Some(handshake_msg) => return Ok(HandshakeMessage(handshake_msg)),
            None => {}
        }

        // ok, no message found. read it from network!
        loop {
            // TODO: what if handshake record is present in buffer then
            // other record comes? is it legal?

            let record = try!(self.read_record());
            match record.content_type {
                ChangeCipherSpecTy => {
                    if record.fragment.len() != 1 || record.fragment[0] != 1 {
                        return tls_err!(UnexpectedMessage, "invalid ChangeCipherSpec arrived");
                    }
                    return Ok(ChangeCipherSpecMessage);
                }
                AlertTy => {
                    let len = record.fragment.len();
                    if len == 0 {
                        return tls_err!(UnexpectedMessage, "zero-length Alert record arrived");
                    } else if len < 2 {
                        // alert packet can be broken into several records,
                        // buf it is rarely used and may cause alert attack
                        // if carelessly implemented:
                        // http://www.mitls.org/wsgi/alert-attack
                        // we just don't accept such record for simplicity.
                        // If alert messages are long, use the first two bytes.
                        return tls_err!(UnexpectedMessage, "awkward Alert record arrived");
                    }
                    let level = FromPrimitive::from_u8(record.fragment[0]);
                    let desc = FromPrimitive::from_u8(record.fragment[1]);
                    match (level, desc) {
                        (Some(level), Some(desc)) => {
                            return Ok(AlertMessage(try!(Alert::new(level, desc))));
                        }
                        _ => return tls_err!(UnexpectedMessage,
                                             "unknown alert: {:?}",
                                             record.fragment),
                    }
                }
                HandshakeTy => {
                    if record.fragment.len() == 0 {
                        return tls_err!(UnexpectedMessage, "zero-length Handshake arrived");
                    }
                    self.handshake_buffer.add_record(&record.fragment);

                    match try!(self.handshake_buffer.get_message()) {
                        Some(handshake_msg) => return Ok(HandshakeMessage(handshake_msg)),
                        _ => {}
                    }
                }
                ApplicationDataTy => {
                    return Ok(ApplicationDataMessage(record.fragment));
                }
            }
        }
    }

    pub fn read_application_data(&mut self) -> TlsResult<Vec<u8>> {
        if self.decryptor.is_none() {
            panic!("ApplicationData called before handshake");
        }
        loop {
            let msg = try!(self.read_message());
            match msg {
                ApplicationDataMessage(msg) => return Ok(msg),
                // TODO: handle other cases
                AlertMessage(..) => unimplemented!(),
                ChangeCipherSpecMessage(..) => unimplemented!(), // this should not come here
                HandshakeMessage(..) => unimplemented!(), // TODO: re-handshake
            }
        }
    }

    pub fn read_handshake(&mut self) -> TlsResult<Handshake> {
        match try!(self.read_message()) {
            HandshakeMessage(handshake) => Ok(handshake),
            AlertMessage(alert) => tls_err!(AlertReceived, "alert: {:?}", alert.description),
            _ => tls_err!(UnexpectedMessage, "expected Handshake"),
        }
    }

    pub fn read_change_cipher_spec(&mut self) -> TlsResult<()> {
        match try!(self.read_message()) {
            ChangeCipherSpecMessage => Ok(()),
            _ => tls_err!(UnexpectedMessage, "expected ChangeCipherSpec"),
        }
    }
}

pub struct Tls<R: Read, W: Write> {
    pub writer: RecordWriter<W>,
    pub reader: RecordReader<R>,
    pub rng: OsRng,
}

impl<R: Read, W: Write> Tls<R, W> {
    pub fn new(reader: R, writer: W, rng: OsRng) -> Tls<R, W> {
        let writer = RecordWriter::new(writer);
        let reader = RecordReader::new(reader);
        Tls {
            writer: writer,
            reader: reader,
            rng: rng,
        }
    }

    pub fn close(&mut self) -> TlsResult<()> {
        let alert_data = alert::Alert {
            level: alert::AlertLevel::fatal,
            description: alert::AlertDescription::close_notify,
        };
        try!(self.writer.write_alert(&alert_data));
        Ok(())
    }

    // send fatal alert and return error
    // (it may be different to `err`, because writing alert can fail)
    pub fn send_tls_alert(&mut self, err: TlsError) -> TlsError {
        match err.kind {
            TlsErrorKind::IoFailure => return err,
            _ => {
                let alert = alert::Alert::from_tls_err(&err);
                let result = self.writer.write_alert(&alert);
                match result {
                    Ok(()) => return err,
                    Err(err) => return err,
                }
            }
        }
    }
}
<commit_msg>tls: Remove `EncryptedRecord`<commit_after>use std::io::prelude::*;
use rand::OsRng;
use num::traits::FromPrimitive;

use tls_result::{TlsResult, TlsError, TlsErrorKind};
use tls_result::TlsErrorKind::{UnexpectedMessage, RecordOverflow, BadRecordMac, AlertReceived};
use alert::{self, Alert};
use handshake::{Handshake, HandshakeBuffer};
use util::u64_be_array;
use util::{ReadExt, WriteExt};
use cipher::{Encryptor, Decryptor};
use tls_item::TlsItem;

use self::ContentType::{ChangeCipherSpecTy, AlertTy, HandshakeTy, ApplicationDataTy};
use self::Message::{HandshakeMessage, ChangeCipherSpecMessage, AlertMessage,
                    ApplicationDataMessage};

pub static TLS_VERSION: (u8, u8) = (3, 3);

enum_from_primitive! {
    #[repr(u8)]
    #[derive(Copy, Clone, PartialEq, Debug)]
    pub enum ContentType {
        ChangeCipherSpecTy = 20,
        AlertTy = 21,
        HandshakeTy = 22,
        ApplicationDataTy = 23,
        // HeartBeat = 24, RFC 6520 extension :-)
    }
}

/// maximum length of Record (excluding content_type, version, length fields)
pub const RECORD_MAX_LEN: usize = 1 << 14;

/// maximum length of EncryptedRecord (excluding content_type, version, length fields)
pub const ENC_RECORD_MAX_LEN: usize = (1 << 14) + 2048;

/// corresponds to `TLSPlaintext` in Section 6.2.1.
#[derive(Debug)]
pub struct Record {
    pub content_type: ContentType,
    pub ver_major: u8,
    pub ver_minor: u8,
    // fragment length < 2^14
    pub fragment: Vec<u8>,
}

impl Record {
    pub fn new(content_type: ContentType,
               ver_major: u8,
               ver_minor: u8,
               fragment: Vec<u8>) -> Record {
        let len = fragment.len();
        if len > RECORD_MAX_LEN {
            panic!("record too long: {} > 2^14", len);
        }

        Record {
            content_type: content_type,
            ver_major: ver_major,
            ver_minor: ver_minor,
            fragment: fragment,
        }
    }
}

pub struct RecordWriter<W: Write> {
    writer: W,
    // if encryptor is None, handshake is not done yet.
    encryptor: Option<Box<Encryptor + Send + 'static>>,
    write_count: u64,
}

impl<W: Write> RecordWriter<W> {
    pub fn new(writer: W) -> RecordWriter<W> {
        RecordWriter {
            writer: writer,
            encryptor: None,
            write_count: 0,
        }
    }

    #[inline]
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    pub fn set_encryptor(&mut self, encryptor: Box<Encryptor + Send + 'static>) {
        self.encryptor = Some(encryptor);
        self.write_count = 0;
    }

    pub fn write_record(&mut self, record: Record) -> TlsResult<()> {
        let encrypted_fragment = match self.encryptor {
            None => record.fragment,
            Some(ref mut encryptor) => {
                let seq_num = u64_be_array(self.write_count);

                let mut ad = Vec::new();
                ad.extend(&seq_num);
                ad.push(record.content_type as u8);
                ad.push(record.ver_major);
                ad.push(record.ver_minor);
                let frag_len = record.fragment.len() as u16;
                ad.push((frag_len >> 8) as u8);
                ad.push(frag_len as u8);

                let encrypted_fragment = encryptor.encrypt(&seq_num,
                                                           &record.fragment,
                                                           &ad);
                encrypted_fragment
            }
        };

        let fragment_len = encrypted_fragment.len();
        if fragment_len > ENC_RECORD_MAX_LEN {
            panic!("record too long: {} > 2^14 + 2048", fragment_len);
        }

        try!(self.writer.write_u8(record.content_type as u8));
        try!(self.writer.write_u8(record.ver_major));
        try!(self.writer.write_u8(record.ver_minor));
        try!(self.writer.write_be_u16(fragment_len as u16));
        try!(self.writer.write_all(&encrypted_fragment));

        self.write_count += 1;

        Ok(())
    }

    pub fn write_data(&mut self, ty: ContentType, data: &[u8]) -> TlsResult<()> {
        let (major, minor) = TLS_VERSION;
        // TODO: configurable maxlen
        for fragment in data.chunks(RECORD_MAX_LEN) {
            let fragment = fragment.to_vec();
            let record = Record::new(ty, major, minor, fragment);
            try!(self.write_record(record));
        }

        Ok(())
    }

    pub fn write_handshake(&mut self, handshake: &Handshake) -> TlsResult<()> {
        let mut data = Vec::new();
        try!(handshake.tls_write(&mut data));
        self.write_data(HandshakeTy, &data)
    }

    pub fn write_alert(&mut self, alert: &Alert) -> TlsResult<()> {
        let mut data = Vec::new();
        try!(alert.tls_write(&mut data));
        self.write_data(AlertTy, &data)
    }

    pub fn write_change_cipher_spec(&mut self) -> TlsResult<()> {
        self.write_data(ChangeCipherSpecTy, &[1u8])
    }

    pub fn write_application_data(&mut self, data: &[u8]) -> TlsResult<()> {
        if self.encryptor.is_none() {
            panic!("attempted to write ApplicationData before handshake");
        }
        self.write_data(ApplicationDataTy, data)
    }
}

pub enum Message {
    HandshakeMessage(Handshake),
    ChangeCipherSpecMessage,
    AlertMessage(Alert),
    ApplicationDataMessage(Vec<u8>),
}

pub struct RecordReader<R: ReadExt> {
    reader: R,
    // if decryptor is none, handshake is not done yet.
    decryptor: Option<Box<Decryptor + Send + 'static>>,
    read_count: u64,
    handshake_buffer: HandshakeBuffer,
}

impl<R: ReadExt> RecordReader<R> {
    pub fn new(reader: R) -> RecordReader<R> {
        RecordReader {
            reader: reader,
            decryptor: None,
            read_count: 0,
            handshake_buffer: HandshakeBuffer::new(),
        }
    }

    #[inline]
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.reader
    }

    pub fn set_decryptor(&mut self, decryptor: Box<Decryptor + Send + 'static>) {
        self.decryptor = Some(decryptor);
        self.read_count = 0;
    }

    fn read_record(&mut self) -> TlsResult<Record> {
        let content_type = {
            let ty = try!(self.reader.read_u8());
            let ct: Option<ContentType> = FromPrimitive::from_u8(ty);
            match ct {
                Some(ty) => ty,
                None => return tls_err!(UnexpectedMessage, "unexpected ContentType: {}", ty),
            }
        };

        let major = try!(self.reader.read_u8());
        let minor = try!(self.reader.read_u8());

        let len = {
            let len = try!(self.reader.read_be_u16()) as usize;
            if len > ENC_RECORD_MAX_LEN {
                return tls_err!(RecordOverflow, "TLSEncryptedText too long: {}", len);
            }
            len
        };

        let fragment = try!(self.reader.read_exact(len as usize));

        let record = match self.decryptor {
            None => {
                if fragment.len() > RECORD_MAX_LEN {
                    return tls_err!(RecordOverflow,
                                    "decrypted record too long: {}",
                                    fragment.len());
                }
                Record::new(content_type, major, minor, fragment)
            }
            Some(ref mut decryptor) => {
                let seq_num = u64_be_array(self.read_count);

                let mut ad = Vec::new();
                ad.extend(&seq_num);
                ad.push(content_type as u8); // TLSCompressed.type
                ad.push(major);
                ad.push(minor);

                let mac_len = decryptor.mac_len();
                let total_len = fragment.len();
                if total_len < mac_len {
                    return tls_err!(BadRecordMac, "encrypted message too short: {}", total_len);
                }
                let frag_len = (total_len - mac_len) as u16;
                ad.push((frag_len >> 8) as u8);
                ad.push(frag_len as u8);

                // TODO: "seq_num as nonce" is chacha20poly1305-specific
                let data = try!(decryptor.decrypt(&seq_num, &fragment, &ad));
                if data.len() > RECORD_MAX_LEN {
                    // decryption routine went wrong.
                    return panic!("decrypted record too long: {}", data.len());
                }

                Record::new(content_type, major, minor, data)
            }
        };

        self.read_count += 1;

        Ok(record)
    }

    /// read records until a "complete" message is found, and return the message.
    /// if invalid ChangeCipherSpec/Alert/Handshake message is found, return Err.
    /// (application record is always considered "complete" and "valid"
    /// since it is opaque to TLS layer.)
    pub fn read_message(&mut self) -> TlsResult<Message> {
        match try!(self.handshake_buffer.get_message()) {
            Some(handshake_msg) => return Ok(HandshakeMessage(handshake_msg)),
            None => {}
        }

        // ok, no message found. read it from network!
        loop {
            // TODO: what if handshake record is present in buffer then
            // other record comes? is it legal?

            let record = try!(self.read_record());
            match record.content_type {
                ChangeCipherSpecTy => {
                    if record.fragment.len() != 1 || record.fragment[0] != 1 {
                        return tls_err!(UnexpectedMessage, "invalid ChangeCipherSpec arrived");
                    }
                    return Ok(ChangeCipherSpecMessage);
                }
                AlertTy => {
                    let len = record.fragment.len();
                    if len == 0 {
                        return tls_err!(UnexpectedMessage, "zero-length Alert record arrived");
                    } else if len < 2 {
                        // alert packet can be broken into several records,
                        // buf it is rarely used and may cause alert attack
                        // if carelessly implemented:
                        // http://www.mitls.org/wsgi/alert-attack
                        // we just don't accept such record for simplicity.
                        // If alert messages are long, use the first two bytes.
                        return tls_err!(UnexpectedMessage, "awkward Alert record arrived");
                    }
                    let level = FromPrimitive::from_u8(record.fragment[0]);
                    let desc = FromPrimitive::from_u8(record.fragment[1]);
                    match (level, desc) {
                        (Some(level), Some(desc)) => {
                            return Ok(AlertMessage(try!(Alert::new(level, desc))));
                        }
                        _ => return tls_err!(UnexpectedMessage,
                                             "unknown alert: {:?}",
                                             record.fragment),
                    }
                }
                HandshakeTy => {
                    if record.fragment.len() == 0 {
                        return tls_err!(UnexpectedMessage, "zero-length Handshake arrived");
                    }
                    self.handshake_buffer.add_record(&record.fragment);

                    match try!(self.handshake_buffer.get_message()) {
                        Some(handshake_msg) => return Ok(HandshakeMessage(handshake_msg)),
                        _ => {}
                    }
                }
                ApplicationDataTy => {
                    return Ok(ApplicationDataMessage(record.fragment));
                }
            }
        }
    }

    pub fn read_application_data(&mut self) -> TlsResult<Vec<u8>> {
        if self.decryptor.is_none() {
            panic!("ApplicationData called before handshake");
        }
        loop {
            let msg = try!(self.read_message());
            match msg {
                ApplicationDataMessage(msg) => return Ok(msg),
                // TODO: handle other cases
                AlertMessage(..) => unimplemented!(),
                ChangeCipherSpecMessage(..) => unimplemented!(), // this should not come here
                HandshakeMessage(..) => unimplemented!(), // TODO: re-handshake
            }
        }
    }

    pub fn read_handshake(&mut self) -> TlsResult<Handshake> {
        match try!(self.read_message()) {
            HandshakeMessage(handshake) => Ok(handshake),
            AlertMessage(alert) => tls_err!(AlertReceived, "alert: {:?}", alert.description),
            _ => tls_err!(UnexpectedMessage, "expected Handshake"),
        }
    }

    pub fn read_change_cipher_spec(&mut self) -> TlsResult<()> {
        match try!(self.read_message()) {
            ChangeCipherSpecMessage => Ok(()),
            _ => tls_err!(UnexpectedMessage, "expected ChangeCipherSpec"),
        }
    }
}

pub struct Tls<R: Read, W: Write> {
    pub writer: RecordWriter<W>,
    pub reader: RecordReader<R>,
    pub rng: OsRng,
}

impl<R: Read, W: Write> Tls<R, W> {
    pub fn new(reader: R, writer: W, rng: OsRng) -> Tls<R, W> {
        let writer = RecordWriter::new(writer);
        let reader = RecordReader::new(reader);
        Tls {
            writer: writer,
            reader: reader,
            rng: rng,
        }
    }

    pub fn close(&mut self) -> TlsResult<()> {
        let alert_data = alert::Alert {
            level: alert::AlertLevel::fatal,
            description: alert::AlertDescription::close_notify,
        };
        try!(self.writer.write_alert(&alert_data));
        Ok(())
    }

    // send fatal alert and return error
    // (it may be different to `err`, because writing alert can fail)
    pub fn send_tls_alert(&mut self, err: TlsError) -> TlsError {
        match err.kind {
            TlsErrorKind::IoFailure => return err,
            _ => {
                let alert = alert::Alert::from_tls_err(&err);
                let result = self.writer.write_alert(&alert);
                match result {
                    Ok(()) => return err,
                    Err(err) => return err,
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate parity_wasm;
extern crate mktemp;

use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

fn wasm_opt() -> PathBuf {
    let bin = PathBuf::from(env!("OUT_DIR")).join("bin").join("wasm-opt");
    assert!(
        bin.exists(),
        format!("could not find wasm-opt at: {:?}", wasm_opt())
    );
    bin
}

fuzz_target!(|data: &[u8]| {
    let seed = mktemp::Temp::new_file().unwrap();
    let mut seedfile = File::create(seed.as_ref()).unwrap();
    seedfile.write_all(data).unwrap();
    seedfile.flush().unwrap();

    let wasm = mktemp::Temp::new_file().unwrap();
    let opt_fuzz = Command::new(wasm_opt())
        .arg("--translate-to-fuzz")
        .arg(seed.as_ref())
        .arg("-o")
        .arg(wasm.as_ref())
        .output()
        .unwrap();

    assert!(
        opt_fuzz.status.success(),
        format!(
            "wasm-opt failed with: {}",
            String::from_utf8_lossy(&opt_fuzz.stderr)
        )
    );

    let _module: parity_wasm::elements::Module = parity_wasm::deserialize_file(wasm.as_ref())
        .unwrap();
});
<commit_msg>deserialize fuzz target: add expect() explanations instad of unwrap()<commit_after>#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate parity_wasm;
extern crate mktemp;

use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

fn wasm_opt() -> PathBuf {
    let bin = PathBuf::from(env!("OUT_DIR")).join("bin").join("wasm-opt");
    assert!(
        bin.exists(),
        format!(
            "could not find wasm-opt at location installed by build.rs: {:?}",
            wasm_opt()
        )
    );
    bin
}

fuzz_target!(|data: &[u8]| {
    let seed = mktemp::Temp::new_file().expect("mktemp file to store fuzzer input");
    let mut seedfile =
        File::create(seed.as_ref()).expect("open temporary file for writing to store fuzzer input");
    seedfile.write_all(data).expect(
        "write fuzzer input to temporary file",
    );
    seedfile.flush().expect(
        "flush fuzzer input to temporary file before starting wasm-opt",
    );

    let wasm = mktemp::Temp::new_file().expect("mktemp file to store wasm-opt output");
    let opt_fuzz = Command::new(wasm_opt())
        .arg("--translate-to-fuzz")
        .arg(seed.as_ref())
        .arg("-o")
        .arg(wasm.as_ref())
        .output()
        .expect("execute wasm-opt installed by build.rs");

    assert!(
        opt_fuzz.status.success(),
        format!(
            "wasm-opt failed with: {}",
            String::from_utf8_lossy(&opt_fuzz.stderr)
        )
    );

    let _module: parity_wasm::elements::Module = parity_wasm::deserialize_file(wasm.as_ref())
        .expect(
            "deserialize output of wasm-opt, indicating possible bug in deserializer",
        );
});
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;
extern crate tokio_signal;

use futures::{Stream, Future};
use tokio_core::reactor::Core;

fn main() {
    // set up a Tokio event loop
    let mut core = Core::new().unwrap();

    // tokio_signal provides a convenience builder for Ctrl+C
    // this even works cross-platform: linux and windows!
    //
    // `fn ctrl_c()` produces a `Future` of the actual stream-initialisation
    // the `flatten_stream()` convenience method lazily defers that
    // initialisation, allowing us to use it 'as if' it is already the
    // stream we want, reducing boilerplate Future-handling.
    let stream = tokio_signal::ctrl_c(&core.handle()).flatten_stream();

    println!("This program is now waiting for you to press Ctrl+C");

    // for_each is a powerful primitive provided by the Futures crate
    // it turns a Stream into a Future that completes after all stream-items
    // have been completed.
    let future = stream.for_each(|()| {
        println!("Ctrl+C received!");
        Ok(())
    });

    // Up until now, we haven't really DONE anything, just prepared
    // now it's time to actually schedule, and thus execute, the stream
    // on our event loop
    core.run(future).unwrap();

    println!("this won't be printed, because the received Ctrl+C will also kill the program");
    unreachable!();
}
<commit_msg>signal: Ctrl+C example: more explanations<commit_after>extern crate futures;
extern crate tokio_core;
extern crate tokio_signal;

use futures::{Stream, Future};
use tokio_core::reactor::Core;

fn main() {
    // set up a Tokio event loop
    let mut core = Core::new().unwrap();

    // tokio_signal provides a convenience builder for Ctrl+C
    // this even works cross-platform: linux and windows!
    //
    // `fn ctrl_c()` produces a `Future` of the actual stream-initialisation
    // the `flatten_stream()` convenience method lazily defers that
    // initialisation, allowing us to use it 'as if' it is already the
    // stream we want, reducing boilerplate Future-handling.
    let stream = tokio_signal::ctrl_c(&core.handle()).flatten_stream();

    println!("This program is now waiting for you to press Ctrl+C
  * If running via `cargo run --example ctrl-c`, Ctrl+C also kills it, \
    due to https://github.com/rust-lang-nursery/rustup.rs/issues/806
  * If running the binary directly, the Ctrl+C is properly trapped. \
    Terminate by opening a second terminal and issue `pkill -sigkil ctrl-c`");

    // Stream::for_each is a powerful primitive provided by the Futures crate.
    // It turns a Stream into a Future that completes after all stream-items
    // have been completed, or the first time the closure returns an error
    let future = stream.for_each(|()| {
        println!("Ctrl+C received!");

        // return Ok-result to continue handling the stream
        Ok(())
    });

    // Up until now, we haven't really DONE anything, just prepared
    // now it's time to actually schedule, and thus execute, the stream
    // on our event loop
    core.run(future).unwrap();

    println!("this won't be printed, because the received Ctrl+C will also kill the program");
    unreachable!();
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Berkus Decker <berkus+github@metta.systems>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// This example shows simple packet_fanout processing under linux.
/// PACKET_FANOUT in linux allows to offload packet processing to multiple threads.
/// See [man 7 packet](http://man7.org/linux/man-pages/man7/packet.7.html) for more details.
extern crate pnet;
extern crate pnet_datalink;

use pnet::datalink::{self, Config, FanoutOption, FanoutType, NetworkInterface};
use std::env;
use std::io::{self, Write};
use std::process;
use std::thread;

#[cfg(not(target_os = "linux"))]
fn main() {
    writeln!(io::stderr(), "fanout is only supported on Linux").unwrap();
    process::exit(1);
}

#[cfg(target_os = "linux")]
fn main() {
    use pnet::datalink::Channel::Ethernet;

    let iface_name = match env::args().nth(1) {
        Some(n) => n,
        None => {
            writeln!(io::stderr(), "USAGE: fanout <NETWORK INTERFACE> [hash|*round-robin*|cpu|rollover|rnd|qm|cbpf|ebpf] [group-id:123]").unwrap();
            process::exit(1);
        }
    };
    let interface_names_match = |iface: &NetworkInterface| iface.name == iface_name;

    // Find the network interface with the provided name
    let interfaces = datalink::linux::interfaces();
    let interface = interfaces
        .into_iter()
        .filter(interface_names_match)
        .next()
        .unwrap();

    let fanout_type = match env::args().nth(2) {
        Some(n) => match n.to_lowercase().as_str() {
            "hash" => FanoutType::HASH,
            "round-robin" => FanoutType::LB,
            "cpu" => FanoutType::CPU,
            "rollover" => FanoutType::ROLLOVER,
            "rnd" => FanoutType::RND,
            "qm" => FanoutType::QM,
            "cbpf" => FanoutType::CBPF,
            "ebpf" => FanoutType::EBPF,
            _ => panic!("Unsupported fanout type, use one of hash, round-robin, cpu, rollover, rnd, qm, cbpf or ebpf")
        },
        None => FanoutType::LB,
    };

    let group_id = match env::args().nth(3) {
        Some(n) => n.parse::<u16>().unwrap(),
        None => 123,
    };

    let mut config: Config = Default::default();
    config.linux_fanout = Some(FanoutOption {
        group_id: group_id,
        fanout_type: fanout_type,
        defrag: true,
        rollover: false,
    });

    let mut threads = vec![];
    for x in 0..3 {
        let itf = interface.clone();
        let thread = thread::Builder::new()
            .name(format!("thread{}", x))
            .spawn(move || {
                // Create a channel to receive on
                let (_, mut rx) = match datalink::channel(&itf, config) {
                    Ok(Ethernet(tx, rx)) => (tx, rx),
                    Ok(_) => panic!("packetdump: unhandled channel type"),
                    Err(e) => panic!("packetdump: unable to create channel: {}", e),
                };

                let handle = thread::current();

                loop {
                    match rx.next() {
                        Ok(_packet) => {
                            writeln!(
                                io::stdout(),
                                "Received packet on thread {:?}",
                                handle.name()
                            )
                            .unwrap();
                        }
                        Err(e) => panic!("packetdump: unable to receive packet: {}", e),
                    }
                }
            })
            .unwrap();
        threads.push(thread);
    }

    for t in threads {
        t.join().unwrap();
    }
}
<commit_msg>Fix fanout example build warnings on macOS<commit_after>// Copyright (c) 2018 Berkus Decker <berkus+github@metta.systems>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// This example shows simple packet_fanout processing under linux.
/// PACKET_FANOUT in linux allows to offload packet processing to multiple threads.
/// See [man 7 packet](http://man7.org/linux/man-pages/man7/packet.7.html) for more details.
extern crate pnet;
extern crate pnet_datalink;

use std::io::{self, Write};
use std::process;

#[cfg(not(target_os = "linux"))]
fn main() {
    writeln!(io::stderr(), "fanout is only supported on Linux").unwrap();
    process::exit(1);
}

#[cfg(target_os = "linux")]
fn main() {
    use pnet::datalink::Channel::Ethernet;
    use pnet::datalink::{self, Config, FanoutOption, FanoutType, NetworkInterface};
    use std::env;
    use std::thread;

    let iface_name = match env::args().nth(1) {
        Some(n) => n,
        None => {
            writeln!(io::stderr(), "USAGE: fanout <NETWORK INTERFACE> [hash|*round-robin*|cpu|rollover|rnd|qm|cbpf|ebpf] [group-id:123]").unwrap();
            process::exit(1);
        }
    };
    let interface_names_match = |iface: &NetworkInterface| iface.name == iface_name;

    // Find the network interface with the provided name
    let interfaces = datalink::linux::interfaces();
    let interface = interfaces
        .into_iter()
        .filter(interface_names_match)
        .next()
        .unwrap();

    let fanout_type = match env::args().nth(2) {
        Some(n) => match n.to_lowercase().as_str() {
            "hash" => FanoutType::HASH,
            "round-robin" => FanoutType::LB,
            "cpu" => FanoutType::CPU,
            "rollover" => FanoutType::ROLLOVER,
            "rnd" => FanoutType::RND,
            "qm" => FanoutType::QM,
            "cbpf" => FanoutType::CBPF,
            "ebpf" => FanoutType::EBPF,
            _ => panic!("Unsupported fanout type, use one of hash, round-robin, cpu, rollover, rnd, qm, cbpf or ebpf")
        },
        None => FanoutType::LB,
    };

    let group_id = match env::args().nth(3) {
        Some(n) => n.parse::<u16>().unwrap(),
        None => 123,
    };

    let mut config: Config = Default::default();
    config.linux_fanout = Some(FanoutOption {
        group_id: group_id,
        fanout_type: fanout_type,
        defrag: true,
        rollover: false,
    });

    let mut threads = vec![];
    for x in 0..3 {
        let itf = interface.clone();
        let thread = thread::Builder::new()
            .name(format!("thread{}", x))
            .spawn(move || {
                // Create a channel to receive on
                let (_, mut rx) = match datalink::channel(&itf, config) {
                    Ok(Ethernet(tx, rx)) => (tx, rx),
                    Ok(_) => panic!("packetdump: unhandled channel type"),
                    Err(e) => panic!("packetdump: unable to create channel: {}", e),
                };

                let handle = thread::current();

                loop {
                    match rx.next() {
                        Ok(_packet) => {
                            writeln!(
                                io::stdout(),
                                "Received packet on thread {:?}",
                                handle.name()
                            )
                            .unwrap();
                        }
                        Err(e) => panic!("packetdump: unable to receive packet: {}", e),
                    }
                }
            })
            .unwrap();
        threads.push(thread);
    }

    for t in threads {
        t.join().unwrap();
    }
}
<|endoftext|>


<commit_before>pub struct AgentController<'a> {
    jvmti: ::env::JvmTiEnv,
    heuristic: Box<super::Heuristic + 'a>,
    actions: Vec<Box<super::Action>>
}

impl<'a> AgentController<'a> {
    pub fn new(ti: ::env::JvmTiEnv, options: *mut ::std::os::raw::c_char) -> Result<Self, ::jvmti::jint> {
        super::heaphistogram::HeapHistogram::new(ti).map(|action| {
            let parms = super::parms::AgentParameters::parseParameters(options);
            Self {
                jvmti: ti,
                heuristic: Box::new(super::threshold::Threshold::new(parms.count_threshold, parms.time_threshold)),
                actions: vec![Box::new(action), Box::new(super::kill::Kill::new())],
            }
        })
    }

    #[cfg(test)]
    fn test_new(ti: ::env::JvmTiEnv, heuristic: Box<super::Heuristic + 'a>, actions: Vec<Box<super::Action>>) -> Self {
        Self {
            jvmti: ti,
            heuristic: heuristic,
            actions: actions,
        }
    }
}

impl<'a> super::MutAction for AgentController<'a> {
    fn on_oom(&mut self, jni_env: ::env::JniEnv, resourceExhaustionFlags: ::jvmti::jint) {
        if self.heuristic.on_oom() {
            for action in &self.actions {
                action.on_oom(jni_env, resourceExhaustionFlags);
            }
        } else {}
    }
}

unsafe impl<'a> Send for AgentController<'a> {}

unsafe impl<'a> Sync for AgentController<'a> {}

#[cfg(test)]
mod tests {
    use agentcontroller::MutAction;

    pub struct TestHeuristic {
        call_count: u32
    }

    impl TestHeuristic {
        pub fn new() -> Self {
            Self {
                call_count: 0,
            }
        }
    }

    impl super::super::Heuristic for TestHeuristic {
        fn on_oom(&mut self) -> bool {
            self.call_count += 1;
            self.call_count >= 2
        }
    }

    pub struct TestAction {}

    impl TestAction {
        pub fn new() -> Self {
            Self {}
        }
    }

    impl super::super::Action for TestAction {
        fn on_oom(&self, _: ::env::JniEnv, _: ::jvmti::jint) {
            panic!("TestAction.on_oom")
        }
    }

    #[test]
    fn does_not_call_action_when_heuristic_returns_false() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(::env::JvmTiEnv::new(dummy_jni()).unwrap(),
                                                      heuristic,
                                                      vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
    }

    #[test]
    #[should_panic(expected = "TestAction.on_oom")]
    fn calls_action_when_heuristic_returns_true() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(::env::JvmTiEnv::new(dummy_jni()).unwrap(),
                                                      heuristic,
                                                      vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
        ac.on_oom(dummy_jni_env(), 0);
    }

    unsafe extern "C" fn test_get_env(vm: *mut ::jvmti::JavaVM,
                                      penv: *mut *mut ::std::os::raw::c_void,
                                      version: ::jvmti::jint)
                                      -> ::jvmti::jint {
        0
    }

    fn dummy_jni_env() -> ::env::JniEnv {
        ::env::JniEnv::new(::std::ptr::null_mut())
    }

    fn dummy_jni() -> *mut ::jvmti::JavaVM {
        &mut (&::jvmti::JNIInvokeInterface_ {
            reserved0: ::std::ptr::null_mut(),
            reserved1: ::std::ptr::null_mut(),
            reserved2: ::std::ptr::null_mut(),
            DestroyJavaVM: None,
            AttachCurrentThread: None,
            DetachCurrentThread: None,
            GetEnv: Some(test_get_env),
            AttachCurrentThreadAsDaemon: None,
        } as *const ::jvmti::JNIInvokeInterface_) as *mut *const ::jvmti::JNIInvokeInterface_
    }
}
<commit_msg>Print about to throw OOME<commit_after>pub struct AgentController<'a> {
    jvmti: ::env::JvmTiEnv,
    heuristic: Box<super::Heuristic + 'a>,
    actions: Vec<Box<super::Action>>
}

impl<'a> AgentController<'a> {
    pub fn new(ti: ::env::JvmTiEnv, options: *mut ::std::os::raw::c_char) -> Result<Self, ::jvmti::jint> {
        super::heaphistogram::HeapHistogram::new(ti).map(|action| {
            let parms = super::parms::AgentParameters::parseParameters(options);
            Self {
                jvmti: ti,
                heuristic: Box::new(super::threshold::Threshold::new(parms.count_threshold, parms.time_threshold)),
                actions: vec![Box::new(action), Box::new(super::kill::Kill::new())],
            }
        })
    }

    #[cfg(test)]
    fn test_new(ti: ::env::JvmTiEnv, heuristic: Box<super::Heuristic + 'a>, actions: Vec<Box<super::Action>>) -> Self {
        Self {
            jvmti: ti,
            heuristic: heuristic,
            actions: actions,
        }
    }
}

impl<'a> super::MutAction for AgentController<'a> {
    fn on_oom(&mut self, jni_env: ::env::JniEnv, resourceExhaustionFlags: ::jvmti::jint) {
        if self.heuristic.on_oom() {
            for action in &self.actions {
                action.on_oom(jni_env, resourceExhaustionFlags);
            }
        } else {
            eprintln!("\nThe JVM is about to throw a java.lang.OutOfMemoryError.");
        }
    }
}

unsafe impl<'a> Send for AgentController<'a> {}

unsafe impl<'a> Sync for AgentController<'a> {}

#[cfg(test)]
mod tests {
    use agentcontroller::MutAction;

    pub struct TestHeuristic {
        call_count: u32
    }

    impl TestHeuristic {
        pub fn new() -> Self {
            Self {
                call_count: 0,
            }
        }
    }

    impl super::super::Heuristic for TestHeuristic {
        fn on_oom(&mut self) -> bool {
            self.call_count += 1;
            self.call_count >= 2
        }
    }

    pub struct TestAction {}

    impl TestAction {
        pub fn new() -> Self {
            Self {}
        }
    }

    impl super::super::Action for TestAction {
        fn on_oom(&self, _: ::env::JniEnv, _: ::jvmti::jint) {
            panic!("TestAction.on_oom")
        }
    }

    #[test]
    fn does_not_call_action_when_heuristic_returns_false() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(::env::JvmTiEnv::new(dummy_jni()).unwrap(),
                                                      heuristic,
                                                      vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
    }

    #[test]
    #[should_panic(expected = "TestAction.on_oom")]
    fn calls_action_when_heuristic_returns_true() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(::env::JvmTiEnv::new(dummy_jni()).unwrap(),
                                                      heuristic,
                                                      vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
        ac.on_oom(dummy_jni_env(), 0);
    }

    unsafe extern "C" fn test_get_env(vm: *mut ::jvmti::JavaVM,
                                      penv: *mut *mut ::std::os::raw::c_void,
                                      version: ::jvmti::jint)
                                      -> ::jvmti::jint {
        0
    }

    fn dummy_jni_env() -> ::env::JniEnv {
        ::env::JniEnv::new(::std::ptr::null_mut())
    }

    fn dummy_jni() -> *mut ::jvmti::JavaVM {
        &mut (&::jvmti::JNIInvokeInterface_ {
            reserved0: ::std::ptr::null_mut(),
            reserved1: ::std::ptr::null_mut(),
            reserved2: ::std::ptr::null_mut(),
            DestroyJavaVM: None,
            AttachCurrentThread: None,
            DetachCurrentThread: None,
            GetEnv: Some(test_get_env),
            AttachCurrentThreadAsDaemon: None,
        } as *const ::jvmti::JNIInvokeInterface_) as *mut *const ::jvmti::JNIInvokeInterface_
    }
}
<|endoftext|>