<commit_before>/*
#[macro_use]
extern crate nom;
extern crate bytes;

use nom::{Compare,CompareResult,InputLength,InputIter,Slice,HexDisplay};

use std::str;
use std::str::FromStr;
use bytes::{Buf,MutBuf};
use bytes::buf::{BlockBuf,BlockBufCursor};
use std::ops::{Range,RangeTo,RangeFrom,RangeFull};
use std::iter::{Enumerate,Iterator};
use std::fmt;
use std::cmp::{min,PartialEq};

#[derive(Clone,Copy)]
#[repr(C)]
pub struct BlockSlice<'a> {
  buf: &'a BlockBuf,
  start: usize,
  end:   usize,
}

impl<'a> BlockSlice<'a> {
  fn cursor(&self) -> WrapCursor<'a> {
    let mut cur = self.buf.buf();
    cur.advance(self.start);
    WrapCursor {
      cursor: cur,
      length: self.end - self.start,
    }
  }
}

impl<'a> fmt::Debug for BlockSlice<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "BlockSlice {{ start: {}, end: {}, data:\n{}\n}}", self.start, self.end, self.buf.bytes().unwrap_or(&b""[..]).to_hex(16))
  }
}

impl<'a> PartialEq for BlockSlice<'a> {
  fn eq(&self, other: &BlockSlice<'a>) -> bool {
    let bufs = (self.buf as *const BlockBuf) == (other.buf as *const BlockBuf);
    self.start == other.start && self.end == other.end && bufs
  }
}

impl<'a> Slice<Range<usize>> for BlockSlice<'a> {
  fn slice(&self, range:Range<usize>) -> Self {
    BlockSlice {
      buf:   self.buf,
      start: self.start + range.start,
      //FIXME: check for valid end here
      end:   self.start + range.end,
    }
  }
}

impl<'a> Slice<RangeTo<usize>> for BlockSlice<'a> {
  fn slice(&self, range:RangeTo<usize>) -> Self {
    self.slice(0..range.end)
  }
}

impl<'a> Slice<RangeFrom<usize>> for BlockSlice<'a> {
  fn slice(&self, range:RangeFrom<usize>) -> Self {
    self.slice(range.start..self.end - self.start)
  }
}

impl<'a> Slice<RangeFull> for BlockSlice<'a> {
  fn slice(&self, _:RangeFull) -> Self {
    BlockSlice {
      buf:   self.buf,
      start: self.start,
      end:   self.end,
    }
  }
}

impl<'a> InputIter for BlockSlice<'a> {
    type Item     = u8;
    type RawItem  = u8;
    type Iter     = Enumerate<WrapCursor<'a>>;
    type IterElem = WrapCursor<'a>;

    fn iter_indices(&self)  -> Self::Iter {
      self.cursor().enumerate()
    }
    fn iter_elements(&self) -> Self::IterElem {
      self.cursor()
    }
    fn position<P>(&self, predicate: P) -> Option<usize> where P: Fn(Self::RawItem) -> bool {
      self.cursor().position(|b| predicate(b))
    }
    fn slice_index(&self, count:usize) -> Option<usize> {
      if self.end - self.start >= count {
        Some(count)
      } else {
        None
      }
    }
}

impl<'a> InputLength for BlockSlice<'a> {
  fn input_len(&self) -> usize {
    self.end - self.start
  }
}

impl<'a,'b> Compare<&'b[u8]> for BlockSlice<'a> {
  fn compare(&self, t: &'b[u8]) -> CompareResult {
    let len     = self.end - self.start;
    let blen    = t.len();
    let m       = if len < blen { len } else { blen };
    let reduced = self.slice(..m);
    let b       = &t[..m];

    for (a,b) in reduced.cursor().zip(b.iter()) {
      if a != *b {
        return CompareResult::Error;
      }
    }
    if m < blen {
      CompareResult::Incomplete
    } else {
      CompareResult::Ok
    }
  }

  #[inline(always)]
  fn compare_no_case(&self, t: &'b[u8]) -> CompareResult {
    let len     = self.end - self.start;
    let blen    = t.len();
    let m       = if len < blen { len } else { blen };
    let reduced = self.slice(..m);
    let other   = &t[..m];

    if !reduced.cursor().zip(other).all(|(a, b)| {
      match (a,*b) {
        (0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == *b,
        (65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122 ) |(97...122, 65...90) => {
          a & 0b01000000 == *b & 0b01000000
        }
        _ => false
      }
    }) {
      CompareResult::Error
    } else if m < blen {
      CompareResult::Incomplete
    } else {
      CompareResult::Ok
    }
  }
}

impl<'a,'b> Compare<&'b str> for BlockSlice<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.compare(str::as_bytes(t))
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.compare_no_case(str::as_bytes(t))
  }
}

//Wrapper to implement Iterator on BlockBufCursor
pub struct WrapCursor<'a> {
  pub cursor: BlockBufCursor<'a>,
  pub length: usize,
}

impl<'a> Iterator for WrapCursor<'a> {
  type Item = u8;
  fn next(&mut self) -> Option<u8> {
    //println!("NEXT: length={}, remaining={}", self.length, self.cursor.remaining());
    if min(self.length, self.cursor.remaining()) > 0 {
      self.length -=1;
      Some(self.cursor.read_u8())
    } else {
      None
    }
  }
}

//Reimplement eat_separator instead of fixing iterators
#[macro_export]
macro_rules! block_eat_separator (
  ($i:expr, $arr:expr) => (
    {
      use nom::{InputLength,InputIter,Slice};
      if ($i).input_len() == 0 {
        Ok(($i, ($i).slice(0..0)))
      } else {
        match ($i).iter_indices().position(|(_, item)| {
          for (_,c) in ($arr).iter_indices() {
            if *c == item { return false; }
          }
          true
        }) {
          Some(index) => {
            Ok((($i).slice(index..), ($i).slice(..index)))
          },
          None => {
            Ok((($i).slice(($i).input_len()..), $i))
          }
        }
      }
    }
  )
);

#[macro_export]
macro_rules! block_named (
  ($name:ident, $submac:ident!( $($args:tt)* )) => (
    fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult<BlockSlice<'a>, BlockSlice<'a>, u32> {
      $submac!(i, $($args)*)
    }
  );
  ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
    fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult<BlockSlice<'a>, $o, u32> {
      $submac!(i, $($args)*)
    }
  );
);

block_named!(sp, block_eat_separator!(&b" \t\r\n"[..]));

macro_rules! block_ws (
  ($i:expr, $($args:tt)*) => (
    {
      sep!($i, sp, $($args)*)
    }
  )
);

block_named!(digit, is_a!("0123456789"));

block_named!(parens<i64>, block_ws!(delimited!( tag!("("), expr, tag!(")") )) );

block_named!(factor<i64>, alt!(
      map_res!(
        block_ws!(digit),
        to_i64
    )
  | parens
  )
);

block_named!(term <i64>, do_parse!(
    init: factor >>
    res:  fold_many0!(
        pair!(alt!(tag!("*") | tag!("/")), factor),
        init,
        |acc, (op, val): (BlockSlice, i64)| {
            if (op.cursor().next().unwrap() as char) == '*' { acc * val } else { acc / val }
        }
    ) >>
    (res)
  )
);

block_named!(expr <i64>, do_parse!(
    init: term >>
    res:  fold_many0!(
        pair!(alt!(tag!("+") | tag!("-")), term),
        init,
        |acc, (op, val): (BlockSlice, i64)| {
            if (op.cursor().next().unwrap() as char) == '+' { acc + val } else { acc - val }
        }
    ) >>
    (res)
  )
);

fn blockbuf_from(input: &[u8]) -> BlockBuf {
  let mut b = BlockBuf::new(2, 100);
  b.copy_from(input);
  b
}

fn sl<'a>(input: &'a BlockBuf) -> BlockSlice<'a> {
  BlockSlice {
    buf: input,
    start: 0,
    end:   input.len(),
  }
}

fn to_i64<'a>(input: BlockSlice<'a>) -> Result<i64, ()> {
  let v: Vec<u8> = input.cursor().collect();

  match str::from_utf8(&v) {
    Err(_) => Err(()),
    Ok(s) => match FromStr::from_str(s) {
      Err(_) => Err(()),
      Ok(i)  => Ok(i)
    }
  }
}

#[test]
fn factor_test() {
  let a = blockbuf_from(&b"3"[..]);
  println!("calculated: {:?}", factor(sl(&a)));
}

#[test]
fn parens_test() {
  let input1 = blockbuf_from(&b" 2* (  3 + 4 ) "[..]);
  println!("calculated 1: {:?}", expr(sl(&input1)));
  let input2 = blockbuf_from(&b"  2*2 / ( 5 - 1) + 3"[..]);
  println!("calculated 2: {:?}", expr(sl(&input2)));
}
*/
<commit_msg>Remove dead code (tests/blockbuf-arithmetic.rs)<commit_after><|endoftext|>


<commit_before>use crate::event::Event;
use crate::sys;

use std::fmt;

