<commit_before>use hash_map::HashMap;
use std::borrow::Borrow;
use std::hash::{BuildHasher, Hash};

use FailedAllocationError;

#[cfg(target_pointer_width = "32")]
const CANARY: usize = 0x42cafe99;
#[cfg(target_pointer_width = "64")]
const CANARY: usize = 0x42cafe9942cafe99;

#[derive(Clone, Debug)]
enum JournalEntry {
    Insert(usize),
    GOIW(usize),
    Remove(usize),
    DidClear(usize),
}

#[derive(Clone, Debug)]
pub struct DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher
{
    map: HashMap<K, (usize, V), S>,
    journal: Vec<JournalEntry>,
    readonly: bool,
}

impl<K: Hash + Eq, V, S: BuildHasher> DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher
{
    #[inline(always)]
    pub fn inner(&self) -> &HashMap<K, (usize, V), S> {
        &self.map
    }

    #[inline(never)]
    pub fn begin_mutation(&mut self) {
        self.map.verify();
        assert!(self.readonly);
        self.readonly = false;
        self.verify();
    }

    #[inline(never)]
    pub fn end_mutation(&mut self) {
        self.map.verify();
        assert!(!self.readonly);
        self.readonly = true;
        self.verify();
    }

    fn verify(&self) {
        let mut position = 0;
        let mut bad_canary: Option<(usize, *const usize)> = None;
        for (_,v) in self.map.iter() {
            let canary_ref = &v.0;
            if *canary_ref == CANARY {
                position += 1;
                continue;
            }
            bad_canary = Some((*canary_ref, canary_ref));
        }
        if let Some(c) = bad_canary {
            self.report_corruption(c.0, c.1, position);
        }
    }

    #[inline(always)]
    pub fn with_hasher(hash_builder: S) -> Self {
        Self {
            map: HashMap::<K, (usize, V), S>::with_hasher(hash_builder),
            journal: Vec::new(),
            readonly: true,
        }
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    #[inline(always)]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    #[inline(always)]
    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        self.map.contains_key(k)
    }

    #[inline(always)]
    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        self.map.get(k).map(|v| &v.1)
    }

    #[inline(always)]
    pub fn try_get_or_insert_with<F: FnOnce() -> V>(
        &mut self,
        key: K,
        default: F
    ) -> Result<&mut V, FailedAllocationError> {
        assert!(!self.readonly);
        self.journal.push(JournalEntry::GOIW(self.map.make_hash(&key).inspect()));
        let entry = self.map.try_entry(key)?;
        Ok(&mut entry.or_insert_with(|| (CANARY, default())).1)
    }

    #[inline(always)]
    pub fn try_insert(&mut self, k: K, v: V) -> Result<Option<V>, FailedAllocationError> {
        assert!(!self.readonly);
        self.journal.push(JournalEntry::Insert(self.map.make_hash(&k).inspect()));
        let old = self.map.try_insert(k, (CANARY, v))?;
        Ok(old.map(|x| x.1))
    }

    #[inline(always)]
    pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        assert!(!self.readonly);
        self.journal.push(JournalEntry::Remove(self.map.make_hash(k).inspect()));
        self.map.remove(k).map(|x| x.1)
    }

    #[inline(always)]
    pub fn clear(&mut self) where K: 'static, V: 'static  {
        // We handle scoped mutations for the caller here, since callsites that
        // invoke clear() don't benefit from the coalescing we do around insertion.
        self.begin_mutation();
        self.journal.clear();
        self.journal.push(JournalEntry::DidClear(self.map.raw_capacity()));
        self.map.clear();
        self.end_mutation();
    }

    #[inline(never)]
    fn report_corruption(
        &self,
        canary: usize,
        canary_addr: *const usize,
        position: usize
    ) {
        use ::std::ffi::CString;
        let key = b"HashMapJournal\0";
        let value = CString::new(format!("{:?}", self.journal)).unwrap();
        unsafe {
            Gecko_AnnotateCrashReport(
                key.as_ptr() as *const ::std::os::raw::c_char,
                value.as_ptr(),
            );
        }
        panic!(
            "HashMap Corruption (sz={}, cap={}, pairsz={}, cnry={:#x}, pos={}, base_addr={:?}, cnry_addr={:?}, jrnl_len={})",
            self.map.len(),
            self.map.raw_capacity(),
            ::std::mem::size_of::<(K, (usize, V))>(),
            canary,
            position,
            self.map.raw_buffer(),
            canary_addr,
            self.journal.len(),
        );
    }
}

impl<K, V, S> PartialEq for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          V: PartialEq,
          S: BuildHasher
{
    fn eq(&self, other: &Self) -> bool {
        self.map.eq(&other.map)
    }
}

impl<K, V, S> Eq for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          V: Eq,
          S: BuildHasher
{
}

impl<K, V, S> Default for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher + Default
{
    fn default() -> Self {
        Self {
            map: HashMap::default(),
            journal: Vec::new(),
            readonly: true,
        }
    }
}

impl<K: Hash + Eq, V, S: BuildHasher> Drop for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher
{
    fn drop(&mut self) {
        debug_assert!(self.readonly, "Dropped while mutating");
    }
}

extern "C" {
    pub fn Gecko_AnnotateCrashReport(key_str: *const ::std::os::raw::c_char,
                                     value_str: *const ::std::os::raw::c_char);
}
<commit_msg>Verify in DiagnosticHashMap::drop.<commit_after>use hash_map::HashMap;
use std::borrow::Borrow;
use std::hash::{BuildHasher, Hash};

use FailedAllocationError;

#[cfg(target_pointer_width = "32")]
const CANARY: usize = 0x42cafe99;
#[cfg(target_pointer_width = "64")]
const CANARY: usize = 0x42cafe9942cafe99;

#[derive(Clone, Debug)]
enum JournalEntry {
    Insert(usize),
    GOIW(usize),
    Remove(usize),
    DidClear(usize),
}

#[derive(Clone, Debug)]
pub struct DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher
{
    map: HashMap<K, (usize, V), S>,
    journal: Vec<JournalEntry>,
    readonly: bool,
}

impl<K: Hash + Eq, V, S: BuildHasher> DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher
{
    #[inline(always)]
    pub fn inner(&self) -> &HashMap<K, (usize, V), S> {
        &self.map
    }

    #[inline(never)]
    pub fn begin_mutation(&mut self) {
        self.map.verify();
        assert!(self.readonly);
        self.readonly = false;
        self.verify();
    }

    #[inline(never)]
    pub fn end_mutation(&mut self) {
        self.map.verify();
        assert!(!self.readonly);
        self.readonly = true;
        self.verify();
    }

    fn verify(&self) {
        let mut position = 0;
        let mut bad_canary: Option<(usize, *const usize)> = None;
        for (_,v) in self.map.iter() {
            let canary_ref = &v.0;
            if *canary_ref == CANARY {
                position += 1;
                continue;
            }
            bad_canary = Some((*canary_ref, canary_ref));
        }
        if let Some(c) = bad_canary {
            self.report_corruption(c.0, c.1, position);
        }
    }

    #[inline(always)]
    pub fn with_hasher(hash_builder: S) -> Self {
        Self {
            map: HashMap::<K, (usize, V), S>::with_hasher(hash_builder),
            journal: Vec::new(),
            readonly: true,
        }
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    #[inline(always)]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    #[inline(always)]
    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        self.map.contains_key(k)
    }

    #[inline(always)]
    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        self.map.get(k).map(|v| &v.1)
    }

    #[inline(always)]
    pub fn try_get_or_insert_with<F: FnOnce() -> V>(
        &mut self,
        key: K,
        default: F
    ) -> Result<&mut V, FailedAllocationError> {
        assert!(!self.readonly);
        self.journal.push(JournalEntry::GOIW(self.map.make_hash(&key).inspect()));
        let entry = self.map.try_entry(key)?;
        Ok(&mut entry.or_insert_with(|| (CANARY, default())).1)
    }

    #[inline(always)]
    pub fn try_insert(&mut self, k: K, v: V) -> Result<Option<V>, FailedAllocationError> {
        assert!(!self.readonly);
        self.journal.push(JournalEntry::Insert(self.map.make_hash(&k).inspect()));
        let old = self.map.try_insert(k, (CANARY, v))?;
        Ok(old.map(|x| x.1))
    }

    #[inline(always)]
    pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>,
              Q: Hash + Eq
    {
        assert!(!self.readonly);
        self.journal.push(JournalEntry::Remove(self.map.make_hash(k).inspect()));
        self.map.remove(k).map(|x| x.1)
    }

    #[inline(always)]
    pub fn clear(&mut self) where K: 'static, V: 'static  {
        // We handle scoped mutations for the caller here, since callsites that
        // invoke clear() don't benefit from the coalescing we do around insertion.
        self.begin_mutation();
        self.journal.clear();
        self.journal.push(JournalEntry::DidClear(self.map.raw_capacity()));
        self.map.clear();
        self.end_mutation();
    }

    #[inline(never)]
    fn report_corruption(
        &self,
        canary: usize,
        canary_addr: *const usize,
        position: usize
    ) {
        use ::std::ffi::CString;
        let key = b"HashMapJournal\0";
        let value = CString::new(format!("{:?}", self.journal)).unwrap();
        unsafe {
            Gecko_AnnotateCrashReport(
                key.as_ptr() as *const ::std::os::raw::c_char,
                value.as_ptr(),
            );
        }
        panic!(
            "HashMap Corruption (sz={}, cap={}, pairsz={}, cnry={:#x}, pos={}, base_addr={:?}, cnry_addr={:?}, jrnl_len={})",
            self.map.len(),
            self.map.raw_capacity(),
            ::std::mem::size_of::<(K, (usize, V))>(),
            canary,
            position,
            self.map.raw_buffer(),
            canary_addr,
            self.journal.len(),
        );
    }
}

