<commit_before>// Copyright 2014-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, is not intended for general usage, but rather as
//! a building block of other libraries. The types and interfaces in this
//! library are re-exported through the [standard library](../std/index.html),
//! and should not be used through this library.
//!
//! ## Boxed values
//!
//! The [`Box`](boxed/index.html) type is a smart pointer type. There can
//! only be one owner of a `Box`, and the owner can decide to mutate the
//! contents, which live on the heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`](rc/index.html) type is a non-threadsafe reference-counted pointer
//! type intended for sharing memory within a thread. An `Rc` pointer wraps a
//! type, `T`, and only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using `Box`) is too
//! constraining for an application, and is often paired with the `Cell` or
//! `RefCell` types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`](arc/index.html) type is the threadsafe equivalent of the `Rc`
//! type. It provides all the same functionality of `Rc`, except it requires
//! that the contained type `T` is shareable. Additionally, `Arc<T>` is itself
//! sendable while `Rc<T>` is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.

#![allow(unused_attributes)]
#![unstable(feature = "alloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
       test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
#![no_std]
#![needs_allocator]
#![deny(missing_debug_implementations)]

#![cfg_attr(test, allow(deprecated))] // rand
#![cfg_attr(not(test), feature(exact_size_is_empty))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(allocator_api)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(ascii_ctype)]
#![feature(box_into_raw_non_null)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(collections_range)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(fmt_internals)]
#![feature(from_ref)]
#![feature(fundamental)]
#![feature(futures_api)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]
#![feature(optin_builtin_traits)]
#![feature(pattern)]
#![feature(pin)]
#![feature(ptr_internals)]
#![feature(ptr_offset_from)]
#![cfg_attr(stage0, feature(repr_transparent))]
#![feature(rustc_attrs)]
#![feature(specialization)]
#![feature(split_ascii_whitespace)]
#![feature(staged_api)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(allocator_internals)]
#![feature(on_unimplemented)]
#![feature(exact_chunks)]
#![feature(pointer_methods)]
#![feature(inclusive_range_methods)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]

#![cfg_attr(not(test), feature(fn_traits, i128))]
#![cfg_attr(test, feature(test))]

// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate rand;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

#[unstable(feature = "futures_api",
           reason = "futures in libcore are unstable",
           issue = "50547")]
pub mod task;
// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
#[cfg(test)]
mod boxed_test;
pub mod collections;
#[cfg(target_has_atomic = "ptr")]
pub mod arc;
pub mod rc;
pub mod raw_vec;

pub mod borrow;
pub mod fmt;
pub mod slice;
pub mod str;
pub mod string;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops;      // RangeFull
}

#[doc(no_inline)]
pub use string::String;
#[doc(no_inline)]
pub use vec::Vec;
<commit_msg>Remove the Vec and String reexports at the root of the alloc crate<commit_after>// Copyright 2014-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, is not intended for general usage, but rather as
//! a building block of other libraries. The types and interfaces in this
//! library are re-exported through the [standard library](../std/index.html),
//! and should not be used through this library.
//!
//! ## Boxed values
//!
//! The [`Box`](boxed/index.html) type is a smart pointer type. There can
//! only be one owner of a `Box`, and the owner can decide to mutate the
//! contents, which live on the heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`](rc/index.html) type is a non-threadsafe reference-counted pointer
//! type intended for sharing memory within a thread. An `Rc` pointer wraps a
//! type, `T`, and only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using `Box`) is too
//! constraining for an application, and is often paired with the `Cell` or
//! `RefCell` types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`](arc/index.html) type is the threadsafe equivalent of the `Rc`
//! type. It provides all the same functionality of `Rc`, except it requires
//! that the contained type `T` is shareable. Additionally, `Arc<T>` is itself
//! sendable while `Rc<T>` is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.

#![allow(unused_attributes)]
#![unstable(feature = "alloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
       test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
#![no_std]
#![needs_allocator]
#![deny(missing_debug_implementations)]

#![cfg_attr(test, allow(deprecated))] // rand
#![cfg_attr(not(test), feature(exact_size_is_empty))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(allocator_api)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(ascii_ctype)]
#![feature(box_into_raw_non_null)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(collections_range)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(fmt_internals)]
#![feature(from_ref)]
#![feature(fundamental)]
#![feature(futures_api)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]
#![feature(optin_builtin_traits)]
#![feature(pattern)]
#![feature(pin)]
#![feature(ptr_internals)]
#![feature(ptr_offset_from)]
#![cfg_attr(stage0, feature(repr_transparent))]
#![feature(rustc_attrs)]
#![feature(specialization)]
#![feature(split_ascii_whitespace)]
#![feature(staged_api)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(allocator_internals)]
#![feature(on_unimplemented)]
#![feature(exact_chunks)]
#![feature(pointer_methods)]
#![feature(inclusive_range_methods)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]

#![cfg_attr(not(test), feature(fn_traits, i128))]
#![cfg_attr(test, feature(test))]

// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate rand;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

#[unstable(feature = "futures_api",
           reason = "futures in libcore are unstable",
           issue = "50547")]
pub mod task;
// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
#[cfg(test)]
mod boxed_test;
pub mod collections;
#[cfg(target_has_atomic = "ptr")]
pub mod arc;
pub mod rc;
pub mod raw_vec;

pub mod borrow;
pub mod fmt;
pub mod slice;
pub mod str;
pub mod string;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops;      // RangeFull
}
<|endoftext|>


<commit_before>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
///
/// The [`unreachable!()`] macro is the safe counterpart of this function, which
/// will panic instead when executed.
///
/// [`unreachable!()`]: ../macro.unreachable.html
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, std::u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
pub unsafe fn unreachable_unchecked() -> ! {
    intrinsics::unreachable()
}

