<commit_before>//! Types for the *m.room.power_levels* event.

use std::collections::BTreeMap;

use js_int::{int, Int};
use ruma_common::power_levels::default_power_level;
use ruma_events_macros::StateEventContent;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};

use crate::{EventType, StateEvent};

pub use ruma_common::power_levels::NotificationPowerLevels;

/// Defines the power levels (privileges) of users in the room.
pub type PowerLevelsEvent = StateEvent<PowerLevelsEventContent>;

/// The payload for `PowerLevelsEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)]
#[ruma_event(type = "m.room.power_levels")]
pub struct PowerLevelsEventContent {
    /// The level required to ban a user.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub ban: Int,

    /// The level required to send specific event types.
    ///
    /// This is a mapping from event type to power level required.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "ruma_serde::btreemap_int_or_string_to_int_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub events: BTreeMap<EventType, Int>,

    /// The default level required to send message events.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub events_default: Int,

    /// The level required to invite a user.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    pub invite: Int,

    /// The level required to kick a user.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub kick: Int,

    /// The level required to redact an event.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub redact: Int,

    /// The default level required to send state events.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub state_default: Int,

    /// The power levels for specific users.
    ///
    /// This is a mapping from `user_id` to power level for that user.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "ruma_serde::btreemap_int_or_string_to_int_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub users: BTreeMap<UserId, Int>,

    /// The default power level for every user in the room.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub users_default: Int,

    /// The power level requirements for specific notification types.
    ///
    /// This is a mapping from `key` to power level for that notifications key.
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    pub notifications: NotificationPowerLevels,
}

impl Default for PowerLevelsEventContent {
    fn default() -> Self {
        // events_default and users_default having a default of 0 while the others have a default
        // of 50 is not an oversight, these defaults are from the Matrix specification.
        Self {
            ban: default_power_level(),
            events: BTreeMap::new(),
            events_default: Int::default(),
            invite: default_power_level(),
            kick: default_power_level(),
            redact: default_power_level(),
            state_default: default_power_level(),
            users: BTreeMap::new(),
            users_default: Int::default(),
            notifications: NotificationPowerLevels::default(),
        }
    }
}

/// Used with `#[serde(skip_serializing_if)]` to omit default power levels.
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_default_power_level(l: &Int) -> bool {
    *l == int!(50)
}

#[cfg(test)]
mod tests {
    use std::{
        collections::BTreeMap,
        time::{Duration, UNIX_EPOCH},
    };

    use js_int::int;
    use maplit::btreemap;
    use ruma_identifiers::{event_id, room_id, user_id};
    use serde_json::{json, to_value as to_json_value};

    use super::{default_power_level, NotificationPowerLevels, PowerLevelsEventContent};
    use crate::{EventType, StateEvent, Unsigned};

    #[test]
    fn serialization_with_optional_fields_as_none() {
        let default = default_power_level();

        let power_levels_event = StateEvent {
            content: PowerLevelsEventContent {
                ban: default,
                events: BTreeMap::new(),
                events_default: int!(0),
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: BTreeMap::new(),
                users_default: int!(0),
                notifications: NotificationPowerLevels::default(),
            },
            event_id: event_id!("$h29iv0s8:example.com"),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: None,
            room_id: room_id!("!n8f893n9:example.com"),
            unsigned: Unsigned::default(),
            sender: user_id!("@carl:example.com"),
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {},
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels"
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialization_with_all_fields() {
        let user = user_id!("@carl:example.com");
        let power_levels_event = StateEvent {
            content: PowerLevelsEventContent {
                ban: int!(23),
                events: btreemap! {
                    EventType::Dummy => int!(23)
                },
                events_default: int!(23),
                invite: int!(23),
                kick: int!(23),
                redact: int!(23),
                state_default: int!(23),
                users: btreemap! {
                    user.clone() => int!(23)
                },
                users_default: int!(23),
                notifications: NotificationPowerLevels { room: int!(23) },
            },
            event_id: event_id!("$h29iv0s8:example.com"),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: Some(PowerLevelsEventContent {
                // Make just one field different so we at least know they're two different objects.
                ban: int!(42),
                events: btreemap! {
                    EventType::Dummy => int!(42)
                },
                events_default: int!(42),
                invite: int!(42),
                kick: int!(42),
                redact: int!(42),
                state_default: int!(42),
                users: btreemap! {
                    user.clone() => int!(42)
                },
                users_default: int!(42),
                notifications: NotificationPowerLevels { room: int!(42) },
            }),
            room_id: room_id!("!n8f893n9:example.com"),
            unsigned: Unsigned { age: Some(int!(100)), ..Unsigned::default() },
            sender: user,
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {
                "ban": 23,
                "events": {
                    "m.dummy": 23
                },
                "events_default": 23,
                "invite": 23,
                "kick": 23,
                "redact": 23,
                "state_default": 23,
                "users": {
                    "@carl:example.com": 23
                },
                "users_default": 23,
                "notifications": {
                    "room": 23
                }
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "prev_content": {
                "ban": 42,
                "events": {
                    "m.dummy": 42
                },
                "events_default": 42,
                "invite": 42,
                "kick": 42,
                "redact": 42,
                "state_default": 42,
                "users": {
                    "@carl:example.com": 42
                },
                "users_default": 42,
                "notifications": {
                    "room": 42
                }
            },
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels",
            "unsigned": {
                "age": 100
            }
        });

        assert_eq!(actual, expected);
    }
}
<commit_msg>events: Fix construction of non-exhaustive struct in tests<commit_after>//! Types for the *m.room.power_levels* event.

use std::collections::BTreeMap;

use js_int::{int, Int};
use ruma_common::power_levels::default_power_level;
use ruma_events_macros::StateEventContent;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};

use crate::{EventType, StateEvent};

pub use ruma_common::power_levels::NotificationPowerLevels;

/// Defines the power levels (privileges) of users in the room.
pub type PowerLevelsEvent = StateEvent<PowerLevelsEventContent>;

/// The payload for `PowerLevelsEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)]
#[ruma_event(type = "m.room.power_levels")]
pub struct PowerLevelsEventContent {
    /// The level required to ban a user.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub ban: Int,

    /// The level required to send specific event types.
    ///
    /// This is a mapping from event type to power level required.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "ruma_serde::btreemap_int_or_string_to_int_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub events: BTreeMap<EventType, Int>,

    /// The default level required to send message events.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub events_default: Int,

    /// The level required to invite a user.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    pub invite: Int,

    /// The level required to kick a user.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub kick: Int,

    /// The level required to redact an event.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub redact: Int,

    /// The default level required to send state events.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
    #[ruma_event(skip_redaction)]
    pub state_default: Int,

    /// The power levels for specific users.
    ///
    /// This is a mapping from `user_id` to power level for that user.
    #[cfg_attr(
        feature = "compat",
        serde(deserialize_with = "ruma_serde::btreemap_int_or_string_to_int_values")
    )]
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    #[ruma_event(skip_redaction)]
    pub users: BTreeMap<UserId, Int>,

    /// The default power level for every user in the room.
    #[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    #[ruma_event(skip_redaction)]
    pub users_default: Int,

    /// The power level requirements for specific notification types.
    ///
    /// This is a mapping from `key` to power level for that notifications key.
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    pub notifications: NotificationPowerLevels,
}

impl Default for PowerLevelsEventContent {
    fn default() -> Self {
        // events_default and users_default having a default of 0 while the others have a default
        // of 50 is not an oversight, these defaults are from the Matrix specification.
        Self {
            ban: default_power_level(),
            events: BTreeMap::new(),
            events_default: Int::default(),
            invite: default_power_level(),
            kick: default_power_level(),
            redact: default_power_level(),
            state_default: default_power_level(),
            users: BTreeMap::new(),
            users_default: Int::default(),
            notifications: NotificationPowerLevels::default(),
        }
    }
}

/// Used with `#[serde(skip_serializing_if)]` to omit default power levels.
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_default_power_level(l: &Int) -> bool {
    *l == int!(50)
}

#[cfg(test)]
mod tests {
    use std::{
        collections::BTreeMap,
        time::{Duration, UNIX_EPOCH},
    };

    use assign::assign;
    use js_int::int;
    use maplit::btreemap;
    use ruma_identifiers::{event_id, room_id, user_id};
    use serde_json::{json, to_value as to_json_value};

    use super::{default_power_level, NotificationPowerLevels, PowerLevelsEventContent};
    use crate::{EventType, StateEvent, Unsigned};