/// A collection of readiness events.
///
/// `Events` is passed as an argument to [`Poll::poll`] and will be used to
/// receive any new readiness events received since the last poll. Usually, a
/// single `Events` instance is created at the same time as a [`Poll`] and
/// reused on each call to [`Poll::poll`].
///
/// See [`Poll`] for more documentation on polling.
///
/// [`Poll::poll`]: ../struct.Poll.html#method.poll
/// [`Poll`]: ../struct.Poll.html
///
/// # Examples
///
/// ```
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
/// use std::time::Duration;
///
/// let mut events = Events::with_capacity(1024);
/// let mut poll = Poll::new()?;
/// #
/// # assert!(events.is_empty());
///
/// // Register `event::Source`s with `poll`.
///
/// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
///
/// for event in events.iter() {
///     println!("Got an event for {:?}", event.token());
/// }
/// #     Ok(())
/// # }
/// ```
pub struct Events {
    inner: sys::Events,
}

/// [`Events`] iterator.
///
/// This struct is created by the [`iter`] method on [`Events`].
///
/// [`Events`]: struct.Events.html
/// [`iter`]: struct.Events.html#method.iter
///
/// # Examples
///
/// ```
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
/// use std::time::Duration;
///
/// let mut events = Events::with_capacity(1024);
/// let mut poll = Poll::new()?;
///
/// // Register handles with `poll`.
///
/// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
///
/// for event in events.iter() {
///     println!("Got an event for {:?}", event.token());
/// }
/// #     Ok(())
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct Iter<'a> {
    inner: &'a Events,
    pos: usize,
}

impl Events {
    /// Return a new `Events` capable of holding up to `capacity` events.
    ///
    /// # Examples
    ///
    /// ```
    /// use mio::Events;
    ///
    /// let events = Events::with_capacity(1024);
    /// assert_eq!(1024, events.capacity());
    /// ```
    pub fn with_capacity(capacity: usize) -> Events {
        Events {
            inner: sys::Events::with_capacity(capacity),
        }
    }

    /// Returns the number of `Event` values that `self` can hold.
    ///
    /// ```
    /// use mio::Events;
    ///
    /// let events = Events::with_capacity(1024);
    /// assert_eq!(1024, events.capacity());
    /// ```
    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    /// Returns `true` if `self` contains no `Event` values.
    ///
    /// # Examples
    ///
    /// ```
    /// use mio::Events;
    ///
    /// let events = Events::with_capacity(1024);
    /// assert!(events.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Returns an iterator over the `Event` values.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::error::Error;
    /// # fn main() -> Result<(), Box<dyn Error>> {
    /// use mio::{Events, Poll};
    /// use std::time::Duration;
    ///
    /// let mut events = Events::with_capacity(1024);
    /// let mut poll = Poll::new()?;
    ///
    /// // Register handles with `poll`.
    ///
    /// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
    ///
    /// for event in events.iter() {
    ///     println!("Got an event for {:?}", event.token());
    /// }
    /// #     Ok(())
    /// # }
    /// ```
    pub fn iter(&self) -> Iter<'_> {
        Iter {
            inner: self,
            pos: 0,
        }
    }

    /// Clearing all `Event` values from container explicitly.
    ///
    /// # Notes
    ///
    /// Events are cleared before every `poll`, so it is not required to call
    /// this manually.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::error::Error;
    /// # fn main() -> Result<(), Box<dyn Error>> {
    /// use mio::{Events, Poll};
    /// use std::time::Duration;
    ///
    /// let mut events = Events::with_capacity(1024);
    /// let mut poll = Poll::new()?;
    ///
    /// // Register handles with `poll`.
    ///
    /// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
    ///
    /// // Clear all events.
    /// events.clear();
    /// assert!(events.is_empty());
    /// #     Ok(())
    /// # }
    /// ```
    pub fn clear(&mut self) {
        self.inner.clear();
    }

    /// Returns the inner `sys::Events`.
    pub(crate) fn sys(&mut self) -> &mut sys::Events {
        &mut self.inner
    }
}

impl<'a> IntoIterator for &'a Events {
    type Item = &'a Event;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = &'a Event;

    fn next(&mut self) -> Option<Self::Item> {
        let ret = self
            .inner
            .inner
            .get(self.pos)
            .map(Event::from_sys_event_ref);
        self.pos += 1;
        ret
    }
}

impl fmt::Debug for Events {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Events")
            .field("capacity", &self.capacity())
            .finish()
    }
}
<commit_msg>Make Events' fmt::Debug implementation more useful<commit_after>use crate::event::Event;
use crate::sys;

use std::fmt;

/// A collection of readiness events.
///
/// `Events` is passed as an argument to [`Poll::poll`] and will be used to
/// receive any new readiness events received since the last poll. Usually, a
/// single `Events` instance is created at the same time as a [`Poll`] and
/// reused on each call to [`Poll::poll`].
///
/// See [`Poll`] for more documentation on polling.
///
/// [`Poll::poll`]: ../struct.Poll.html#method.poll
/// [`Poll`]: ../struct.Poll.html
///
/// # Examples
///
/// ```
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
/// use std::time::Duration;
///
/// let mut events = Events::with_capacity(1024);
/// let mut poll = Poll::new()?;
/// #
/// # assert!(events.is_empty());
///
/// // Register `event::Source`s with `poll`.
///
/// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
///
/// for event in events.iter() {
///     println!("Got an event for {:?}", event.token());
/// }
/// #     Ok(())
/// # }
/// ```
pub struct Events {
    inner: sys::Events,
}

/// [`Events`] iterator.
///
/// This struct is created by the [`iter`] method on [`Events`].
///
/// [`Events`]: struct.Events.html
/// [`iter`]: struct.Events.html#method.iter
///
/// # Examples
///
/// ```
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use mio::{Events, Poll};
/// use std::time::Duration;
///
/// let mut events = Events::with_capacity(1024);
/// let mut poll = Poll::new()?;
///
/// // Register handles with `poll`.
///
/// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
///
/// for event in events.iter() {
///     println!("Got an event for {:?}", event.token());
/// }
/// #     Ok(())
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct Iter<'a> {
    inner: &'a Events,
    pos: usize,
}

impl Events {
    /// Return a new `Events` capable of holding up to `capacity` events.
    ///
    /// # Examples
    ///
    /// ```
    /// use mio::Events;
    ///
    /// let events = Events::with_capacity(1024);
    /// assert_eq!(1024, events.capacity());
    /// ```
    pub fn with_capacity(capacity: usize) -> Events {
        Events {
            inner: sys::Events::with_capacity(capacity),
        }
    }

    /// Returns the number of `Event` values that `self` can hold.
    ///
    /// ```
    /// use mio::Events;
    ///
    /// let events = Events::with_capacity(1024);
    /// assert_eq!(1024, events.capacity());
    /// ```
    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    /// Returns `true` if `self` contains no `Event` values.
    ///
    /// # Examples
    ///
    /// ```
    /// use mio::Events;
    ///
    /// let events = Events::with_capacity(1024);
    /// assert!(events.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Returns an iterator over the `Event` values.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::error::Error;
    /// # fn main() -> Result<(), Box<dyn Error>> {
    /// use mio::{Events, Poll};
    /// use std::time::Duration;
    ///
    /// let mut events = Events::with_capacity(1024);
    /// let mut poll = Poll::new()?;
    ///
    /// // Register handles with `poll`.
    ///
    /// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
    ///
    /// for event in events.iter() {
    ///     println!("Got an event for {:?}", event.token());
    /// }
    /// #     Ok(())
    /// # }
    /// ```
    pub fn iter(&self) -> Iter<'_> {
        Iter {
            inner: self,
            pos: 0,
        }
    }

    /// Clearing all `Event` values from container explicitly.
    ///
    /// # Notes
    ///
    /// Events are cleared before every `poll`, so it is not required to call
    /// this manually.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::error::Error;
    /// # fn main() -> Result<(), Box<dyn Error>> {
    /// use mio::{Events, Poll};
    /// use std::time::Duration;
    ///
    /// let mut events = Events::with_capacity(1024);
    /// let mut poll = Poll::new()?;
    ///
    /// // Register handles with `poll`.
    ///
    /// poll.poll(&mut events, Some(Duration::from_millis(100)))?;
    ///
    /// // Clear all events.
    /// events.clear();
    /// assert!(events.is_empty());
    /// #     Ok(())
    /// # }
    /// ```
    pub fn clear(&mut self) {
        self.inner.clear();
    }

    /// Returns the inner `sys::Events`.
    pub(crate) fn sys(&mut self) -> &mut sys::Events {
        &mut self.inner
    }
}

impl<'a> IntoIterator for &'a Events {
    type Item = &'a Event;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = &'a Event;

    fn next(&mut self) -> Option<Self::Item> {
        let ret = self
            .inner
            .inner
            .get(self.pos)
            .map(Event::from_sys_event_ref);
        self.pos += 1;
        ret
    }
}

impl fmt::Debug for Events {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_list().entries(self).finish()
    }
}
<|endoftext|>


<commit_before>//! This module is UNSTABLE, the reason is - recently added.