/// Signals the processor that it is entering a busy-wait spin-loop.
///
/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
/// power or switching hyper-threads.
///
/// This function is different than [`std::thread::yield_now`] which directly yields to the
/// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a
/// busy-wait spin-loop without yielding control to the system's scheduler.
///
/// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a
/// contended lock is held by another thread executed on a different CPU and where the waiting
/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's
/// scheduler, no overhead for switching threads occurs. However, if the thread holding the
/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice
/// before switching to the thread that holds the lock. If the contending lock is held by a thread
/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to
/// use [`std::thread::yield_now`].
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
/// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(
        all(
            any(target_arch = "x86", target_arch = "x86_64"),
            target_feature = "sse2"
        )
    )] {
        #[cfg(target_arch = "x86")] {
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")] {
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(
        any(
            target_arch = "aarch64",
            all(target_arch = "arm", target_feature = "v6")
        )
    )] {
        #[cfg(target_arch = "aarch64")] {
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")] {
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[inline]
#[unstable(feature = "test", issue = "27812")]
pub fn black_box<T>(dummy: T) -> T {
    cfg_if! {
        if #[cfg(any(
            target_arch = "asmjs",
            all(
                target_arch = "wasm32",
                target_os = "emscripten"
            )
        ))] {
            #[inline]
            unsafe fn black_box_impl<T>(d: T) -> T {
                // these targets do not support inline assembly
                let ret = crate::ptr::read_volatile(&d);
                crate::mem::forget(d);
                ret
            }
        } else {
            #[inline]
            unsafe fn black_box_impl<T>(d: T) -> T {
                // we need to "use" the argument in some way LLVM can't
                // introspect.
                asm!("" : : "r"(&d));
                d
            }
        }
    }
    unsafe { black_box_impl(dummy) }
}
<commit_msg>improve docs for std::hint::unreachable_unchecked()<commit_after>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!()`] macro, which does not allow
/// optimizations but will panic when executed.
///
/// [`unreachable!()`]: ../macro.unreachable.html
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, std::u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
pub unsafe fn unreachable_unchecked() -> ! {
    intrinsics::unreachable()
}

/// Signals the processor that it is entering a busy-wait spin-loop.
///
/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
/// power or switching hyper-threads.
///
/// This function is different than [`std::thread::yield_now`] which directly yields to the
/// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a
/// busy-wait spin-loop without yielding control to the system's scheduler.
///
/// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a
/// contended lock is held by another thread executed on a different CPU and where the waiting
/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's
/// scheduler, no overhead for switching threads occurs. However, if the thread holding the
/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice
/// before switching to the thread that holds the lock. If the contending lock is held by a thread
/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to
/// use [`std::thread::yield_now`].
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
/// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(
        all(
            any(target_arch = "x86", target_arch = "x86_64"),
            target_feature = "sse2"
        )
    )] {
        #[cfg(target_arch = "x86")] {
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")] {
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(
        any(
            target_arch = "aarch64",
            all(target_arch = "arm", target_feature = "v6")
        )
    )] {
        #[cfg(target_arch = "aarch64")] {
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")] {
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[inline]
#[unstable(feature = "test", issue = "27812")]
pub fn black_box<T>(dummy: T) -> T {
    cfg_if! {
        if #[cfg(any(
            target_arch = "asmjs",
            all(
                target_arch = "wasm32",
                target_os = "emscripten"
            )
        ))] {
            #[inline]
            unsafe fn black_box_impl<T>(d: T) -> T {
                // these targets do not support inline assembly
                let ret = crate::ptr::read_volatile(&d);
                crate::mem::forget(d);
                ret
            }
        } else {
            #[inline]
            unsafe fn black_box_impl<T>(d: T) -> T {
                // we need to "use" the argument in some way LLVM can't
                // introspect.
                asm!("" : : "r"(&d));
                d
            }
        }
    }
    unsafe { black_box_impl(dummy) }
}
<|endoftext|>


<commit_before>pub trait MessageParser {
    type WeChatMessage;

    fn from_xml(xml: &str) -> Self::WeChatMessage;
}

mod text;
mod image;
mod voice;
mod shortvideo;
mod video;
mod location;
mod link;
mod unknown;

// export Message types
pub use self::text::TextMessage;
pub use self::image::ImageMessage;
pub use self::voice::VoiceMessage;
pub use self::shortvideo::ShortVideoMessage;
pub use self::video::VideoMessage;
pub use self::location::LocationMessage;
pub use self::link::LinkMessage;
pub use self::unknown::UnknownMessage;

// export Event types
pub use events::SubscribeEvent;
pub use events::UnsubscribeEvent;
pub use events::ScanEvent;
pub use events::SubscribeScanEvent;
pub use events::LocationEvent;
pub use events::ClickEvent;
pub use events::ViewEvent;

// an enum or messages and events
pub enum Message {
    TextMessage(TextMessage),
    ImageMessage(ImageMessage),
    VoiceMessage(VoiceMessage),
    ShortVideoMessage(ShortVideoMessage),
    VideoMessage(VideoMessage),
    LocationMessage(LocationMessage),
    LinkMessage(LinkMessage),
    UnknownMessage(UnknownMessage),
    SubscribeEvent(SubscribeEvent),
    UnsubscribeEvent(UnsubscribeEvent),
    ScanEvent(ScanEvent),
    SubscribeScanEvent(SubscribeScanEvent),
    LocationEvent(LocationEvent),
    ClickEvent(ClickEvent),
    ViewEvent(ViewEvent),
}
<commit_msg>Derive Debug and Clone traits for Message enum<commit_after>pub trait MessageParser {
    type WeChatMessage;

    fn from_xml(xml: &str) -> Self::WeChatMessage;
}

mod text;
mod image;
mod voice;
mod shortvideo;
mod video;
mod location;
mod link;
mod unknown;

// export Message types
pub use self::text::TextMessage;
pub use self::image::ImageMessage;
pub use self::voice::VoiceMessage;
pub use self::shortvideo::ShortVideoMessage;
pub use self::video::VideoMessage;
pub use self::location::LocationMessage;
pub use self::link::LinkMessage;
pub use self::unknown::UnknownMessage;

// export Event types
pub use events::SubscribeEvent;
pub use events::UnsubscribeEvent;
pub use events::ScanEvent;
pub use events::SubscribeScanEvent;
pub use events::LocationEvent;
pub use events::ClickEvent;
pub use events::ViewEvent;

// an enum or messages and events
#[derive(Debug, Clone)]
pub enum Message {
    TextMessage(TextMessage),
    ImageMessage(ImageMessage),
    VoiceMessage(VoiceMessage),
    ShortVideoMessage(ShortVideoMessage),
    VideoMessage(VideoMessage),
    LocationMessage(LocationMessage),
    LinkMessage(LinkMessage),
    UnknownMessage(UnknownMessage),
    SubscribeEvent(SubscribeEvent),
    UnsubscribeEvent(UnsubscribeEvent),
    ScanEvent(ScanEvent),
    SubscribeScanEvent(SubscribeScanEvent),
    LocationEvent(LocationEvent),
    ClickEvent(ClickEvent),
    ViewEvent(ViewEvent),
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter};

use ein_syntax::ast::{BinaryOp, Expr, Stmt, UnaryOp};

#[derive(Debug, Clone)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Value::Nil => write!(f, "nil"),
            Value::Boolean(v) => write!(f, "{}", v),
            Value::Number(v) => write!(f, "{}", v),
        }
    }
}

#[derive(Debug)]
pub enum Instruction {
    Return,
    Pop,

    LoadNil,
    LoadTrue,
    LoadFalse,
    LoadConstant(usize),

    Add,
    Subtract,
    Multiply,
    Divide,
    Negate,
}

pub trait Emit {
    fn emit(&self, chunk: &mut Chunk);
}

impl Emit for Expr {
    fn emit(&self, chunk: &mut Chunk) {
        match self {
            Expr::Nil => {
                chunk.add_instruction(Instruction::LoadNil);
            }
            Expr::BooleanLiteral(v) => {
                chunk.add_instruction(if *v {
                    Instruction::LoadTrue
                } else {
                    Instruction::LoadFalse
                });
            }
            Expr::NumberLiteral(v) => {
                let constant = chunk.add_constant(Value::Number(*v));
                chunk.add_instruction(Instruction::LoadConstant(constant));
            }
            Expr::UnaryOp(op, val) => {
                val.emit(chunk);

                chunk.add_instruction(match op {
                    UnaryOp::UnaryMinus => Instruction::Negate,
                    _ => unimplemented!(),
                });
            }
            Expr::BinaryOp(op, lhs, rhs) => {
                lhs.emit(chunk);
                rhs.emit(chunk);

                chunk.add_instruction(match op {
                    BinaryOp::Add => Instruction::Add,
                    BinaryOp::Subtract => Instruction::Subtract,
                    BinaryOp::Multiply => Instruction::Multiply,
                    BinaryOp::Divide => Instruction::Divide,
                    _ => unimplemented!(),
                });
            }
            _ => unimplemented!(),
        }
    }
}

impl Emit for Stmt {
    fn emit(&self, chunk: &mut Chunk) {
        match self {
            Stmt::ExprStmt(e) => {
                e.emit(chunk);
                chunk.add_instruction(Instruction::Pop);
            }
            _ => unimplemented!(),
        }
    }
}

impl Emit for Vec<Stmt> {
    fn emit(&self, chunk: &mut Chunk) {
        for stmt in self {
            stmt.emit(chunk)
        }
    }
}

#[derive(Debug)]
pub struct Chunk {
    constants: Vec<Value>,
    instructions: Vec<Instruction>,
}

impl Chunk {
    pub fn new() -> Chunk {
        Chunk {
            constants: vec![],
            instructions: vec![],
        }
    }

    pub fn add_instruction(&mut self, instruction: Instruction) -> usize {
        let i = self.instructions.len();
        self.instructions.push(instruction);
        i
    }

    pub fn add_constant(&mut self, value: Value) -> usize {
        let i = self.constants.len();
        self.constants.push(value);
        i
    }

    pub fn emit<T>(&mut self, node: &T)
    where
        T: Emit,
    {
        node.emit(self)
    }
}

macro_rules! binary_op_impl {
    ($self:ident, $name:literal, $op:tt) => {
        {
            let rhs = $self.stack.pop().unwrap();
            let lhs = $self.stack.pop().unwrap();

            match (lhs, rhs) {
                (Value::Number(a), Value::Number(b)) => $self.stack.push(Value::Number(a $op b)),
                (other_a, other_b) => panic!("Cannot {} {} and {}", $name, other_a, other_b),
            }
        }
    }
}

pub struct VirtualMachine {
    pc: usize,
    stack: Vec<Value>,
}

impl VirtualMachine {
    pub fn new() -> VirtualMachine {
        VirtualMachine {
            pc: 0,
            stack: vec![],
        }
    }

    pub fn run(&mut self, chunk: &Chunk) -> Option<Value> {
        self.pc = 0;
        self.stack = vec![];

        loop {
            let instruction = &chunk.instructions[self.pc];
            self.pc += 1;

            match instruction {
                Instruction::Return => {
                    return self.stack.last().cloned();
                }
                Instruction::Pop => {
                    self.stack.pop().unwrap();
                }
                Instruction::LoadNil => {
                    self.stack.push(Value::Nil);
                }
                Instruction::LoadTrue => {
                    self.stack.push(Value::Boolean(true));
                }
                Instruction::LoadFalse => {
                    self.stack.push(Value::Boolean(false));
                }
                Instruction::LoadConstant(i) => {
                    let constant = &chunk.constants[*i];
                    self.stack.push(constant.clone());
                }
                Instruction::Add => binary_op_impl!(self, "add", +),
                Instruction::Subtract => binary_op_impl!(self, "subtract", -),
                Instruction::Multiply => binary_op_impl!(self, "multiply", *),
                Instruction::Divide => binary_op_impl!(self, "divide", /),
                Instruction::Negate => {
                    let val = self.stack.pop().unwrap();

                    match val {
                        Value::Number(i) => self.stack.push(Value::Number(-i)),
                        other => panic!("Cannot negate {}", other),
                    }
                }
            }
        }
    }
}
<commit_msg>Make codegen branches exhaustive<commit_after>use std::fmt::{self, Display, Formatter};

use ein_syntax::ast::{BinaryOp, Expr, Stmt, UnaryOp};

#[derive(Debug, Clone)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Value::Nil => write!(f, "nil"),
            Value::Boolean(v) => write!(f, "{}", v),
            Value::Number(v) => write!(f, "{}", v),
        }
    }
}

#[derive(Debug)]
pub enum Instruction {
    Return,
    Pop,

    LoadNil,
    LoadTrue,
    LoadFalse,
    LoadConstant(usize),

    Add,
    Subtract,
    Multiply,
    Divide,
    Negate,
}

pub trait Emit {
    fn emit(&self, chunk: &mut Chunk);
}

impl Emit for Expr {
    fn emit(&self, chunk: &mut Chunk) {
        match self {
            Expr::Nil => {
                chunk.add_instruction(Instruction::LoadNil);
            }

            Expr::Identifier(_) => unimplemented!(),

            Expr::NumberLiteral(v) => {
                let constant = chunk.add_constant(Value::Number(*v));
                chunk.add_instruction(Instruction::LoadConstant(constant));
            }

            Expr::StringLiteral(_) => unimplemented!(),

            Expr::BooleanLiteral(v) => {
                chunk.add_instruction(if *v {
                    Instruction::LoadTrue
                } else {
                    Instruction::LoadFalse
                });
            }

            Expr::Assign(_, _) => unimplemented!(),

            Expr::Function(_, _) => unimplemented!(),

            Expr::Call(_, _) => unimplemented!(),

            Expr::UnaryOp(op, val) => {
                val.emit(chunk);

                chunk.add_instruction(match op {
                    UnaryOp::Not => unimplemented!(),
                    UnaryOp::UnaryMinus => Instruction::Negate,
                });
            }

            Expr::BinaryOp(op, lhs, rhs) => {
                lhs.emit(chunk);
                rhs.emit(chunk);

                chunk.add_instruction(match op {
                    BinaryOp::And => unimplemented!(),
                    BinaryOp::Or => unimplemented!(),
                    BinaryOp::Equals => unimplemented!(),
                    BinaryOp::NotEquals => unimplemented!(),
                    BinaryOp::GreaterThan => unimplemented!(),
                    BinaryOp::GreaterEquals => unimplemented!(),
                    BinaryOp::LessThan => unimplemented!(),
                    BinaryOp::LessEquals => unimplemented!(),
                    BinaryOp::Add => Instruction::Add,
                    BinaryOp::Subtract => Instruction::Subtract,
                    BinaryOp::Multiply => Instruction::Multiply,
                    BinaryOp::Divide => Instruction::Divide,
                });
            }
        }
    }
}

impl Emit for Stmt {
    fn emit(&self, chunk: &mut Chunk) {
        match self {
            Stmt::Return(_) => unimplemented!(),

            Stmt::ExprStmt(e) => {
                e.emit(chunk);
                chunk.add_instruction(Instruction::Pop);
            }

            Stmt::Declaration(_, _) => unimplemented!(),

            Stmt::If(_, _, _) => unimplemented!(),

            Stmt::While(_, _) => unimplemented!(),
        }
    }
}

impl Emit for Vec<Stmt> {
    fn emit(&self, chunk: &mut Chunk) {
        for stmt in self {
            stmt.emit(chunk)
        }
    }
}

#[derive(Debug)]
pub struct Chunk {
    constants: Vec<Value>,
    instructions: Vec<Instruction>,
}

impl Chunk {
    pub fn new() -> Chunk {
        Chunk {
            constants: vec![],
            instructions: vec![],
        }
    }

    pub fn add_instruction(&mut self, instruction: Instruction) -> usize {
        let i = self.instructions.len();
        self.instructions.push(instruction);
        i
    }

    pub fn add_constant(&mut self, value: Value) -> usize {
        let i = self.constants.len();
        self.constants.push(value);
        i
    }

    pub fn emit<T>(&mut self, node: &T)
    where
        T: Emit,
    {
        node.emit(self)
    }
}

macro_rules! arith_impl {
    ($self:ident, $name:literal, $op:tt) => {
        {
            let rhs = $self.stack.pop().unwrap();
            let lhs = $self.stack.pop().unwrap();

            match (lhs, rhs) {
                (Value::Number(a), Value::Number(b)) => $self.stack.push(Value::Number(a $op b)),
                (other_a, other_b) => panic!("Cannot {} {} and {}", $name, other_a, other_b),
            }
        }
    }
}

pub struct VirtualMachine {
    pc: usize,
    stack: Vec<Value>,
}

impl VirtualMachine {
    pub fn new() -> VirtualMachine {
        VirtualMachine {
            pc: 0,
            stack: vec![],
        }
    }

    pub fn run(&mut self, chunk: &Chunk) -> Option<Value> {
        self.pc = 0;
        self.stack = vec![];

        loop {
            let instruction = &chunk.instructions[self.pc];

            println!("{:04X} {:?}", self.pc, instruction);

            self.pc += 1;

            match instruction {
                Instruction::Return => {
                    return self.stack.last().cloned();
                }

                Instruction::Pop => {
                    self.stack.pop().unwrap();
                }

                Instruction::LoadNil => {
                    self.stack.push(Value::Nil);
                }

                Instruction::LoadTrue => {
                    self.stack.push(Value::Boolean(true));
                }

                Instruction::LoadFalse => {
                    self.stack.push(Value::Boolean(false));
                }

                Instruction::LoadConstant(i) => {
                    let constant = &chunk.constants[*i];
                    self.stack.push(constant.clone());
                }

                Instruction::Add => arith_impl!(self, "add", +),
                Instruction::Subtract => arith_impl!(self, "subtract", -),
                Instruction::Multiply => arith_impl!(self, "multiply", *),
                Instruction::Divide => arith_impl!(self, "divide", /),

                Instruction::Negate => {
                    let val = self.stack.pop().unwrap();

                    match val {
                        Value::Number(i) => self.stack.push(Value::Number(-i)),
                        other => panic!("Cannot negate {}", other),
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate base64;
extern crate md5;

use std::collections::HashMap;
use std::io::Write;

use super::bucket::Bucket;
use super::command::Command;
use chrono::{DateTime, Utc};
use hmac::Mac;
use reqwest::header::{self, HeaderMap, HeaderName, HeaderValue};
use reqwest::{Client, Response};
use sha2::{Digest, Sha256};
use url::Url;

use crate::signing;

use crate::EMPTY_PAYLOAD_SHA;
use crate::LONG_DATE;
use crate::{Result, S3Error};

use tokio::io::AsyncWriteExt;
use tokio::stream::StreamExt;
use once_cell::sync::Lazy;

/// Collection of HTTP headers sent to S3 service, in key/value format.
pub type Headers = HashMap<String, String>;

/// Collection of HTTP query parameters sent to S3 service, in key/value
/// format.
pub type Query = HashMap<String, String>;

static CLIENT: Lazy<Client> = Lazy::new(|| {
    if cfg!(feature = "no-verify-ssl") {
        Client::builder()
            .danger_accept_invalid_certs(true)
            .danger_accept_invalid_hostnames(true)
            .build()
            .expect("Could not build dangerous client!")
    } else {
        Client::new()
    }
});

// Temporary structure for making a request
pub struct Request<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
    pub sync: bool,
}

impl<'a> Request<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> Request<'b> {
        Request {
            bucket,
            path,
            command,
            datetime: Utc::now(),
            sync: false,
        }
    }

    fn url(&self) -> Url {
        let mut url_str = if cfg!(feature = "path-style") {
            format!("{}://{}/{}", self.bucket.scheme(), self.bucket.host(), self.bucket.name())
        } else {
            format!("{}://{}", self.bucket.scheme(), self.bucket.self_host())
        };

        if !self.path.starts_with('/') {
            url_str.push_str("/");
        }

        url_str.push_str(self.path);

        // Since every part of this URL is either pre-encoded or statically
        // generated, there's really no way this should fail.
        let mut url = Url::parse(&url_str).expect("static URL parsing");

        for (key, value) in &self.bucket.extra_query {
            url.query_pairs_mut().append_pair(key, value);
        }

        if let Command::ListBucket {
            prefix,
            delimiter,
            continuation_token,
        } = self.command.clone()
        {
            let mut query_pairs = url.query_pairs_mut();
            delimiter.map(|d| query_pairs.append_pair("delimiter", &d));
            query_pairs.append_pair("prefix", &prefix);
            query_pairs.append_pair("list-type", "2");
            if let Some(token) = continuation_token {
                query_pairs.append_pair("continuation-token", &token);
            }
        }

        match self.command {
            Command::PutObjectTagging { .. }
            | Command::GetObjectTagging
            | Command::DeleteObjectTagging => {
                url.query_pairs_mut().append_pair("tagging", "");
            }
            _ => {}
        }

        url
    }

    fn content_length(&self) -> usize {
        match self.command {
            Command::PutObject { content, .. } => content.len(),
            Command::PutObjectTagging { tags } => tags.len(),
            _ => 0,
        }
    }

    fn content_type(&self) -> String {
        match self.command {
            Command::PutObject { content_type, .. } => content_type.into(),
            _ => "text/plain".into(),
        }
    }

    fn sha256(&self) -> String {
        match self.command {
            Command::PutObject { content, .. } => {
                let mut sha = Sha256::default();
                sha.input(content);
                hex::encode(sha.result().as_slice())
            }
            Command::PutObjectTagging { tags } => {
                let mut sha = Sha256::default();
                sha.input(tags.as_bytes());
                hex::encode(sha.result().as_slice())
            }
            _ => EMPTY_PAYLOAD_SHA.into(),
        }
    }

    fn long_date(&self) -> String {
        self.datetime.format(LONG_DATE).to_string()
    }

    fn canonical_request(&self, headers: &HeaderMap) -> String {
        signing::canonical_request(
            self.command.http_verb().as_str(),
            &self.url(),
            headers,
            &self.sha256(),
        )
    }

    fn string_to_sign(&self, request: &str) -> String {
        signing::string_to_sign(&self.datetime, &self.bucket.region(), request)
    }

    fn signing_key(&self) -> Result<Vec<u8>> {
        Ok(signing::signing_key(
            &self.datetime,
            &self
                .bucket
                .secret_key()
                .expect("Secret key must be provided to sign headers, found None"),
            &self.bucket.region(),
            "s3",
        )?)
    }

    fn authorization(&self, headers: &HeaderMap) -> Result<String> {
        let canonical_request = self.canonical_request(headers);
        let string_to_sign = self.string_to_sign(&canonical_request);
        let mut hmac = signing::HmacSha256::new_varkey(&self.signing_key()?)?;
        hmac.input(string_to_sign.as_bytes());
        let signature = hex::encode(hmac.result().code());
        let signed_header = signing::signed_header_string(headers);
        Ok(signing::authorization_header(
            &self.bucket.access_key().unwrap(),
            &self.datetime,
            &self.bucket.region(),
            &signed_header,
            &signature,
        ))
    }

    fn headers(&self) -> Result<HeaderMap> {
        // Generate this once, but it's used in more than one place.
        let sha256 = self.sha256();

        // Start with extra_headers, that way our headers replace anything with
        // the same name.
        let mut headers = self
            .bucket
            .extra_headers
            .iter()
            .map(|(k, v)| Ok((k.parse::<HeaderName>()?, v.parse::<HeaderValue>()?)))
            .collect::<Result<HeaderMap, S3Error>>()?;

        headers.insert(header::HOST, self.bucket.self_host().parse()?);

        if cfg!(feature = "path-style") {
            headers.insert(header::HOST, self.bucket.host().parse()?);
        } else {
            headers.insert(header::HOST, self.bucket.self_host().parse()?);
        };

        match self.command {
            Command::ListBucket { .. } => {}
            Command::GetObject => {}
            Command::GetObjectTagging => {}
            Command::GetBucketLocation => {}
            _ => {
                headers.insert(
                    header::CONTENT_LENGTH,
                    self.content_length().to_string().parse()?,
                );
                headers.insert(header::CONTENT_TYPE, self.content_type().parse()?);
            }
        }
        headers.insert("X-Amz-Content-Sha256", sha256.parse()?);
        headers.insert("X-Amz-Date", self.long_date().parse()?);

        if let Some(session_token) = self.bucket.session_token() {
            headers.insert("X-Amz-Security-Token", session_token.parse()?);
        } else if let Some(security_token) = self.bucket.security_token() {
            headers.insert("X-Amz-Security-Token", security_token.parse()?);
        }

        if let Command::PutObjectTagging { tags } = self.command {
            let digest = md5::compute(tags);
            let hash = base64::encode(digest.as_ref());
            headers.insert("Content-MD5", hash.parse()?);
        } else if let Command::PutObject { content, .. } = self.command {
            let digest = md5::compute(content);
            let hash = base64::encode(digest.as_ref());
            headers.insert("Content-MD5", hash.parse()?);
        } else if let Command::GetObject {} = self.command {
            headers.insert(
                header::ACCEPT,
                HeaderValue::from_str("application/octet-stream")?,
            );
            // headers.insert(header::ACCEPT_CHARSET, HeaderValue::from_str("UTF-8")?);
        }

        // This must be last, as it signs the other headers, omitted if no secret key is provided
        if self.bucket.secret_key().is_some() {
            let authorization = self.authorization(&headers)?;
            headers.insert(header::AUTHORIZATION, authorization.parse()?);
        }

        // The format of RFC2822 is somewhat malleable, so including it in
        // signed headers can cause signature mismatches. We do include the
        // X-Amz-Date header, so requests are still properly limited to a date
        // range and can't be used again e.g. reply attacks. Adding this header
        // after the generation of the Authorization header leaves it out of
        // the signed headers.
        headers.insert(header::DATE, self.datetime.to_rfc2822().parse()?);

        Ok(headers)
    }

    // pub fn response_data(&self) -> Result<(Vec<u8>, u16)> {
    //     Ok(futures::executor::block_on(self.response_data_future())?)
    // }

    // pub fn response_data_to_writer<T: Write>(&self, writer: &mut T) -> Result<u16> {
    //     Ok(futures::executor::block_on(self.response_data_to_writer_future(writer))?)
    // }

    pub async fn response_future(&self) -> Result<Response> {
        // Build headers
        let headers = self.headers().expect("Could not get headers!");

        // Get owned content to pass to reqwest
        let content = if let Command::PutObject { content, .. } = self.command {
            Vec::from(content)
        } else if let Command::PutObjectTagging { tags } = self.command {
            Vec::from(tags)
        } else {
            Vec::new()
        };

        let request = CLIENT
            .request(self.command.http_verb(), self.url().as_str())
            .headers(headers.to_owned())
            .body(content.to_owned());

        let response = request.send().await?;

        if cfg!(feature = "fail-on-err") && response.status().as_u16() >= 400 {
            return Err(S3Error::from(
                format!(
                    "Request failed with code {}\n{}",
                    response.status().as_u16(),
                    response.text().await?
                )
                .as_str(),
            ));
        }

        Ok(response)
    }

    pub async fn response_data_future(&self) -> Result<(Vec<u8>, u16)> {
        let response = self.response_future().await?;
        let status_code = response.status().as_u16();
        let body = response.bytes().await?;
        let mut body_vec = Vec::new();
        body_vec.extend_from_slice(&body[..]);
        Ok((body_vec, status_code))
    }

    pub async fn response_data_to_writer_future<'b, T: Write>(
        &self,
        writer: &'b mut T,
    ) -> Result<u16> {
        let response = self.response_future().await?;

        let status_code = response.status();
        let mut stream = response.bytes_stream();

        while let Some(item) = stream.next().await {
            writer.write(&item?)?;
        }

        Ok(status_code.as_u16())
    }

    pub async fn tokio_response_data_to_writer_future<'b, T: AsyncWriteExt + Unpin>(
        &self,
        writer: &'b mut T,
    ) -> Result<u16> {
        let response = self.response_future().await?;

        let status_code = response.status();
        let mut stream = response.bytes_stream();

        while let Some(item) = stream.next().await {
            writer.write(&item?).await?;
        }

        Ok(status_code.as_u16())
    }
}

#[cfg(test)]
mod tests {
    use crate::bucket::Bucket;
    use crate::command::Command;
    use crate::request::Request;
    use crate::Result;
    use awscreds::Credentials;

    // Fake keys - otherwise using Credentials::default will use actual user
    // credentials if they exist.
    fn fake_credentials() -> Credentials {
        const ACCESS_KEY: &'static str = "AKIAIOSFODNN7EXAMPLE";
        const SECRET_KEY: &'static str = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
        Credentials::new_blocking(
            Some(ACCESS_KEY.into()),
            Some(SECRET_KEY.into()),
            None,
            None,
            None,
        )
        .unwrap()
    }

    #[test]
    fn url_uses_https_by_default() -> Result<()> {
        let region = "custom-region".parse()?;
        let bucket = Bucket::new("my-first-bucket", region, fake_credentials())?;
        let path = "/my-first/path";
        let request = Request::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        if cfg!(feature = "path-style") {
            assert_eq!(*host, "custom-region".to_string());
        } else {
            assert_eq!(*host, "my-first-bucket.custom-region".to_string());
        }
        Ok(())
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined() -> Result<()> {
        let region = "http://custom-region".parse()?;
        let bucket = Bucket::new("my-second-bucket", region, fake_credentials())?;
        let path = "/my-second/path";
        let request = Request::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();
        if cfg!(feature = "path-style") {
            assert_eq!(*host, "custom-region".to_string());
        } else {
            assert_eq!(*host, "my-second-bucket.custom-region".to_string());
        }
        Ok(())
    }
}
<commit_msg>Use result<commit_after>extern crate base64;
extern crate md5;

use std::collections::HashMap;
use std::io::Write;

use super::bucket::Bucket;
use super::command::Command;
use chrono::{DateTime, Utc};
use hmac::Mac;
use reqwest::header::{self, HeaderMap, HeaderName, HeaderValue};
use reqwest::{Client, Response};
use sha2::{Digest, Sha256};
use url::Url;

use crate::signing;

use crate::EMPTY_PAYLOAD_SHA;
use crate::LONG_DATE;
use crate::{Result, S3Error};

use tokio::io::AsyncWriteExt;
use tokio::stream::StreamExt;
use once_cell::sync::Lazy;

/// Collection of HTTP headers sent to S3 service, in key/value format.
pub type Headers = HashMap<String, String>;

/// Collection of HTTP query parameters sent to S3 service, in key/value
/// format.
pub type Query = HashMap<String, String>;

static CLIENT: Lazy<Client> = Lazy::new(|| {
    if cfg!(feature = "no-verify-ssl") {
        Client::builder()
            .danger_accept_invalid_certs(true)
            .danger_accept_invalid_hostnames(true)
            .build()
            .expect("Could not build dangerous client!")
    } else {
        Client::new()
    }
});

// Temporary structure for making a request
pub struct Request<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
    pub sync: bool,
}

impl<'a> Request<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> Request<'b> {
        Request {
            bucket,
            path,
            command,
            datetime: Utc::now(),
            sync: false,
        }
    }

    fn url(&self) -> Url {
        let mut url_str = if cfg!(feature = "path-style") {
            format!("{}://{}/{}", self.bucket.scheme(), self.bucket.host(), self.bucket.name())
        } else {
            format!("{}://{}", self.bucket.scheme(), self.bucket.self_host())
        };

        if !self.path.starts_with('/') {
            url_str.push_str("/");
        }

        url_str.push_str(self.path);

        // Since every part of this URL is either pre-encoded or statically
        // generated, there's really no way this should fail.
        let mut url = Url::parse(&url_str).expect("static URL parsing");

        for (key, value) in &self.bucket.extra_query {
            url.query_pairs_mut().append_pair(key, value);
        }

        if let Command::ListBucket {
            prefix,
            delimiter,
            continuation_token,
        } = self.command.clone()
        {
            let mut query_pairs = url.query_pairs_mut();
            delimiter.map(|d| query_pairs.append_pair("delimiter", &d));
            query_pairs.append_pair("prefix", &prefix);
            query_pairs.append_pair("list-type", "2");
            if let Some(token) = continuation_token {
                query_pairs.append_pair("continuation-token", &token);
            }
        }

        match self.command {
            Command::PutObjectTagging { .. }
            | Command::GetObjectTagging
            | Command::DeleteObjectTagging => {
                url.query_pairs_mut().append_pair("tagging", "");
            }
            _ => {}
        }

        url
    }

    fn content_length(&self) -> usize {
        match self.command {
            Command::PutObject { content, .. } => content.len(),
            Command::PutObjectTagging { tags } => tags.len(),
            _ => 0,
        }
    }

    fn content_type(&self) -> String {
        match self.command {
            Command::PutObject { content_type, .. } => content_type.into(),
            _ => "text/plain".into(),
        }
    }

    fn sha256(&self) -> String {
        match self.command {
            Command::PutObject { content, .. } => {
                let mut sha = Sha256::default();
                sha.input(content);
                hex::encode(sha.result().as_slice())
            }
            Command::PutObjectTagging { tags } => {
                let mut sha = Sha256::default();
                sha.input(tags.as_bytes());
                hex::encode(sha.result().as_slice())
            }
            _ => EMPTY_PAYLOAD_SHA.into(),
        }
    }

    fn long_date(&self) -> String {
        self.datetime.format(LONG_DATE).to_string()
    }

    fn canonical_request(&self, headers: &HeaderMap) -> String {
        signing::canonical_request(
            self.command.http_verb().as_str(),
            &self.url(),
            headers,
            &self.sha256(),
        )
    }

    fn string_to_sign(&self, request: &str) -> String {
        signing::string_to_sign(&self.datetime, &self.bucket.region(), request)
    }

    fn signing_key(&self) -> Result<Vec<u8>> {
        Ok(signing::signing_key(
            &self.datetime,
            &self
                .bucket
                .secret_key()
                .expect("Secret key must be provided to sign headers, found None"),
            &self.bucket.region(),
            "s3",
        )?)
    }

    fn authorization(&self, headers: &HeaderMap) -> Result<String> {
        let canonical_request = self.canonical_request(headers);
        let string_to_sign = self.string_to_sign(&canonical_request);
        let mut hmac = signing::HmacSha256::new_varkey(&self.signing_key()?)?;
        hmac.input(string_to_sign.as_bytes());
        let signature = hex::encode(hmac.result().code());
        let signed_header = signing::signed_header_string(headers);
        Ok(signing::authorization_header(
            &self.bucket.access_key().unwrap(),
            &self.datetime,
            &self.bucket.region(),
            &signed_header,
            &signature,
        ))
    }

    fn headers(&self) -> Result<HeaderMap> {
        // Generate this once, but it's used in more than one place.
        let sha256 = self.sha256();

        // Start with extra_headers, that way our headers replace anything with
        // the same name.
        let mut headers = self
            .bucket
            .extra_headers
            .iter()
            .map(|(k, v)| Ok((k.parse::<HeaderName>()?, v.parse::<HeaderValue>()?)))
            .collect::<Result<HeaderMap, S3Error>>()?;

        headers.insert(header::HOST, self.bucket.self_host().parse()?);

        if cfg!(feature = "path-style") {
            headers.insert(header::HOST, self.bucket.host().parse()?);
        } else {
            headers.insert(header::HOST, self.bucket.self_host().parse()?);
        };

        match self.command {
            Command::ListBucket { .. } => {}
            Command::GetObject => {}
            Command::GetObjectTagging => {}
            Command::GetBucketLocation => {}
            _ => {
                headers.insert(
                    header::CONTENT_LENGTH,
                    self.content_length().to_string().parse()?,
                );
                headers.insert(header::CONTENT_TYPE, self.content_type().parse()?);
            }
        }
        headers.insert("X-Amz-Content-Sha256", sha256.parse()?);
        headers.insert("X-Amz-Date", self.long_date().parse()?);

        if let Some(session_token) = self.bucket.session_token() {
            headers.insert("X-Amz-Security-Token", session_token.parse()?);
        } else if let Some(security_token) = self.bucket.security_token() {
            headers.insert("X-Amz-Security-Token", security_token.parse()?);
        }

        if let Command::PutObjectTagging { tags } = self.command {
            let digest = md5::compute(tags);
            let hash = base64::encode(digest.as_ref());
            headers.insert("Content-MD5", hash.parse()?);
        } else if let Command::PutObject { content, .. } = self.command {
            let digest = md5::compute(content);
            let hash = base64::encode(digest.as_ref());
            headers.insert("Content-MD5", hash.parse()?);
        } else if let Command::GetObject {} = self.command {
            headers.insert(
                header::ACCEPT,
                HeaderValue::from_str("application/octet-stream")?,
            );
            // headers.insert(header::ACCEPT_CHARSET, HeaderValue::from_str("UTF-8")?);
        }

        // This must be last, as it signs the other headers, omitted if no secret key is provided
        if self.bucket.secret_key().is_some() {
            let authorization = self.authorization(&headers)?;
            headers.insert(header::AUTHORIZATION, authorization.parse()?);
        }

        // The format of RFC2822 is somewhat malleable, so including it in
        // signed headers can cause signature mismatches. We do include the
        // X-Amz-Date header, so requests are still properly limited to a date
        // range and can't be used again e.g. reply attacks. Adding this header
        // after the generation of the Authorization header leaves it out of
        // the signed headers.
        headers.insert(header::DATE, self.datetime.to_rfc2822().parse()?);

        Ok(headers)
    }

    // pub fn response_data(&self) -> Result<(Vec<u8>, u16)> {
    //     Ok(futures::executor::block_on(self.response_data_future())?)
    // }

    // pub fn response_data_to_writer<T: Write>(&self, writer: &mut T) -> Result<u16> {
    //     Ok(futures::executor::block_on(self.response_data_to_writer_future(writer))?)
    // }

    pub async fn response_future(&self) -> Result<Response> {
        // Build headers
        let headers = self.headers().expect("Could not get headers!");

        // Get owned content to pass to reqwest
        let content = if let Command::PutObject { content, .. } = self.command {
            Vec::from(content)
        } else if let Command::PutObjectTagging { tags } = self.command {
            Vec::from(tags)
        } else {
            Vec::new()
        };

        let request = CLIENT
            .request(self.command.http_verb(), self.url().as_str())
            .headers(headers.to_owned())
            .body(content.to_owned());

        let response = request.send().await?;

        if cfg!(feature = "fail-on-err") && response.status().as_u16() >= 400 {
            return Err(S3Error::from(
                format!(
                    "Request failed with code {}\n{}",
                    response.status().as_u16(),
                    response.text().await?
                )
                .as_str(),
            ));
        }

        Ok(response)
    }

    pub async fn response_data_future(&self) -> Result<(Vec<u8>, u16)> {
        let response = self.response_future().await?;
        let status_code = response.status().as_u16();
        let body = response.bytes().await?;
        let mut body_vec = Vec::new();
        body_vec.extend_from_slice(&body[..]);
        Ok((body_vec, status_code))
    }

    pub async fn response_data_to_writer_future<'b, T: Write>(
        &self,
        writer: &'b mut T,
    ) -> Result<u16> {
        let response = self.response_future().await?;

        let status_code = response.status();
        let mut stream = response.bytes_stream();

        while let Some(item) = stream.next().await {
            writer.write_all(&item?)?;
        }

        Ok(status_code.as_u16())
    }

    pub async fn tokio_response_data_to_writer_future<'b, T: AsyncWriteExt + Unpin>(
        &self,
        writer: &'b mut T,
    ) -> Result<u16> {
        let response = self.response_future().await?;

        let status_code = response.status();
        let mut stream = response.bytes_stream();

        while let Some(item) = stream.next().await {
            writer.write(&item?).await?;
        }

        Ok(status_code.as_u16())
    }
}

#[cfg(test)]
mod tests {
    use crate::bucket::Bucket;
    use crate::command::Command;
    use crate::request::Request;
    use crate::Result;
    use awscreds::Credentials;

    // Fake keys - otherwise using Credentials::default will use actual user
    // credentials if they exist.
    fn fake_credentials() -> Credentials {
        const ACCESS_KEY: &'static str = "AKIAIOSFODNN7EXAMPLE";
        const SECRET_KEY: &'static str = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
        Credentials::new_blocking(
            Some(ACCESS_KEY.into()),
            Some(SECRET_KEY.into()),
            None,
            None,
            None,
        )
        .unwrap()
    }

    #[test]
    fn url_uses_https_by_default() -> Result<()> {
        let region = "custom-region".parse()?;
        let bucket = Bucket::new("my-first-bucket", region, fake_credentials())?;
        let path = "/my-first/path";
        let request = Request::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        if cfg!(feature = "path-style") {
            assert_eq!(*host, "custom-region".to_string());
        } else {
            assert_eq!(*host, "my-first-bucket.custom-region".to_string());
        }
        Ok(())
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined() -> Result<()> {
        let region = "http://custom-region".parse()?;
        let bucket = Bucket::new("my-second-bucket", region, fake_credentials())?;
        let path = "/my-second/path";
        let request = Request::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();
        if cfg!(feature = "path-style") {
            assert_eq!(*host, "custom-region".to_string());
        } else {
            assert_eq!(*host, "my-second-bucket.custom-region".to_string());
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate comm;

use comm::address::Address;
use comm::client;
use comm::client::{Client, Event, Task, TaskSender};
use comm::network::Network;
use comm::node::{Node, UdpNode};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::sync::mpsc;
use std::thread;

#[no_mangle]
pub extern "C" fn comm_initialize() {
    env_logger::init().expect("Couldn't initialize logger");
}

#[no_mangle]
pub extern "C" fn comm_address_for_content(content: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(content) };
    let address = Address::for_content(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_from_str(string: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(string) };
    let address = Address::from_str(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_null() -> *const Address {
    Box::into_raw(Box::new(Address::null()))
}

#[no_mangle]
pub extern "C" fn comm_address_copy(address: *const Address) -> *const Address {
    let copy = unsafe { *address }.clone();
    Box::into_raw(Box::new(copy))
}

// TODO: impl API to clean up leaked strings
#[no_mangle]
pub extern "C" fn comm_address_to_str(address: *const Address) -> *const c_char {
    let string = unsafe { *address }.to_str();
    let string = CString::new(string).unwrap();
    string.into_raw()
}

#[no_mangle]
pub unsafe extern "C" fn comm_address_destroy(address: *mut Address) {
    let _ = Box::from_raw(address);
}

#[no_mangle]
pub extern "C" fn comm_udp_node_new(
    address: *const Address, socket_address: *const c_char) -> *const UdpNode {
    let socket_address: &CStr = unsafe { CStr::from_ptr(socket_address) };
    let node = UdpNode::new(unsafe { *address }, socket_address.to_str().unwrap());
    Box::into_raw(Box::new(node))
}

#[no_mangle]
pub unsafe extern "C" fn comm_udp_node_destroy(udp_node: *mut UdpNode) {
    let _ = Box::from_raw(udp_node);
}

#[no_mangle]
pub extern "C" fn comm_network_new(
    self_address: *mut Address, host: *const c_char,
    routers: *mut *mut UdpNode, routers_count: usize) -> *mut Network {

    use std::mem;

    let self_address = unsafe { *self_address };
    let host: &CStr = unsafe { CStr::from_ptr(host) };
    let raw_routers = unsafe { Vec::from_raw_parts(routers, routers_count, routers_count) };
    let routers: Vec<Box<Node>> = raw_routers.iter().map(|&r| unsafe {
        Box::from_raw(r) as Box<Node>
    }).collect();
    mem::forget(raw_routers);
    let network = Network::new(self_address, host.to_str().unwrap(), routers);
    Box::into_raw(Box::new(network))
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_run(network: *mut Network) {
    let network = Box::from_raw(network);
    network.run();
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_destroy(network: *mut Network) {
    let _ = Box::from_raw(network);
}

#[no_mangle]
pub extern "C" fn comm_text_message_new(sender: *mut Address, text: *const c_char) -> *const client::messages::TextMessage {
    let sender = unsafe { *Box::from_raw(sender) };
    let c_str: &CStr = unsafe { CStr::from_ptr(text) };
    let message_text = c_str.to_str().unwrap().to_string();

    Box::into_raw(Box::new(client::messages::TextMessage::new(sender, message_text)))
}

// TODO: impl API to clean up leaked strings
#[no_mangle]
pub extern "C" fn comm_text_message_text(text_message: *const client::messages::TextMessage) -> *const c_char {
    let text_message = unsafe { &*text_message };
    let string = CString::new(text_message.text.clone()).unwrap();
    string.into_raw()
}

#[no_mangle]
pub extern "C" fn comm_text_message_sender(text_message: *const client::messages::TextMessage) -> *const Address {
    let text_message = unsafe { &*text_message };
    Box::into_raw(Box::new(text_message.sender))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_new(address: *const Address) -> *mut Client {
    Box::into_raw(Box::new(Client::new(*address)))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_run(
    client: *mut Client, network: *mut Network) -> *mut TaskSender {
    let client = Box::from_raw(client);
    let network = *Box::from_raw(network);
    Box::into_raw(Box::new(client.run(network)))
}

#[no_mangle]
pub extern "C" fn comm_client_register_text_message_received_callback(
    client: *mut Client, callback: extern fn(*const client::messages::TextMessage) -> ()) {

    let client = unsafe { &mut *client };
    let (event_sender, events) = mpsc::channel();
    client.register_event_listener(event_sender);

    thread::spawn(move || {
        for event in events {
            if let Event::ReceivedTextMessage(text_message) = event {
                callback(Box::into_raw(Box::new(text_message)));
            }
        }
    });
}

#[no_mangle]
pub extern "C" fn comm_client_commands_send_text_message(
    commands: *mut TaskSender,
    recipient: *mut Address,
    text_message: *mut client::messages::TextMessage) {
    let commands = unsafe { &mut *commands };
    let recipient = unsafe { *Box::from_raw(recipient) };
    let text_message = unsafe { *Box::from_raw(text_message) };
    commands.send(Task::ScheduleMessageDelivery(recipient, text_message)).unwrap();
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_destroy(client: *mut Client) {
    let _ = Box::from_raw(client);
}
<commit_msg>Return TaskSender from network_run function<commit_after>extern crate env_logger;
extern crate comm;

use comm::address::Address;
use comm::client;
use comm::client::{Client, Event, Task, TaskSender};
use comm::network::Network;
use comm::node::{Node, UdpNode};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::sync::mpsc;
use std::thread;

#[no_mangle]
pub extern "C" fn comm_initialize() {
    env_logger::init().expect("Couldn't initialize logger");
}

#[no_mangle]
pub extern "C" fn comm_address_for_content(content: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(content) };
    let address = Address::for_content(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_from_str(string: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(string) };
    let address = Address::from_str(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_null() -> *const Address {
    Box::into_raw(Box::new(Address::null()))
}

#[no_mangle]
pub extern "C" fn comm_address_copy(address: *const Address) -> *const Address {
    let copy = unsafe { *address }.clone();
    Box::into_raw(Box::new(copy))
}

// TODO: impl API to clean up leaked strings
#[no_mangle]
pub extern "C" fn comm_address_to_str(address: *const Address) -> *const c_char {
    let string = unsafe { *address }.to_str();
    let string = CString::new(string).unwrap();
    string.into_raw()
}

#[no_mangle]
pub unsafe extern "C" fn comm_address_destroy(address: *mut Address) {
    let _ = Box::from_raw(address);
}

#[no_mangle]
pub extern "C" fn comm_udp_node_new(
    address: *const Address, socket_address: *const c_char) -> *const UdpNode {
    let socket_address: &CStr = unsafe { CStr::from_ptr(socket_address) };
    let node = UdpNode::new(unsafe { *address }, socket_address.to_str().unwrap());
    Box::into_raw(Box::new(node))
}

#[no_mangle]
pub unsafe extern "C" fn comm_udp_node_destroy(udp_node: *mut UdpNode) {
    let _ = Box::from_raw(udp_node);
}

#[no_mangle]
pub extern "C" fn comm_network_new(
    self_address: *mut Address, host: *const c_char,
    routers: *mut *mut UdpNode, routers_count: usize) -> *mut Network {

    use std::mem;

    let self_address = unsafe { *self_address };
    let host: &CStr = unsafe { CStr::from_ptr(host) };
    let raw_routers = unsafe { Vec::from_raw_parts(routers, routers_count, routers_count) };
    let routers: Vec<Box<Node>> = raw_routers.iter().map(|&r| unsafe {
        Box::from_raw(r) as Box<Node>
    }).collect();
    mem::forget(raw_routers);
    let network = Network::new(self_address, host.to_str().unwrap(), routers);
    Box::into_raw(Box::new(network))
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_run(network: *mut Network) -> *mut network::TaskSender {
    let network = Box::from_raw(network);
    Box::into_raw(Box::new(network.run()))
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_destroy(network: *mut Network) {
    let _ = Box::from_raw(network);
}

#[no_mangle]
pub extern "C" fn comm_text_message_new(sender: *mut Address, text: *const c_char) -> *const client::messages::TextMessage {
    let sender = unsafe { *Box::from_raw(sender) };
    let c_str: &CStr = unsafe { CStr::from_ptr(text) };
    let message_text = c_str.to_str().unwrap().to_string();

    Box::into_raw(Box::new(client::messages::TextMessage::new(sender, message_text)))
}

// TODO: impl API to clean up leaked strings
#[no_mangle]
pub extern "C" fn comm_text_message_text(text_message: *const client::messages::TextMessage) -> *const c_char {
    let text_message = unsafe { &*text_message };
    let string = CString::new(text_message.text.clone()).unwrap();
    string.into_raw()
}

#[no_mangle]
pub extern "C" fn comm_text_message_sender(text_message: *const client::messages::TextMessage) -> *const Address {
    let text_message = unsafe { &*text_message };
    Box::into_raw(Box::new(text_message.sender))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_new(address: *const Address) -> *mut Client {
    Box::into_raw(Box::new(Client::new(*address)))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_run(
    client: *mut Client, network: *mut Network) -> *mut TaskSender {
    let client = Box::from_raw(client);
    let network = *Box::from_raw(network);
    Box::into_raw(Box::new(client.run(network)))
}

#[no_mangle]
pub extern "C" fn comm_client_register_text_message_received_callback(
    client: *mut Client, callback: extern fn(*const client::messages::TextMessage) -> ()) {

    let client = unsafe { &mut *client };
    let (event_sender, events) = mpsc::channel();
    client.register_event_listener(event_sender);

    thread::spawn(move || {
        for event in events {
            if let Event::ReceivedTextMessage(text_message) = event {
                callback(Box::into_raw(Box::new(text_message)));
            }
        }
    });
}

#[no_mangle]
pub extern "C" fn comm_client_commands_send_text_message(
    commands: *mut TaskSender,
    recipient: *mut Address,
    text_message: *mut client::messages::TextMessage) {
    let commands = unsafe { &mut *commands };
    let recipient = unsafe { *Box::from_raw(recipient) };
    let text_message = unsafe { *Box::from_raw(text_message) };
    commands.send(Task::ScheduleMessageDelivery(recipient, text_message)).unwrap();
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_destroy(client: *mut Client) {
    let _ = Box::from_raw(client);
}
<|endoftext|>


<commit_before>use criterion::{criterion_group, criterion_main, Criterion};

fn emu_fetch_benchmark(c: &mut Criterion) {
    // 0:  48 c7 c0 01 00 00 00    mov    rax,0x1
    let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\xC7\xC0\x01\x00\x00\x00"[..]);
    emu.reg.rip = 0x0;

    c.bench_function("fetch", |b| {
        b.iter(|| {
            emu.mem.read_u128(criterion::black_box(0x0)).unwrap();
        })
    });

    c.bench_function("fetch and decode", |b| {
        b.iter(|| {
            emu.fetch().unwrap();
        })
    });
}

fn emu_insn_benchmark(c: &mut Criterion) {
    c.bench_function("mov rax, 0x1", |b| {
        // 0:  48 c7 c0 01 00 00 00    mov    rax,0x1
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\xC7\xC0\x01\x00\x00\x00"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.step().unwrap();
        })
    });

    c.bench_function("push 0x1", |b| {
        // 0:  6a 01                   push   0x1
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x6A\x01"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.reg.rsp = 0x6000;
            emu.step().unwrap();
        })
    });

    c.bench_function("sub rax, rbx", |b| {
        // 0:  48 29 d8                sub    rax,rbx
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\x29\xD8"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.reg.rax = 0x1;
            emu.reg.rbx = 0x1;
            emu.step().unwrap();
        })
    });

    c.bench_function("add rax, rbx", |b| {
        // 0:  48 01 d8                add    rax,rbx
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\x01\xD8"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.reg.rax = 0x1;
            emu.reg.rbx = 0x1;
            emu.step().unwrap();
        })
    });
}

fn cfg_benchmark(c: &mut Criterion) {
    use lancelot::analysis::cfg::instruction_index::*;

    c.bench_function("InstructionIndex.build_index", |b| {
        let buf = lancelot::rsrc::get_buf(lancelot::rsrc::Rsrc::K32);
        let pe = lancelot::loader::pe::PE::from_bytes(&buf).unwrap();

        let mut functions: Vec<_> = Default::default();
        functions.extend(lancelot::analysis::pe::entrypoints::find_pe_entrypoint(&pe).unwrap());
        functions.extend(lancelot::analysis::pe::exports::find_pe_exports(&pe).unwrap());

        b.iter(|| {
            let mut insns: InstructionIndex = Default::default();

            for &function in functions.iter() {
                insns.build_index(&pe.module, function).unwrap();
            }
        })
    });

    c.bench_function("CFG.from_instructions", |b| {
        let buf = lancelot::rsrc::get_buf(lancelot::rsrc::Rsrc::K32);
        let pe = lancelot::loader::pe::PE::from_bytes(&buf).unwrap();

        let mut functions: Vec<_> = Default::default();
        functions.extend(lancelot::analysis::pe::entrypoints::find_pe_entrypoint(&pe).unwrap());
        functions.extend(lancelot::analysis::pe::exports::find_pe_exports(&pe).unwrap());

        let mut insns: InstructionIndex = Default::default();
        for &function in functions.iter() {
            insns.build_index(&pe.module, function).unwrap();
        }

        b.iter(|| CFG::from_instructions(insns.clone()))
    });
}

criterion_group!(cfg, cfg_benchmark);
criterion_group!(emu_fetch, emu_fetch_benchmark);
criterion_group!(emu_insn, emu_insn_benchmark);
criterion_main!(emu_fetch, emu_insn, cfg);
<commit_msg>core: bench: rename cfg benches<commit_after>use criterion::{criterion_group, criterion_main, Criterion};

fn emu_fetch_benchmark(c: &mut Criterion) {
    // 0:  48 c7 c0 01 00 00 00    mov    rax,0x1
    let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\xC7\xC0\x01\x00\x00\x00"[..]);
    emu.reg.rip = 0x0;

    c.bench_function("fetch", |b| {
        b.iter(|| {
            emu.mem.read_u128(criterion::black_box(0x0)).unwrap();
        })
    });

    c.bench_function("fetch and decode", |b| {
        b.iter(|| {
            emu.fetch().unwrap();
        })
    });
}

fn emu_insn_benchmark(c: &mut Criterion) {
    c.bench_function("mov rax, 0x1", |b| {
        // 0:  48 c7 c0 01 00 00 00    mov    rax,0x1
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\xC7\xC0\x01\x00\x00\x00"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.step().unwrap();
        })
    });

    c.bench_function("push 0x1", |b| {
        // 0:  6a 01                   push   0x1
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x6A\x01"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.reg.rsp = 0x6000;
            emu.step().unwrap();
        })
    });

    c.bench_function("sub rax, rbx", |b| {
        // 0:  48 29 d8                sub    rax,rbx
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\x29\xD8"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.reg.rax = 0x1;
            emu.reg.rbx = 0x1;
            emu.step().unwrap();
        })
    });

    c.bench_function("add rax, rbx", |b| {
        // 0:  48 01 d8                add    rax,rbx
        let mut emu = lancelot::test::emu_from_shellcode64(&b"\x48\x01\xD8"[..]);
        b.iter(|| {
            emu.reg.rip = 0x0;
            emu.reg.rax = 0x1;
            emu.reg.rbx = 0x1;
            emu.step().unwrap();
        })
    });
}

fn cfg_benchmark(c: &mut Criterion) {
    use lancelot::analysis::cfg::instruction_index::*;

    c.bench_function("cfg::InstructionIndex::build_index", |b| {
        let buf = lancelot::rsrc::get_buf(lancelot::rsrc::Rsrc::K32);
        let pe = lancelot::loader::pe::PE::from_bytes(&buf).unwrap();

        let mut functions: Vec<_> = Default::default();
        functions.extend(lancelot::analysis::pe::entrypoints::find_pe_entrypoint(&pe).unwrap());
        functions.extend(lancelot::analysis::pe::exports::find_pe_exports(&pe).unwrap());

        b.iter(|| {
            let mut insns: InstructionIndex = Default::default();

            for &function in functions.iter() {
                insns.build_index(&pe.module, function).unwrap();
            }
        })
    });

    c.bench_function("cfg::CFG::from_instructions", |b| {
        let buf = lancelot::rsrc::get_buf(lancelot::rsrc::Rsrc::K32);
        let pe = lancelot::loader::pe::PE::from_bytes(&buf).unwrap();

        let mut functions: Vec<_> = Default::default();
        functions.extend(lancelot::analysis::pe::entrypoints::find_pe_entrypoint(&pe).unwrap());
        functions.extend(lancelot::analysis::pe::exports::find_pe_exports(&pe).unwrap());

        let mut insns: InstructionIndex = Default::default();
        for &function in functions.iter() {
            insns.build_index(&pe.module, function).unwrap();
        }

        b.iter(|| CFG::from_instructions(insns.clone()))
    });
}

criterion_group!(cfg, cfg_benchmark);
criterion_group!(emu_fetch, emu_fetch_benchmark);
criterion_group!(emu_insn, emu_insn_benchmark);
criterion_main!(emu_fetch, emu_insn, cfg);
<|endoftext|>


<commit_before><commit_msg>fixed errors<commit_after><|endoftext|>


<commit_before>extern crate env_logger;
extern crate fuse;
extern crate libc;
extern crate time;

use std::env;
use std::ffi::OsStr;
use libc::ENOENT;
use time::Timespec;
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory};

const TTL: Timespec = Timespec { sec: 1, nsec: 0 };                     // 1 second

const CREATE_TIME: Timespec = Timespec { sec: 1381237736, nsec: 0 };    // 2013-10-08 08:56

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &'static str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct HelloFS;

impl Filesystem for HelloFS {
    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, _size: u32, reply: ReplyData) {
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, ".");
                reply.add(1, 1, FileType::Directory, "..");
                reply.add(2, 2, FileType::RegularFile, "hello.txt");
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    env_logger::init().unwrap();
    let mountpoint = env::args_os().nth(1).unwrap();
    fuse::mount(HelloFS, &mountpoint, &[]).unwrap();
}
<commit_msg>add some example options to example/hello.rs<commit_after>extern crate env_logger;
extern crate fuse;
extern crate libc;
extern crate time;

use std::env;
use std::ffi::OsStr;
use libc::ENOENT;
use time::Timespec;
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory};

const TTL: Timespec = Timespec { sec: 1, nsec: 0 };                     // 1 second

const CREATE_TIME: Timespec = Timespec { sec: 1381237736, nsec: 0 };    // 2013-10-08 08:56

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &'static str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: CREATE_TIME,
    mtime: CREATE_TIME,
    ctime: CREATE_TIME,
    crtime: CREATE_TIME,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct HelloFS;

impl Filesystem for HelloFS {
    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, _size: u32, reply: ReplyData) {
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, ".");
                reply.add(1, 1, FileType::Directory, "..");
                reply.add(2, 2, FileType::RegularFile, "hello.txt");
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    env_logger::init().unwrap();
    let mountpoint = env::args_os().nth(1).unwrap();
    let options = ["-o", "ro", "-o", "fsname=hello"]
        .iter()
        .map(|o| o.as_ref())
        .collect::<Vec<&OsStr>>();
    fuse::mount(HelloFS, &mountpoint, &options).unwrap();
}
<|endoftext|>


<commit_before>use crossterm::{
    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{error::Error, io};
use tui::{
    backend::{Backend, CrosstermBackend},
    layout::{Constraint, Layout},
    style::{Color, Modifier, Style},
    widgets::{Block, Borders, Cell, Row, Table, TableState},
    Frame, Terminal,
};

struct App<'a> {
    state: TableState,
    items: Vec<Vec<&'a str>>,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            state: TableState::default(),
            items: vec![
                vec!["Row11", "Row12", "Row13"],
                vec!["Row21", "Row22", "Row23"],
                vec!["Row31", "Row32", "Row33"],
                vec!["Row41", "Row42", "Row43"],
                vec!["Row51", "Row52", "Row53"],
                vec!["Row61", "Row62\nTest", "Row63"],
                vec!["Row71", "Row72", "Row73"],
                vec!["Row81", "Row82", "Row83"],
                vec!["Row91", "Row92", "Row93"],
                vec!["Row101", "Row102", "Row103"],
                vec!["Row111", "Row112", "Row113"],
                vec!["Row121", "Row122", "Row123"],
                vec!["Row131", "Row132", "Row133"],
                vec!["Row141", "Row142", "Row143"],
                vec!["Row151", "Row152", "Row153"],
                vec!["Row161", "Row162", "Row163"],
                vec!["Row171", "Row172", "Row173"],
                vec!["Row181", "Row182", "Row183"],
                vec!["Row191", "Row192", "Row193"],
            ],
        }
    }
    pub fn next(&mut self) {
        let i = match self.state.selected() {
            Some(i) => {
                if i >= self.items.len() - 1 {
                    0
                } else {
                    i + 1
                }
            }
            None => 0,
        };
        self.state.select(Some(i));
    }

    pub fn previous(&mut self) {
        let i = match self.state.selected() {
            Some(i) => {
                if i == 0 {
                    self.items.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.state.select(Some(i));
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let app = App::new();
    let res = run_app(&mut terminal, app);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{:?}", err)
    }

    Ok(())
}

fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
    loop {
        terminal.draw(|f| ui(f, &mut app))?;

        if let Event::Key(key) = event::read()? {
            match key.code {
                KeyCode::Char('q') => return Ok(()),
                KeyCode::Down => app.next(),
                KeyCode::Up => app.previous(),
                _ => {}
            }
        }
    }
}

fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
    let rects = Layout::default()
        .constraints([Constraint::Percentage(100)].as_ref())
        .margin(5)
        .split(f.size());

    let selected_style = Style::default().add_modifier(Modifier::REVERSED);
    let normal_style = Style::default().bg(Color::Blue);
    let header_cells = ["Header1", "Header2", "Header3"]
        .iter()
        .map(|h| Cell::from(*h).style(Style::default().fg(Color::Red)));
    let header = Row::new(header_cells)
        .style(normal_style)
        .height(1)
        .bottom_margin(1);
    let rows = app.items.iter().map(|item| {
        let height = item
            .iter()
            .map(|content| content.chars().filter(|c| *c == '\n').count())
            .max()
            .unwrap_or(0)
            + 1;
        let cells = item.iter().map(|c| Cell::from(*c));
        Row::new(cells).height(height as u16).bottom_margin(1)
    });
    let t = Table::new(rows)
        .header(header)
        .block(Block::default().borders(Borders::ALL).title("Table"))
        .highlight_style(selected_style)
        .highlight_symbol(">> ")
        .widths(&[
            Constraint::Percentage(50),
            Constraint::Length(30),
            Constraint::Max(10),
        ]);
    f.render_stateful_widget(t, rects[0], &mut app.state);
}
<commit_msg>chore: fix table example<commit_after>use crossterm::{
    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{error::Error, io};
use tui::{
    backend::{Backend, CrosstermBackend},
    layout::{Constraint, Layout},
    style::{Color, Modifier, Style},
    widgets::{Block, Borders, Cell, Row, Table, TableState},
    Frame, Terminal,
};

struct App<'a> {
    state: TableState,
    items: Vec<Vec<&'a str>>,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            state: TableState::default(),
            items: vec![
                vec!["Row11", "Row12", "Row13"],
                vec!["Row21", "Row22", "Row23"],
                vec!["Row31", "Row32", "Row33"],
                vec!["Row41", "Row42", "Row43"],
                vec!["Row51", "Row52", "Row53"],
                vec!["Row61", "Row62\nTest", "Row63"],
                vec!["Row71", "Row72", "Row73"],
                vec!["Row81", "Row82", "Row83"],
                vec!["Row91", "Row92", "Row93"],
                vec!["Row101", "Row102", "Row103"],
                vec!["Row111", "Row112", "Row113"],
                vec!["Row121", "Row122", "Row123"],
                vec!["Row131", "Row132", "Row133"],
                vec!["Row141", "Row142", "Row143"],
                vec!["Row151", "Row152", "Row153"],
                vec!["Row161", "Row162", "Row163"],
                vec!["Row171", "Row172", "Row173"],
                vec!["Row181", "Row182", "Row183"],
                vec!["Row191", "Row192", "Row193"],
            ],
        }
    }
    pub fn next(&mut self) {
        let i = match self.state.selected() {
            Some(i) => {
                if i >= self.items.len() - 1 {
                    0
                } else {
                    i + 1
                }
            }
            None => 0,
        };
        self.state.select(Some(i));
    }

    pub fn previous(&mut self) {
        let i = match self.state.selected() {
            Some(i) => {
                if i == 0 {
                    self.items.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.state.select(Some(i));
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let app = App::new();
    let res = run_app(&mut terminal, app);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{:?}", err)
    }

    Ok(())
}

fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
    loop {
        terminal.draw(|f| ui(f, &mut app))?;

        if let Event::Key(key) = event::read()? {
            match key.code {
                KeyCode::Char('q') => return Ok(()),
                KeyCode::Down => app.next(),
                KeyCode::Up => app.previous(),
                _ => {}
            }
        }
    }
}

fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
    let rects = Layout::default()
        .constraints([Constraint::Percentage(100)].as_ref())
        .margin(5)
        .split(f.size());

    let selected_style = Style::default().add_modifier(Modifier::REVERSED);
    let normal_style = Style::default().bg(Color::Blue);
    let header_cells = ["Header1", "Header2", "Header3"]
        .iter()
        .map(|h| Cell::from(*h).style(Style::default().fg(Color::Red)));
    let header = Row::new(header_cells)
        .style(normal_style)
        .height(1)
        .bottom_margin(1);
    let rows = app.items.iter().map(|item| {
        let height = item
            .iter()
            .map(|content| content.chars().filter(|c| *c == '\n').count())
            .max()
            .unwrap_or(0)
            + 1;
        let cells = item.iter().map(|c| Cell::from(*c));
        Row::new(cells).height(height as u16).bottom_margin(1)
    });
    let t = Table::new(rows)
        .header(header)
        .block(Block::default().borders(Borders::ALL).title("Table"))
        .highlight_style(selected_style)
        .highlight_symbol(">> ")
        .widths(&[
            Constraint::Percentage(50),
            Constraint::Length(30),
            Constraint::Min(10),
        ]);
    f.render_stateful_widget(t, rects[0], &mut app.state);
}
<|endoftext|>