    #[test]
    fn serialization_with_optional_fields_as_none() {
        let default = default_power_level();

        let power_levels_event = StateEvent {
            content: PowerLevelsEventContent {
                ban: default,
                events: BTreeMap::new(),
                events_default: int!(0),
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: BTreeMap::new(),
                users_default: int!(0),
                notifications: NotificationPowerLevels::default(),
            },
            event_id: event_id!("$h29iv0s8:example.com"),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: None,
            room_id: room_id!("!n8f893n9:example.com"),
            unsigned: Unsigned::default(),
            sender: user_id!("@carl:example.com"),
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {},
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels"
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialization_with_all_fields() {
        let user = user_id!("@carl:example.com");
        let power_levels_event = StateEvent {
            content: PowerLevelsEventContent {
                ban: int!(23),
                events: btreemap! {
                    EventType::Dummy => int!(23)
                },
                events_default: int!(23),
                invite: int!(23),
                kick: int!(23),
                redact: int!(23),
                state_default: int!(23),
                users: btreemap! {
                    user.clone() => int!(23)
                },
                users_default: int!(23),
                notifications: assign!(NotificationPowerLevels::new(), { room: int!(23) }),
            },
            event_id: event_id!("$h29iv0s8:example.com"),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: Some(PowerLevelsEventContent {
                // Make just one field different so we at least know they're two different objects.
                ban: int!(42),
                events: btreemap! {
                    EventType::Dummy => int!(42)
                },
                events_default: int!(42),
                invite: int!(42),
                kick: int!(42),
                redact: int!(42),
                state_default: int!(42),
                users: btreemap! {
                    user.clone() => int!(42)
                },
                users_default: int!(42),
                notifications: assign!(NotificationPowerLevels::new(), { room: int!(42) }),
            }),
            room_id: room_id!("!n8f893n9:example.com"),
            unsigned: Unsigned { age: Some(int!(100)), ..Unsigned::default() },
            sender: user,
            state_key: "".into(),
        };

        let actual = to_json_value(&power_levels_event).unwrap();
        let expected = json!({
            "content": {
                "ban": 23,
                "events": {
                    "m.dummy": 23
                },
                "events_default": 23,
                "invite": 23,
                "kick": 23,
                "redact": 23,
                "state_default": 23,
                "users": {
                    "@carl:example.com": 23
                },
                "users_default": 23,
                "notifications": {
                    "room": 23
                }
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "prev_content": {
                "ban": 42,
                "events": {
                    "m.dummy": 42
                },
                "events_default": 42,
                "invite": 42,
                "kick": 42,
                "redact": 42,
                "state_default": 42,
                "users": {
                    "@carl:example.com": 42
                },
                "users_default": 42,
                "notifications": {
                    "room": 42
                }
            },
            "room_id": "!n8f893n9:example.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.power_levels",
            "unsigned": {
                "age": 100
            }
        });

        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
#![feature(type_ascription)]
#![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

use std::intrinsics;

#[allow(dead_code)]
mod byteorder;
#[allow(dead_code, unused_imports, unused_variables, unused_mut)]
mod elf;

mod backtrace_hack;
mod llvm_stackmaps;

const DEMO_ID: i64 = 0;
const SUBCALL_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

fn subcall(data: *mut u8) {
    println!("Enter `subcall`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL_ID, 0, subcall_2, data);
    }
    println!("Finis `subcall`");
}

fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

impl StackMap {
    pub fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        println!("");
        println!("addr: {:?}", addr);

	if let Some(base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                println!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

static mut MAIN_LOCAL: usize = 0;
pub fn main_height() -> usize { unsafe { MAIN_LOCAL } }

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;
use std::sync::RwLock;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use std::path::Path;
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL_ID as usize] = subcall as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
#[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<commit_msg>commenting out the graphviz emission.<commit_after>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
#![feature(type_ascription)]
#![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

use std::intrinsics;

#[allow(dead_code)]
mod byteorder;
#[allow(dead_code, unused_imports, unused_variables, unused_mut)]
mod elf;

mod backtrace_hack;
mod llvm_stackmaps;

const DEMO_ID: i64 = 0;
const SUBCALL_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

fn subcall(data: *mut u8) {
    println!("Enter `subcall`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL_ID, 0, subcall_2, data);
    }
    println!("Finis `subcall`");
}

fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

impl StackMap {
    pub fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        println!("");
        println!("addr: {:?}", addr);

	if let Some(base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                println!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

static mut MAIN_LOCAL: usize = 0;
pub fn main_height() -> usize { unsafe { MAIN_LOCAL } }

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;
use std::sync::RwLock;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use std::path::Path;
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL_ID as usize] = subcall as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<|endoftext|>


<commit_before>/*!

LZ4 Decompression and Compression

This module contains an implementation in Rust of decompression and compression
of LZ4-encoded streams. These are exposed as a standard `Reader` and `Writer`
interfaces wrapping an underlying stream.

# Example

```rust
let stream = Path::new("path/to/file.lz4");
let decompressed = l4z::Decoder::new(stream).read_to_end();
```

# Credit

This implementation is largely based on Branimir Karadžić's implementation which
can be found at https://github.com/bkaradzic/go-lz4.

*/

use std::rt::io;
use std::rt::io::Writer;
use std::rt::io::extensions::{ReaderUtil, ReaderByteConversions,
                              WriterByteConversions};
use std::vec;
use std::num;

static MAGIC: u32 = 0x184d2204;

struct BlockDecoder<'self> {
    input: &'self [u8],
    output: &'self mut ~[u8],
    cur: uint,

    start: uint,
    end: uint,
}

impl<'self> BlockDecoder<'self> {
    /// Decodes this block of data from 'input' to 'output', returning the
    /// number of valid bytes in the output.
    fn decode(&mut self) -> uint {
        while self.cur < self.input.len() {
            let code = self.bump();
            debug!("block with code: {:x}", code);
            // Extract a chunk of data from the input to the output.
            {
                let len = self.length(code >> 4);
                debug!("consume len {}", len);
                self.grow_output(self.end + len);
                vec::bytes::copy_memory(self.output.mut_slice_from(self.end),
                                        self.input.slice_from(self.cur), len);
                self.end += len;
                self.cur += len;
            }
            if self.cur == self.input.len() { break }

            // Read off the next i16 offset
            {
                let back = (self.bump() as uint) | ((self.bump() as uint) << 8);
                debug!("found back {}", back);
                self.start = self.end - back;
            }

            // Slosh around some bytes now
            {
                let mut len = self.length(code & 0xf);
                let literal = self.end - self.start;
                if literal < 4 {
                    static DECR: [uint, ..4] = [0, 3, 2, 3];
                    self.cp(4, DECR[literal]);
                } else {
                    len += 4;
                }
                self.cp(len, 0);
            }
        }
        return self.end;
    }

    fn length(&mut self, code: u8) -> uint {
        let mut ret = code as uint;
        if code == 0xf {
            loop {
                let tmp = self.bump();
                ret += tmp as uint;
                if tmp != 0xff { break }
            }
        }
        return ret;
    }

    fn bump(&mut self) -> u8 {
        let ret = self.input[self.cur];
        self.cur += 1;
        return ret;
    }

    fn cp(&mut self, len: uint, decr: uint) {
        self.grow_output(self.end + len);
        for i in range(0, len) {
            self.output[self.end + i] = self.output[self.start + i];
        }

        self.end += len;
        self.start += len - decr;
    }

    fn grow_output(&mut self, target: uint) {
        if self.output.len() < target {
            debug!("growing to {}", target);
            let target = target - self.output.len();
            self.output.grow(target, &0);
        }
    }
}

/// This structure is used to decode a stream of LZ4 blocks. This wraps an
/// internal reader which is read from when this decoder's read method is
/// called.
pub struct Decoder<R> {
    /// The internally wrapped reader. This is exposed so it may be moved out
    /// of. Note that if data is read from the reader while decoding is in
    /// progress the output stream will get corrupted.
    r: R,

    priv temp: ~[u8],
    priv output: ~[u8],

    priv start: uint,
    priv end: uint,
    priv eof: bool,

    priv header: bool,
    priv blk_checksum: bool,
    priv stream_checksum: bool,
    priv max_block_size: uint,
}

impl<R: io::Reader> Decoder<R> {
    /// Creates a new decoder which will read data from the given stream. The
    /// inner stream can be re-acquired by moving out of the `r` field of this
    /// structure.
    pub fn new(r: R) -> Decoder<R> {
        Decoder {
            r: r,
            temp: ~[],
            output: ~[],
            header: false,
            blk_checksum: false,
            stream_checksum: false,
            start: 0,
            end: 0,
            eof: false,
            max_block_size: 0,
        }
    }

    /// Resets this decoder back to its initial state. Note that the underlying
    /// stream is not seeked on or has any alterations performed on it.
    pub fn reset(&mut self) {
        self.header = false;
        self.eof = false;
        self.start = 0;
        self.end = 0;
    }

    fn read_header(&mut self) -> Option<()> {
        // Make sure the magic number is what's expected.
        if self.r.read_le_u32_() != MAGIC { return None }

        let mut bits = [0, ..3];
        if self.r.read(bits.mut_slice_to(2)).is_none() { return None }
        let flg = bits[0];
        let bd = bits[1];

        // bits 7/6, the version number. Right now this must be 1
        if (flg >> 6) != 0b01 { return None }
        // bit 5 is the "block independence", don't care about this yet
        // bit 4 is whether blocks have checksums or not
        self.blk_checksum = (flg & 0x10) != 0;
        // bit 3 is whether there is a following stream size
        let stream_size = (flg & 0x08) != 0;
        // bit 2 is whether there is a stream checksum
        self.stream_checksum = (flg & 0x04) != 0;
        // bit 1 is reserved
        // bit 0 is whether there is a preset dictionary
        let preset_dictionary = (flg & 0x01) != 0;

        static MAX_SIZES: [uint, ..8] =
            [0, 0, 0, 0, // all N/A
             64 << 10,   // 64KB
             256 << 10,  // 256 KB
             1 << 20,    // 1MB
             4 << 20];   // 4MB

        // bit 7 is reserved
        // bits 6-4 are the maximum block size
        let max_block_size = MAX_SIZES[(bd >> 4) & 0x7];
        // bits 3-0 are reserved

        // read off other portions of the stream
        let size = if stream_size {Some(self.r.read_le_u64_())} else {None};
        assert!(!preset_dictionary, "preset dictionaries not supported yet");

        debug!("blk: {}", self.blk_checksum);
        debug!("stream: {}", self.stream_checksum);
        debug!("max size: {}", max_block_size);
        debug!("stream size: {:?}", size);

        self.max_block_size = max_block_size;

        // XXX: implement checksums
        let cksum = self.r.read_byte();
        debug!("ignoring header checksum: {:?}", cksum);
        return Some(());
    }

    fn decode_block(&mut self) -> bool {
        match self.r.read_le_u32_() {
            // final block, we're done here
            0 => return false,

            // raw block to read
            n if n & 0x80000000 != 0 => {
                let amt = (n & 0x7fffffff) as uint;
                self.output.truncate(0);
                self.output.reserve(amt);
                self.r.push_bytes(&mut self.output, amt);
                self.start = 0;
                self.end = amt;
            }

            // actual block to decompress
            n => {
                let n = n as uint;
                self.temp.truncate(0);
                self.temp.reserve(n);
                self.r.push_bytes(&mut self.temp, n);

                let target = num::min(self.max_block_size, 4 * n / 3);
                self.output.truncate(0);
                self.output.reserve(target);
                let mut decoder = BlockDecoder {
                    input: self.temp.slice_to(n),
                    output: &mut self.output,
                    cur: 0,
                    start: 0,
                    end: 0,
                };
                self.start = 0;
                self.end = decoder.decode();
            }
        }

        if self.blk_checksum {
            let cksum = self.r.read_le_u32_();
            debug!("ignoring block checksum {:?}", cksum);
        }
        return true;
    }
}

impl<R: io::Reader> io::Reader for Decoder<R> {
    fn read(&mut self, dst: &mut [u8]) -> Option<uint> {
        if self.eof { return None }
        if !self.header {
            self.read_header();
            self.header = true;
        }
        let mut amt = dst.len();
        let len = amt;

        while amt > 0 {
            if self.start == self.end {
                if !self.decode_block() {
                    self.eof = true;
                    break;
                }
            }
            let n = num::min(amt, self.end - self.start);
            vec::bytes::copy_memory(dst.mut_slice_from(len - amt),
                                    self.output.slice_from(self.start), n);
            self.start += n;
            amt -= n;
        }

        return Some(len - amt);
    }

    fn eof(&mut self) -> bool { return self.eof }
}

/// This structure is used to compress a stream of bytes using the LZ4
/// compression algorithm. This is a wrapper around an internal writer which
/// bytes will be written to.
pub struct Encoder<W> {
    priv w: W,
    priv buf: ~[u8],
    priv tmp: ~[u8],
    priv wrote_header: bool,
    priv limit: uint,
}

impl<W: io::Writer> Encoder<W> {
    /// Creates a new encoder which will have its output written to the given
    /// output stream. The output stream can be re-acquired by calling
    /// `finish()`
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: w,
            wrote_header: false,
            buf: vec::with_capacity(1024),
            tmp: ~[],
            limit: 256 * 1024,
        }
    }

    fn encode_block(&mut self) {
        self.tmp.truncate(0);
        if self.compress() {
            self.w.write_le_u32_(self.tmp.len() as u32);
            self.w.write(self.tmp)
        } else {
            self.w.write_le_u32_((self.buf.len() as u32) | 0x80000000);
            self.w.write(self.buf)
        }
        self.buf.truncate(0);
    }

    fn compress(&mut self) -> bool {
        false
    }

    /// This function is used to flag that this session of compression is done
    /// with. The stream is finished up (final bytes are written), and then the
    /// wrapped writer is returned.
    pub fn finish(mut self) -> W {
        self.flush();
        self.write_le_u32_(0);
        self.write_le_u32_(0); // XXX: this checksum is wrong
        self.w
    }
}

impl<W: io::Writer> io::Writer for Encoder<W> {
    fn write(&mut self, mut buf: &[u8]) {
        if !self.wrote_header {
            self.w.write_le_u32_(MAGIC);
            // version 01, turn on block independence, but turn off
            // everything else (we have no checksums right now).
            self.w.write_u8_(0b01_100000);
            // Maximum block size is 256KB
            self.w.write_u8_(0b0_101_0000);
            // XXX: this checksum is just plain wrong.
            self.w.write_u8_(0);
            self.wrote_header = true;
        }

        while buf.len() > 0 {
            let amt = num::min(self.limit - self.buf.len(), buf.len());
            self.buf.push_all(buf.slice_to(amt));

            if self.buf.len() == self.limit {
                self.encode_block();
            }
            buf = buf.slice_from(amt);
        }
    }

    fn flush(&mut self) {
        if self.buf.len() > 0 {
            self.encode_block();
        }
    }
}

#[cfg(test)]
mod test {
    use extra::test;
    use std::rand;
    use std::rt::io::{Reader, Writer, Decorator};
    use std::rt::io::extensions::ReaderUtil;
    use std::rt::io::mem::{BufReader, MemWriter};
    use super::{Decoder, Encoder};

    fn test_decode(input: &[u8], output: &[u8]) {
        let mut d = Decoder::new(BufReader::new(input));

        let got = d.read_to_end();
        assert!(got.as_slice() == output);
    }

    #[test]
    fn decode() {
        let reference = include_bin!("data/test.txt");
        test_decode(include_bin!("data/test.lz4.1"), reference);
        test_decode(include_bin!("data/test.lz4.2"), reference);
        test_decode(include_bin!("data/test.lz4.3"), reference);
        test_decode(include_bin!("data/test.lz4.4"), reference);
        test_decode(include_bin!("data/test.lz4.5"), reference);
        test_decode(include_bin!("data/test.lz4.6"), reference);
        test_decode(include_bin!("data/test.lz4.7"), reference);
        test_decode(include_bin!("data/test.lz4.8"), reference);
        test_decode(include_bin!("data/test.lz4.9"), reference);
    }

    #[test]
    fn one_byte_at_a_time() {
        let input = include_bin!("data/test.lz4.1");
        let mut d = Decoder::new(BufReader::new(input));
        assert!(!d.eof());
        let mut out = ~[];
        loop {
            match d.read_byte() {
                Some(b) => out.push(b),
                None => break
            }
        }
        assert!(d.eof());
        assert!(out.as_slice() == include_bin!("data/test.txt"));
    }

    #[test]
    fn random_byte_lengths() {
        let input = include_bin!("data/test.lz4.1");
        let mut d = Decoder::new(BufReader::new(input));
        let mut out = ~[];
        let mut buf = [0u8, ..40];
        loop {
            match d.read(buf.mut_slice_to(1 + rand::random::<uint>() % 40)) {
                Some(n) => {
                    out.push_all(buf.slice_to(n));
                }
                None => break
            }
        }
        assert!(out.as_slice() == include_bin!("data/test.txt"));
    }

    fn roundtrip(bytes: &[u8]) {
        let mut e = Encoder::new(MemWriter::new());
        e.write(bytes);
        let encoded = e.finish().inner();

        let mut d = Decoder::new(BufReader::new(encoded));
        let decoded = d.read_to_end();
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn some_roundtrips() {
        roundtrip(bytes!("test"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("data/test.txt"));
    }

    #[bench]
    fn decompress_speed(bh: &mut test::BenchHarness) {
        let input = include_bin!("data/test.lz4.9");
        let mut d = Decoder::new(BufReader::new(input));
        let mut output = [0u8, ..65536];
        let mut output_size = 0;
        do bh.iter {
            d.r = BufReader::new(input);
            d.reset();
            output_size = d.read(output).unwrap();
        }
        bh.bytes = output_size as u64;
    }
}
<commit_msg>Remove usage of rt::io::extensions<commit_after>/*!

LZ4 Decompression and Compression

This module contains an implementation in Rust of decompression and compression
of LZ4-encoded streams. These are exposed as a standard `Reader` and `Writer`
interfaces wrapping an underlying stream.

# Example

```rust
let stream = Path::new("path/to/file.lz4");
let decompressed = l4z::Decoder::new(stream).read_to_end();
```

# Credit

This implementation is largely based on Branimir Karadžić's implementation which
can be found at https://github.com/bkaradzic/go-lz4.

*/

use std::rt::io::{Writer, Reader};
use std::vec;
use std::num;

static MAGIC: u32 = 0x184d2204;

struct BlockDecoder<'self> {
    input: &'self [u8],
    output: &'self mut ~[u8],
    cur: uint,

    start: uint,
    end: uint,
}

impl<'self> BlockDecoder<'self> {
    /// Decodes this block of data from 'input' to 'output', returning the
    /// number of valid bytes in the output.
    fn decode(&mut self) -> uint {
        while self.cur < self.input.len() {
            let code = self.bump();
            debug!("block with code: {:x}", code);
            // Extract a chunk of data from the input to the output.
            {
                let len = self.length(code >> 4);
                debug!("consume len {}", len);
                self.grow_output(self.end + len);
                vec::bytes::copy_memory(self.output.mut_slice_from(self.end),
                                        self.input.slice_from(self.cur), len);
                self.end += len;
                self.cur += len;
            }
            if self.cur == self.input.len() { break }

            // Read off the next i16 offset
            {
                let back = (self.bump() as uint) | ((self.bump() as uint) << 8);
                debug!("found back {}", back);
                self.start = self.end - back;
            }

            // Slosh around some bytes now
            {
                let mut len = self.length(code & 0xf);
                let literal = self.end - self.start;
                if literal < 4 {
                    static DECR: [uint, ..4] = [0, 3, 2, 3];
                    self.cp(4, DECR[literal]);
                } else {
                    len += 4;
                }
                self.cp(len, 0);
            }
        }
        return self.end;
    }

    fn length(&mut self, code: u8) -> uint {
        let mut ret = code as uint;
        if code == 0xf {
            loop {
                let tmp = self.bump();
                ret += tmp as uint;
                if tmp != 0xff { break }
            }
        }
        return ret;
    }

    fn bump(&mut self) -> u8 {
        let ret = self.input[self.cur];
        self.cur += 1;
        return ret;
    }

    fn cp(&mut self, len: uint, decr: uint) {
        self.grow_output(self.end + len);
        for i in range(0, len) {
            self.output[self.end + i] = self.output[self.start + i];
        }

        self.end += len;
        self.start += len - decr;
    }

    fn grow_output(&mut self, target: uint) {
        if self.output.len() < target {
            debug!("growing to {}", target);
            let target = target - self.output.len();
            self.output.grow(target, &0);
        }
    }
}

/// This structure is used to decode a stream of LZ4 blocks. This wraps an
/// internal reader which is read from when this decoder's read method is
/// called.
pub struct Decoder<R> {
    /// The internally wrapped reader. This is exposed so it may be moved out
    /// of. Note that if data is read from the reader while decoding is in
    /// progress the output stream will get corrupted.
    r: R,

    priv temp: ~[u8],
    priv output: ~[u8],

    priv start: uint,
    priv end: uint,
    priv eof: bool,

    priv header: bool,
    priv blk_checksum: bool,
    priv stream_checksum: bool,
    priv max_block_size: uint,
}

impl<R: Reader> Decoder<R> {
    /// Creates a new decoder which will read data from the given stream. The
    /// inner stream can be re-acquired by moving out of the `r` field of this
    /// structure.
    pub fn new(r: R) -> Decoder<R> {
        Decoder {
            r: r,
            temp: ~[],
            output: ~[],
            header: false,
            blk_checksum: false,
            stream_checksum: false,
            start: 0,
            end: 0,
            eof: false,
            max_block_size: 0,
        }
    }

    /// Resets this decoder back to its initial state. Note that the underlying
    /// stream is not seeked on or has any alterations performed on it.
    pub fn reset(&mut self) {
        self.header = false;
        self.eof = false;
        self.start = 0;
        self.end = 0;
    }

    fn read_header(&mut self) -> Option<()> {
        // Make sure the magic number is what's expected.
        if self.r.read_le_u32() != MAGIC { return None }

        let mut bits = [0, ..3];
        if self.r.read(bits.mut_slice_to(2)).is_none() { return None }
        let flg = bits[0];
        let bd = bits[1];

        // bits 7/6, the version number. Right now this must be 1
        if (flg >> 6) != 0b01 { return None }
        // bit 5 is the "block independence", don't care about this yet
        // bit 4 is whether blocks have checksums or not
        self.blk_checksum = (flg & 0x10) != 0;
        // bit 3 is whether there is a following stream size
        let stream_size = (flg & 0x08) != 0;
        // bit 2 is whether there is a stream checksum
        self.stream_checksum = (flg & 0x04) != 0;
        // bit 1 is reserved
        // bit 0 is whether there is a preset dictionary
        let preset_dictionary = (flg & 0x01) != 0;

        static MAX_SIZES: [uint, ..8] =
            [0, 0, 0, 0, // all N/A
             64 << 10,   // 64KB
             256 << 10,  // 256 KB
             1 << 20,    // 1MB
             4 << 20];   // 4MB

        // bit 7 is reserved
        // bits 6-4 are the maximum block size
        let max_block_size = MAX_SIZES[(bd >> 4) & 0x7];
        // bits 3-0 are reserved

        // read off other portions of the stream
        let size = if stream_size {Some(self.r.read_le_u64())} else {None};
        assert!(!preset_dictionary, "preset dictionaries not supported yet");

        debug!("blk: {}", self.blk_checksum);
        debug!("stream: {}", self.stream_checksum);
        debug!("max size: {}", max_block_size);
        debug!("stream size: {:?}", size);

        self.max_block_size = max_block_size;

        // XXX: implement checksums
        let cksum = self.r.read_byte();
        debug!("ignoring header checksum: {:?}", cksum);
        return Some(());
    }

    fn decode_block(&mut self) -> bool {
        match self.r.read_le_u32() {
            // final block, we're done here
            0 => return false,

            // raw block to read
            n if n & 0x80000000 != 0 => {
                let amt = (n & 0x7fffffff) as uint;
                self.output.truncate(0);
                self.output.reserve(amt);
                self.r.push_bytes(&mut self.output, amt);
                self.start = 0;
                self.end = amt;
            }

            // actual block to decompress
            n => {
                let n = n as uint;
                self.temp.truncate(0);
                self.temp.reserve(n);
                self.r.push_bytes(&mut self.temp, n);

                let target = num::min(self.max_block_size, 4 * n / 3);
                self.output.truncate(0);
                self.output.reserve(target);
                let mut decoder = BlockDecoder {
                    input: self.temp.slice_to(n),
                    output: &mut self.output,
                    cur: 0,
                    start: 0,
                    end: 0,
                };
                self.start = 0;
                self.end = decoder.decode();
            }
        }

        if self.blk_checksum {
            let cksum = self.r.read_le_u32();
            debug!("ignoring block checksum {:?}", cksum);
        }
        return true;
    }
}

impl<R: Reader> Reader for Decoder<R> {
    fn read(&mut self, dst: &mut [u8]) -> Option<uint> {
        if self.eof { return None }
        if !self.header {
            self.read_header();
            self.header = true;
        }
        let mut amt = dst.len();
        let len = amt;

        while amt > 0 {
            if self.start == self.end {
                if !self.decode_block() {
                    self.eof = true;
                    break;
                }
            }
            let n = num::min(amt, self.end - self.start);
            vec::bytes::copy_memory(dst.mut_slice_from(len - amt),
                                    self.output.slice_from(self.start), n);
            self.start += n;
            amt -= n;
        }

        return Some(len - amt);
    }

    fn eof(&mut self) -> bool { return self.eof }
}

/// This structure is used to compress a stream of bytes using the LZ4
/// compression algorithm. This is a wrapper around an internal writer which
/// bytes will be written to.
pub struct Encoder<W> {
    priv w: W,
    priv buf: ~[u8],
    priv tmp: ~[u8],
    priv wrote_header: bool,
    priv limit: uint,
}

impl<W: Writer> Encoder<W> {
    /// Creates a new encoder which will have its output written to the given
    /// output stream. The output stream can be re-acquired by calling
    /// `finish()`
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: w,
            wrote_header: false,
            buf: vec::with_capacity(1024),
            tmp: ~[],
            limit: 256 * 1024,
        }
    }

    fn encode_block(&mut self) {
        self.tmp.truncate(0);
        if self.compress() {
            self.w.write_le_u32(self.tmp.len() as u32);
            self.w.write(self.tmp)
        } else {
            self.w.write_le_u32((self.buf.len() as u32) | 0x80000000);
            self.w.write(self.buf)
        }
        self.buf.truncate(0);
    }

    fn compress(&mut self) -> bool {
        false
    }

    /// This function is used to flag that this session of compression is done
    /// with. The stream is finished up (final bytes are written), and then the
    /// wrapped writer is returned.
    pub fn finish(mut self) -> W {
        self.flush();
        self.write_le_u32(0);
        self.write_le_u32(0); // XXX: this checksum is wrong
        self.w
    }
}

impl<W: Writer> Writer for Encoder<W> {
    fn write(&mut self, mut buf: &[u8]) {
        if !self.wrote_header {
            self.w.write_le_u32(MAGIC);
            // version 01, turn on block independence, but turn off
            // everything else (we have no checksums right now).
            self.w.write_u8(0b01_100000);
            // Maximum block size is 256KB
            self.w.write_u8(0b0_101_0000);
            // XXX: this checksum is just plain wrong.
            self.w.write_u8(0);
            self.wrote_header = true;
        }

        while buf.len() > 0 {
            let amt = num::min(self.limit - self.buf.len(), buf.len());
            self.buf.push_all(buf.slice_to(amt));

            if self.buf.len() == self.limit {
                self.encode_block();
            }
            buf = buf.slice_from(amt);
        }
    }

    fn flush(&mut self) {
        if self.buf.len() > 0 {
            self.encode_block();
        }
    }
}

#[cfg(test)]
mod test {
    use extra::test;
    use std::rand;
    use std::rt::io::{Reader, Writer, Decorator};
    use std::rt::io::mem::{BufReader, MemWriter};
    use super::{Decoder, Encoder};

    fn test_decode(input: &[u8], output: &[u8]) {
        let mut d = Decoder::new(BufReader::new(input));

        let got = d.read_to_end();
        assert!(got.as_slice() == output);
    }

    #[test]
    fn decode() {
        let reference = include_bin!("data/test.txt");
        test_decode(include_bin!("data/test.lz4.1"), reference);
        test_decode(include_bin!("data/test.lz4.2"), reference);
        test_decode(include_bin!("data/test.lz4.3"), reference);
        test_decode(include_bin!("data/test.lz4.4"), reference);
        test_decode(include_bin!("data/test.lz4.5"), reference);
        test_decode(include_bin!("data/test.lz4.6"), reference);
        test_decode(include_bin!("data/test.lz4.7"), reference);
        test_decode(include_bin!("data/test.lz4.8"), reference);
        test_decode(include_bin!("data/test.lz4.9"), reference);
    }

    #[test]
    fn one_byte_at_a_time() {
        let input = include_bin!("data/test.lz4.1");
        let mut d = Decoder::new(BufReader::new(input));
        assert!(!d.eof());
        let mut out = ~[];
        loop {
            match d.read_byte() {
                Some(b) => out.push(b),
                None => break
            }
        }
        assert!(d.eof());
        assert!(out.as_slice() == include_bin!("data/test.txt"));
    }

    #[test]
    fn random_byte_lengths() {
        let input = include_bin!("data/test.lz4.1");
        let mut d = Decoder::new(BufReader::new(input));
        let mut out = ~[];
        let mut buf = [0u8, ..40];
        loop {
            match d.read(buf.mut_slice_to(1 + rand::random::<uint>() % 40)) {
                Some(n) => {
                    out.push_all(buf.slice_to(n));
                }
                None => break
            }
        }
        assert!(out.as_slice() == include_bin!("data/test.txt"));
    }

    fn roundtrip(bytes: &[u8]) {
        let mut e = Encoder::new(MemWriter::new());
        e.write(bytes);
        let encoded = e.finish().inner();

        let mut d = Decoder::new(BufReader::new(encoded));
        let decoded = d.read_to_end();
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn some_roundtrips() {
        roundtrip(bytes!("test"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("data/test.txt"));
    }

    #[bench]
    fn decompress_speed(bh: &mut test::BenchHarness) {
        let input = include_bin!("data/test.lz4.9");
        let mut d = Decoder::new(BufReader::new(input));
        let mut output = [0u8, ..65536];
        let mut output_size = 0;
        do bh.iter {
            d.r = BufReader::new(input);
            d.reset();
            output_size = d.read(output).unwrap();
        }
        bh.bytes = output_size as u64;
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate futures;
extern crate test;
extern crate tokio_core;

extern crate trust_dns;
extern crate trust_dns_server;

use std::fs::DirBuilder;
use std::env;
use std::mem;
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
use std::path::Path;
use std::process::{Child, Command, Stdio};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use test::Bencher;
use tokio_core::reactor::Core;

use trust_dns::client::*;
use trust_dns::op::*;
use trust_dns::rr::*;
use trust_dns::udp::*;
use trust_dns::tcp::*;

fn find_test_port() -> u16 {
    let server = std::net::UdpSocket::bind(("0.0.0.0", 0)).unwrap();
    let server_addr = server.local_addr().unwrap();
    server_addr.port()
}

struct NamedProcess {
    named: Child,
}

impl Drop for NamedProcess {
    fn drop(&mut self) {
        self.named.kill().expect("could not kill process");
        self.named.wait().expect("waiting failed");
    }
}

fn wrap_process(named: Child, server_port: u16) -> NamedProcess {
    let mut started = false;

    for _ in 0..20 {
        let mut io_loop = Core::new().unwrap();
        let addr: SocketAddr = ("127.0.0.1", server_port)
            .to_socket_addrs()
            .unwrap()
            .next()
            .unwrap();
        let handle = io_loop.handle();
        let (stream, sender) = UdpClientStream::new(addr, &handle);
        let mut client = ClientFuture::new(stream, sender, &handle, None);

        let name = domain::Name::from_str("www.example.com.").unwrap();
        let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A));

        if response.is_ok() {
            started = true;
            break;
        } else {
            // wait for the server to start
            thread::sleep(Duration::from_millis(500));
        }
    }

    assert!(started, "server did not startup...");
    // return handle to child process
    NamedProcess { named: named }
}

/// Returns a NamedProcess (cleans the process up on drop), and a socket addr for connecting
///  to the server.
fn trust_dns_process() -> (NamedProcess, u16) {
    // find a random port to listen on
    let test_port = find_test_port();

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or_else(|_| ".".to_owned());

    let named = Command::new(&format!("{}/../target/release/named", server_path))
        .stdout(Stdio::null())
        .arg("-q") // TODO: need to rethink this one...
        .arg(&format!(
            "--config={}/tests/named_test_configs/example.toml",
            server_path
        ))
        .arg(&format!(
            "--zonedir={}/tests/named_test_configs",
            server_path
        ))
        .arg(&format!("--port={}", test_port))
        .spawn()
        .expect("failed to start named");
    //

    let process = wrap_process(named, test_port);

    // return handle to child process
    (process, test_port)
}

/// Runs the bench tesk using the specified client
fn bench(b: &mut Bencher, io_loop: &mut Core, client: &mut BasicClientHandle) {
    let name = domain::Name::from_str("www.example.com.").unwrap();

    // validate the request
    let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A));
    assert!(
        !response.is_err(),
        "request failed: {}",
        response.unwrap_err()
    );

    let response = response.unwrap();
    assert_eq!(response.response_code(), ResponseCode::NoError);

    let record = &response.answers()[0];
    if let RData::A(ref address) = *record.rdata() {
        assert_eq!(address, &Ipv4Addr::new(127, 0, 0, 1));
    } else {
        assert!(false);
    }

    b.iter(|| {
        let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A));
        response.unwrap();
    });
}

#[bench]
fn trust_dns_udp_bench(b: &mut Bencher) {
    let (named, server_port) = trust_dns_process();

    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let handle = io_loop.handle();
    let (stream, sender) = UdpClientStream::new(addr, &handle);
    let mut client = ClientFuture::new(stream, sender, &handle, None);

    bench(b, &mut io_loop, &mut client);

    // cleaning up the named process
    drop(named);
}

#[bench]
#[ignore]
fn trust_dns_udp_bench_prof(b: &mut Bencher) {
    let server_port = 6363;

    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let handle = io_loop.handle();
    let (stream, sender) = UdpClientStream::new(addr, &handle);
    let mut client = ClientFuture::new(stream, sender, &handle, None);

    bench(b, &mut io_loop, &mut client);
}

#[bench]
fn trust_dns_tcp_bench(b: &mut Bencher) {
    let (named, server_port) = trust_dns_process();

    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let handle = io_loop.handle();
    let (stream, sender) = TcpClientStream::new(addr, &handle);
    let mut client = ClientFuture::new(stream, sender, &handle, None);

    bench(b, &mut io_loop, &mut client);

    // cleaning up the named process
    drop(named);
}

// downloaded from https://www.isc.org/downloads/file/bind-9-11-0-p1/
// cd bind-9-11-0-p1
// .configure
// make
// export TDNS_BIND_PATH=${PWD}/bin/named/named
fn bind_process() -> (NamedProcess, u16) {
    let test_port = find_test_port();

    let bind_path = env::var("TDNS_BIND_PATH").unwrap_or_else(|_| "bind".to_owned());
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or_else(|_| ".".to_owned());

    // create the work directory
    let working_dir = format!("{}/../target/bind_pwd", server_path);
    if !Path::new(&working_dir).exists() {
        DirBuilder::new()
            .create(&working_dir)
            .expect("failed to create dir");
    }

    let mut named = Command::new(bind_path)
                      .current_dir(&working_dir)
                      .stderr(Stdio::piped())
                      .arg("-c").arg("../../server/benches/bind_conf/example.conf")
                      //.arg("-d").arg("0")
                      .arg("-D").arg("TRust-DNS cmp bench")
                      .arg("-g")
                      .arg("-p").arg(&format!("{}", test_port))
                      .spawn()
                      .expect("failed to start named");

    mem::replace(&mut named.stderr, None).unwrap();
    let process = wrap_process(named, test_port);
    (process, test_port)
}

#[bench]
#[ignore]
fn bind_udp_bench(b: &mut Bencher) {
    let (named, server_port) = bind_process();

    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let handle = io_loop.handle();
    let (stream, sender) = UdpClientStream::new(addr, &handle);
    let mut client = ClientFuture::new(stream, sender, &handle, None);

    bench(b, &mut io_loop, &mut client);

    // cleaning up the named process
    drop(named);
}

#[bench]
#[ignore]
fn bind_tcp_bench(b: &mut Bencher) {
    let (named, server_port) = bind_process();

    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let handle = io_loop.handle();
    let (stream, sender) = TcpClientStream::new(addr, &handle);
    let mut client = ClientFuture::new(stream, sender, &handle, None);

    bench(b, &mut io_loop, &mut client);

    // cleaning up the named process
    drop(named);
}
<commit_msg>server: switch comparison_benches to tokio-executor.<commit_after>#![feature(test)]

extern crate futures;
extern crate test;
extern crate tokio;

extern crate trust_dns;
extern crate trust_dns_server;

use std::fs::DirBuilder;
use std::env;
use std::mem;
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
use std::path::Path;
use std::process::{Child, Command, Stdio};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use test::Bencher;
use tokio::runtime::current_thread::Runtime;

use trust_dns::client::*;
use trust_dns::error::*;
use trust_dns::op::*;
use trust_dns::rr::*;
use trust_dns::udp::*;
use trust_dns::tcp::*;

fn find_test_port() -> u16 {
    let server = std::net::UdpSocket::bind(("0.0.0.0", 0)).unwrap();
    let server_addr = server.local_addr().unwrap();
    server_addr.port()
}

struct NamedProcess {
    named: Child,
}

impl Drop for NamedProcess {
    fn drop(&mut self) {
        self.named.kill().expect("could not kill process");
        self.named.wait().expect("waiting failed");
    }
}

fn wrap_process(named: Child, server_port: u16) -> NamedProcess {
    let mut started = false;

    for _ in 0..20 {
        let mut io_loop = Runtime::new().unwrap();
        let addr: SocketAddr = ("127.0.0.1", server_port)
            .to_socket_addrs()
            .unwrap()
            .next()
            .unwrap();
        let (stream, sender) = UdpClientStream::new(addr);
        let mut client = ClientFuture::new(stream, sender, None);
        let mut client = io_loop.block_on(client).unwrap();

        let name = domain::Name::from_str("www.example.com.").unwrap();
        let response = io_loop.block_on(client.query(name.clone(), DNSClass::IN, RecordType::A));

        if response.is_ok() {
            started = true;
            break;
        } else {
            // wait for the server to start
            thread::sleep(Duration::from_millis(500));
        }
    }

    assert!(started, "server did not startup...");
    // return handle to child process
    NamedProcess { named: named }
}

/// Returns a NamedProcess (cleans the process up on drop), and a socket addr for connecting
///  to the server.
fn trust_dns_process() -> (NamedProcess, u16) {
    // find a random port to listen on
    let test_port = find_test_port();

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or_else(|_| ".".to_owned());

    let named = Command::new(&format!("{}/../target/release/named", server_path))
        .stdout(Stdio::null())
        .arg("-q") // TODO: need to rethink this one...
        .arg(&format!(
            "--config={}/tests/named_test_configs/example.toml",
            server_path
        ))
        .arg(&format!(
            "--zonedir={}/tests/named_test_configs",
            server_path
        ))
        .arg(&format!("--port={}", test_port))
        .spawn()
        .expect("failed to start named");
    //

    let process = wrap_process(named, test_port);

    // return handle to child process
    (process, test_port)
}

/// Runs the bench tesk using the specified client
fn bench(
    b: &mut Bencher,
    client: &mut futures::Future<Item = BasicClientHandle, Error = ClientError>
) {
    let mut io_loop = Runtime::new().unwrap();
    let mut client = io_loop.block_on(client).unwrap();
    let name = domain::Name::from_str("www.example.com.").unwrap();

    // validate the request
    let response = io_loop.block_on(client.query(name.clone(), DNSClass::IN, RecordType::A));
    assert!(
        !response.is_err(),
        "request failed: {}",
        response.unwrap_err()
    );

    let response = response.unwrap();
    assert_eq!(response.response_code(), ResponseCode::NoError);

    let record = &response.answers()[0];
    if let RData::A(ref address) = *record.rdata() {
        assert_eq!(address, &Ipv4Addr::new(127, 0, 0, 1));
    } else {
        assert!(false);
    }

    b.iter(|| {
        let response = io_loop.block_on(client.query(name.clone(), DNSClass::IN, RecordType::A));
        response.unwrap();
    });
}

#[bench]
fn trust_dns_udp_bench(b: &mut Bencher) {
    let (named, server_port) = trust_dns_process();

    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = UdpClientStream::new(addr);
    let mut client = ClientFuture::new(stream, sender, None);

    bench(b, &mut *client);

    // cleaning up the named process
    drop(named);
}

#[bench]
#[ignore]
fn trust_dns_udp_bench_prof(b: &mut Bencher) {
    let server_port = 6363;

    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = UdpClientStream::new(addr);
    let mut client = ClientFuture::new(stream, sender, None);

    bench(b, &mut client);
}

#[bench]
fn trust_dns_tcp_bench(b: &mut Bencher) {
    let (named, server_port) = trust_dns_process();

    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr);
    let mut client = ClientFuture::new(stream, sender, None);