use std::convert::From;
use std::io::{Cursor, Read};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::{Float, Integer, ValueRef};

trait ToUnsigned {
    fn from(v: Self) -> Option<usize> where Self: Sized;
}

impl ToUnsigned for u8 {
    fn from(v: u8) -> Option<usize> {
        // Impossible to panic, since u8 always fits in usize.
        Some(v as usize)
    }
}

impl ToUnsigned for u16 {
    fn from(v: u16) -> Option<usize> {
        // TODO: This can overflow on 8-bit systems.
        Some(v as usize)
    }
}

impl ToUnsigned for u32 {
    fn from(v: u32) -> Option<usize> {
        // TODO: This can overflow on 8- and 16-bit systems.
        Some(v as usize)
    }
}

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),
    /// Failed to cast the length read to machine size.
    InvalidLengthSize,
    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
    /// Failed to read ext type.
    InvalidExtTypeRead(ReadError),
    /// Using Reserved type found.
    TypeMismatch,
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_num<'a, R, D>(mut rd: &mut R) -> Result<D, Error<'a>>
    where R: BufRead<'a>,
          D: BigEndianRead
{
    D::read(&mut rd).map_err(|err| Error::InvalidDataRead(From::from(err)))
}

// TODO: Rename to `read_len`.
fn read_length<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_str<'a, R>(buf: &mut R, len: usize) -> Result<&'a str, Error<'a>>
    where R: BufRead<'a>
{
    let buf = try!(read_bin(buf, len));

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

fn read_bin<'a, R>(rd: &mut R, len: usize) -> Result<&'a [u8], Error<'a>>
    where R: BufRead<'a>
{
    let buf = rd.fill_buf();

    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];
    rd.consume(len);

    Ok(buf)
}

// Helper function that reads a single byte from the given `Read` and interpret it as an Ext type.
fn read_ext_type<R>(rd: &mut R) -> Result<i8, ReadError>
    where R: Read
{
    i8::read(rd).map_err(From::from)
}

fn read_ext<'a, R>(mut buf: &mut R, len: usize) -> Result<(i8, &'a [u8]), Error<'a>>
    where R: BufRead<'a>
{
    let ty  = try!(read_ext_type(&mut buf).map_err(|err| Error::InvalidExtTypeRead(err)));
    let buf = try!(read_bin(buf, len));

    Ok((ty, buf))
}

#[inline]
fn read_str_value<'a, R, U>(buf: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_str(buf, len));

    Ok(ValueRef::String(res))
}

#[inline]
fn read_bin_value<'a, R, U>(buf: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_bin(buf, len));

    Ok(ValueRef::Binary(res))
}

#[inline]
fn read_ext_value<'a, R, U>(mut buf: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let (ty, buf) = try!(read_ext(buf, len));

    Ok(ValueRef::Ext(ty, buf))
}

#[inline]
fn read_array_value<'a, R, U>(rd: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let vec = try!(read_array(rd, len));

    Ok(ValueRef::Array(vec))
}

#[inline]
fn read_map_value<'a, R, U>(rd: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let map = try!(read_map(rd, len));

    Ok(ValueRef::Map(map))
}

fn read_array<'a, R>(rd: &mut R, len: usize) -> Result<Vec<ValueRef<'a>>, Error<'a>>
    where R: BufRead<'a>
{
    let mut vec = Vec::with_capacity(len);

    for _ in 0..len {
        let val = try!(read_value_ref(rd));

        vec.push(val);
    }

    Ok(vec)
}

fn read_map<'a, R>(rd: &mut R, len: usize) -> Result<Vec<(ValueRef<'a>, ValueRef<'a>)>, Error<'a>>
    where R: BufRead<'a>
{
    let mut vec = Vec::with_capacity(len);

    for _ in 0..len {
        let key = try!(read_value_ref(rd));
        let val = try!(read_value_ref(rd));

        vec.push((key, val));
    }

    Ok(vec)
}

/// A BufRead is a type of Reader which has an internal buffer.
///
/// This magic trait acts like a standard BufRead but unlike the standard this has an explicit
/// internal buffer lifetime, which allows to borrow from underlying buffer while consuming bytes.
pub trait BufRead<'a>: Read {
    /// Returns the buffer contents.
    ///
    /// This function is a lower-level call. It needs to be paired with the consume method to
    /// function properly. When calling this method, none of the contents will be "read" in the
    /// sense that later calling read may return the same contents. As such, consume must be called
    /// with the number of bytes that are consumed from this buffer to ensure that the bytes are
    /// never returned twice.
    ///
    /// An empty buffer returned indicates that the stream has reached EOF.
    fn fill_buf(&self) -> &'a [u8];

    /// Tells this buffer that len bytes have been consumed from the buffer, so they should no
    /// longer be returned in calls to read.
    fn consume(&mut self, len: usize);
}

impl<'a> BufRead<'a> for &'a [u8] {
    fn fill_buf(&self) -> &'a [u8] {
        self
    }

    fn consume(&mut self, len: usize) {
        *self = &(*self)[len..];
    }
}

/// Useful when you want to know how much bytes has been consumed during ValueRef decoding.
impl<'a> BufRead<'a> for Cursor<&'a [u8]> {
    fn fill_buf(&self) -> &'a [u8] {
        use std::cmp;

        let len = cmp::min(self.position(), self.get_ref().len() as u64);
        &self.get_ref()[len as usize..]
    }

    fn consume(&mut self, len: usize) {
        let pos = self.position();
        self.set_position(pos + len as u64);
    }
}

// TODO: Doc, examples.
pub fn read_value_ref<'a, R>(rd: &mut R) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>
{
    let mut rd = rd;

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `rd`.
    let marker = try!(read_marker(rd));

    let val = match marker {
        Marker::Null => ValueRef::Nil,
        Marker::True => ValueRef::Boolean(true),
        Marker::False => ValueRef::Boolean(false),
        Marker::PositiveFixnum(val) => {
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U8 => {
            let val: u8 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U16 => {
            let val: u16 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U32 => {
            let val: u32 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U64 => {
            let val: u64 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val))
        }
        Marker::NegativeFixnum(val) => {
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I8 => {
            let val: i8 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I16 => {
            let val: i16 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I32 => {
            let val: i32 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I64 => {
            let val: i64 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val))
        }
        Marker::F32 => {
            let val: f32 = try!(read_num(rd));
            ValueRef::Float(Float::F32(val))
        }
        Marker::F64 => {
            let val: f64 = try!(read_num(rd));
            ValueRef::Float(Float::F64(val))
        }
        Marker::FixedString(len) => {
            try!(read_str_value(rd, len))
        }
        Marker::Str8 => {
            let len: u8 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(rd, len))
        }
        Marker::Str16 => {
            let len: u16 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(rd, len))
        }
        Marker::Str32 => {
            let len: u32 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(rd, len))
        }
        Marker::Bin8 => {
            let len: u8 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_bin_value(rd, len))
        }
        Marker::Bin16 => {
            let len: u16 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_bin_value(rd, len))
        }
        Marker::Bin32 => {
            let len: u32 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_bin_value(rd, len))
        }
        Marker::FixedArray(len) => {
            try!(read_array_value(rd, len))
        }
        Marker::Array16 => {
            let len: u16 = try!(read_length(&mut rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_array_value(rd, len))
        }
        Marker::Array32 => {
            let len: u32 = try!(read_length(&mut rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_array_value(rd, len))
        }
        Marker::FixedMap(len) => {
            try!(read_map_value(rd, len))
        }
        Marker::Map16 => {
            let len: u16 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_map_value(rd, len))
        }
        Marker::Map32 => {
            let len: u32 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_map_value(rd, len))
        }
        Marker::FixExt1 => {
            try!(read_ext_value(rd, 1u8))
        }
        Marker::FixExt2 => {
            try!(read_ext_value(rd, 2u8))
        }
        Marker::FixExt4 => {
            try!(read_ext_value(rd, 4u8))
        }
        Marker::FixExt8 => {
            try!(read_ext_value(rd, 8u8))
        }
        Marker::FixExt16 => {
            try!(read_ext_value(rd, 16u8))
        }
        Marker::Ext8 => {
            let len: u8 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_ext_value(rd, len))
        }
        Marker::Ext16 => {
            let len: u16 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_ext_value(rd, len))
        }
        Marker::Ext32 => {
            let len: u32 = try!(read_length(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_ext_value(rd, len))
        }
        Marker::Reserved => return Err(Error::TypeMismatch),
    };

    Ok(val)
}
<commit_msg>Misc: renaming again.<commit_after>//! This module is UNSTABLE, the reason is - recently added.

use std::convert::From;
use std::io::{Cursor, Read};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::{Float, Integer, ValueRef};

trait ToUnsigned {
    fn from(v: Self) -> Option<usize> where Self: Sized;
}

impl ToUnsigned for u8 {
    fn from(v: u8) -> Option<usize> {
        // Impossible to panic, since u8 always fits in usize.
        Some(v as usize)
    }
}