impl<K, V, S> PartialEq for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          V: PartialEq,
          S: BuildHasher
{
    fn eq(&self, other: &Self) -> bool {
        self.map.eq(&other.map)
    }
}

impl<K, V, S> Eq for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          V: Eq,
          S: BuildHasher
{
}

impl<K, V, S> Default for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher + Default
{
    fn default() -> Self {
        Self {
            map: HashMap::default(),
            journal: Vec::new(),
            readonly: true,
        }
    }
}

impl<K: Hash + Eq, V, S: BuildHasher> Drop for DiagnosticHashMap<K, V, S>
    where K: Eq + Hash,
          S: BuildHasher
{
    fn drop(&mut self) {
        self.map.verify();
        debug_assert!(self.readonly, "Dropped while mutating");
        self.verify();
    }
}

extern "C" {
    pub fn Gecko_AnnotateCrashReport(key_str: *const ::std::os::raw::c_char,
                                     value_str: *const ::std::os::raw::c_char);
}
<|endoftext|>


<commit_before>extern crate regex;

use self::regex::Regex;

pub struct Matcher<'a> {
    pub lines: &'a Vec<String>,
    pub matches: Vec<&'a String>,
    pub input: String,
    pub selection: usize,
}

impl<'a> Matcher<'a> {
    pub fn new(lines: &'a Vec<String>) -> Matcher<'a> {
        let mut matches: Vec<&'a String> = Vec::new();

        for line in lines {
            matches.push(&line);
        }

        Matcher {
            lines: lines,
            input: String::new(),
            selection: 0,
            matches: matches,
        }
    }

    pub fn push_char(&mut self, input: char) {
        self.input = format!("{}{}", self.input, input);
        self.update_matches();
    }

    pub fn pop_char(&mut self) {
        self.input.pop();
        self.update_matches();
    }

    pub fn selected_match(&mut self) -> String {
        match self.matches.get(self.selection) {
            Some(match_text) => match_text.clone().to_string(),
            None => "".to_string(),
        }
    }

    pub fn move_up(&mut self) {
        if self.selection != 0 {
            self.selection -= 1;
        }
    }

    pub fn move_down(&mut self) {
        if self.selection != self.matches.len() {
            self.selection += 1;
        }
    }

    fn update_matches(&mut self) {
        self.matches.clear();

        let regex_string: String = self.input.split("").fold(String::new(), |acc, input| {
            acc + ".*" + input
        });

        let re = Regex::new(&regex_string).unwrap();

        for line in self.lines {
            if re.is_match(&line) {
                self.matches.push(&line);
            }
        }
    }
}
<commit_msg>Stop selection highlight from going out of bounds<commit_after>extern crate regex;

use self::regex::Regex;

pub struct Matcher<'a> {
    pub lines: &'a Vec<String>,
    pub matches: Vec<&'a String>,
    pub input: String,
    pub selection: usize,
}

impl<'a> Matcher<'a> {
    pub fn new(lines: &'a Vec<String>) -> Matcher<'a> {
        let mut matches: Vec<&'a String> = Vec::new();

        for line in lines {
            matches.push(&line);
        }

        Matcher {
            lines: lines,
            input: String::new(),
            selection: 0,
            matches: matches,
        }
    }

    pub fn push_char(&mut self, input: char) {
        self.input = format!("{}{}", self.input, input);
        self.update_matches();
    }

    pub fn pop_char(&mut self) {
        self.input.pop();
        self.update_matches();
    }

    pub fn selected_match(&mut self) -> String {
        match self.matches.get(self.selection) {
            Some(match_text) => match_text.clone().to_string(),
            None => "".to_string(),
        }
    }

    pub fn move_up(&mut self) {
        if self.selection != 0 {
            self.selection -= 1;
        }
    }

    pub fn move_down(&mut self) {
        if self.selection != self.matches.len() - 1 {
            self.selection += 1;
        }
    }

    fn update_matches(&mut self) {
        self.matches.clear();

        let regex_string: String = self.input.split("").fold(String::new(), |acc, input| {
            acc + ".*" + input
        });

        let re = Regex::new(&regex_string).unwrap();

        for line in self.lines {
            if re.is_match(&line) {
                self.matches.push(&line);
            }
        }

        let length = self.matches.len() - 1;

        if self.selection >= length {
            self.selection = length
        }
    }
}
<|endoftext|>


<commit_before>//! Store and manipulate Kafka messages.
use rdsys;
use rdsys::types::*;

use std::ffi::CStr;
use std::slice;
use std::str;

/// Timestamp of a message
#[derive(Debug,PartialEq,Eq)]
pub enum Timestamp {
    NotAvailable,
    CreateTime(i64),
    LogAppendTime(i64)
}

/// A native librdkafka message.
#[derive(Debug)]
pub struct Message {
    ptr: *mut RDKafkaMessage,
}

unsafe impl Send for Message {}

impl<'a> Message {
    /// Creates a new Message that wraps the native Kafka message pointer.
    pub fn new(ptr: *mut RDKafkaMessage) -> Message {
        Message { ptr: ptr }
    }

    /// Returns a pointer to the RDKafkaMessage.
    pub fn ptr(&self) -> *mut RDKafkaMessage {
        self.ptr
    }

    /// Returns a pointer to the message's RDKafkaTopic
    pub fn topic_ptr(&self) -> *mut RDKafkaTopic {
        unsafe { (*self.ptr).rkt }
    }

    /// Returns the length of the key field of the message.
    pub fn key_len(&self) -> usize {
        unsafe { (*self.ptr).key_len }
    }

    /// Returns the length of the payload field of the message.
    pub fn payload_len(&self) -> usize {
        unsafe { (*self.ptr).len }
    }

    /// Returns the key of the message, or None if there is no key.
    pub fn key(&'a self) -> Option<&'a [u8]> {
        unsafe {
            if (*self.ptr).key.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).key as *const u8, (*self.ptr).key_len))
            }
        }
    }

    /// Returns the payload of the message, or None if there is no payload.
    pub fn payload(&'a self) -> Option<&'a [u8]> {
        unsafe {
            if (*self.ptr).payload.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).payload as *const u8, (*self.ptr).len))
            }
        }
    }

    /// Returns the source topic of the message.
    pub fn topic_name(&'a self) -> &'a str {
         unsafe {
             CStr::from_ptr(rdsys::rd_kafka_topic_name((*self.ptr).rkt))
                 .to_str()
                 .expect("Topic name is not valid UTF-8")
         }
     }

    /// Converts the raw bytes of the payload to a reference of type &P, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn payload_view<P: ?Sized + FromBytes>(&'a self) -> Option<Result<&'a P, P::Error>> {
        self.payload().map(P::from_bytes)
    }

    /// Converts the raw bytes of the key to a reference of type &K, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn key_view<K: ?Sized + FromBytes>(&'a self) -> Option<Result<&'a K, K::Error>> {
        self.key().map(K::from_bytes)
    }

    /// Returns the partition number where the message is stored.
    pub fn partition(&self) -> i32 {
        unsafe { (*self.ptr).partition }
    }

    /// Returns the offset of the message.
    pub fn offset(&self) -> i64 {
        unsafe { (*self.ptr).offset }
    }

    /// Returns the message timestamp for a consumed message if available.
    pub fn timestamp(&self) -> Timestamp {
        let mut timestamp_type = rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE;
        let timestamp = unsafe {
            rdsys::rd_kafka_message_timestamp(
                self.ptr,
                &mut timestamp_type
            )

        };
        match timestamp_type {
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE => Timestamp::NotAvailable,
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_CREATE_TIME => Timestamp::CreateTime(timestamp),
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME => Timestamp::LogAppendTime(timestamp)
        }
    }
}

impl Drop for Message {
    fn drop(&mut self) {
        trace!("Destroying message {:?}", self);
        unsafe { rdsys::rd_kafka_message_destroy(self.ptr) };
    }
}

/// Given a reference to a byte array, returns a different view of the same data.
/// No copy of the data should be performed.
pub trait FromBytes {
    type Error;
    fn from_bytes(&[u8]) -> Result<&Self, Self::Error>;
}

impl FromBytes for [u8] {
    type Error = ();
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        Ok(bytes)
    }
}

impl FromBytes for str {
    type Error = str::Utf8Error;
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        str::from_utf8(bytes)
    }
}