    bench(b, &mut client);

    // cleaning up the named process
    drop(named);
}

// downloaded from https://www.isc.org/downloads/file/bind-9-11-0-p1/
// cd bind-9-11-0-p1
// .configure
// make
// export TDNS_BIND_PATH=${PWD}/bin/named/named
fn bind_process() -> (NamedProcess, u16) {
    let test_port = find_test_port();

    let bind_path = env::var("TDNS_BIND_PATH").unwrap_or_else(|_| "bind".to_owned());
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or_else(|_| ".".to_owned());

    // create the work directory
    let working_dir = format!("{}/../target/bind_pwd", server_path);
    if !Path::new(&working_dir).exists() {
        DirBuilder::new()
            .create(&working_dir)
            .expect("failed to create dir");
    }

    let mut named = Command::new(bind_path)
                      .current_dir(&working_dir)
                      .stderr(Stdio::piped())
                      .arg("-c").arg("../../server/benches/bind_conf/example.conf")
                      //.arg("-d").arg("0")
                      .arg("-D").arg("TRust-DNS cmp bench")
                      .arg("-g")
                      .arg("-p").arg(&format!("{}", test_port))
                      .spawn()
                      .expect("failed to start named");

    mem::replace(&mut named.stderr, None).unwrap();
    let process = wrap_process(named, test_port);
    (process, test_port)
}