impl ToUnsigned for u16 {
    fn from(v: u16) -> Option<usize> {
        // TODO: This can overflow on 8-bit systems.
        Some(v as usize)
    }
}

impl ToUnsigned for u32 {
    fn from(v: u32) -> Option<usize> {
        // TODO: This can overflow on 8- and 16-bit systems.
        Some(v as usize)
    }
}

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),
    /// Failed to cast the length read to machine size.
    InvalidLengthSize,
    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
    /// Failed to read ext type.
    InvalidExtTypeRead(ReadError),
    /// Using Reserved type found.
    TypeMismatch,
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_len<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_num<'a, R, D>(mut rd: &mut R) -> Result<D, Error<'a>>
    where R: BufRead<'a>,
          D: BigEndianRead
{
    D::read(&mut rd).map_err(|err| Error::InvalidDataRead(From::from(err)))
}

fn read_str<'a, R>(buf: &mut R, len: usize) -> Result<&'a str, Error<'a>>
    where R: BufRead<'a>
{
    let buf = try!(read_bin(buf, len));

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

fn read_bin<'a, R>(rd: &mut R, len: usize) -> Result<&'a [u8], Error<'a>>
    where R: BufRead<'a>
{
    let buf = rd.fill_buf();

    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];
    rd.consume(len);

    Ok(buf)
}

// Helper function that reads a single byte from the given `Read` and interpret it as an Ext type.
fn read_ext_type<R>(rd: &mut R) -> Result<i8, ReadError>
    where R: Read
{
    i8::read(rd).map_err(From::from)
}

fn read_ext<'a, R>(mut buf: &mut R, len: usize) -> Result<(i8, &'a [u8]), Error<'a>>
    where R: BufRead<'a>
{
    let ty  = try!(read_ext_type(&mut buf).map_err(|err| Error::InvalidExtTypeRead(err)));
    let buf = try!(read_bin(buf, len));

    Ok((ty, buf))
}

#[inline]
fn read_str_value<'a, R, U>(buf: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_str(buf, len));

    Ok(ValueRef::String(res))
}

#[inline]
fn read_bin_value<'a, R, U>(buf: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_bin(buf, len));

    Ok(ValueRef::Binary(res))
}

#[inline]
fn read_ext_value<'a, R, U>(mut buf: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let (ty, buf) = try!(read_ext(buf, len));

    Ok(ValueRef::Ext(ty, buf))
}

#[inline]
fn read_array_value<'a, R, U>(rd: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let vec = try!(read_array(rd, len));

    Ok(ValueRef::Array(vec))
}

#[inline]
fn read_map_value<'a, R, U>(rd: &mut R, len: U) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>,
          U: ToUnsigned
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let map = try!(read_map(rd, len));

    Ok(ValueRef::Map(map))
}

fn read_array<'a, R>(rd: &mut R, len: usize) -> Result<Vec<ValueRef<'a>>, Error<'a>>
    where R: BufRead<'a>
{
    let mut vec = Vec::with_capacity(len);

    for _ in 0..len {
        let val = try!(read_value_ref(rd));

        vec.push(val);
    }

    Ok(vec)
}

fn read_map<'a, R>(rd: &mut R, len: usize) -> Result<Vec<(ValueRef<'a>, ValueRef<'a>)>, Error<'a>>
    where R: BufRead<'a>
{
    let mut vec = Vec::with_capacity(len);

    for _ in 0..len {
        let key = try!(read_value_ref(rd));
        let val = try!(read_value_ref(rd));

        vec.push((key, val));
    }

    Ok(vec)
}

/// A BufRead is a type of Reader which has an internal buffer.
///
/// This magic trait acts like a standard BufRead but unlike the standard this has an explicit
/// internal buffer lifetime, which allows to borrow from underlying buffer while consuming bytes.
pub trait BufRead<'a>: Read {
    /// Returns the buffer contents.
    ///
    /// This function is a lower-level call. It needs to be paired with the consume method to
    /// function properly. When calling this method, none of the contents will be "read" in the
    /// sense that later calling read may return the same contents. As such, consume must be called
    /// with the number of bytes that are consumed from this buffer to ensure that the bytes are
    /// never returned twice.
    ///
    /// An empty buffer returned indicates that the stream has reached EOF.
    fn fill_buf(&self) -> &'a [u8];

    /// Tells this buffer that len bytes have been consumed from the buffer, so they should no
    /// longer be returned in calls to read.
    fn consume(&mut self, len: usize);
}

impl<'a> BufRead<'a> for &'a [u8] {
    fn fill_buf(&self) -> &'a [u8] {
        self
    }

    fn consume(&mut self, len: usize) {
        *self = &(*self)[len..];
    }
}

/// Useful when you want to know how much bytes has been consumed during ValueRef decoding.
impl<'a> BufRead<'a> for Cursor<&'a [u8]> {
    fn fill_buf(&self) -> &'a [u8] {
        use std::cmp;

        let len = cmp::min(self.position(), self.get_ref().len() as u64);
        &self.get_ref()[len as usize..]
    }

    fn consume(&mut self, len: usize) {
        let pos = self.position();
        self.set_position(pos + len as u64);
    }
}

// TODO: Doc, examples.
pub fn read_value_ref<'a, R>(rd: &mut R) -> Result<ValueRef<'a>, Error<'a>>
    where R: BufRead<'a>
{
    let mut rd = rd;

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `rd`.
    let marker = try!(read_marker(rd));

    let val = match marker {
        Marker::Null => ValueRef::Nil,
        Marker::True => ValueRef::Boolean(true),
        Marker::False => ValueRef::Boolean(false),
        Marker::PositiveFixnum(val) => {
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U8 => {
            let val: u8 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U16 => {
            let val: u16 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U32 => {
            let val: u32 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U64 => {
            let val: u64 = try!(read_num(rd));
            ValueRef::Integer(Integer::U64(val))
        }
        Marker::NegativeFixnum(val) => {
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I8 => {
            let val: i8 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I16 => {
            let val: i16 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I32 => {
            let val: i32 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I64 => {
            let val: i64 = try!(read_num(rd));
            ValueRef::Integer(Integer::I64(val))
        }
        Marker::F32 => {
            let val: f32 = try!(read_num(rd));
            ValueRef::Float(Float::F32(val))
        }
        Marker::F64 => {
            let val: f64 = try!(read_num(rd));
            ValueRef::Float(Float::F64(val))
        }
        Marker::FixedString(len) => {
            try!(read_str_value(rd, len))
        }
        Marker::Str8 => {
            let len: u8 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(rd, len))
        }
        Marker::Str16 => {
            let len: u16 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(rd, len))
        }
        Marker::Str32 => {
            let len: u32 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(rd, len))
        }
        Marker::Bin8 => {
            let len: u8 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_bin_value(rd, len))
        }
        Marker::Bin16 => {
            let len: u16 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_bin_value(rd, len))
        }
        Marker::Bin32 => {
            let len: u32 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_bin_value(rd, len))
        }
        Marker::FixedArray(len) => {
            try!(read_array_value(rd, len))
        }
        Marker::Array16 => {
            let len: u16 = try!(read_len(&mut rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_array_value(rd, len))
        }
        Marker::Array32 => {
            let len: u32 = try!(read_len(&mut rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_array_value(rd, len))
        }
        Marker::FixedMap(len) => {
            try!(read_map_value(rd, len))
        }
        Marker::Map16 => {
            let len: u16 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_map_value(rd, len))
        }
        Marker::Map32 => {
            let len: u32 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_map_value(rd, len))
        }
        Marker::FixExt1 => {
            try!(read_ext_value(rd, 1u8))
        }
        Marker::FixExt2 => {
            try!(read_ext_value(rd, 2u8))
        }
        Marker::FixExt4 => {
            try!(read_ext_value(rd, 4u8))
        }
        Marker::FixExt8 => {
            try!(read_ext_value(rd, 8u8))
        }
        Marker::FixExt16 => {
            try!(read_ext_value(rd, 16u8))
        }
        Marker::Ext8 => {
            let len: u8 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_ext_value(rd, len))
        }
        Marker::Ext16 => {
            let len: u16 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_ext_value(rd, len))
        }
        Marker::Ext32 => {
            let len: u32 = try!(read_len(rd).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_ext_value(rd, len))
        }
        Marker::Reserved => return Err(Error::TypeMismatch),
    };

    Ok(val)
}
<|endoftext|>


<commit_before>use dynasmrt::x64::Assembler;
use dynasmrt::{DynasmApi, DynasmLabelApi};

use super::*;
use common::Count;
use peephole;

dynasm!(asm
    ; .alias pointer, r12
    ; .alias mem_start, r13
    ; .alias mem_limit, r14
    ; .alias rts, r15
);

/// Compiles peephole-optimized AST to x64 machine code.
///
/// Uses the `dynasmrt` assembler
pub fn compile(program: &peephole::Program, checked: bool) -> Program {
    let mut compiler = Compiler::new(checked);
    compiler.compile(program);
    compiler.into_program()
}