/// Given some data, returns the byte representation of that data.
/// No copy of the data should be performed.
pub trait ToBytes {
    fn to_bytes(&self) -> &[u8];
}

impl ToBytes for [u8] {
    fn to_bytes(&self) -> &[u8] {
        self
    }
}

impl ToBytes for str {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToBytes for Vec<u8> {
    fn to_bytes(&self) -> &[u8] {
        self.as_slice()
    }
}

impl ToBytes for String {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a, T: ToBytes> ToBytes for &'a T {
    fn to_bytes(&self) -> &[u8] {
        (*self).to_bytes()
    }
}

impl ToBytes for () {
    fn to_bytes(&self) -> &[u8] {
        &[]
    }
}
<commit_msg>Remove explicit lifetime for Message<commit_after>//! Store and manipulate Kafka messages.
use rdsys;
use rdsys::types::*;

use std::ffi::CStr;
use std::slice;
use std::str;

/// Timestamp of a message
#[derive(Debug,PartialEq,Eq)]
pub enum Timestamp {
    NotAvailable,
    CreateTime(i64),
    LogAppendTime(i64)
}

/// A native librdkafka message.
#[derive(Debug)]
pub struct Message {
    ptr: *mut RDKafkaMessage,
}

unsafe impl Send for Message {}

impl Message {
    /// Creates a new Message that wraps the native Kafka message pointer.
    pub fn new(ptr: *mut RDKafkaMessage) -> Message {
        Message { ptr: ptr }
    }

    /// Returns a pointer to the RDKafkaMessage.
    pub fn ptr(&self) -> *mut RDKafkaMessage {
        self.ptr
    }

    /// Returns a pointer to the message's RDKafkaTopic
    pub fn topic_ptr(&self) -> *mut RDKafkaTopic {
        unsafe { (*self.ptr).rkt }
    }

    /// Returns the length of the key field of the message.
    pub fn key_len(&self) -> usize {
        unsafe { (*self.ptr).key_len }
    }

    /// Returns the length of the payload field of the message.
    pub fn payload_len(&self) -> usize {
        unsafe { (*self.ptr).len }
    }

    /// Returns the key of the message, or None if there is no key.
    pub fn key(&self) -> Option<&[u8]> {
        unsafe {
            if (*self.ptr).key.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).key as *const u8, (*self.ptr).key_len))
            }
        }
    }

    /// Returns the payload of the message, or None if there is no payload.
    pub fn payload(&self) -> Option<&[u8]> {
        unsafe {
            if (*self.ptr).payload.is_null() {
                None
            } else {
                Some(slice::from_raw_parts::<u8>((*self.ptr).payload as *const u8, (*self.ptr).len))
            }
        }
    }

    /// Returns the source topic of the message.
    pub fn topic_name(&self) -> &str {
         unsafe {
             CStr::from_ptr(rdsys::rd_kafka_topic_name((*self.ptr).rkt))
                 .to_str()
                 .expect("Topic name is not valid UTF-8")
         }
     }

    /// Converts the raw bytes of the payload to a reference of type &P, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn payload_view<P: ?Sized + FromBytes>(&self) -> Option<Result<&P, P::Error>> {
        self.payload().map(P::from_bytes)
    }

    /// Converts the raw bytes of the key to a reference of type &K, pointing to the same data inside
    /// the message. The returned reference cannot outlive the message.
    pub fn key_view<K: ?Sized + FromBytes>(&self) -> Option<Result<&K, K::Error>> {
        self.key().map(K::from_bytes)
    }

    /// Returns the partition number where the message is stored.
    pub fn partition(&self) -> i32 {
        unsafe { (*self.ptr).partition }
    }

    /// Returns the offset of the message.
    pub fn offset(&self) -> i64 {
        unsafe { (*self.ptr).offset }
    }

    /// Returns the message timestamp for a consumed message if available.
    pub fn timestamp(&self) -> Timestamp {
        let mut timestamp_type = rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE;
        let timestamp = unsafe {
            rdsys::rd_kafka_message_timestamp(
                self.ptr,
                &mut timestamp_type
            )

        };
        match timestamp_type {
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_NOT_AVAILABLE => Timestamp::NotAvailable,
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_CREATE_TIME => Timestamp::CreateTime(timestamp),
            rdsys::rd_kafka_timestamp_type_t::RD_KAFKA_TIMESTAMP_LOG_APPEND_TIME => Timestamp::LogAppendTime(timestamp)
        }
    }
}

impl Drop for Message {
    fn drop(&mut self) {
        trace!("Destroying message {:?}", self);
        unsafe { rdsys::rd_kafka_message_destroy(self.ptr) };
    }
}

/// Given a reference to a byte array, returns a different view of the same data.
/// No copy of the data should be performed.
pub trait FromBytes {
    type Error;
    fn from_bytes(&[u8]) -> Result<&Self, Self::Error>;
}

impl FromBytes for [u8] {
    type Error = ();
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        Ok(bytes)
    }
}

impl FromBytes for str {
    type Error = str::Utf8Error;
    fn from_bytes(bytes: &[u8]) -> Result<&Self, Self::Error> {
        str::from_utf8(bytes)
    }
}

/// Given some data, returns the byte representation of that data.
/// No copy of the data should be performed.
pub trait ToBytes {
    fn to_bytes(&self) -> &[u8];
}

impl ToBytes for [u8] {
    fn to_bytes(&self) -> &[u8] {
        self
    }
}

impl ToBytes for str {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToBytes for Vec<u8> {
    fn to_bytes(&self) -> &[u8] {
        self.as_slice()
    }
}

impl ToBytes for String {
    fn to_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a, T: ToBytes> ToBytes for &'a T {
    fn to_bytes(&self) -> &[u8] {
        (*self).to_bytes()
    }
}

impl ToBytes for () {
    fn to_bytes(&self) -> &[u8] {
        &[]
    }
}
<|endoftext|>


<commit_before>use assembler::x64::{Addr, R64};
use assembler::x64::R64::*;
use assembler::x64::traits::*;
use assembler::emit::{Emit, Label};

use template_interp::shared::{Dispatchable, build_interp, breakpoint};

use std::mem;
use std::env;
use std::collections::HashSet;

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
enum Op {
    // stack.push(oparg_i8)
    LoadI8 = 0,

    // stack.push(stack[oparg_i8])
    LoadL,

    // r = stack.pop(); l = stack.pop(); if l < r then pc += oparg_i8
    BranchLt,

    // Callee clears the stack.
    // func_ix = oparg_u8; stack.push(pc); pc = func_table[oparg_u8]; locals = args
    Call,

    // res = stack.pop(); pc = stack.pop(); stack.pops(oparg_u8); stack.push(res)
    Ret,

    // rax = stack.pop(); halt
    Halt,

    // r = stack.pop(); l = stack.pop(); stack.push(l + r)
    Add,
}

#[derive(Debug, Clone, Copy)]
enum Instr {
    OpOnly(Op),
    OpWithArg(Op, i8),
}

fn instr_to_bs(is: &[Instr]) -> Vec<u8> {
    let mut bs = vec![];
    for i in is {
        match i {
            &Instr::OpOnly(op) => {
                bs.push(op as u8);
            }
            &Instr::OpWithArg(op, arg) => {
                bs.push(op as u8);
                bs.push(arg as u8);
            }
        }
    }
    bs
}

const LAST_OP: Op = Op::Add;

#[repr(C)]
struct InterpContext {
    pc: isize,
    dispatch_table: isize,
    func_table: isize,
    trace_ctx: isize,
    sp: isize,
}

// Can we have offsetof?
const PC_OFFSET: i32 = 0;
const DT_OFFSET: i32 = 1 * 8;
const FT_OFFSET: i32 = 2 * 8;
const TC_OFFSET: i32 = 3 * 8;
const SP_OFFSET: i32 = 4 * 8;

impl InterpContext {
    fn location_mapping(base: R64, vr: &VMRegs) -> Vec<(R64, Addr)>{
        vec![
            (vr.pc, base + PC_OFFSET),
            (vr.dispatch_table, base + DT_OFFSET),
            (vr.func_table, base + FT_OFFSET),
            (vr.trace_ctx, base + TC_OFFSET),
            (vr.sp, base + SP_OFFSET),
        ]
    }

    fn build_unpack_to_reg(emit: &mut Emit, vr: &VMRegs) {
        // TODO
        let mut last_move: Option<Box<FnMut(&mut Emit)>> = None;
        for (r, m) in InterpContext::location_mapping(rdi, vr) {
            if r == rdi {
                last_move = Some(Box::new(move |emit| {
                    emit.mov(r, &m);
                }));
            } else {
                emit.mov(r, &m);
            }
        }
        if let Some(mut f) = last_move {
            f(emit);
        }
    }
}

#[derive(Debug)]
struct Trace {
    bc_list: Vec<isize>,
    bc_set: HashSet<isize>,
}

impl Trace {
    fn new() -> Self {
        Trace {
            bc_list: Default::default(),
            bc_set: Default::default(),
        }
    }