#[bench]
#[ignore]
fn bind_udp_bench(b: &mut Bencher) {
    let (named, server_port) = bind_process();

    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = UdpClientStream::new(addr);
    let mut client = ClientFuture::new(stream, sender, None);

    bench(b, &mut client);

    // cleaning up the named process
    drop(named);
}

#[bench]
#[ignore]
fn bind_tcp_bench(b: &mut Bencher) {
    let (named, server_port) = bind_process();

    let addr: SocketAddr = ("127.0.0.1", server_port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr);
    let mut client = ClientFuture::new(stream, sender, None);

    bench(b, &mut client);

    // cleaning up the named process
    drop(named);
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

// Test inclusive range syntax.

use std::ops::{RangeInclusive, RangeToInclusive};

fn foo() -> isize { 42 }

// Test that range syntax works in return statements
fn return_range_to() -> RangeToInclusive<i32> { return ..=1; }

pub fn main() {
    let mut count = 0;
    for i in 0_usize..=10 {
        assert!(i >= 0 && i <= 10);
        count += i;
    }
    assert_eq!(count, 55);

    let mut count = 0;
    let mut range = 0_usize..=10;
    for i in range {
        assert!(i >= 0 && i <= 10);
        count += i;
    }
    assert_eq!(count, 55);

    let mut count = 0;
    for i in (0_usize..=10).step_by(2) {
        assert!(i >= 0 && i <= 10 && i % 2 == 0);
        count += i;
    }
    assert_eq!(count, 30);

    let _ = 0_usize..=4+4-3;
    let _ = 0..=foo();

    let _ = { &42..=&100 }; // references to literals are OK
    let _ = ..=42_usize;

    // Test we can use two different types with a common supertype.
    let x = &42;
    {
        let y = 42;
        let _ = x..=&y;
    }

    // test collection indexing
    let vec = (0..=10).collect::<Vec<_>>();
    let slice: &[_] = &*vec;
    let string = String::from("hello world");
    let stir = "hello world";

    assert_eq!(&vec[3..=6], &[3, 4, 5, 6]);
    assert_eq!(&vec[ ..=6], &[0, 1, 2, 3, 4, 5, 6]);

    assert_eq!(&slice[3..=6], &[3, 4, 5, 6]);
    assert_eq!(&slice[ ..=6], &[0, 1, 2, 3, 4, 5, 6]);

    assert_eq!(&string[3..=6], "lo w");
    assert_eq!(&string[ ..=6], "hello w");

    assert_eq!(&stir[3..=6], "lo w");
    assert_eq!(&stir[ ..=6], "hello w");

    // test the size hints and emptying
    let mut long = 0..=255u8;
    let mut short = 42..=42u8;
    assert_eq!(long.size_hint(), (256, Some(256)));
    assert_eq!(short.size_hint(), (1, Some(1)));
    long.next();
    short.next();
    assert_eq!(long.size_hint(), (255, Some(255)));
    assert_eq!(short.size_hint(), (0, Some(0)));
    assert_eq!(short, 1..=0);

    assert_eq!(long.len(), 255);
    assert_eq!(short.len(), 0);

    // test iterating backwards
    assert_eq!(long.next_back(), Some(255));
    assert_eq!(long.next_back(), Some(254));
    assert_eq!(long.next_back(), Some(253));
    assert_eq!(long.next(), Some(1));
    assert_eq!(long.next(), Some(2));
    assert_eq!(long.next_back(), Some(252));
    for i in 3..=251 {
        assert_eq!(long.next(), Some(i));
    }
    assert_eq!(long, 1..=0);

    // check underflow
    let mut narrow = 1..=0;
    assert_eq!(narrow.next_back(), None);
    assert_eq!(narrow, 1..=0);
    let mut zero = 0u8..=0;
    assert_eq!(zero.next_back(), Some(0));
    assert_eq!(zero.next_back(), None);
    assert_eq!(zero, 1..=0);
    let mut high = 255u8..=255;
    assert_eq!(high.next_back(), Some(255));
    assert_eq!(high.next_back(), None);
    assert_eq!(high, 1..=0);

    // what happens if you have a nonsense range?
    let mut nonsense = 10..=5;
    assert_eq!(nonsense.next(), None);
    assert_eq!(nonsense, 10..=5);

    // output
    assert_eq!(format!("{:?}", 0..=10), "0..=10");
    assert_eq!(format!("{:?}", ..=10), "..=10");
    assert_eq!(format!("{:?}", long), "1..=0");
}
<commit_msg>Fix some RangeInclusive test cases.<commit_after>// Copyright 2016 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.

// Test inclusive range syntax.

#![feature(range_is_empty)]
#![allow(unused_comparisons)]

use std::ops::RangeToInclusive;

fn foo() -> isize { 42 }

// Test that range syntax works in return statements
pub fn return_range_to() -> RangeToInclusive<i32> { return ..=1; }

#[derive(Debug)]
struct P(u8);

pub fn main() {
    let mut count = 0;
    for i in 0_usize..=10 {
        assert!(i >= 0 && i <= 10);
        count += i;
    }
    assert_eq!(count, 55);

    let mut count = 0;
    let range = 0_usize..=10;
    for i in range {
        assert!(i >= 0 && i <= 10);
        count += i;
    }
    assert_eq!(count, 55);

    let mut count = 0;
    for i in (0_usize..=10).step_by(2) {
        assert!(i >= 0 && i <= 10 && i % 2 == 0);
        count += i;
    }
    assert_eq!(count, 30);

    let _ = 0_usize..=4+4-3;
    let _ = 0..=foo();

    let _ = { &42..=&100 }; // references to literals are OK
    let _ = ..=42_usize;

    // Test we can use two different types with a common supertype.
    let x = &42;
    {
        let y = 42;
        let _ = x..=&y;
    }

    // test collection indexing
    let vec = (0..=10).collect::<Vec<_>>();
    let slice: &[_] = &*vec;
    let string = String::from("hello world");
    let stir = "hello world";

    assert_eq!(&vec[3..=6], &[3, 4, 5, 6]);
    assert_eq!(&vec[ ..=6], &[0, 1, 2, 3, 4, 5, 6]);

    assert_eq!(&slice[3..=6], &[3, 4, 5, 6]);
    assert_eq!(&slice[ ..=6], &[0, 1, 2, 3, 4, 5, 6]);

    assert_eq!(&string[3..=6], "lo w");
    assert_eq!(&string[ ..=6], "hello w");

    assert_eq!(&stir[3..=6], "lo w");
    assert_eq!(&stir[ ..=6], "hello w");

    // test the size hints and emptying
    let mut long = 0..=255u8;
    let mut short = 42..=42u8;
    assert_eq!(long.size_hint(), (256, Some(256)));
    assert_eq!(short.size_hint(), (1, Some(1)));
    long.next();
    short.next();
    assert_eq!(long.size_hint(), (255, Some(255)));
    assert_eq!(short.size_hint(), (0, Some(0)));
    assert!(short.is_empty());

    assert_eq!(long.len(), 255);
    assert_eq!(short.len(), 0);

    // test iterating backwards
    assert_eq!(long.next_back(), Some(255));
    assert_eq!(long.next_back(), Some(254));
    assert_eq!(long.next_back(), Some(253));
    assert_eq!(long.next(), Some(1));
    assert_eq!(long.next(), Some(2));
    assert_eq!(long.next_back(), Some(252));
    for i in 3..=251 {
        assert_eq!(long.next(), Some(i));
    }
    assert!(long.is_empty());

    // check underflow
    let mut narrow = 1..=0;
    assert_eq!(narrow.next_back(), None);
    assert!(narrow.is_empty());
    let mut zero = 0u8..=0;
    assert_eq!(zero.next_back(), Some(0));
    assert_eq!(zero.next_back(), None);
    assert!(zero.is_empty());
    let mut high = 255u8..=255;
    assert_eq!(high.next_back(), Some(255));
    assert_eq!(high.next_back(), None);
    assert!(high.is_empty());

    // what happens if you have a nonsense range?
    let mut nonsense = 10..=5;
    assert_eq!(nonsense.next(), None);
    assert!(nonsense.is_empty());

    // output
    assert_eq!(format!("{:?}", 0..=10), "0..=10");
    assert_eq!(format!("{:?}", ..=10), "..=10");
    assert_eq!(format!("{:?}", 9..=6), "9..=6");

    // ensure that constructing a RangeInclusive does not need PartialOrd bound
    assert_eq!(format!("{:?}", P(1)..=P(2)), "P(1)..=P(2)");
}
<|endoftext|>


<commit_before>#[macro_use(mvec)]
extern crate simdop;
extern crate simdty;
extern crate llvmint;

use simdop::*;

fn main() {

  let sse2 = arch::x86::SSE2::detect().unwrap();

  let m: M4<i32> = mvec![1,2,3,4];
  println!("M: {:?}", m);

  let m1: M2<i64> = sse2.set1(1);
  let m2: M2<i64> = sse2.set1(2);
  println!("Sum:    {:?}", sse2.add(m1, m2));
  println!("Double: {:?}", sse2.shli(m1, 1));
  println!("Half:   {:?}", sse2.shri(m2, 1));
  let m3: M4<i32> = sse2.set1(1);
  let m4: M4<i32> = sse2.set1(2);
  println!("Sum:    {:?}", sse2.add(m3, m4));
  println!("Double: {:?}", sse2.shli(m3, 1));
  println!("Half:   {:?}", sse2.shri(m4, 1));

}
<commit_msg>refactor: use Option::map in example<commit_after>#[macro_use(mvec)]
extern crate simdop;
extern crate simdty;
extern crate llvmint;

use simdop::*;

fn main() {

  let m: M4<i32> = mvec![1,2,3,4];
  println!("M: {:?}", m);

  arch::x86::SSE2::detect().map(|sse2| {
    let m1: M2<i64> = sse2.set1(1);
    let m2: M2<i64> = sse2.set1(2);
    println!("Sum:    {:?}", sse2.add(m1, m2));
    println!("Double: {:?}", sse2.shli(m1, 1));
    println!("Half:   {:?}", sse2.shri(m2, 1));
    let m3: M4<i32> = sse2.set1(1);
    let m4: M4<i32> = sse2.set1(2);
    println!("Sum:    {:?}", sse2.add(m3, m4));
    println!("Double: {:?}", sse2.shli(m3, 1));
    println!("Half:   {:?}", sse2.shri(m4, 1));
  });

}
<|endoftext|>


<commit_before>//! Download and manage sysroots.

use std::env;
use std::fs;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::process::Command;

use flate2::bufread::GzDecoder;
use reqwest;
use tar::Archive;

use errors::{Result, ResultExt};

const BASE_PATH: &'static str = "https://s3.amazonaws.com/rust-lang-ci/rustc-builds";

pub struct Sysroot {
    pub sha: String,
    pub rustc: PathBuf,
    pub cargo: PathBuf,
    pub preserve: bool,
}

impl Sysroot {
    // if running with cargo run, we want to avoid things like CARGO_INCREMENTAL
    // sneaking into the command's environment, but we do need the PATH to
    // find linkers and other things that cargo and rust needs.
    pub fn command<P: AsRef<Path>>(&self, path: P) -> Command {
        let mut command = Command::new(path.as_ref().as_os_str());
        command
            .env_clear()
            .env("PATH", env::var("PATH").unwrap_or_default())
            .env("CARGO_HOME", env::var("CARGO_HOME").unwrap_or_default())
            .env("CARGO", &self.cargo)
            .env("RUSTC", &self.rustc);
        command
    }

    pub fn install(sha: &str, triple: &str, preserve: bool) -> Result<Self> {
        let unpack_into = format!("rust-{}", sha);
        get_and_extract(
            &format!("{}/{}/rustc-nightly-{}.tar.gz", BASE_PATH, sha, triple),
            &unpack_into,
            false,
         )?;
        get_and_extract(
            &format!("{}/{}/rust-std-nightly-{}.tar.gz", BASE_PATH, sha, triple),
            &unpack_into,
            true,
        )?;
        get_and_extract(
            &format!("{}/{}/cargo-nightly-{}.tar.gz", BASE_PATH, sha, triple),
            &unpack_into,
            false,
        )?;

        let result = Sysroot {
            rustc: PathBuf::from(format!("rust-{}/rustc/bin/rustc", sha)).canonicalize()
                .chain_err(|| "failed to canonicalize rustc path")?,
            cargo: PathBuf::from(format!("rust-{}/cargo/bin/cargo", sha)).canonicalize()
                .chain_err(|| "failed to canonicalize cargo path")?,
            sha: sha.to_owned(),
            preserve: preserve,
        };

        let version = result.command(&result.rustc).arg("--version").output()
            .chain_err(|| format!("{} --version", result.rustc.display()))?;
        let version = String::from_utf8(version.stdout).unwrap();
        info!("version: {}", version);

        Ok(result)
    }

    pub fn path(&self) -> String {
        format!("rust-{}", self.sha)
    }
}

impl Drop for Sysroot {
    fn drop(&mut self) {
        if self.preserve {
            return
        }

        fs::remove_dir_all(&self.path()).unwrap_or_else(|err| {
            info!("failed to remove {}, please do so manually: {:?}", self.path(), err);
        });
    }
}

fn get_and_extract(url: &str, into: &str, is_std: bool) -> Result<()> {
    info!("requesting: {}", url);
    let resp = reqwest::get(url)?;
    info!("{}", resp.status());
    let mut resp = BufReader::new(resp);

    let decoder = GzDecoder::new(&mut resp)?;
    let mut archive = Archive::new(decoder);
    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?.into_owned();
        let mut components = path.components();
        assert!(components.next().is_some(), "strip container directory");
        let path = components.as_path();
        let path = if is_std {
            if let Ok(path) = path.strip_prefix("rust-std-x86_64-unknown-linux-gnu/lib/rustlib") {
                Path::new("rustc/lib/rustlib").join(path)
            } else {
                continue;
            }
        } else {
            path.into()
        };
        let path = Path::new(into).join(path);
        fs::create_dir_all(&path.parent().unwrap())
            .chain_err(|| format!("could not create intermediate directories for {}",
                    path.display()))?;
        entry.unpack(path)?;
    }
    Ok(())
}
<commit_msg>use fallback Cargo instead of old broken Cargos<commit_after>//! Download and manage sysroots.