/// The compiler state.
struct Compiler {
    /// The underlying assembler.
    asm: Assembler,
    /// The offset of the starting instruction for the object function.
    start: dynasmrt::AssemblyOffset,
    /// Whether we are emitting bounds checks.
    checked: bool,
    /// Abstract interpreter for bounds checking analysis.
    interpreter: AbstractInterpreter,
}

impl Compiler {
    fn new(checked: bool) -> Self {
        let asm = Assembler::new();
        let start = asm.offset();

        let mut result = Compiler {
            asm: asm,
            start: start,
            checked: checked,
            interpreter: AbstractInterpreter::new(),
        };

        result.emit_prologue();

        result
    }

    fn into_program(mut self) -> Program {
        self.emit_epilogue();

        let code = self.asm.finalize().unwrap();

        Program {
            code: code,
            start: self.start,
        }
    }

    fn emit_prologue(&mut self) {
        dynasm!(self.asm
            ; push r12
            ; push r13
            ; push r14
            ; push r15
            ; mov pointer, rcx
            ; mov mem_start, rcx
            ; mov mem_limit, rcx
            ; add mem_limit, rdx
            ; mov rts, r8
        );
    }

    fn emit_epilogue(&mut self) {
        dynasm!(self.asm
            ; mov rax, rts::OKAY as i32
            ; jmp ->finish

            ; ->underflow:
            ; mov rax, rts::UNDERFLOW as i32
            ; jmp ->finish

            ; ->overflow:
            ; mov rax, rts::OVERFLOW as i32

            ; ->finish:
            ; pop r15
            ; pop r14
            ; pop r13
            ; pop r12
            ; ret
        );
    }

    fn compile(&mut self, program: &[peephole::Statement]) {
        for stm in program {
            self.compile_statement(stm);
        }
    }

    fn compile_statement(&mut self, stm: &peephole::Statement) {
        use peephole::Statement::*;
        use common::Instruction::*;

        match *stm {
            Instr(Right(count)) => {
                let proved = self.interpreter.right(count);

                dynasm!(self.asm
                    ;; self.load_pos_offset(count, proved)
                    ; add pointer, rax
                );
            }

            Instr(Left(count)) => {
                let proved = self.interpreter.left(count);

                dynasm!(self.asm
                    ;; self.load_neg_offset(count, proved)
                    ; sub pointer, rax
                );
            }

            Instr(Add(count)) => {
                dynasm!(self.asm
                    ; add [pointer], BYTE count as i8
                );
            }

            Instr(In) => {
                dynasm!(self.asm
                    ; mov rax, QWORD rts::RtsState::read as _
                    ; mov rcx, rts
                    ; sub rsp, BYTE 0x28
                    ; call rax
                    ; add rsp, BYTE 0x28
                    ; mov [pointer], al
                );
            }

            Instr(Out) => {
                dynasm!(self.asm
                    ; mov rax, QWORD rts::RtsState::write as _
                    ; mov rcx, rts
                    ; xor rdx, rdx
                    ; mov dl, [pointer]
                    ; sub rsp, BYTE 0x28
                    ; call rax
                    ; add rsp, BYTE 0x28
                );
            }

            Instr(SetZero) => {
                dynasm!(self.asm
                    ; mov BYTE [pointer], 0
                )
            }

            Instr(FindZeroRight(skip)) => {
                self.interpreter.reset_right();

                dynasm!(self.asm
                    ; jmp >end_loop
                    ; begin_loop:
                    ;; self.load_pos_offset(skip, false)
                    ; add pointer, rax
                    ; end_loop:
                    ; cmp BYTE [pointer], 0
                    ; jnz <begin_loop
                )
            }

            Instr(FindZeroLeft(skip)) => {
                self.interpreter.reset_left();

                dynasm!(self.asm
                    ; jmp >end_loop
                    ; begin_loop:
                    ;; self.load_neg_offset(skip, false)
                    ; sub pointer, rax
                    ; end_loop:
                    ; cmp BYTE [pointer], 0
                    ; jnz <begin_loop
                )
            }

            Instr(OffsetAddRight(offset)) => {
                let proved = self.interpreter.right(offset);
                self.interpreter.left(offset);

                dynasm!(self.asm
                    ; cmp BYTE [pointer], 0
                    ; jz >skip
                    ;; self.load_pos_offset(offset, proved)
                    ; mov cl, BYTE [pointer]
                    ; mov BYTE [pointer], 0
                    ; add BYTE [pointer + rax], cl
                    ; skip:
                );
            }

            Instr(OffsetAddLeft(offset)) => {
                let proved = self.interpreter.left(offset);
                self.interpreter.right(offset);

                dynasm!(self.asm
                    ; cmp BYTE [pointer], 0
                    ; jz >skip
                    ;; self.load_neg_offset(offset, proved)
                    ; mov cl, BYTE [pointer]
                    ; mov BYTE [pointer], 0
                    ; neg rax
                    ; add BYTE [pointer + rax], cl
                    ; skip:
                );
            }

            Instr(JumpZero(_)) | Instr(JumpNotZero(_)) =>
                panic!("unexpected jump instruction"),

            Loop(ref body) => {
                let begin_label = self.asm.new_dynamic_label();
                let end_label   = self.asm.new_dynamic_label();

                self.interpreter.reset();

                dynasm!(self.asm
                    ; jmp =>end_label
                    ; =>begin_label
                    ;; self.compile(body)
                    ; =>end_label
                    ; cmp BYTE [pointer], 0
                    ; jnz =>begin_label
                );

                self.interpreter.reset();
            }
        }
    }

    #[inline]
    fn load_offset(&mut self, offset: Count) {
        if offset as i32 as Count == offset {
            dynasm!(self.asm
            ; mov rax, DWORD offset as i32
        );
        } else {
            dynasm!(self.asm
            ; mov rax, QWORD offset as i64
        );
        }
    }

    #[inline]
    fn load_pos_offset(&mut self, offset: Count, proved: bool) {
        self.load_offset(offset);

        if self.checked && !proved {
            dynasm!(self.asm
                ; mov rcx, mem_limit
                ; sub rcx, pointer
                ; cmp rcx, rax
                ; jle ->overflow
            );
        }
    }

    #[inline]
    fn load_neg_offset(&mut self, offset: Count, proved: bool) {
        self.load_offset(offset);

        if self.checked && !proved {
            dynasm!(self.asm
                ; mov rcx, pointer
                ; sub rcx, mem_start
                ; cmp rcx, rax
                ; jl ->underflow
            );
        }
    }
}

/// The abstract interpreter tracks an abstraction of the pointer position.
///
/// In particular, it tracks the minimum distances from each end of memory. This can be used to
/// prove some bounds checks unnecessary.
#[derive(Debug, Clone)]
struct AbstractInterpreter {
    /// The minimum distance from the bottom of memory.
    low_mark: usize,
    /// The minimum distance from the top of memory.
    high_mark: usize,
}

impl AbstractInterpreter {
    /// In the initial state, we know nothing.
    fn new() -> Self {
        AbstractInterpreter {
            low_mark: 0,
            high_mark: 0,
        }
    }

    /// Moves the pointer the given distance to the left.
    ///
    /// Returns whether we can prove that this move will not underflow.
    fn left(&mut self, count: Count) -> bool {
        let count = count as usize;

        self.high_mark += count;
        if count <= self.low_mark {
            self.low_mark -= count;
            true
        } else {
            self.low_mark = 0;
            false
        }
    }

    /// Moves the pointer the given distance to the right.
    ///
    /// Returns whether we can prove that this move will not overflow.
    fn right(&mut self, count: Count) -> bool {
        let count = count as usize;

        self.low_mark += count;
        if count <= self.high_mark {
            self.high_mark -= count;
            true
        } else {
            self.high_mark = 0;
            false
        }
    }

    /// Resets the left mark.
    ///
    /// This is used when we may move an arbitrary distance to the left.
    fn reset_left(&mut self) {
        self.low_mark = 0;
    }

    /// Resets the right mark.
    ///
    /// This is used when we may move an arbitrary distance to the right.
    fn reset_right(&mut self) {
        self.high_mark = 0;
    }

    /// Resets both marks.
    ///
    /// This is used when we enter and leave a loop.
    fn reset(&mut self) {
        self.reset_left();
        self.reset_right();
    }
}
<commit_msg>Some better variable names.<commit_after>use dynasmrt::x64::Assembler;
use dynasmrt::{DynasmApi, DynasmLabelApi};

use super::*;
use common::Count;
use peephole;

dynasm!(asm
    ; .alias pointer, r12
    ; .alias mem_start, r13
    ; .alias mem_limit, r14
    ; .alias rts, r15
);

/// Compiles peephole-optimized AST to x64 machine code.
///
/// Uses the `dynasmrt` assembler
pub fn compile(program: &peephole::Program, checked: bool) -> Program {
    let mut compiler = Compiler::new(checked);
    compiler.compile(program);
    compiler.into_program()
}

/// The compiler state.
struct Compiler {
    /// The underlying assembler.
    asm: Assembler,
    /// The offset of the starting instruction for the object function.
    start: dynasmrt::AssemblyOffset,
    /// Whether we are emitting bounds checks.
    checked: bool,
    /// Abstract interpreter for bounds checking analysis.
    interpreter: AbstractInterpreter,
}