    // Returns false if this trace is finished.
    fn record(&mut self, bc_ptr: isize) -> bool {
        self.bc_list.push(bc_ptr);
        if self.bc_set.contains(&bc_ptr) {
            return false;
        }
        self.bc_set.insert(bc_ptr);
        true
    }
}

#[derive(Debug)]
struct TraceContext {
    current: Trace,
    traces: Vec<Trace>,
}

impl TraceContext {
    fn new() -> Box<Self> {
        Box::new(TraceContext {
            current: Trace::new(),
            traces: vec![],
        })
    }

    fn as_ptr(&self) -> *const Self {
        self as *const _
    }

    fn record(&mut self, bc_ptr: isize) {
        if !self.current.record(bc_ptr) {
            let mut new_trace = Trace::new();
            mem::swap(&mut self.current, &mut new_trace);
            self.traces.push(new_trace);

            // Shall we record the trace bridge?
            self.record(bc_ptr);
        }
    }

    unsafe extern "C" fn record_unsafe(raw: *mut TraceContext, bc_ptr: isize) {
        (&mut *raw).record(bc_ptr);
    }
}

struct VMRegs {
    pc: R64,
    tmpl: R64,
    tmpr: R64,
    dispatch_table: R64,
    func_table: R64,
    trace_ctx: R64,
    sp: R64,
    scratch: R64,
}

impl VMRegs {
    fn new() -> Self {
        VMRegs {
            pc: rdi,
            dispatch_table: rsi,
            func_table: rdx,
            tmpl: rcx,
            tmpr: r8,
            trace_ctx: r9,
            sp: r10,
            scratch: r11,
        }
    }

    fn regs(&self) -> Vec<R64> {
        vec![self.pc, self.dispatch_table, self.func_table, self.tmpr, self.tmpl, self.trace_ctx]
    }
}

struct Opts {
    duplicate_branch_op_tails: bool,
    trace_on: bool,
}

impl Opts {
    fn new() -> Self {
        Opts {
            duplicate_branch_op_tails: true,
            trace_on: false,
        }
    }
}

impl From<u8> for Op {
    fn from(repr: u8) -> Self {
        Op::from_u8(repr)
    }
}

impl From<Op> for u8 {
    fn from(repr: Op) -> Self {
        repr as u8
    }
}

impl Dispatchable<(VMRegs, Opts)> for Op {
    fn build_interp_entry(emit: &mut Emit, args: &(VMRegs, Opts)) {
        InterpContext::build_unpack_to_reg(emit, &args.0);
    }

    fn build_dispatch_case(self, emit: &mut Emit, args: &(VMRegs, Opts)) {
        Op::build_dispatch_case(self, emit, &args.0, &args.1);
    }

    fn build_dispatch_with_pc_offset(emit: &mut Emit, args: &(VMRegs, Opts), offset: i32) {
        build_dispatch_with_pc_offset(emit, &args.0, &args.1, offset);
    }
}

impl Op {
    fn from_u8(repr: u8) -> Self {
        unsafe { mem::transmute(repr) }
    }

    fn build_dispatch_case(self, emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
        use self::Op::*;

        fn push_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(&(vr.sp + (-8)), r)
                .sub(vr.sp, 8);
        }

        fn push_a(emit: &mut Emit, vr: &VMRegs, a: &Addr) {
            emit.mov(vr.scratch, a)
                .mov(&(vr.sp + (-8)), vr.scratch)
                .sub(vr.sp, 8);
        }

        fn pop_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(r, &Addr::B(vr.sp))
                .add(vr.sp, 8);
        }

        match self {
            LoadI8 => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            LoadL => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_a(emit, vr, &(vr.sp + vr.tmpl * 8));
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            BranchLt => {
                pop_r(emit, vr, vr.tmpr);
                pop_r(emit, vr, vr.tmpl);
                emit.cmp(vr.tmpl, vr.tmpr);

                if opts.duplicate_branch_op_tails {
                    let mut lt = Label::new();
                    emit.jl(&mut lt);
                    build_dispatch_skip_oparg(emit, vr, opts);
                    emit.bind(&mut lt)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl);
                    build_dispatch_skip_oparg(emit, vr, opts);
                } else {
                    let mut ge = Label::new();
                    emit.jge(&mut ge)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl)
                        .bind(&mut ge);
                    build_dispatch_skip_oparg(emit, vr, opts);
                }
            }
            Call => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .add(vr.pc, 2);

                push_r(emit, vr, vr.pc);
                emit.mov(vr.pc, &(vr.func_table + vr.tmpl * 8));
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Ret => {
                pop_r(emit, vr, vr.tmpl);
                emit.movsb(vr.tmpr, &(vr.pc + 1));
                pop_r(emit, vr, vr.pc);
                emit.lea(vr.sp, &(vr.sp + vr.tmpr * 8));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Halt => {
                pop_r(emit, vr, rax);
                emit.ret();
            }
            Add => {
                pop_r(emit, vr, vr.tmpr);
                emit.add(&Addr::B(vr.sp), vr.tmpr);
                build_dispatch_with_pc_offset(emit, vr, opts, 1);
            }
        }
    }

}

fn build_dispatch_with_pc_offset(emit: &mut Emit, vr: &VMRegs, opts: &Opts, offset: i32) {
    if offset == 0 {
        emit.movsb(vr.tmpl, &Addr::B(vr.pc));
    } else {
        emit.movsb(vr.tmpl, &(vr.pc + offset))
            .add(vr.pc, offset);
    }

    // Like PyPy's jit_merge_point
    if opts.trace_on {
        let rs = vr.regs();
        for r in &rs {
            emit.push(*r);
        }

        let mut moar_pops: Box<FnMut(&mut Emit)> = if rs.len() % 2 == 0 {
            // Stack alignment
            emit.push(rax);
            Box::new(|emit| { emit.pop(rax); })
        } else {
            Box::new(|_| ())
        };

        emit.mov(rdi, vr.trace_ctx)
            .mov(rsi, vr.pc)
            .mov(rax, unsafe { mem::transmute::<_, i64>(TraceContext::record_unsafe) })
            .call(rax);

        moar_pops(emit);

        for r in rs.iter().rev() {
            emit.pop(*r);
        }
    }

    emit.jmp(&(vr.dispatch_table + vr.tmpl * 8));
}

fn build_dispatch_skip_oparg(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 2)
}

fn build_dispatch_correct_pc(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 0)
}

pub fn main(n: u8) {
    use self::Instr::*;
    use self::Op::*;

    let mut opts = Opts::new();
    if env::var("NO_DUP_BR_TAILS").is_ok() {
        opts.duplicate_branch_op_tails = false;
    };

    if env::var("TRACE_ON").is_ok() {
        opts.trace_on = true;
    };

    let (labels, jm) = build_interp(LAST_OP, &(VMRegs::new(), opts));

    let main_code = instr_to_bs(&[
        OpWithArg(LoadI8, n as i8),
        OpWithArg(Call, 1),
        OpOnly(Halt),
    ]);

    let id_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let fibo_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, 2),
        OpWithArg(BranchLt, 17),

        // Recur case.
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, -1),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpWithArg(LoadL, 2),
        OpWithArg(LoadI8, -2),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpOnly(Add),
        OpWithArg(Ret, 1),

        // Base case.
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let func_table = [
        id_code.as_ptr(),
        fibo_code.as_ptr(),
    ];

    let trace_ctx = TraceContext::new();

    let stack = [0_isize; 1024];

    let res = unsafe {
        let pc = main_code.as_ptr() as isize;
        let lbl_ptr = labels.as_ptr() as isize;
        let func_table_ptr = func_table.as_ptr() as isize;
        let trace_ctx_ptr = trace_ctx.as_ptr() as isize;
        let stack_ptr = stack.as_ptr().offset(stack.len() as isize) as isize;
        let ictx = InterpContext {
            pc: pc,
            func_table: func_table_ptr,
            trace_ctx: trace_ctx_ptr,
            dispatch_table: lbl_ptr,
            sp: stack_ptr,
        };
        if env::var("BREAK").is_ok() {
            breakpoint();
        }
        jm.call_ptr_ptr(&ictx as *const _ as isize)
    };
    println!("res = {}", res);
    println!("trace = {:?}", trace_ctx);
}
<commit_msg>I forgot that I need to manage rbp...<commit_after>use assembler::x64::{Addr, R64};
use assembler::x64::R64::*;
use assembler::x64::traits::*;
use assembler::emit::{Emit, Label};

use template_interp::shared::{Dispatchable, build_interp, breakpoint};

use std::mem;
use std::env;
use std::collections::HashSet;

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
enum Op {
    // stack.push(oparg_i8)
    LoadI8 = 0,

    // stack.push(stack[oparg_i8])
    LoadL,

    // r = stack.pop(); l = stack.pop(); if l < r then pc += oparg_i8
    BranchLt,

    // Callee clears the stack.
    // func_ix = oparg_u8; stack.push(pc); pc = func_table[oparg_u8]; locals = args
    Call,

    // res = stack.pop(); pc = stack.pop(); stack.pops(oparg_u8); stack.push(res)
    Ret,

    // rax = stack.pop(); halt
    Halt,