use std::env;
use std::fs;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::process::Command;

use flate2::bufread::GzDecoder;
use reqwest;
use tar::Archive;

use errors::{Result, ResultExt};

const BASE_PATH: &'static str = "https://s3.amazonaws.com/rust-lang-ci/rustc-builds";

pub struct Sysroot {
    pub sha: String,
    pub rustc: PathBuf,
    pub cargo: PathBuf,
    pub preserve: bool,
}

impl Sysroot {
    // if running with cargo run, we want to avoid things like CARGO_INCREMENTAL
    // sneaking into the command's environment, but we do need the PATH to
    // find linkers and other things that cargo and rust needs.
    pub fn command<P: AsRef<Path>>(&self, path: P) -> Command {
        let mut command = Command::new(path.as_ref().as_os_str());
        command
            .env_clear()
            .env("PATH", env::var("PATH").unwrap_or_default())
            .env("CARGO_HOME", env::var("CARGO_HOME").unwrap_or_default())
            .env("CARGO", &self.cargo)
            .env("RUSTC", &self.rustc);
        command
    }

    pub fn install(sha: &str, triple: &str, preserve: bool) -> Result<Self> {
        let unpack_into = format!("rust-{}", sha);
        get_and_extract(
            &format!("{}/{}/rustc-nightly-{}.tar.gz", BASE_PATH, sha, triple),
            &unpack_into,
            false,
         )?;
        get_and_extract(
            &format!("{}/{}/rust-std-nightly-{}.tar.gz", BASE_PATH, sha, triple),
            &unpack_into,
            true,
        )?;

        let mut result = Sysroot {
            rustc: PathBuf::from(format!("rust-{}/rustc/bin/rustc", sha)).canonicalize()
                .chain_err(|| "failed to canonicalize rustc path")?,
            cargo: PathBuf::new(),
            sha: sha.to_owned(),
            preserve: preserve,
        };

        let version = result.command(&result.rustc).arg("--version").output()
            .chain_err(|| format!("{} --version", result.rustc.display()))?;
        let version = String::from_utf8(version.stdout).unwrap();
        info!("version: {}", version);

        let mut cargo_sha = sha;
        let index = version.find('(');
        if let Some(index) = index {
            let version = &version[index..];
            if let Some(index) = version.find(' ') {
                let version = &version[index..];
                if let Some(rindex) = version.rfind(')') {
                    let date = version[..rindex].trim();
                    info!("date: {}", date);
                    if date < "2017-03-20" {
                        // Versions of rustc older than Mar 20 have bugs in
                        // their cargo. Use a known-good cargo for older rustcs
                        // instead.
                        info!("using fallback cargo");
                        cargo_sha = "53eb08bedc8719844bb553dbe1a39d9010783ff5";
                    }
                }
            }
        }

        get_and_extract(
            &format!("{}/{}/cargo-nightly-{}.tar.gz", BASE_PATH, cargo_sha, triple),
            &unpack_into,
            false,
        )?;

        result.cargo = PathBuf::from(format!("rust-{}/cargo/bin/cargo", sha)).canonicalize()
            .chain_err(|| "failed to canonicalize cargo path")?;

        Ok(result)
    }