impl Compiler {
    fn new(checked: bool) -> Self {
        let asm = Assembler::new();
        let start = asm.offset();

        let mut result = Compiler {
            asm: asm,
            start: start,
            checked: checked,
            interpreter: AbstractInterpreter::new(),
        };

        result.emit_prologue();

        result
    }

    fn into_program(mut self) -> Program {
        self.emit_epilogue();

        let code = self.asm.finalize().unwrap();

        Program {
            code: code,
            start: self.start,
        }
    }

    fn emit_prologue(&mut self) {
        dynasm!(self.asm
            ; push r12
            ; push r13
            ; push r14
            ; push r15
            ; mov pointer, rcx
            ; mov mem_start, rcx
            ; mov mem_limit, rcx
            ; add mem_limit, rdx
            ; mov rts, r8
        );
    }

    fn emit_epilogue(&mut self) {
        dynasm!(self.asm
            ; mov rax, rts::OKAY as i32
            ; jmp ->finish

            ; ->underflow:
            ; mov rax, rts::UNDERFLOW as i32
            ; jmp ->finish

            ; ->overflow:
            ; mov rax, rts::OVERFLOW as i32

            ; ->finish:
            ; pop r15
            ; pop r14
            ; pop r13
            ; pop r12
            ; ret
        );
    }

    fn compile(&mut self, program: &[peephole::Statement]) {
        for stm in program {
            self.compile_statement(stm);
        }
    }

    fn compile_statement(&mut self, stm: &peephole::Statement) {
        use peephole::Statement::*;
        use common::Instruction::*;

        match *stm {
            Instr(Right(count)) => {
                let proved = self.interpreter.right(count);

                dynasm!(self.asm
                    ;; self.load_pos_offset(count, proved)
                    ; add pointer, rax
                );
            }

            Instr(Left(count)) => {
                let proved = self.interpreter.left(count);

                dynasm!(self.asm
                    ;; self.load_neg_offset(count, proved)
                    ; sub pointer, rax
                );
            }

            Instr(Add(count)) => {
                dynasm!(self.asm
                    ; add [pointer], BYTE count as i8
                );
            }

            Instr(In) => {
                dynasm!(self.asm
                    ; mov rax, QWORD rts::RtsState::read as _
                    ; mov rcx, rts
                    ; sub rsp, BYTE 0x28
                    ; call rax
                    ; add rsp, BYTE 0x28
                    ; mov [pointer], al
                );
            }

            Instr(Out) => {
                dynasm!(self.asm
                    ; mov rax, QWORD rts::RtsState::write as _
                    ; mov rcx, rts
                    ; xor rdx, rdx
                    ; mov dl, [pointer]
                    ; sub rsp, BYTE 0x28
                    ; call rax
                    ; add rsp, BYTE 0x28
                );
            }

            Instr(SetZero) => {
                dynasm!(self.asm
                    ; mov BYTE [pointer], 0
                )
            }

            Instr(FindZeroRight(skip)) => {
                self.interpreter.reset_right();

                dynasm!(self.asm
                    ; jmp >end_loop
                    ; begin_loop:
                    ;; self.load_pos_offset(skip, false)
                    ; add pointer, rax
                    ; end_loop:
                    ; cmp BYTE [pointer], 0
                    ; jnz <begin_loop
                )
            }

            Instr(FindZeroLeft(skip)) => {
                self.interpreter.reset_left();

                dynasm!(self.asm
                    ; jmp >end_loop
                    ; begin_loop:
                    ;; self.load_neg_offset(skip, false)
                    ; sub pointer, rax
                    ; end_loop:
                    ; cmp BYTE [pointer], 0
                    ; jnz <begin_loop
                )
            }

            Instr(OffsetAddRight(offset)) => {
                let proved = self.interpreter.right(offset);
                self.interpreter.left(offset);

                dynasm!(self.asm
                    ; cmp BYTE [pointer], 0
                    ; jz >skip
                    ;; self.load_pos_offset(offset, proved)
                    ; mov cl, BYTE [pointer]
                    ; mov BYTE [pointer], 0
                    ; add BYTE [pointer + rax], cl
                    ; skip:
                );
            }

            Instr(OffsetAddLeft(offset)) => {
                let proved = self.interpreter.left(offset);
                self.interpreter.right(offset);

                dynasm!(self.asm
                    ; cmp BYTE [pointer], 0
                    ; jz >skip
                    ;; self.load_neg_offset(offset, proved)
                    ; mov cl, BYTE [pointer]
                    ; mov BYTE [pointer], 0
                    ; neg rax
                    ; add BYTE [pointer + rax], cl
                    ; skip:
                );
            }

            Instr(JumpZero(_)) | Instr(JumpNotZero(_)) =>
                panic!("unexpected jump instruction"),

            Loop(ref body) => {
                let begin_label = self.asm.new_dynamic_label();
                let end_label   = self.asm.new_dynamic_label();

                self.interpreter.reset();

                dynasm!(self.asm
                    ; jmp =>end_label
                    ; =>begin_label
                    ;; self.compile(body)
                    ; =>end_label
                    ; cmp BYTE [pointer], 0
                    ; jnz =>begin_label
                );

                self.interpreter.reset();
            }
        }
    }

    #[inline]
    fn load_offset(&mut self, offset: Count) {
        if offset as i32 as Count == offset {
            dynasm!(self.asm
            ; mov rax, DWORD offset as i32
        );
        } else {
            dynasm!(self.asm
            ; mov rax, QWORD offset as i64
        );
        }
    }

    #[inline]
    fn load_pos_offset(&mut self, offset: Count, proved: bool) {
        self.load_offset(offset);

        if self.checked && !proved {
            dynasm!(self.asm
                ; mov rcx, mem_limit
                ; sub rcx, pointer
                ; cmp rcx, rax
                ; jle ->overflow
            );
        }
    }

    #[inline]
    fn load_neg_offset(&mut self, offset: Count, proved: bool) {
        self.load_offset(offset);

        if self.checked && !proved {
            dynasm!(self.asm
                ; mov rcx, pointer
                ; sub rcx, mem_start
                ; cmp rcx, rax
                ; jl ->underflow
            );
        }
    }
}

/// The abstract interpreter tracks an abstraction of the pointer position.
///
/// In particular, it tracks the minimum distances from each end of memory. This can be used to
/// prove some bounds checks unnecessary.
#[derive(Debug, Clone)]
struct AbstractInterpreter {
    /// The minimum distance from the bottom of memory.
    left_mark: usize,
    /// The minimum distance from the top of memory.
    right_mark: usize,
}

impl AbstractInterpreter {
    /// In the initial state, we know nothing.
    fn new() -> Self {
        AbstractInterpreter {
            left_mark: 0,
            right_mark: 0,
        }
    }

    /// Moves the pointer the given distance to the left.
    ///
    /// Returns whether we can prove that this move will not underflow.
    fn left(&mut self, count: Count) -> bool {
        let count = count as usize;

        self.right_mark += count;
        if count <= self.left_mark {
            self.left_mark -= count;
            true
        } else {
            self.left_mark = 0;
            false
        }
    }

    /// Moves the pointer the given distance to the right.
    ///
    /// Returns whether we can prove that this move will not overflow.
    fn right(&mut self, count: Count) -> bool {
        let count = count as usize;

        self.left_mark += count;
        if count <= self.right_mark {
            self.right_mark -= count;
            true
        } else {
            self.right_mark = 0;
            false
        }
    }

    /// Resets the left mark.
    ///
    /// This is used when we may move an arbitrary distance to the left.
    fn reset_left(&mut self) {
        self.left_mark = 0;
    }

    /// Resets the right mark.
    ///
    /// This is used when we may move an arbitrary distance to the right.
    fn reset_right(&mut self) {
        self.right_mark = 0;
    }