    // r = stack.pop(); l = stack.pop(); stack.push(l + r)
    Add,
}

#[derive(Debug, Clone, Copy)]
enum Instr {
    OpOnly(Op),
    OpWithArg(Op, i8),
}

fn instr_to_bs(is: &[Instr]) -> Vec<u8> {
    let mut bs = vec![];
    for i in is {
        match i {
            &Instr::OpOnly(op) => {
                bs.push(op as u8);
            }
            &Instr::OpWithArg(op, arg) => {
                bs.push(op as u8);
                bs.push(arg as u8);
            }
        }
    }
    bs
}

const LAST_OP: Op = Op::Add;

#[repr(C)]
struct InterpContext {
    pc: isize,
    dispatch_table: isize,
    func_table: isize,
    trace_ctx: isize,
    sp: isize,
}

// Can we have offsetof?
const PC_OFFSET: i32 = 0;
const DT_OFFSET: i32 = 1 * 8;
const FT_OFFSET: i32 = 2 * 8;
const TC_OFFSET: i32 = 3 * 8;
const SP_OFFSET: i32 = 4 * 8;

impl InterpContext {
    fn location_mapping(base: R64, vr: &VMRegs) -> Vec<(R64, Addr)>{
        vec![
            (vr.pc, base + PC_OFFSET),
            (vr.dispatch_table, base + DT_OFFSET),
            (vr.func_table, base + FT_OFFSET),
            (vr.trace_ctx, base + TC_OFFSET),
            (vr.sp, base + SP_OFFSET),
        ]
    }

    fn build_unpack_to_reg(emit: &mut Emit, vr: &VMRegs) {
        // TODO
        let mut last_move: Option<Box<FnMut(&mut Emit)>> = None;
        for (r, m) in InterpContext::location_mapping(rdi, vr) {
            if r == rdi {
                last_move = Some(Box::new(move |emit| {
                    emit.mov(r, &m);
                }));
            } else {
                emit.mov(r, &m);
            }
        }
        if let Some(mut f) = last_move {
            f(emit);
        }
    }
}

#[derive(Debug)]
struct Trace {
    bc_list: Vec<isize>,
    bc_set: HashSet<isize>,
}

impl Trace {
    fn new() -> Self {
        Trace {
            bc_list: Default::default(),
            bc_set: Default::default(),
        }
    }

    // Returns false if this trace is finished.
    fn record(&mut self, bc_ptr: isize) -> bool {
        self.bc_list.push(bc_ptr);
        if self.bc_set.contains(&bc_ptr) {
            return false;
        }
        self.bc_set.insert(bc_ptr);
        true
    }
}

#[derive(Debug)]
struct TraceContext {
    current: Trace,
    traces: Vec<Trace>,
}

impl TraceContext {
    fn new() -> Box<Self> {
        Box::new(TraceContext {
            current: Trace::new(),
            traces: vec![],
        })
    }

    fn as_ptr(&self) -> *const Self {
        self as *const _
    }

    fn record(&mut self, bc_ptr: isize) {
        if !self.current.record(bc_ptr) {
            let mut new_trace = Trace::new();
            mem::swap(&mut self.current, &mut new_trace);
            self.traces.push(new_trace);

            // Shall we record the trace bridge?
            self.record(bc_ptr);
        }
    }

    pub unsafe extern "C" fn record_unsafe(raw: *mut TraceContext, bc_ptr: isize) {
        (&mut *raw).record(bc_ptr);
    }
}

struct VMRegs {
    pc: R64,
    tmpl: R64,
    tmpr: R64,
    dispatch_table: R64,
    func_table: R64,
    trace_ctx: R64,
    sp: R64,
    scratch: R64,
}

impl VMRegs {
    fn new() -> Self {
        VMRegs {
            pc: rdi,
            dispatch_table: rsi,
            func_table: rdx,
            tmpl: rcx,
            tmpr: r8,
            trace_ctx: r9,
            sp: r10,
            scratch: r11,
        }
    }

    fn regs(&self) -> Vec<R64> {
        vec![self.pc, self.dispatch_table, self.func_table, self.tmpr, self.tmpl, self.trace_ctx]
    }
}

struct Opts {
    duplicate_branch_op_tails: bool,
    trace_on: bool,
}

impl Opts {
    fn new() -> Self {
        Opts {
            duplicate_branch_op_tails: true,
            trace_on: false,
        }
    }
}

impl From<u8> for Op {
    fn from(repr: u8) -> Self {
        Op::from_u8(repr)
    }
}

impl From<Op> for u8 {
    fn from(repr: Op) -> Self {
        repr as u8
    }
}

impl Dispatchable<(VMRegs, Opts)> for Op {
    fn build_interp_entry(emit: &mut Emit, args: &(VMRegs, Opts)) {
        InterpContext::build_unpack_to_reg(emit, &args.0);
    }

    fn build_dispatch_case(self, emit: &mut Emit, args: &(VMRegs, Opts)) {
        Op::build_dispatch_case(self, emit, &args.0, &args.1);
    }

    fn build_dispatch_with_pc_offset(emit: &mut Emit, args: &(VMRegs, Opts), offset: i32) {
        build_dispatch_with_pc_offset(emit, &args.0, &args.1, offset);
    }
}

impl Op {
    fn from_u8(repr: u8) -> Self {
        unsafe { mem::transmute(repr) }
    }

    fn build_dispatch_case(self, emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
        use self::Op::*;

        fn push_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(&(vr.sp + (-8)), r)
                .sub(vr.sp, 8);
        }

        fn push_a(emit: &mut Emit, vr: &VMRegs, a: &Addr) {
            emit.mov(vr.scratch, a)
                .mov(&(vr.sp + (-8)), vr.scratch)
                .sub(vr.sp, 8);
        }

        fn pop_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(r, &Addr::B(vr.sp))
                .add(vr.sp, 8);
        }

        match self {
            LoadI8 => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            LoadL => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_a(emit, vr, &(vr.sp + vr.tmpl * 8));
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            BranchLt => {
                pop_r(emit, vr, vr.tmpr);
                pop_r(emit, vr, vr.tmpl);
                emit.cmp(vr.tmpl, vr.tmpr);

                if opts.duplicate_branch_op_tails {
                    let mut lt = Label::new();
                    emit.jl(&mut lt);
                    build_dispatch_skip_oparg(emit, vr, opts);
                    emit.bind(&mut lt)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl);
                    build_dispatch_skip_oparg(emit, vr, opts);
                } else {
                    let mut ge = Label::new();
                    emit.jge(&mut ge)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl)
                        .bind(&mut ge);
                    build_dispatch_skip_oparg(emit, vr, opts);
                }
            }
            Call => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .add(vr.pc, 2);

                push_r(emit, vr, vr.pc);
                emit.mov(vr.pc, &(vr.func_table + vr.tmpl * 8));
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Ret => {
                pop_r(emit, vr, vr.tmpl);
                emit.movsb(vr.tmpr, &(vr.pc + 1));
                pop_r(emit, vr, vr.pc);
                emit.lea(vr.sp, &(vr.sp + vr.tmpr * 8));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Halt => {
                pop_r(emit, vr, rax);
                emit.ret();
            }
            Add => {
                pop_r(emit, vr, vr.tmpr);
                emit.add(&Addr::B(vr.sp), vr.tmpr);
                build_dispatch_with_pc_offset(emit, vr, opts, 1);
            }
        }
    }

}

fn build_dispatch_with_pc_offset(emit: &mut Emit, vr: &VMRegs, opts: &Opts, offset: i32) {
    if offset == 0 {
        emit.movsb(vr.tmpl, &Addr::B(vr.pc));
    } else {
        emit.movsb(vr.tmpl, &(vr.pc + offset))
            .add(vr.pc, offset);
    }

    // Like PyPy's jit_merge_point
    if opts.trace_on {
        let rs = vr.regs();
        for r in &rs {
            emit.push(*r);
        }

        let mut moar_pops: Box<FnMut(&mut Emit)> = if rs.len() % 2 == 0 {
            // Stack alignment
            emit.push(rax);
            Box::new(|emit| { emit.pop(rax); })
        } else {
            Box::new(|_| ())
        };

        emit.mov(rsi, vr.pc)  // Since pc == rdi. XXX: hardcoded...
            .mov(rdi, vr.trace_ctx)
            .mov(rax, unsafe { mem::transmute::<_, i64>(TraceContext::record_unsafe) })
            .call(rax);

        moar_pops(emit);

        for r in rs.iter().rev() {
            emit.pop(*r);
        }
    }

    emit.jmp(&(vr.dispatch_table + vr.tmpl * 8));
}

fn build_dispatch_skip_oparg(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 2)
}

fn build_dispatch_correct_pc(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 0)
}