    pub fn path(&self) -> String {
        format!("rust-{}", self.sha)
    }
}

impl Drop for Sysroot {
    fn drop(&mut self) {
        if self.preserve {
            return
        }

        fs::remove_dir_all(&self.path()).unwrap_or_else(|err| {
            info!("failed to remove {}, please do so manually: {:?}", self.path(), err);
        });
    }
}

fn get_and_extract(url: &str, into: &str, is_std: bool) -> Result<()> {
    info!("requesting: {}", url);
    let resp = reqwest::get(url)?;
    info!("{}", resp.status());
    let mut resp = BufReader::new(resp);

    let decoder = GzDecoder::new(&mut resp)?;
    let mut archive = Archive::new(decoder);
    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?.into_owned();
        let mut components = path.components();
        assert!(components.next().is_some(), "strip container directory");
        let path = components.as_path();
        let path = if is_std {
            if let Ok(path) = path.strip_prefix("rust-std-x86_64-unknown-linux-gnu/lib/rustlib") {
                Path::new("rustc/lib/rustlib").join(path)
            } else {
                continue;
            }
        } else {
            path.into()
        };
        let path = Path::new(into).join(path);
        fs::create_dir_all(&path.parent().unwrap())
            .chain_err(|| format!("could not create intermediate directories for {}",
                    path.display()))?;
        entry.unpack(path)?;
    }
    Ok(())
}
<|endoftext|>