    /// Resets both marks.
    ///
    /// This is used when we enter and leave a loop.
    fn reset(&mut self) {
        self.reset_left();
        self.reset_right();
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use libc::{c_char, c_int, c_void};
use std::mem;
use sys::ffi;
use ComponentExt;

pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[
    ("CPU Die", &['T' as i8, 'C' as i8, '0' as i8, 'F' as i8]), // CPU Die "TC0F"
    ("CPU Proximity", &['T' as i8, 'C' as i8, '0' as i8, 'P' as i8]), // CPU Proximity "TC0P"
    ("GPU", &['T' as i8, 'G' as i8, '0' as i8, 'P' as i8]), // GPU "TG0P"
    ("Battery", &['T' as i8, 'B' as i8, '0' as i8, 'T' as i8]), // Battery "TB0T"
];

pub struct ComponentFFI {
    input_structure: ffi::KeyData_t,
    val: ffi::Val_t,
}

impl ComponentFFI {
    fn new(key: &[i8], con: ffi::io_connect_t) -> Option<ComponentFFI> {
        unsafe { get_key_size(con, key) }
            .ok()
            .map(|(input_structure, val)| ComponentFFI {
                input_structure,
                val,
            })
    }

    fn get_temperature(&self, con: ffi::io_connect_t) -> Option<f32> {
        get_temperature_inner(con, &self.input_structure, &self.val)
    }
}

/// Struct containing a component information (temperature and name for the moment).
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    ffi_part: ComponentFFI,
    connection: ffi::io_connect_t,
}

impl Component {
    /// Creates a new `Component` with the given information.
    pub(crate) fn new(
        label: String,
        max: Option<f32>,
        critical: Option<f32>,
        key: &[i8],
        connection: ffi::io_connect_t,
    ) -> Option<Component> {
        let ffi_part = ComponentFFI::new(key, connection)?;
        ffi_part
            .get_temperature(connection)
            .map(|temperature| Component {
                temperature,
                label,
                max: max.unwrap_or(0.0),
                critical,
                ffi_part,
                connection,
            })
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(temp) = self.ffi_part.get_temperature(self.connection) {
            self.temperature = temp;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

unsafe fn perform_call(
    conn: ffi::io_connect_t,
    index: c_int,
    input_structure: *const ffi::KeyData_t,
    output_structure: *mut ffi::KeyData_t,
) -> i32 {
    let mut structure_output_size = mem::size_of::<ffi::KeyData_t>();

    ffi::IOConnectCallStructMethod(
        conn,
        index as u32,
        input_structure,
        mem::size_of::<ffi::KeyData_t>(),
        output_structure,
        &mut structure_output_size,
    )
}

// Adapted from https://github.com/lavoiesl/osx-cpu-temp/blob/master/smc.c#L28
#[inline]
fn strtoul(s: &[i8]) -> u32 {
    ((s[0] as u32) << (3u32 << 3))
        + ((s[1] as u32) << (2u32 << 3))
        + ((s[2] as u32) << (1u32 << 3))
        + ((s[3] as u32) << (0u32 << 3))
}

#[inline]
unsafe fn ultostr(s: *mut c_char, val: u32) {
    *s.offset(0) = ((val >> 24) % 128) as i8;
    *s.offset(1) = ((val >> 16) % 128) as i8;
    *s.offset(2) = ((val >> 8) % 128) as i8;
    *s.offset(3) = (val % 128) as i8;
    *s.offset(4) = 0;
}

unsafe fn get_key_size(
    con: ffi::io_connect_t,
    key: &[i8],
) -> Result<(ffi::KeyData_t, ffi::Val_t), i32> {
    let mut input_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();
    let mut output_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();
    let mut val: ffi::Val_t = mem::zeroed::<ffi::Val_t>();

    input_structure.key = strtoul(key);
    input_structure.data8 = ffi::SMC_CMD_READ_KEYINFO;

    let result = perform_call(
        con,
        ffi::KERNEL_INDEX_SMC,
        &input_structure,
        &mut output_structure,
    );
    if result != ffi::KIO_RETURN_SUCCESS {
        return Err(result);
    }

    val.data_size = output_structure.key_info.data_size;
    ultostr(
        val.data_type.as_mut_ptr(),
        output_structure.key_info.data_type,
    );
    input_structure.key_info.data_size = val.data_size;
    input_structure.data8 = ffi::SMC_CMD_READ_BYTES;
    Ok((input_structure, val))
}

unsafe fn read_key(
    con: ffi::io_connect_t,
    input_structure: &ffi::KeyData_t,
    mut val: ffi::Val_t,
) -> Result<ffi::Val_t, i32> {
    let mut output_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();

    match perform_call(
        con,
        ffi::KERNEL_INDEX_SMC,
        input_structure,
        &mut output_structure,
    ) {
        ffi::KIO_RETURN_SUCCESS => {
            libc::memcpy(
                val.bytes.as_mut_ptr() as *mut c_void,
                output_structure.bytes.as_mut_ptr() as *mut c_void,
                mem::size_of::<[u8; 32]>(),
            );
            Ok(val)
        }
        result => Err(result),
    }
}

fn get_temperature_inner(
    con: ffi::io_connect_t,
    input_structure: &ffi::KeyData_t,
    original_val: &ffi::Val_t,
) -> Option<f32> {
    if let Ok(val) = unsafe { read_key(con, input_structure, (*original_val).clone()) } {
        if val.data_size > 0
            && unsafe { libc::strcmp(val.data_type.as_ptr(), b"sp78\0".as_ptr() as *const i8) } == 0
        {
            // convert sp78 value to temperature
            let x = (i32::from(val.bytes[0]) << 6) + (i32::from(val.bytes[1]) >> 2);
            return Some(x as f32 / 64f32);
        }
    }
    None
}

pub(crate) fn get_temperature(con: ffi::io_connect_t, key: &[i8]) -> Option<f32> {
    let (input_structure, val) = unsafe { get_key_size(con, &key) }.ok()?;
    get_temperature_inner(con, &input_structure, &val)
}
<commit_msg>improved naming and description for mac/component.rs<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use libc::{c_char, c_int, c_void};
use std::mem;
use sys::ffi;
use ComponentExt;

pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[
    ("CPU", &['T' as i8, 'C' as i8, '0' as i8, 'F' as i8]), // CPU Die "TC0F"
    ("CPU Proximity", &['T' as i8, 'C' as i8, '0' as i8, 'P' as i8]), // CPU Proximity (heat spreader) "TC0P"
    ("GPU", &['T' as i8, 'G' as i8, '0' as i8, 'P' as i8]), // GPU "TG0P"
    ("Battery", &['T' as i8, 'B' as i8, '0' as i8, 'T' as i8]), // Battery "TB0T"
];

pub struct ComponentFFI {
    input_structure: ffi::KeyData_t,
    val: ffi::Val_t,
}

impl ComponentFFI {
    fn new(key: &[i8], con: ffi::io_connect_t) -> Option<ComponentFFI> {
        unsafe { get_key_size(con, key) }
            .ok()
            .map(|(input_structure, val)| ComponentFFI {
                input_structure,
                val,
            })
    }

    fn get_temperature(&self, con: ffi::io_connect_t) -> Option<f32> {
        get_temperature_inner(con, &self.input_structure, &self.val)
    }
}

/// Struct containing a component information (temperature and name for the moment).
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    ffi_part: ComponentFFI,
    connection: ffi::io_connect_t,
}

impl Component {
    /// Creates a new `Component` with the given information.
    pub(crate) fn new(
        label: String,
        max: Option<f32>,
        critical: Option<f32>,
        key: &[i8],
        connection: ffi::io_connect_t,
    ) -> Option<Component> {
        let ffi_part = ComponentFFI::new(key, connection)?;
        ffi_part
            .get_temperature(connection)
            .map(|temperature| Component {
                temperature,
                label,
                max: max.unwrap_or(0.0),
                critical,
                ffi_part,
                connection,
            })
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(temp) = self.ffi_part.get_temperature(self.connection) {
            self.temperature = temp;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

unsafe fn perform_call(
    conn: ffi::io_connect_t,
    index: c_int,
    input_structure: *const ffi::KeyData_t,
    output_structure: *mut ffi::KeyData_t,
) -> i32 {
    let mut structure_output_size = mem::size_of::<ffi::KeyData_t>();

    ffi::IOConnectCallStructMethod(
        conn,
        index as u32,
        input_structure,
        mem::size_of::<ffi::KeyData_t>(),
        output_structure,
        &mut structure_output_size,
    )
}

// Adapted from https://github.com/lavoiesl/osx-cpu-temp/blob/master/smc.c#L28
#[inline]
fn strtoul(s: &[i8]) -> u32 {
    ((s[0] as u32) << (3u32 << 3))
        + ((s[1] as u32) << (2u32 << 3))
        + ((s[2] as u32) << (1u32 << 3))
        + ((s[3] as u32) << (0u32 << 3))
}

#[inline]
unsafe fn ultostr(s: *mut c_char, val: u32) {
    *s.offset(0) = ((val >> 24) % 128) as i8;
    *s.offset(1) = ((val >> 16) % 128) as i8;
    *s.offset(2) = ((val >> 8) % 128) as i8;
    *s.offset(3) = (val % 128) as i8;
    *s.offset(4) = 0;
}

unsafe fn get_key_size(
    con: ffi::io_connect_t,
    key: &[i8],
) -> Result<(ffi::KeyData_t, ffi::Val_t), i32> {
    let mut input_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();
    let mut output_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();
    let mut val: ffi::Val_t = mem::zeroed::<ffi::Val_t>();

    input_structure.key = strtoul(key);
    input_structure.data8 = ffi::SMC_CMD_READ_KEYINFO;

    let result = perform_call(
        con,
        ffi::KERNEL_INDEX_SMC,
        &input_structure,
        &mut output_structure,
    );
    if result != ffi::KIO_RETURN_SUCCESS {
        return Err(result);
    }

    val.data_size = output_structure.key_info.data_size;
    ultostr(
        val.data_type.as_mut_ptr(),
        output_structure.key_info.data_type,
    );
    input_structure.key_info.data_size = val.data_size;
    input_structure.data8 = ffi::SMC_CMD_READ_BYTES;
    Ok((input_structure, val))
}

unsafe fn read_key(
    con: ffi::io_connect_t,
    input_structure: &ffi::KeyData_t,
    mut val: ffi::Val_t,
) -> Result<ffi::Val_t, i32> {
    let mut output_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();

    match perform_call(
        con,
        ffi::KERNEL_INDEX_SMC,
        input_structure,
        &mut output_structure,
    ) {
        ffi::KIO_RETURN_SUCCESS => {
            libc::memcpy(
                val.bytes.as_mut_ptr() as *mut c_void,
                output_structure.bytes.as_mut_ptr() as *mut c_void,
                mem::size_of::<[u8; 32]>(),
            );
            Ok(val)
        }
        result => Err(result),
    }
}

fn get_temperature_inner(
    con: ffi::io_connect_t,
    input_structure: &ffi::KeyData_t,
    original_val: &ffi::Val_t,
) -> Option<f32> {
    if let Ok(val) = unsafe { read_key(con, input_structure, (*original_val).clone()) } {
        if val.data_size > 0
            && unsafe { libc::strcmp(val.data_type.as_ptr(), b"sp78\0".as_ptr() as *const i8) } == 0
        {
            // convert sp78 value to temperature
            let x = (i32::from(val.bytes[0]) << 6) + (i32::from(val.bytes[1]) >> 2);
            return Some(x as f32 / 64f32);
        }
    }
    None
}

pub(crate) fn get_temperature(con: ffi::io_connect_t, key: &[i8]) -> Option<f32> {
    let (input_structure, val) = unsafe { get_key_size(con, &key) }.ok()?;
    get_temperature_inner(con, &input_structure, &val)
}
<|endoftext|>


<commit_before>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

//! Simple SMTP headers

use time::Tm;

use std::fmt::{Show, Formatter, Result};

use common::{SP, COLON};
use mailer::address::Address;

/// Converts to an `Header`
pub trait ToHeader {
    /// Converts to an `Header` struct
    fn to_header(&self) -> Header;
}

impl ToHeader for Header {
    fn to_header(&self) -> Header {
        (*self).clone()
    }
}

impl<'a> ToHeader for (&'a str, &'a str) {
    fn to_header(&self) -> Header {
        let (name, value) = *self;
        Header::new(name, value)
    }
}

/// Contains a header
#[deriving(PartialEq,Eq,Clone)]
pub enum Header {
    /// `To`
    To(Address),
    /// `From`
    From(Address),
    /// `Cc`
    Cc(Address),
    /// `Reply-To`
    ReplyTo(Address),
    /// `Sender`
    Sender(Address),
    /// `Date`
    Date(Tm),
    /// `Subject`
    Subject(String),
    /// `MIME-Version`
    MimeVersion(String),
    /// `Content-Type`
    ContentType(String),
    /// `Message-Id`
    MessageId(String),
    /// Any header (name, value)
    Other(String, String),
}

impl Show for Header {
    fn fmt(&self, f: &mut Formatter) -> Result {

        f.write(format!("{}{}{}{}",
        match *self {

            Header::To(_) => "To",
            Header::From(_) => "From",
            Header::Cc(_) => "Cc",
            Header::ReplyTo(_) => "Reply-To",
            Header::Sender(_) => "Sender",
            Header::Date(_) => "Date",
            Header::Subject(_) => "Subject",
            Header::MimeVersion(_) => "MIME-Version",
            Header::ContentType(_) => "Content-Type",
            Header::MessageId(_) => "Message-Id",
            Header::Other(ref name, _) => name.as_slice(),
        },
        COLON, SP,
        match *self {
            Header::To(ref address) => address.to_string(),
            Header::From(ref address) => address.to_string(),
            Header::Cc(ref address) => address.to_string(),
            Header::ReplyTo(ref address) => address.to_string(),
            Header::Sender(ref address) => address.to_string(),
            Header::Date(ref date) => Tm::rfc822(date).to_string(),
            Header::Subject(ref subject) => subject.clone(),
            Header::MimeVersion(ref string) => string.clone(),
            Header::ContentType(ref string) => string.clone(),
            Header::MessageId(ref string) => string.clone(),
            Header::Other(_, ref value) => value.clone(),
        }
        ).as_bytes())
    }
}

impl Header {
    /// Creates ah `Header`
    pub fn new(name: &str, value: &str) -> Header {
        Header::Other(name.to_string(), value.to_string())
    }
}

#[cfg(test)]
mod test {
    use super::Header;
    use mailer::address::Address;

    use time::{at_utc, Timespec};

    #[test]
    fn test_new() {
        assert_eq!(
            Header::new("From", "me"),
            Header::Other("From".to_string(), "me".to_string())
        );
    }

    #[test]
    fn test_fmt() {
        assert_eq!(
            format!("{}", Header::new("From", "me")),
            "From: me".to_string()
        );
        assert_eq!(
            format!("{}", Header::To(Address::new("me@example.com", Some("My Name")))),
            "To: My Name <me@example.com>".to_string()
        );
        assert_eq!(
            format!("{}", Header::Subject("Test subject".to_string())),
            "Subject: Test subject".to_string()
        );
        let time = at_utc(Timespec::new(1234567890, 54321));
        assert_eq!(
            format!("{}", Header::Date(time)),
            "Date: Fri, 13 Feb 2009 23:31:30 GMT".to_string()
        );
    }
}
<commit_msg>MIME-Version does not really need to be configurable<commit_after>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

//! Simple SMTP headers

use time::Tm;

use std::fmt::{Show, Formatter, Result};

use common::{SP, COLON};
use mailer::address::Address;

/// Converts to an `Header`
pub trait ToHeader {
    /// Converts to an `Header` struct
    fn to_header(&self) -> Header;
}

impl ToHeader for Header {
    fn to_header(&self) -> Header {
        (*self).clone()
    }
}

impl<'a> ToHeader for (&'a str, &'a str) {
    fn to_header(&self) -> Header {
        let (name, value) = *self;
        Header::new(name, value)
    }
}

/// Contains a header
#[deriving(PartialEq,Eq,Clone)]
pub enum Header {
    /// `To`
    To(Address),
    /// `From`
    From(Address),
    /// `Cc`
    Cc(Address),
    /// `Reply-To`
    ReplyTo(Address),
    /// `Sender`
    Sender(Address),
    /// `Date`
    Date(Tm),
    /// `Subject`
    Subject(String),
    /// `MIME-Version`
    MimeVersion,
    /// `Content-Type`
    ContentType(String),
    /// `Message-Id`
    MessageId(String),
    /// Any header (name, value)
    Other(String, String),
}

impl Show for Header {
    fn fmt(&self, f: &mut Formatter) -> Result {

        f.write(format!("{}{}{}{}",
        match *self {

            Header::To(_) => "To",
            Header::From(_) => "From",
            Header::Cc(_) => "Cc",
            Header::ReplyTo(_) => "Reply-To",
            Header::Sender(_) => "Sender",
            Header::Date(_) => "Date",
            Header::Subject(_) => "Subject",
            Header::MimeVersion => "MIME-Version",
            Header::ContentType(_) => "Content-Type",
            Header::MessageId(_) => "Message-Id",
            Header::Other(ref name, _) => name.as_slice(),
        },
        COLON, SP,
        match *self {
            Header::To(ref address) => address.to_string(),
            Header::From(ref address) => address.to_string(),
            Header::Cc(ref address) => address.to_string(),
            Header::ReplyTo(ref address) => address.to_string(),
            Header::Sender(ref address) => address.to_string(),
            Header::Date(ref date) => Tm::rfc822(date).to_string(),
            Header::Subject(ref subject) => subject.clone(),
            Header::MimeVersion => "1.0".to_string(),
            Header::ContentType(ref string) => string.clone(),
            Header::MessageId(ref string) => string.clone(),
            Header::Other(_, ref value) => value.clone(),
        }
        ).as_bytes())
    }
}

impl Header {
    /// Creates ah `Header`
    pub fn new(name: &str, value: &str) -> Header {
        Header::Other(name.to_string(), value.to_string())
    }
}

#[cfg(test)]
mod test {
    use super::Header;
    use mailer::address::Address;

    use time::{at_utc, Timespec};

    #[test]
    fn test_new() {
        assert_eq!(
            Header::new("From", "me"),
            Header::Other("From".to_string(), "me".to_string())
        );
    }

    #[test]
    fn test_fmt() {
        assert_eq!(
            format!("{}", Header::new("From", "me")),
            "From: me".to_string()
        );
        assert_eq!(
            format!("{}", Header::To(Address::new("me@example.com", Some("My Name")))),
            "To: My Name <me@example.com>".to_string()
        );
        assert_eq!(
            format!("{}", Header::Subject("Test subject".to_string())),
            "Subject: Test subject".to_string()
        );
        let time = at_utc(Timespec::new(1234567890, 54321));
        assert_eq!(
            format!("{}", Header::Date(time)),
            "Date: Fri, 13 Feb 2009 23:31:30 GMT".to_string()
        );
    }
}
<|endoftext|>