pub fn main(n: u8) {
    use self::Instr::*;
    use self::Op::*;

    let mut opts = Opts::new();
    if env::var("NO_DUP_BR_TAILS").is_ok() {
        opts.duplicate_branch_op_tails = false;
    };

    if env::var("TRACE_ON").is_ok() {
        opts.trace_on = true;
    };

    let (labels, jm) = build_interp(LAST_OP, &(VMRegs::new(), opts));

    let main_code = instr_to_bs(&[
        OpWithArg(LoadI8, n as i8),
        OpWithArg(Call, 1),
        OpOnly(Halt),
    ]);

    let id_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let fibo_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, 2),
        OpWithArg(BranchLt, 17),

        // Recur case.
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, -1),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpWithArg(LoadL, 2),
        OpWithArg(LoadI8, -2),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpOnly(Add),
        OpWithArg(Ret, 1),

        // Base case.
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let func_table = [
        id_code.as_ptr(),
        fibo_code.as_ptr(),
    ];

    let trace_ctx = TraceContext::new();

    let stack = [0_isize; 1024];

    let res = unsafe {
        let pc = main_code.as_ptr() as isize;
        let lbl_ptr = labels.as_ptr() as isize;
        let func_table_ptr = func_table.as_ptr() as isize;
        let trace_ctx_ptr = trace_ctx.as_ptr() as isize;
        let stack_ptr = stack.as_ptr().offset(stack.len() as isize) as isize;
        let ictx = InterpContext {
            pc: pc,
            func_table: func_table_ptr,
            trace_ctx: trace_ctx_ptr,
            dispatch_table: lbl_ptr,
            sp: stack_ptr,
        };
        if env::var("BREAK").is_ok() {
            breakpoint();
        }
        jm.call_ptr_ptr(&ictx as *const _ as isize)
    };
    println!("res = {}", res);
    println!("trace = {:?}", trace_ctx);
}
<|endoftext|>


<commit_before>use std::mem;

use cmd::*;

#[deriving(Show, Clone)]
// Helper struct to efficently adress the different parts
// of the message.
struct ASlice {
    start: uint,
    end: uint
}

impl ASlice {
    #[inline]
    fn slice_vec<'a, T>(&self, vec: &'a Vec<T>) -> &'a[T] {
        vec.slice(self.start, self.end)
    }
}

/// IRC message
// TODO: do not use vecs for that, better [u8, ..510] and slices to that
// or just safe offsets in the message parts fields…
#[deriving(Show, Clone)]
pub struct RawMessage {
    raw_message: Vec<u8>,
    prefix: Option<ASlice>,
    command: ASlice,
    params: Vec<ASlice>
}

/// Searches a slice for the first occurence of needle
fn position<T: PartialEq>(this: &[T], needle: &[T]) -> Option<uint> {
    this.windows(needle.len()).position(|v| v == needle)
}

impl RawMessage {
    /// Creates a new message
    pub fn new(command: Command,
                params: &[&str],
                prefix: Option<&str>) -> RawMessage {
        RawMessage::new_raw(
            command,
            unsafe { mem::transmute(params) },
            prefix.map(|v| v.as_bytes())
        )
    }

    /// Creates a new message
    pub fn new_raw(command: Command,
                   params: &[&[u8]],
                   prefix: Option<&[u8]>) -> RawMessage {
        let mut raw_message = Vec::with_capacity(20);
        let msg_prefix = prefix.map(|p| {
            raw_message.push(b':');
            raw_message.push_all(p);
            raw_message.push(b' ');
            ASlice { start: 1, end: p.len() + 1 }
        });
        let cmd = command.to_bytes();
        let cmd_bytes = cmd.as_slice();
        let msg_command = ASlice{ start: raw_message.len(),
                                    end: raw_message.len() + cmd_bytes.len() };
        raw_message.push_all(cmd_bytes);
        let mut start = msg_command.end;
        let num_params = params.len();
        let msg_params = params.iter().enumerate().map( |(i, &param)| {
            let bytes = param;
            raw_message.push(b' ');
            let offset = if i + 1 == num_params {// && bytes.iter().position(|&v| v == b' ').is_some() {
                raw_message.push(b':');
                1
            } else { 0 };
            raw_message.push_all(bytes);
            let end = start + 1 + bytes.len() + offset;
            let slice = ASlice { start: start + 1 + offset, end: end };
            start = end;
            slice
        }).collect();
        RawMessage {
            raw_message: raw_message,
            prefix: msg_prefix,
            command: msg_command,
            params: msg_params
        }
    }

    /// Parses a message. Extracts the prefix, command and the params
    pub fn parse(mut message: &[u8]) -> Result<RawMessage, &'static str> {
        // Check for message prefix (starts with : and ends with space)
        let raw_message = message.to_vec();
        let prefix = if message.starts_with([b':']) {
            let prefix_end = match message.position_elem(&b' ') {
                Some(v) => v,
                None => return Err("RawMessage does not contain a command.")
            };
            message = message.slice_from(prefix_end + 1);
            Some(ASlice{ start: 1, end: prefix_end })
        } else {
            None
        };
        let cmd_start = prefix.map(|v| v.end + 1).unwrap_or(0);
        let trailing = match position(message, " :".as_bytes()) {
            Some(trailing_pos) => {
                message = message.slice_to(trailing_pos);
                Some(ASlice {
                    start: cmd_start + trailing_pos + 2,
                    end: raw_message.len() })
            },
            None => None
        };
        let mut middle_iter = message.split(|&x| x == b' ');
        let command = match middle_iter.next() {
            Some(cmd) =>
                ASlice { start: cmd_start,
                           end: cmd_start + cmd.len() },
            None => return Err("RawMessage does not contain a command.")
        };
        let mut start = command.end + 1;
        let mut params: Vec<ASlice> = middle_iter.map(|p| {
            let slice = ASlice { start: start, end: start + p.len() };
            start = slice.end + 1;
            slice
        }).collect();
        if trailing.is_some() {
            params.push(trailing.unwrap())
        }
        Ok(RawMessage {
            raw_message: raw_message,
            prefix: prefix,
            command: command,
            params: params
        })
    }

    /// Returns the message prefix
    /// It might contain non-utf8 chars and thus only bytes are returned.
    pub fn prefix<'a>(&'a self) -> Option<&'a[u8]> {
        self.prefix.map(|p| p.slice_vec(&self.raw_message))
    }

    /// Sets the message prefix
    /// For all purposes of this library &str should be fine since only
    /// ASCII chars will be used for the prefix.
    pub fn set_prefix(&mut self, prefix: &str) {
        let bytes = prefix.as_bytes();
        let offset = match self.prefix {
            Some(ref mut old_prefix) => {
                let mut temp = b":".to_vec();
                temp.push_all(bytes);
                temp.push_all(self.raw_message.slice_from(old_prefix.end));
                self.raw_message = temp;
                let offset = prefix.len() - old_prefix.end + 1;
                old_prefix.end += offset;
                offset
            },
            None => {
                let mut temp = b":".to_vec();
                temp.push_all(bytes);
                temp.push_all(b" ");
                temp.push_all(self.raw_message.as_slice());
                self.raw_message = temp;
                prefix.len() + 2
            }
        };
        self.command.start += offset;
        self.command.end += offset;
        for param in self.params.iter_mut() {
            param.start += offset;
            param.end += offset;
        }
    }

    /// Returns the message command
    pub fn command<'a>(&'a self) -> Command<'a> {
        Command::from_bytes(self.command.slice_vec(&self.raw_message))
    }

    /// Returns the parameters of the command
    /// *Note* since the IRC protocol does not define any encoding
    /// raw bytes are returned.
    pub fn params<'a>(&'a self) -> Vec<&'a[u8]> {
        self.params.iter().map(
            |slice| slice.slice_vec(&self.raw_message)
        ).collect()
    }

    /// Returns the raw message
    pub fn as_slice<'a>(&'a self) -> &'a[u8] {
        self.raw_message.as_slice()
    }

    /// Returns the message as an string for debugging/logging
    pub fn to_string(&self) -> String {
        String::from_utf8_lossy(self.raw_message.as_slice()).into_string()
    }
}

#[cfg(test)]
mod tests {
	use super::{RawMessage};
	use cmd::{JOIN};
	/// Test the nickname validation function
	#[test]
	fn test_message_parser() {
        let m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
	}
	/// Test the prefix setter
	#[test]
	fn test_prefix_setter() {
        let mut m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        m.set_prefix("new prefix");
        assert_eq!(String::from_utf8_lossy(m.prefix().unwrap()).to_owned(),
                   String::from_str("new prefix").to_owned())
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":new prefix JOIN #channel")
	}
	/// Test message creation
	#[test]
	fn test_msg_new() {
        let m = RawMessage::new(JOIN, &["#channel"], Some("prefix"));
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":prefix JOIN :#channel")
	}
}<commit_msg>deprecation warnings…<commit_after>use std::mem;

use cmd::*;

#[deriving(Show, Clone)]
// Helper struct to efficently adress the different parts
// of the message.
struct ASlice {
    start: uint,
    end: uint
}

impl ASlice {
    #[inline]
    fn slice_vec<'a, T>(&self, vec: &'a Vec<T>) -> &'a[T] {
        vec.slice(self.start, self.end)
    }
}

/// IRC message
// TODO: do not use vecs for that, better [u8, ..510] and slices to that
// or just safe offsets in the message parts fields…
#[deriving(Show, Clone)]
pub struct RawMessage {
    raw_message: Vec<u8>,
    prefix: Option<ASlice>,
    command: ASlice,
    params: Vec<ASlice>
}

/// Searches a slice for the first occurence of needle
fn position<T: PartialEq>(this: &[T], needle: &[T]) -> Option<uint> {
    this.windows(needle.len()).position(|v| v == needle)
}

impl RawMessage {
    /// Creates a new message
    pub fn new(command: Command,
                params: &[&str],
                prefix: Option<&str>) -> RawMessage {
        RawMessage::new_raw(
            command,
            unsafe { mem::transmute(params) },
            prefix.map(|v| v.as_bytes())
        )
    }

    /// Creates a new message
    pub fn new_raw(command: Command,
                   params: &[&[u8]],
                   prefix: Option<&[u8]>) -> RawMessage {
        let mut raw_message = Vec::with_capacity(20);
        let msg_prefix = prefix.map(|p| {
            raw_message.push(b':');
            raw_message.push_all(p);
            raw_message.push(b' ');
            ASlice { start: 1, end: p.len() + 1 }
        });
        let cmd = command.to_bytes();
        let cmd_bytes = cmd.as_slice();
        let msg_command = ASlice{ start: raw_message.len(),
                                    end: raw_message.len() + cmd_bytes.len() };
        raw_message.push_all(cmd_bytes);
        let mut start = msg_command.end;
        let num_params = params.len();
        let msg_params = params.iter().enumerate().map( |(i, &param)| {
            let bytes = param;
            raw_message.push(b' ');
            let offset = if i + 1 == num_params {// && bytes.iter().position(|&v| v == b' ').is_some() {
                raw_message.push(b':');
                1
            } else { 0 };
            raw_message.push_all(bytes);
            let end = start + 1 + bytes.len() + offset;
            let slice = ASlice { start: start + 1 + offset, end: end };
            start = end;
            slice
        }).collect();
        RawMessage {
            raw_message: raw_message,
            prefix: msg_prefix,
            command: msg_command,
            params: msg_params
        }
    }

    /// Parses a message. Extracts the prefix, command and the params
    pub fn parse(mut message: &[u8]) -> Result<RawMessage, &'static str> {
        // Check for message prefix (starts with : and ends with space)
        let raw_message = message.to_vec();
        let prefix = if message.starts_with([b':']) {
            let prefix_end = match message.position_elem(&b' ') {
                Some(v) => v,
                None => return Err("RawMessage does not contain a command.")
            };
            message = message.slice_from(prefix_end + 1);
            Some(ASlice{ start: 1, end: prefix_end })
        } else {
            None
        };
        let cmd_start = prefix.map(|v| v.end + 1).unwrap_or(0);
        let trailing = match position(message, " :".as_bytes()) {
            Some(trailing_pos) => {
                message = message.slice_to(trailing_pos);
                Some(ASlice {
                    start: cmd_start + trailing_pos + 2,
                    end: raw_message.len() })
            },
            None => None
        };
        let mut middle_iter = message.split(|&x| x == b' ');
        let command = match middle_iter.next() {
            Some(cmd) =>
                ASlice { start: cmd_start,
                           end: cmd_start + cmd.len() },
            None => return Err("RawMessage does not contain a command.")
        };
        let mut start = command.end + 1;
        let mut params: Vec<ASlice> = middle_iter.map(|p| {
            let slice = ASlice { start: start, end: start + p.len() };
            start = slice.end + 1;
            slice
        }).collect();
        if trailing.is_some() {
            params.push(trailing.unwrap())
        }
        Ok(RawMessage {
            raw_message: raw_message,
            prefix: prefix,
            command: command,
            params: params
        })
    }

    /// Returns the message prefix
    /// It might contain non-utf8 chars and thus only bytes are returned.
    pub fn prefix<'a>(&'a self) -> Option<&'a[u8]> {
        self.prefix.map(|p| p.slice_vec(&self.raw_message))
    }

    /// Sets the message prefix
    /// For all purposes of this library &str should be fine since only
    /// ASCII chars will be used for the prefix.
    pub fn set_prefix(&mut self, prefix: &str) {
        let bytes = prefix.as_bytes();
        let offset = match self.prefix {
            Some(ref mut old_prefix) => {
                let mut temp = b":".to_vec();
                temp.push_all(bytes);
                temp.push_all(self.raw_message.slice_from(old_prefix.end));
                self.raw_message = temp;
                let offset = prefix.len() - old_prefix.end + 1;
                old_prefix.end += offset;
                offset
            },
            None => {
                let mut temp = b":".to_vec();
                temp.push_all(bytes);
                temp.push_all(b" ");
                temp.push_all(self.raw_message.as_slice());
                self.raw_message = temp;
                prefix.len() + 2
            }
        };
        self.command.start += offset;
        self.command.end += offset;
        for param in self.params.iter_mut() {
            param.start += offset;
            param.end += offset;
        }
    }

    /// Returns the message command
    pub fn command<'a>(&'a self) -> Command<'a> {
        Command::from_bytes(self.command.slice_vec(&self.raw_message))
    }

    /// Returns the parameters of the command
    /// *Note* since the IRC protocol does not define any encoding
    /// raw bytes are returned.
    pub fn params<'a>(&'a self) -> Vec<&'a[u8]> {
        self.params.iter().map(
            |slice| slice.slice_vec(&self.raw_message)
        ).collect()
    }

    /// Returns the raw message
    pub fn as_slice<'a>(&'a self) -> &'a[u8] {
        self.raw_message.as_slice()
    }

    /// Returns the message as an string for debugging/logging
    pub fn to_string(&self) -> String {
        String::from_utf8_lossy(self.raw_message.as_slice()).into_string()
    }
}

#[cfg(test)]
mod tests {
	use super::{RawMessage};
	use cmd::{JOIN};
	/// Test the nickname validation function
	#[test]
	fn test_message_parser() {
        let m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
	}
	/// Test the prefix setter
	#[test]
	fn test_prefix_setter() {
        let mut m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        m.set_prefix("new prefix");
        assert_eq!(String::from_utf8_lossy(m.prefix().unwrap()).to_string(),
                   String::from_str("new prefix").to_string())
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":new prefix JOIN #channel")
	}
	/// Test message creation
	#[test]
	fn test_msg_new() {
        let m = RawMessage::new(JOIN, &["#channel"], Some("prefix"));
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":prefix JOIN :#channel")
	}
}<|endoftext|>


<commit_before>use std::io::MemReader;
use vault::http::authenticate_header::*;
use hyper::header::{Headers};

fn setup() {
}

fn mem(s: &str) -> MemReader {
  MemReader::new(s.as_bytes().to_vec())
}

test!(test_raw_auth {
  let mut headers = Headers::new();
  headers.set(WwwAuthenticate("foo bar baz".to_string()));
  assert_eq!(headers.to_string(), "WWW-Authenticate: foo bar baz\r\n".to_string());
});

test!(test_raw_auth_parse {
  let headers = Headers::from_raw(&mut mem("WWW-Authenticate: hello world\r\n\r\n")).unwrap();
  assert_eq!(&headers.get::<WwwAuthenticate<String>>().unwrap().0[], "hello world");
});

test!(test_basic_auth {
  let mut headers = Headers::new();
  headers.set(WwwAuthenticate(Bearer { authorization: "https://login.windows.net/123".to_string(), resource: "https://vault.azure.net".to_string() }));
  assert_eq!(headers.to_string(), "WWW-Authenticate: Bearer authorization=\"https://login.windows.net/123\", resource=\"https://vault.azure.net\"\r\n".to_string());
});

test!(test_basic_auth_parse {
  let headers = Headers::from_raw(&mut mem("WWW-Authenticate: Bearer authorization=\"https://login.windows.net/123\", resource=\"https://vault.azure.net\"\r\n\r\n")).unwrap();
  let auth = headers.get::<WwwAuthenticate<Bearer>>().unwrap();
  assert_eq!(&auth.0.authorization[], "https://login.windows.net/123");
  assert_eq!(auth.0.resource, "https://vault.azure.net");
});
<commit_msg>std::old_io fix for MemReader<commit_after>use std::old_io::MemReader;
use vault::http::authenticate_header::*;
use hyper::header::{Headers};

fn setup() {
}

fn mem(s: &str) -> MemReader {
  MemReader::new(s.as_bytes().to_vec())
}

test!(test_raw_auth {
  let mut headers = Headers::new();
  headers.set(WwwAuthenticate("foo bar baz".to_string()));
  assert_eq!(headers.to_string(), "WWW-Authenticate: foo bar baz\r\n".to_string());
});

test!(test_raw_auth_parse {
  let headers = Headers::from_raw(&mut mem("WWW-Authenticate: hello world\r\n\r\n")).unwrap();
  assert_eq!(&headers.get::<WwwAuthenticate<String>>().unwrap().0[], "hello world");
});

test!(test_basic_auth {
  let mut headers = Headers::new();
  headers.set(WwwAuthenticate(Bearer { authorization: "https://login.windows.net/123".to_string(), resource: "https://vault.azure.net".to_string() }));
  assert_eq!(headers.to_string(), "WWW-Authenticate: Bearer authorization=\"https://login.windows.net/123\", resource=\"https://vault.azure.net\"\r\n".to_string());
});

test!(test_basic_auth_parse {
  let headers = Headers::from_raw(&mut mem("WWW-Authenticate: Bearer authorization=\"https://login.windows.net/123\", resource=\"https://vault.azure.net\"\r\n\r\n")).unwrap();
  let auth = headers.get::<WwwAuthenticate<Bearer>>().unwrap();
  assert_eq!(&auth.0.authorization[], "https://login.windows.net/123");
  assert_eq!(auth.0.resource, "https://vault.azure.net");
});
<|endoftext|>


<commit_before>use crate::utils::{
    contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAPS,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        match fn_kind {
            FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
                if visibility.node.is_pub() {
                    return;
                }
            },
            FnKind::Closure(..) => return,
            _ => (),
        }

        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) {
                return;
            }
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                if !contains_return(&args[0]);
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg && !suggs.is_empty() {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAPS,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MaybeIncorrect,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<commit_msg>Auto merge of #6418 - flip1995:apple_wraps_mhm, r=llogiq<commit_after>use crate::utils::{
    contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAPS,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        match fn_kind {
            FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
                if visibility.node.is_pub() {
                    return;
                }
            },
            FnKind::Closure(..) => return,
            _ => (),
        }

        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) {
                return;
            }
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                if !contains_return(&args[0]);
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg && !suggs.is_empty() {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAPS,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MaybeIncorrect,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MaybeIncorrect,
                    );
                },
            );
        }
    }
}
<|endoftext|>


<commit_before>// ignore-windows: Concurrency on Windows is not supported yet.

use std::cell::RefCell;
use std::thread;

struct TestCell {
    value: RefCell<u8>,
}

impl Drop for TestCell {
    fn drop(&mut self) {
        for _ in 0..10 { thread::yield_now(); }
        println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow())
    }
}

thread_local! {
    static A: TestCell = TestCell { value: RefCell::new(0) };
    static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } };
}

/// Check that destructors of the library thread locals are executed immediately
/// after a thread terminates.
fn check_destructors() {
    thread::spawn(|| {
        A.with(|f| {
            assert_eq!(*f.value.borrow(), 0);
            *f.value.borrow_mut() = 5;
        });
        A_CONST.with(|f| {
            assert_eq!(*f.value.borrow(), 10);
            *f.value.borrow_mut() = 15;
        });
    })
    .join()
    .unwrap();
    println!("Continue main 1.")
}

struct JoinCell {
    value: RefCell<Option<thread::JoinHandle<u8>>>,
}

impl Drop for JoinCell {
    fn drop(&mut self) {
        for _ in 0..10 { thread::yield_now(); }
        let join_handle = self.value.borrow_mut().take().unwrap();
        println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap());
    }
}

thread_local! {
    static B: JoinCell = JoinCell { value: RefCell::new(None) };
}

/// Check that the destructor can be blocked joining another thread.
fn check_blocking() {
    thread::spawn(|| {
        B.with(|f| {
            assert!(f.value.borrow().is_none());
            let handle = thread::spawn(|| 7);
            *f.value.borrow_mut() = Some(handle);
        });
    })
    .join()
    .unwrap();
    println!("Continue main 2.");
    // Preempt the main thread so that the destructor gets executed and can join
    // the thread.
    thread::yield_now();
    thread::yield_now();
}

fn main() {
    check_destructors();
    check_blocking();
}
<commit_msg>Auto merge of #2210 - RalfJung:tls-drop-test, r=RalfJung<commit_after>// ignore-windows: Concurrency on Windows is not supported yet.

use std::cell::RefCell;
use std::thread;

struct TestCell {
    value: RefCell<u8>,
}

impl Drop for TestCell {
    fn drop(&mut self) {
        for _ in 0..10 { thread::yield_now(); }
        println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow())
    }
}

thread_local! {
    static A: TestCell = TestCell { value: RefCell::new(0) };
    static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } };
}

/// Check that destructors of the library thread locals are executed immediately
/// after a thread terminates.
fn check_destructors() {
    thread::spawn(|| {
        A.with(|f| {
            assert_eq!(*f.value.borrow(), 0);
            *f.value.borrow_mut() = 5;
        });
        A_CONST.with(|f| {
            assert_eq!(*f.value.borrow(), 10);
            *f.value.borrow_mut() = 15;
        });
    })
    .join()
    .unwrap();
    println!("Continue main 1.")
}

struct JoinCell {
    value: RefCell<Option<thread::JoinHandle<u8>>>,
}

impl Drop for JoinCell {
    fn drop(&mut self) {
        for _ in 0..10 { thread::yield_now(); }
        let join_handle = self.value.borrow_mut().take().unwrap();
        println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap());
    }
}

thread_local! {
    static B: JoinCell = JoinCell { value: RefCell::new(None) };
}

/// Check that the destructor can be blocked joining another thread.
fn check_blocking() {
    thread::spawn(|| {
        B.with(|f| {
            assert!(f.value.borrow().is_none());
            let handle = thread::spawn(|| 7);
            *f.value.borrow_mut() = Some(handle);
        });
    })
    .join()
    .unwrap();
    println!("Continue main 2.");
    // Preempt the main thread so that the destructor gets executed and can join
    // the thread.
    thread::yield_now();
    thread::yield_now();
}

// This test tests that TLS destructors have run before the thread joins. The
// test has no false positives (meaning: if the test fails, there's actually
// an ordering problem). It may have false negatives, where the test passes but
// join is not guaranteed to be after the TLS destructors. However, false
// negatives should be exceedingly rare due to judicious use of
// thread::yield_now and running the test several times.
fn join_orders_after_tls_destructors() {
    use std::sync::atomic::{AtomicU8, Ordering};

    // We emulate a synchronous MPSC rendezvous channel using only atomics and
    // thread::yield_now. We can't use std::mpsc as the implementation itself
    // may rely on thread locals.
    //
    // The basic state machine for an SPSC rendezvous channel is:
    //           FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS
    // where the first transition is done by the “receiving” thread and the 2nd
    // transition is done by the “sending” thread.
    //
    // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and
    // `THREAD1_WAITING` to block until all threads are actually running.
    //
    // A thread that joins on the “receiving” thread completion should never
    // observe the channel in the `THREAD1_WAITING` state. If this does occur,
    // we switch to the “poison” state `THREAD2_JOINED` and panic all around.
    // (This is equivalent to “sending” from an alternate producer thread.)
    const FRESH: u8 = 0;
    const THREAD2_LAUNCHED: u8 = 1;
    const THREAD1_WAITING: u8 = 2;
    const MAIN_THREAD_RENDEZVOUS: u8 = 3;
    const THREAD2_JOINED: u8 = 4;
    static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH);

    for _ in 0..10 {
        SYNC_STATE.store(FRESH, Ordering::SeqCst);

        let jh = thread::Builder::new()
            .name("thread1".into())
            .spawn(move || {
                struct TlDrop;

                impl Drop for TlDrop {
                    fn drop(&mut self) {
                        let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst);
                        loop {
                            match sync_state {
                                THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(),
                                MAIN_THREAD_RENDEZVOUS => break,
                                THREAD2_JOINED => panic!(
                                    "Thread 1 still running after thread 2 joined on thread 1"
                                ),
                                v => unreachable!("sync state: {}", v),
                            }
                            sync_state = SYNC_STATE.load(Ordering::SeqCst);
                        }
                    }
                }

                thread_local! {
                    static TL_DROP: TlDrop = TlDrop;
                }

                TL_DROP.with(|_| {});

                loop {
                    match SYNC_STATE.load(Ordering::SeqCst) {
                        FRESH => thread::yield_now(),
                        THREAD2_LAUNCHED => break,
                        v => unreachable!("sync state: {}", v),
                    }
                }
            })
            .unwrap();

        let jh2 = thread::Builder::new()
            .name("thread2".into())
            .spawn(move || {
                assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH);
                jh.join().unwrap();
                match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) {
                    MAIN_THREAD_RENDEZVOUS => return,
                    THREAD2_LAUNCHED | THREAD1_WAITING => {
                        panic!("Thread 2 running after thread 1 join before main thread rendezvous")
                    }
                    v => unreachable!("sync state: {:?}", v),
                }
            })
            .unwrap();

        loop {
            match SYNC_STATE.compare_exchange(
                THREAD1_WAITING,
                MAIN_THREAD_RENDEZVOUS,
                Ordering::SeqCst,
                Ordering::SeqCst,
            ) {
                Ok(_) => break,
                Err(FRESH) => thread::yield_now(),
                Err(THREAD2_LAUNCHED) => thread::yield_now(),
                Err(THREAD2_JOINED) => {
                    panic!("Main thread rendezvous after thread 2 joined thread 1")
                }
                v => unreachable!("sync state: {:?}", v),
            }
        }
        jh2.join().unwrap();
    }
}

fn main() {
    check_destructors();
    check_blocking();
    join_orders_after_tls_destructors();
}
<|endoftext|>