<commit_before>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream
 {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
  producer: P,
}

fn parser<'a>(input: &'a [u8], is_start: &mut bool)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;

  if *is_start {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice     = i;
    *is_start = false;
  }

  metadata_parser(slice)
}

impl
 Stream
 where P: StreamProducer {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  /// Returns information for the current stream.
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream<ReadStream<File>>> {
    File::open(filename).and_then(|file| {
      let producer  = ReadStream::new(file);
      let error_str = format!("parser: couldn't parse the given file {}",
                              filename);

      Stream::from_stream_producer(producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream<ByteStream>> {
    let producer  = ByteStream::new(buffer);
    let error_str = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(producer, error_str)
  }

  fn from_stream_producer(mut producer: P, error_str: &str)
                          -> io::Result<Self> {
    let mut is_start    = true;
    let mut is_error    = false;
    let mut stream_info = StreamInfo::new();
    let mut metadata    = Vec::new();

    loop {
      match producer.parse(|i| parser(i, &mut is_start)) {
        Ok(block)                  => {
          let is_last = block.is_last;

          if let metadata::Data::StreamInfo(info) = block.data {
            stream_info = info;
          } else {
            metadata.push(block);
          }

          if is_last {
            break;
          }
        }
        Err(ErrorKind::EndOfInput) => break,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream_info.channels as usize;
      let block_size  = stream_info.max_block_size as usize;
      let output_size = block_size * channels;
      let mut output  = Vec::with_capacity(output_size);

      unsafe { output.set_len(output_size) }

      Ok(Stream {
        info: stream_info,
        metadata: metadata,
        frames: Vec::new(),
        state: ParserState::Marker,
        output: output,
        frame_index: 0,
        producer: producer,
      })
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  /// Returns an iterator over the decoded samples.
  pub fn iter(&mut self) -> Iter
 {
    let samples_left = self.info.total_samples;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }

  fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a, P> where P: 'a + StreamProducer {
  stream: &'a mut Stream
,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a, P> Iterator for Iter<'a, P> where P: StreamProducer {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      let frame_index = self.stream.frame_index;

      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a, P> IntoIterator for &'a mut Stream

 where P: StreamProducer {
  type Item     = i32;
  type IntoIter = Iter<'a, P>;

  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<commit_msg>Refactor next_frame to use iterative parsing<commit_after>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream
 {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
  producer: P,
}

fn parser<'a>(input: &'a [u8], is_start: &mut bool)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;

  if *is_start {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice     = i;
    *is_start = false;
  }

  metadata_parser(slice)
}

impl
 Stream
 where P: StreamProducer {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  /// Returns information for the current stream.
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream<ReadStream<File>>> {
    File::open(filename).and_then(|file| {
      let producer  = ReadStream::new(file);
      let error_str = format!("parser: couldn't parse the given file {}",
                              filename);

      Stream::from_stream_producer(producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream<ByteStream>> {
    let producer  = ByteStream::new(buffer);
    let error_str = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(producer, error_str)
  }

  fn from_stream_producer(mut producer: P, error_str: &str)
                          -> io::Result<Self> {
    let mut is_start    = true;
    let mut is_error    = false;
    let mut stream_info = StreamInfo::new();
    let mut metadata    = Vec::new();

    loop {
      match producer.parse(|i| parser(i, &mut is_start)) {
        Ok(block)                  => {
          let is_last = block.is_last;

          if let metadata::Data::StreamInfo(info) = block.data {
            stream_info = info;
          } else {
            metadata.push(block);
          }

          if is_last {
            break;
          }
        }
        Err(ErrorKind::EndOfInput) => break,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream_info.channels as usize;
      let block_size  = stream_info.max_block_size as usize;
      let output_size = block_size * channels;
      let mut output  = Vec::with_capacity(output_size);

      unsafe { output.set_len(output_size) }

      Ok(Stream {
        info: stream_info,
        metadata: metadata,
        frames: Vec::new(),
        state: ParserState::Marker,
        output: output,
        frame_index: 0,
        producer: producer,
      })
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  /// Returns an iterator over the decoded samples.
  pub fn iter(&mut self) -> Iter
 {
    let samples_left = self.info.total_samples;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }

  fn next_frame<'a>(&'a mut self) -> Option<usize> {
    let stream_info = self.info();

    loop {
      match self.producer.parse(|i| frame_parser(i, &stream_info)) {
        Ok(frame)                  => {
          let channels    = frame.header.channels as usize;
          let block_size  = frame.header.block_size as usize;
          let mut channel = 0;

          for subframe in &frame.subframes[0..channels] {
            let start  = channel * block_size;
            let end    = (channel + 1) * block_size;
            let output = &mut self.output[start..end];

            subframe::decode(&subframe, output);

            channel += 1;
          }

          frame::decode(frame.header.channel_assignment, &mut self.output);

          self.frame_index += 1;

          return Some(block_size);
        }
        Err(ErrorKind::EndOfInput) => return None,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => return None,
      }
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a, P> where P: 'a + StreamProducer {
  stream: &'a mut Stream
,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a, P> Iterator for Iter<'a, P> where P: StreamProducer {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      let frame_index = self.stream.frame_index;

      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a, P> IntoIterator for &'a mut Stream

 where P: StreamProducer {
  type Item     = i32;
  type IntoIter = Iter<'a, P>;

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


<commit_before>use gcref::GCRef;

/// `InHeap` types can be stored directly in the GC heap.
///
/// Application code does not need to use this trait. It is only public so that
/// the public macros can use it. Use the friendly macros!
///
/// GC types come in pairs: an `InHeap` type, which is stored physically inside
/// the heap, and may be packed with pointer fields and unsafe methods; and an
/// `IntoHeap` type, which is safe, is used in application code, and lives on
/// the stack.
///
/// Users never get a direct `&` reference to any value stored in the heap. All
/// access is through safe `IntoHeap` types, like `GCRef`.
///
/// *   For primitive types, like `i32`, the two types are the same.
///
/// *   `GCRef<'a, T>` is an `IntoHeap` type; the corresponding `InHeap` type
///     is the pointer type `*mut T`.
///
/// *   For macro-generated structs and enums, the user specifies the names of
///     both types. Both types have identical fields or variants, but fields of
///     the `InHeap` type are `InHeap`, and fields of the `IntoHeap` type are
///     `IntoHeap`.
///
/// Unsafe to implement: `from_heap` is incredibly dangerous. It receives a
/// non-mut reference to a heap value. That value may contain gc-references to
/// itself, directly or indirectly, in which case `from_heap` (or other code it
/// calls) could *without using any unsafe code* modify the heap while this
/// direct, non-mut reference exists. This breaks Rust's aliasing rules and
/// could cause crashes.
///
pub unsafe trait InHeap<'a>: Sized {
    type Out: IntoHeap<'a, In=Self>;

    unsafe fn mark(ptr: *mut Self);

    /// Extract the value from the heap. This turns any raw pointers in the
    /// `InHeap` value into safe references, so while it's an unsafe function,
    /// the result of a correct call can be safely handed out to user code.
    ///
    /// Unsafe to call: It is impossible for ordinary users to call this
    /// safely, because `self` must be a direct, unwrapped reference to a value
    /// stored in the GC heap, which ordinary users cannot obtain.
    ///
    unsafe fn from_heap(&self) -> Self::Out;
}

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
pub unsafe fn mark_entry_point<'a, T: InHeap<'a>>(addr: *mut ()) {
    InHeap::mark(addr as *mut T);
}

/// `IntoHeap` types live on the stack, in application code. They are the
/// safe, user-friendly analogues to pointer-filled `InHeap` types. When you
/// use `gc_ref_type!` to declare a new GC struct or enum, `IntoHeap` types are
/// the types you use for fields.
///
/// Application code does not need to use this trait. It is only public so that
/// the public macros can use it. Use the friendly macros!
///
/// "Safe to use" means they don't expose pointers or references to GC memory;
/// and they obey Rust's safety and aliasing rules. If an `IntoHeap` value
/// contains a pointer to a GC allocation, then that allocation (and everything
/// reachable from it) is protected from GC.
///
/// "Stored in a field of a GC struct" - This includes primitive types like
/// `i32`, but also GC structs and enums (they can nest).
///
/// Unsafe to implement: `InHeap` objects are full of pointers; if `into_heap`
/// puts garbage into them, GC will crash.
///
pub unsafe trait IntoHeap<'a>: Sized {
    /// The type of the value when it is physically stored in the heap.
    type In: InHeap<'a, Out=Self>;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn into_heap(self) -> Self::In;
}

pub fn heap_type_id<'a, T: InHeap<'a>>() -> usize {
    mark_entry_point::<T> as *const () as usize
}

/// Relate an `IntoHeap` type to the corresponding safe reference type.
///
/// Application code does not need to use this trait. It is only public so that
/// the public macros can use it. Use the friendly macros!
///
pub trait IntoHeapAllocation<'a>: IntoHeap<'a>
{
    type Ref: IntoHeap<'a>;

    fn wrap_gcref(gcref: GCRef<'a, Self::In>) -> Self::Ref;
}

// === Provided implmentations for primitive types

macro_rules! gc_trivial_impl {
    ($t:ty) => {
        unsafe impl<'a> InHeap<'a> for $t {
            type Out = $t;
            unsafe fn mark(_ptr: *mut $t) {}
            unsafe fn from_heap(&self) -> $t { self.clone() }
        }

        unsafe impl<'a> IntoHeap<'a> for $t {
            type In = $t;
            fn into_heap(self) -> $t { self }
        }
    }
}

macro_rules! gc_generic_trivial_impl {
    (#[AS_ITEM] $it:item) => { $it};
    ([$($x:tt)*] $t:ty) => {
        gc_generic_trivial_impl! {
            #[AS_ITEM]
            unsafe impl<'a, $($x)*> InHeap<'a> for $t {
                type Out = $t;
                unsafe fn mark(_ptr: *mut $t) {}
                unsafe fn from_heap(&self) -> $t { self.clone() }
            }
        }

        gc_generic_trivial_impl! {
            #[AS_ITEM]
            unsafe impl<'a, $($x)*> IntoHeap<'a> for $t {
                type In = $t;
                fn into_heap(self) -> $t { self }
            }
        }
    }
}

gc_trivial_impl!(bool);
gc_trivial_impl!(char);
gc_trivial_impl!(i8);
gc_trivial_impl!(u8);
gc_trivial_impl!(i16);
gc_trivial_impl!(u16);
gc_trivial_impl!(i32);
gc_trivial_impl!(u32);
gc_trivial_impl!(i64);
gc_trivial_impl!(u64);
gc_trivial_impl!(isize);
gc_trivial_impl!(usize);
gc_trivial_impl!(f32);
gc_trivial_impl!(f64);

gc_generic_trivial_impl!([T: ?Sized] &'static T);
gc_generic_trivial_impl!([T: Clone + 'static] Box<T>);

use std::rc::Rc;
gc_generic_trivial_impl!([T: Clone + 'static] Rc<T>);

unsafe impl<'a, U: InHeap<'a>> InHeap<'a> for Option<U> {
    type Out = Option<U::Out>;

    unsafe fn mark(ptr: *mut Option<U>) {
        match *ptr {
            None => (),
            Some(ref mut u) => InHeap::mark(u as *mut U)
        }
    }

    unsafe fn from_heap(&self) -> Option<U::Out> {
        match self {
            &None => None,
            &Some(ref u) => Some(u.from_heap())
        }
    }
}

unsafe impl<'a, T: IntoHeap<'a>> IntoHeap<'a> for Option<T> {
    type In = Option<T::In>;
    fn into_heap(self) -> Option<T::In> {
        self.map(|t| t.into_heap())
    }
}

/*
// 'static types are heap-safe because ref types are never 'static.
// Unfortunately I can't make the compiler understand this: the rules
// to prevent conflicting trait impls make this conflict with almost
// everything.
unsafe impl<'a, T: Clone + 'static> InHeap<'a> for T { ...trivial... }
unsafe impl<'a, T: Clone + 'static> IntoHeap<'a> for T { ...trivial... }
*/
<commit_msg>Allow small tuples in the heap. (Bah, for this effort I could have supported tuple structs, which would have been more useful. Oh well.)<commit_after>use gcref::GCRef;

/// `InHeap` types can be stored directly in the GC heap. All primitive types
/// and many standard types implement `InHeap`.
///
/// Application code does not need to use this trait. It is only public so that
/// the public macros can use it. Use the friendly macros!
///
/// GC types come in pairs: an `InHeap` type, which is stored physically inside
/// the heap, and may be packed with pointer fields and unsafe methods; and an
/// `IntoHeap` type, which is safe, is used in application code, and lives on
/// the stack.
///
/// Users never get a direct `&` reference to any value stored in the heap. All
/// access is through safe `IntoHeap` types, like `GCRef`.
///
/// *   For primitive types, like `i32`, the two types are the same.
///
/// *   `GCRef<'a, T>` is an `IntoHeap` type; the corresponding `InHeap` type
///     is the pointer type `*mut T`.
///
/// *   For macro-generated structs and enums, the user specifies the names of
///     both types. Both types have identical fields or variants, but fields of
///     the `InHeap` type are `InHeap`, and fields of the `IntoHeap` type are
///     `IntoHeap`.
///
/// Unsafe to implement: `from_heap` is incredibly dangerous. It receives a
/// non-mut reference to a heap value. That value may contain gc-references to
/// itself, directly or indirectly, in which case `from_heap` (or other code it
/// calls) could *without using any unsafe code* modify the heap while this
/// direct, non-mut reference exists. This breaks Rust's aliasing rules and
/// could cause crashes.
///
/// Implementation note: every type with `'static` lifetime should be safe to
/// store in the heap, because ref types are never `'static`. Unfortunately I
/// can't make rustc understand this. It would be *legal* to write this:
///
/// ```ignore
/// unsafe impl<'a, T: Clone + 'static> InHeap<'a> for T { ...trivial... }
/// unsafe impl<'a, T: Clone + 'static> IntoHeap<'a> for T { ...trivial... }
/// ```
///
/// but alas, Rust thinks those impls conflict with almost all others, making
/// it impossible to get the macros to work. So instead we `impl InHeap for` a
/// lot of individual types by hand.
///
pub unsafe trait InHeap<'a>: Sized {
    type Out: IntoHeap<'a, In=Self>;

    unsafe fn mark(ptr: *mut Self);

    /// Extract the value from the heap. This turns any raw pointers in the
    /// `InHeap` value into safe references, so while it's an unsafe function,
    /// the result of a correct call can be safely handed out to user code.
    ///
    /// Unsafe to call: It is impossible for ordinary users to call this
    /// safely, because `self` must be a direct, unwrapped reference to a value
    /// stored in the GC heap, which ordinary users cannot obtain.
    ///
    unsafe fn from_heap(&self) -> Self::Out;
}

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
pub unsafe fn mark_entry_point<'a, T: InHeap<'a>>(addr: *mut ()) {
    InHeap::mark(addr as *mut T);
}

/// `IntoHeap` types live on the stack, in application code. They are the
/// safe, user-friendly analogues to pointer-filled `InHeap` types. When you
/// use `gc_ref_type!` to declare a new GC struct or enum, `IntoHeap` types are
/// the types you use for fields.
///
/// Application code does not need to use this trait. It is only public so that
/// the public macros can use it. Use the friendly macros!
///
/// "Safe to use" means they don't expose pointers or references to GC memory;
/// and they obey Rust's safety and aliasing rules. If an `IntoHeap` value
/// contains a pointer to a GC allocation, then that allocation (and everything
/// reachable from it) is protected from GC.
///
/// "Stored in a field of a GC struct" - This includes primitive types like
/// `i32`, but also GC structs and enums (they can nest).
///
/// Unsafe to implement: `InHeap` objects are full of pointers; if `into_heap`
/// puts garbage into them, GC will crash.
///
pub unsafe trait IntoHeap<'a>: Sized {
    /// The type of the value when it is physically stored in the heap.
    type In: InHeap<'a, Out=Self>;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn into_heap(self) -> Self::In;
}

pub fn heap_type_id<'a, T: InHeap<'a>>() -> usize {
    mark_entry_point::<T> as *const () as usize
}

/// Relate an `IntoHeap` type to the corresponding safe reference type.
///
/// Application code does not need to use this trait. It is only public so that
/// the public macros can use it. Use the friendly macros!
///
pub trait IntoHeapAllocation<'a>: IntoHeap<'a>
{
    type Ref: IntoHeap<'a>;

    fn wrap_gcref(gcref: GCRef<'a, Self::In>) -> Self::Ref;
}

// === Provided implmentations for primitive types

macro_rules! gc_trivial_impl {
    ($t:ty) => {
        unsafe impl<'a> InHeap<'a> for $t {
            type Out = $t;
            unsafe fn mark(_ptr: *mut $t) {}
            unsafe fn from_heap(&self) -> $t { self.clone() }
        }

        unsafe impl<'a> IntoHeap<'a> for $t {
            type In = $t;
            fn into_heap(self) -> $t { self }
        }
    }
}

macro_rules! gc_generic_trivial_impl {
    (#[as_item] $it:item) => { $it};
    ([$($x:tt)*] $t:ty) => {
        gc_generic_trivial_impl! {
            #[as_item]
            unsafe impl<'a, $($x)*> InHeap<'a> for $t {
                type Out = $t;
                unsafe fn mark(_ptr: *mut $t) {}
                unsafe fn from_heap(&self) -> $t { self.clone() }
            }
        }

        gc_generic_trivial_impl! {
            #[as_item]
            unsafe impl<'a, $($x)*> IntoHeap<'a> for $t {
                type In = $t;
                fn into_heap(self) -> $t { self }
            }
        }
    }
}

gc_trivial_impl!(bool);
gc_trivial_impl!(char);
gc_trivial_impl!(i8);
gc_trivial_impl!(u8);
gc_trivial_impl!(i16);
gc_trivial_impl!(u16);
gc_trivial_impl!(i32);
gc_trivial_impl!(u32);
gc_trivial_impl!(i64);
gc_trivial_impl!(u64);
gc_trivial_impl!(isize);
gc_trivial_impl!(usize);
gc_trivial_impl!(f32);
gc_trivial_impl!(f64);

gc_generic_trivial_impl!([T: ?Sized] &'static T);
gc_generic_trivial_impl!([T: Clone + 'static] Box<T>);
gc_generic_trivial_impl!([T: Clone + 'static] ::std::rc::Rc<T>);

// Transitive implementations ("this particular kind of struct/enum is InHeap
// if all its fields are") are slightly less trivial.

unsafe impl<'a, U: InHeap<'a>> InHeap<'a> for Option<U> {
    type Out = Option<U::Out>;

    unsafe fn mark(ptr: *mut Option<U>) {
        match *ptr {
            None => (),
            Some(ref mut u) => InHeap::mark(u as *mut U)
        }
    }

    unsafe fn from_heap(&self) -> Option<U::Out> {
        match self {
            &None => None,
            &Some(ref u) => Some(u.from_heap())
        }
    }
}

unsafe impl<'a, T: IntoHeap<'a>> IntoHeap<'a> for Option<T> {
    type In = Option<T::In>;
    fn into_heap(self) -> Option<T::In> {
        self.map(|t| t.into_heap())
    }
}

macro_rules! gc_trivial_tuple_impl {
    (#[as_item] $it:item) => { $it };
    ($($t:ident),*) => {
        gc_trivial_tuple_impl! {
            #[as_item]
            unsafe impl<'a $(, $t: InHeap<'a>)*> InHeap<'a> for ($($t,)*) {
                type Out = ($($t::Out,)*);

                #[allow(non_snake_case)]  // because we use the type names as variable names (!)
                unsafe fn mark(ptr: *mut Self) {
                    let ($(ref mut $t,)*) = *ptr;
                    $(InHeap::mark($t as *mut $t);)*
                }

                #[allow(non_snake_case)]
                unsafe fn from_heap(&self) -> Self::Out {
                    let ($(ref $t,)*) = *self;
                    ($($t.from_heap(),)*)
                }
            }
        }

        gc_trivial_tuple_impl! {
            #[as_item]
            unsafe impl<'a, $($t: IntoHeap<'a>,)*> IntoHeap<'a> for ($($t,)*) {
                type In = ($($t::In,)*);

                #[allow(non_snake_case)]
                fn into_heap(self) -> Self::In {
                    let ($($t,)*) = self;
                    ($($t.into_heap(),)*)
                }
            }
        }
    }
}

gc_trivial_tuple_impl!();
gc_trivial_tuple_impl!(T);
gc_trivial_tuple_impl!(T, U);
gc_trivial_tuple_impl!(T, U, V);
gc_trivial_tuple_impl!(T, U, V, W);
gc_trivial_tuple_impl!(T, U, V, W, X);
gc_trivial_tuple_impl!(T, U, V, W, X, Y);
gc_trivial_tuple_impl!(T, U, V, W, X, Y, Z);
<|endoftext|>


<commit_before>//! See librustc_codegen_llvm/meth.rs for reference

use crate::prelude::*;

const DROP_FN_INDEX: usize = 0;
const SIZE_INDEX: usize = 1;
const ALIGN_INDEX: usize = 2;

fn vtable_memflags() -> MemFlags {
    let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
    flags.set_readonly(); // A vtable is always read-only.
    flags
}

pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (DROP_FN_INDEX * usize_size) as i32,
    )
}

pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (SIZE_INDEX * usize_size) as i32,
    )
}

pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ALIGN_INDEX * usize_size) as i32,
    )
}

pub(crate) fn get_ptr_and_method_ref<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
    arg: CValue<'tcx>,
    idx: usize,
) -> (Value, Value) {
    let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi {
        arg.load_scalar_pair(fx)
    } else {
        let (ptr, vtable) = arg.try_to_ptr().unwrap();
        (
            ptr.get_addr(fx),
            vtable.unwrap()
        )
    };

    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
    let func_ref = fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        ((idx + 3) * usize_size as usize) as i32,
    );
    (ptr, func_ref)
}

pub(crate) fn get_vtable<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Value {
    let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
        *data_id
    } else {
        let data_id = build_vtable(fx, layout, trait_ref);
        fx.vtables.insert((layout.ty, trait_ref), data_id);
        data_id
    };

    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}

fn build_vtable<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> DataId {
    let tcx = fx.tcx;
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;

    let drop_in_place_fn =
        import_function(tcx, fx.module, Instance::resolve_drop_in_place(tcx, layout.ty));

    let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];

    let methods_root;
    let methods = if let Some(trait_ref) = trait_ref {
        methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
        methods_root.iter()
    } else {
        (&[]).iter()
    };
    let methods = methods.cloned().map(|opt_mth| {
        opt_mth.map_or(None, |(def_id, substs)| {
            Some(import_function(
                tcx,
                fx.module,
                Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            ))
        })
    });
    components.extend(methods);

    let mut data_ctx = DataContext::new();
    let mut data = ::std::iter::repeat(0u8)
        .take(components.len() * usize_size)
        .collect::<Vec<u8>>()
        .into_boxed_slice();

    write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
    write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
    data_ctx.define(data);

    for (i, component) in components.into_iter().enumerate() {
        if let Some(func_id) = component {
            let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
            data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
        }
    }

    let data_id = fx
        .module
        .declare_data(
            &format!(
                "__vtable.{}.for.{:?}",
                trait_ref
                    .as_ref()
                    .map(|trait_ref| format!("{:?}", trait_ref.skip_binder()).into())
                    .unwrap_or(std::borrow::Cow::Borrowed("???")),
                layout.ty
            ),
            Linkage::Local,
            false,
            false,
            Some(
                fx.tcx
                    .data_layout
                    .pointer_align
                    .pref
                    .bytes()
                    .try_into()
                    .unwrap(),
            ),
        )
        .unwrap();

    match fx.module.define_data(data_id, &data_ctx) {
        Ok(()) | Err(cranelift_module::ModuleError::DuplicateDefinition(_)) => {}
        err => err.unwrap(),
    }

    data_id
}

fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) {
    use byteorder::{BigEndian, LittleEndian, WriteBytesExt};

    let usize_size = tcx
        .layout_of(ParamEnv::reveal_all().and(tcx.types.usize))
        .unwrap()
        .size
        .bytes() as usize;
    let mut target = &mut buf[idx * usize_size..(idx + 1) * usize_size];

    match tcx.data_layout.endian {
        rustc_target::abi::Endian::Little => target.write_uint::<LittleEndian>(num, usize_size),
        rustc_target::abi::Endian::Big => target.write_uint::<BigEndian>(num, usize_size),
    }
    .unwrap()
}
<commit_msg>Prevent different vtables with the same name<commit_after>//! See librustc_codegen_llvm/meth.rs for reference

use crate::prelude::*;

const DROP_FN_INDEX: usize = 0;
const SIZE_INDEX: usize = 1;
const ALIGN_INDEX: usize = 2;

fn vtable_memflags() -> MemFlags {
    let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
    flags.set_readonly(); // A vtable is always read-only.
    flags
}

pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (DROP_FN_INDEX * usize_size) as i32,
    )
}

pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (SIZE_INDEX * usize_size) as i32,
    )
}

pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ALIGN_INDEX * usize_size) as i32,
    )
}

pub(crate) fn get_ptr_and_method_ref<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
    arg: CValue<'tcx>,
    idx: usize,
) -> (Value, Value) {
    let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi {
        arg.load_scalar_pair(fx)
    } else {
        let (ptr, vtable) = arg.try_to_ptr().unwrap();
        (
            ptr.get_addr(fx),
            vtable.unwrap()
        )
    };

    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
    let func_ref = fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        ((idx + 3) * usize_size as usize) as i32,
    );
    (ptr, func_ref)
}

pub(crate) fn get_vtable<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Value {
    let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
        *data_id
    } else {
        let data_id = build_vtable(fx, layout, trait_ref);
        fx.vtables.insert((layout.ty, trait_ref), data_id);
        data_id
    };

    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}

fn build_vtable<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> DataId {
    let tcx = fx.tcx;
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;

    let drop_in_place_fn =
        import_function(tcx, fx.module, Instance::resolve_drop_in_place(tcx, layout.ty));

    let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];

    let methods_root;
    let methods = if let Some(trait_ref) = trait_ref {
        methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
        methods_root.iter()
    } else {
        (&[]).iter()
    };
    let methods = methods.cloned().map(|opt_mth| {
        opt_mth.map_or(None, |(def_id, substs)| {
            Some(import_function(
                tcx,
                fx.module,
                Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            ))
        })
    });
    components.extend(methods);

    let mut data_ctx = DataContext::new();
    let mut data = ::std::iter::repeat(0u8)
        .take(components.len() * usize_size)
        .collect::<Vec<u8>>()
        .into_boxed_slice();

    write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
    write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
    data_ctx.define(data);

    for (i, component) in components.into_iter().enumerate() {
        if let Some(func_id) = component {
            let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
            data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
        }
    }

    let data_id = fx
        .module
        .declare_data(
            &format!(
                "__vtable.{}.for.{:?}.{}",
                trait_ref
                    .as_ref()
                    .map(|trait_ref| format!("{:?}", trait_ref.skip_binder()).into())
                    .unwrap_or(std::borrow::Cow::Borrowed("???")),
                layout.ty,
                fx.vtables.len(),
            ),
            Linkage::Local,
            false,
            false,
            Some(
                fx.tcx
                    .data_layout
                    .pointer_align
                    .pref
                    .bytes()
                    .try_into()
                    .unwrap(),
            ),
        )
        .unwrap();

    fx.module.define_data(data_id, &data_ctx).unwrap();

    data_id
}

fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) {
    use byteorder::{BigEndian, LittleEndian, WriteBytesExt};

    let usize_size = tcx
        .layout_of(ParamEnv::reveal_all().and(tcx.types.usize))
        .unwrap()
        .size
        .bytes() as usize;
    let mut target = &mut buf[idx * usize_size..(idx + 1) * usize_size];

    match tcx.data_layout.endian {
        rustc_target::abi::Endian::Little => target.write_uint::<LittleEndian>(num, usize_size),
        rustc_target::abi::Endian::Big => target.write_uint::<BigEndian>(num, usize_size),
    }
    .unwrap()
}
<|endoftext|>


<commit_before>//! Object for creating .sdc files.

use std::fs;
use std::io::{BufWriter, Write};
use std::path::Path;

use byteorder::{LittleEndian, WriteBytesExt};

use point::Point;
use result::Result;

/// An .sdc writer.
pub struct Writer<W: Write> {
    writer: W,
}

impl Writer<BufWriter<fs::File>> {
    /// Creates a new SDC file and opens it for writing.
    ///
    /// The file will be closed when the file goes out of scope.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::remove_file;
    /// use sdc::writer::Writer;
    /// {
    ///     let writer = Writer::from_path("temp.sdc").unwrap();
    /// }
    /// remove_file("temp.sdc").unwrap();
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Writer<BufWriter<fs::File>>> {
        let writer = BufWriter::new(try!(fs::File::create(path)));
        let mut writer = Writer {
            writer: writer,
        };
        try!(writer.write_header());
        Ok(writer)
    }
}

impl<W: Write> Writer<W> {
    fn write_header(&mut self) -> Result<()> {
        try!(self.writer.write_u32::<LittleEndian>(8));
        // TODO hardcoded version, make this smahtar.
        try!(self.writer.write_u16::<LittleEndian>(5));
        try!(self.writer.write_u16::<LittleEndian>(0));
        Ok(())
    }

    /// Writes a point to this SDC file.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::fs::remove_file;
    /// use sdc::writer::Writer;
    /// use sdc::point::Point;
    /// let ref point = Point::new();
    /// {
    ///     let mut file = Writer::from_path("temp.sdc").unwrap();
    ///     file.write_point(point).unwrap();
    /// }
    /// # remove_file("temp.sdc").unwrap();
    pub fn write_point(&mut self, point: &Point) -> Result<()> {
        try!(self.writer.write_f64::<LittleEndian>(point.time));
        try!(self.writer.write_f32::<LittleEndian>(point.range));
        try!(self.writer.write_f32::<LittleEndian>(point.theta));
        try!(self.writer.write_f32::<LittleEndian>(point.x));
        try!(self.writer.write_f32::<LittleEndian>(point.y));
        try!(self.writer.write_f32::<LittleEndian>(point.z));
        try!(self.writer.write_u16::<LittleEndian>(point.amplitude));
        try!(self.writer.write_u16::<LittleEndian>(point.width));
        try!(self.writer.write_u8(point.target_type.as_u8()));
        try!(self.writer.write_u8(point.target));
        try!(self.writer.write_u8(point.num_target));
        try!(self.writer.write_u16::<LittleEndian>(point.rg_index));
        try!(self.writer.write_u8(point.channel_desc_byte()));
        Ok(())
    }
}
<commit_msg>Add `Writer::new`<commit_after>//! Object for creating .sdc files.

use std::fs;
use std::io::{BufWriter, Write};
use std::path::Path;

use byteorder::{LittleEndian, WriteBytesExt};

use point::Point;
use result::Result;

/// An .sdc writer.
pub struct Writer<W: Write> {
    writer: W,
}

impl Writer<BufWriter<fs::File>> {
    /// Creates a new SDC file and opens it for writing.
    ///
    /// The file will be closed when the file goes out of scope.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::remove_file;
    /// use sdc::writer::Writer;
    /// {
    ///     let writer = Writer::from_path("temp.sdc").unwrap();
    /// }
    /// remove_file("temp.sdc").unwrap();
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Writer<BufWriter<fs::File>>> {
        let writer = BufWriter::new(try!(fs::File::create(path)));
        Writer::new(writer)
    }
}

impl<W: Write> Writer<W> {
    /// Creates a new writer, consuming the provided `Write`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::fs::remove_file;
    /// use std::fs::File;
    /// use sdc::writer::Writer;
    /// let writer = File::create("temp.sdc").unwrap();
    /// {
    ///     let writer = Writer::new(writer).unwrap();
    /// }
    /// # remove_file("temp.sdc").unwrap();
    pub fn new(mut writer: W) -> Result<Writer<W>> {
        try!(writer.write_u32::<LittleEndian>(8));
        // TODO hardcoded version, make this smahtar.
        try!(writer.write_u16::<LittleEndian>(5));
        try!(writer.write_u16::<LittleEndian>(0));
        Ok(Writer { writer: writer })
    }

    /// Writes a point to this SDC file.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::fs::remove_file;
    /// use sdc::writer::Writer;
    /// use sdc::point::Point;
    /// let ref point = Point::new();
    /// {
    ///     let mut file = Writer::from_path("temp.sdc").unwrap();
    ///     file.write_point(point).unwrap();
    /// }
    /// # remove_file("temp.sdc").unwrap();
    pub fn write_point(&mut self, point: &Point) -> Result<()> {
        try!(self.writer.write_f64::<LittleEndian>(point.time));
        try!(self.writer.write_f32::<LittleEndian>(point.range));
        try!(self.writer.write_f32::<LittleEndian>(point.theta));
        try!(self.writer.write_f32::<LittleEndian>(point.x));
        try!(self.writer.write_f32::<LittleEndian>(point.y));
        try!(self.writer.write_f32::<LittleEndian>(point.z));
        try!(self.writer.write_u16::<LittleEndian>(point.amplitude));
        try!(self.writer.write_u16::<LittleEndian>(point.width));
        try!(self.writer.write_u8(point.target_type.as_u8()));
        try!(self.writer.write_u8(point.target));
        try!(self.writer.write_u8(point.num_target));
        try!(self.writer.write_u16::<LittleEndian>(point.rg_index));
        try!(self.writer.write_u8(point.channel_desc_byte()));
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate nom;
extern crate classfile_parser;

// use std::fs::File;
// use std::io::Read;

use nom::IResult;

use classfile_parser::class_parser;
use classfile_parser::constant_info::ConstantInfo;

#[test]
fn test_valid_class() {
    let valid_class = include_bytes!("../java-assets/compiled-classes/BasicClass.class");
    let res = class_parser(valid_class);
    match res {
        IResult::Done(_, c) => {
            println!("Valid class file, version {},{} const_pool({}), this=const[{}], super=const[{}], interfaces({}), fields({}), methods({}), attributes({}), access({:?})", c.major_version, c.minor_version, c.const_pool_size, c.this_class, c.super_class, c.interfaces_count, c.fields_count, c.methods_count, c.attributes_count, c.access_flags);

            let mut code_const_index = 0;

            println!("Constant pool:");
            for (const_index, const_item) in c.const_pool.iter().enumerate() {
                println!("\t[{}] = {:?}", (const_index + 1), const_item);
                match *const_item {
                    ConstantInfo::Utf8(ref c) => {
                        if c.utf8_string == "Code" {
                            code_const_index = (const_index + 1) as u16;
                        }
                    },
                    _ => {},
                }
            }
            println!("Code index = {}", code_const_index);

            println!("Interfaces:");
            let mut interface_index = 0;
            for i in &c.interfaces {
                println!("\t[{}] = const[{}] = {:?}", interface_index, i, c.const_pool[(i-1) as usize]);

                interface_index += 1;
            }
            println!("Fields:");
            let mut field_index = 0;
            for f in &c.fields {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", field_index, f.name_index, c.const_pool[(f.name_index - 1) as usize], f.access_flags);
                field_index += 1;
            }
            println!("Methods:");
            let mut method_index = 0;
            for m in &c.methods {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", method_index, m.name_index, c.const_pool[(m.name_index - 1) as usize], m.access_flags);
                method_index += 1;

                for a in &m.attributes {
                    if a.attribute_name_index == code_const_index {
                        println!("\t\tCode attr found, len = {}", a.attribute_length);
                        let code_result = classfile_parser::attribute_info::code_attribute_parser(&a.info);
                        match code_result {
                            IResult::Done(_, code) => {
                                println!("\t\t\tCode! code_length = {}", code.code_length);
                            },
                            _ => panic!("Not a valid code attr?"),

                        }
                    }
                    else {
                        println!("\t\tAttribute: {:?}", a);
                    }
                }
            }
        },
        _ => panic!("Not a class file"),
    };
}

#[test]
fn test_malformed_class() {
    let malformed_class = include_bytes!("../java-assets/compiled-classes/malformed.class");
    let res = class_parser(malformed_class);
    match res {
        IResult::Done(_, _) => panic!("The file is not valid and shouldn't be parsed"),
        _ => res,
    };
}

// #[test]
// fn test_constant_utf8() {
//     let hello_world_data = &[
//         // 0x01, // tag = 1
//         0x00, 0x0C, // length = 12
//         0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 // 'Hello world!' in UTF8
//     ];
//     let res = const_utf8(hello_world_data);

//     match res {
//         IResult::Done(_, c) =>
//         match c {
//             Constant::Utf8(ref s) =>
//                  println!("Valid UTF8 const: {}", s.utf8_string),
//             _ => panic!("It's a const, but of what type?")
//         },
//         _ => panic!("Not a UTF type const?"),
//     };
// }
<commit_msg>Add basic parsing test for StackMapTable<commit_after>extern crate nom;
extern crate classfile_parser;

// use std::fs::File;
// use std::io::Read;

use nom::IResult;

use classfile_parser::class_parser;
use classfile_parser::constant_info::ConstantInfo;

#[test]
fn test_valid_class() {
    let valid_class = include_bytes!("../java-assets/compiled-classes/BasicClass.class");
    let res = class_parser(valid_class);
    match res {
        IResult::Done(_, c) => {
            println!("Valid class file, version {},{} const_pool({}), this=const[{}], super=const[{}], interfaces({}), fields({}), methods({}), attributes({}), access({:?})", c.major_version, c.minor_version, c.const_pool_size, c.this_class, c.super_class, c.interfaces_count, c.fields_count, c.methods_count, c.attributes_count, c.access_flags);

            let mut code_const_index = 0;

            println!("Constant pool:");
            for (const_index, const_item) in c.const_pool.iter().enumerate() {
                println!("\t[{}] = {:?}", (const_index + 1), const_item);
                match *const_item {
                    ConstantInfo::Utf8(ref c) => {
                        if c.utf8_string == "Code" {
                            code_const_index = (const_index + 1) as u16;
                        }
                    },
                    _ => {},
                }
            }
            println!("Code index = {}", code_const_index);

            println!("Interfaces:");
            let mut interface_index = 0;
            for i in &c.interfaces {
                println!("\t[{}] = const[{}] = {:?}", interface_index, i, c.const_pool[(i-1) as usize]);

                interface_index += 1;
            }
            println!("Fields:");
            let mut field_index = 0;
            for f in &c.fields {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", field_index, f.name_index, c.const_pool[(f.name_index - 1) as usize], f.access_flags);
                field_index += 1;
            }
            println!("Methods:");
            let mut method_index = 0;
            for m in &c.methods {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", method_index, m.name_index, c.const_pool[(m.name_index - 1) as usize], m.access_flags);
                method_index += 1;

                for a in &m.attributes {
                    if a.attribute_name_index == code_const_index {
                        println!("\t\tCode attr found, len = {}", a.attribute_length);
                        let code_result = classfile_parser::attribute_info::code_attribute_parser(&a.info);
                        match code_result {
                            IResult::Done(_, code) => {
                                println!("\t\t\tCode! code_length = {}", code.code_length);
                            },
                            _ => panic!("Not a valid code attr?"),

                        }
                    }
                    else {
                        println!("\t\tAttribute: {:?}", a);
                    }
                }
            }
        },
        _ => panic!("Not a class file"),
    };
}

#[test]
fn test_malformed_class() {
    let malformed_class = include_bytes!("../java-assets/compiled-classes/malformed.class");
    let res = class_parser(malformed_class);
    match res {
        IResult::Done(_, _) => panic!("The file is not valid and shouldn't be parsed"),
        _ => res,
    };
}

#[test]
fn test_stack_map_table() {
    let stack_map_class = include_bytes!("../java-assets/compiled-classes/Factorial.class");
    let res = class_parser(stack_map_class);
    match res {
        IResult::Done(_, c) => {
            use classfile_parser::attribute_info::code_attribute_parser;
            use classfile_parser::attribute_info::stack_map_table_attribute_parser;

            assert_eq!(c.methods.len(), 2);
            assert_eq!(c.methods.len(), c.methods_count as usize);

            let method = &c.methods[1];
            assert_eq!(method.attributes.len(), 1);
            assert_eq!(method.attributes.len(), method.attributes_count as usize);

            let code = code_attribute_parser(&method.attributes[0].info).to_result().unwrap();
            assert_eq!(code.attributes_count, 1);

            let p = stack_map_table_attribute_parser(&code.attributes[0].info);
            match p {
                IResult::Done(_, a) => {
                    assert_eq!(a.entries.len(), a.number_of_entries as usize);
                    assert_eq!(a.entries.len(), 2);

                    use classfile_parser::attribute_info::StackMapFrame::*;
                    match a.entries[0] {
                        SameFrame { .. } => {},
                        _ => panic!("unexpected frame type for frame 0"),
                    };
                    match a.entries[1] {
                        SameLocals1StackItemFrame { .. } => {},
                        _ => panic!("unexpected frame type for frame 1: {:?}", &a.entries[1]),
                    };
                },
                _ => panic!("failed to parse StackMapTable"),
            };

        },
        _ => panic!("not a class file"),
    };
}

// #[test]
// fn test_constant_utf8() {
//     let hello_world_data = &[
//         // 0x01, // tag = 1
//         0x00, 0x0C, // length = 12
//         0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 // 'Hello world!' in UTF8
//     ];
//     let res = const_utf8(hello_world_data);

//     match res {
//         IResult::Done(_, c) =>
//         match c {
//             Constant::Utf8(ref s) =>
//                  println!("Valid UTF8 const: {}", s.utf8_string),
//             _ => panic!("It's a const, but of what type?")
//         },
//         _ => panic!("Not a UTF type const?"),
//     };
// }
<|endoftext|>


<commit_before>// error-pattern:the trait bound `str: std::marker::Sized` is not satisfied
#[macro_use]
extern crate lazy_static_compiletest as lazy_static;

lazy_static! {
    pub static ref FOO: str = panic!();
}

fn main() {
}
<commit_msg>update unsized error msg pattern<commit_after>// error-pattern:the size for value values of type `str` cannot be known at compilation time
#[macro_use]
extern crate lazy_static_compiletest as lazy_static;

lazy_static! {
    pub static ref FOO: str = panic!();
}

fn main() {
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::f32;
use std::f64;
use std::fmt;
use std::io::{Read, Write};

use postgres::{Connection, SslMode, Result};
use postgres::error::Error;
use postgres::types::{ToSql, FromSql, Slice, WrongType, Type, IsNull, Kind, SessionInfo};

#[cfg(feature = "bit-vec")]
mod bit_vec;
#[cfg(feature = "uuid")]
mod uuid;
#[cfg(feature = "time")]
mod time;
#[cfg(feature = "rustc-serialize")]
mod rustc_serialize;
#[cfg(feature = "serde_json")]
mod serde_json;
#[cfg(feature = "chrono")]
mod chrono;

fn test_type<T: PartialEq+FromSql+ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    for &(ref val, ref repr) in checks.iter() {
        let stmt = or_panic!(conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)));
        let result = or_panic!(stmt.query(&[])).iter().next().unwrap().get(0);
        assert_eq!(val, &result);

        let stmt = or_panic!(conn.prepare(&*format!("SELECT $1::{}", sql_type)));
        let result = or_panic!(stmt.query(&[val])).iter().next().unwrap().get(0);
        assert_eq!(val, &result);
    }
}

#[test]
fn test_ref_tosql() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    let stmt = conn.prepare("SELECT $1::Int").unwrap();
    let num: &ToSql = &&7;
    stmt.query(&[num]).unwrap();
}

#[test]
fn test_bool_params() {
    test_type("BOOL", &[(Some(true), "'t'"), (Some(false), "'f'"),
                       (None, "NULL")]);
}

#[test]
fn test_i8_params() {
    test_type("\"char\"", &[(Some('a' as i8), "'a'"), (None, "NULL")]);
}

#[test]
fn test_name_params() {
    test_type("NAME", &[(Some("hello world".to_owned()), "'hello world'"),
                       (Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
                       (None, "NULL")]);
}

#[test]
fn test_i16_params() {
    test_type("SMALLINT", &[(Some(15001i16), "15001"),
                           (Some(-15001i16), "-15001"), (None, "NULL")]);
}

#[test]
fn test_i32_params() {
    test_type("INT", &[(Some(2147483548i32), "2147483548"),
                      (Some(-2147483548i32), "-2147483548"), (None, "NULL")]);
}

#[test]
fn test_oid_params() {
    test_type("OID", &[(Some(2147483548u32), "2147483548"),
                       (Some(4000000000), "4000000000"), (None, "NULL")]);
}

#[test]
fn test_i64_params() {
    test_type("BIGINT", &[(Some(9223372036854775708i64), "9223372036854775708"),
                         (Some(-9223372036854775708i64), "-9223372036854775708"),
                         (None, "NULL")]);
}

#[test]
fn test_f32_params() {
    test_type("REAL", &[(Some(f32::INFINITY), "'infinity'"),
                       (Some(f32::NEG_INFINITY), "'-infinity'"),
                       (Some(1000.55), "1000.55"), (None, "NULL")]);
}

#[test]
fn test_f64_params() {
    test_type("DOUBLE PRECISION", &[(Some(f64::INFINITY), "'infinity'"),
                                   (Some(f64::NEG_INFINITY), "'-infinity'"),
                                   (Some(10000.55), "10000.55"),
                                   (None, "NULL")]);
}

#[test]
fn test_varchar_params() {
    test_type("VARCHAR", &[(Some("hello world".to_owned()), "'hello world'"),
                          (Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
                          (None, "NULL")]);
}

#[test]
fn test_text_params() {
    test_type("TEXT", &[(Some("hello world".to_owned()), "'hello world'"),
                       (Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
                       (None, "NULL")]);
}

#[test]
fn test_bpchar_params() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
                            id SERIAL PRIMARY KEY,
                            b CHAR(5)
                           )", &[]));
    or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
                           &[&Some("12345"), &Some("123"), &None::<&'static str>]));
    let stmt = or_panic!(conn.prepare("SELECT b FROM foo ORDER BY id"));
    let res = or_panic!(stmt.query(&[]));

    assert_eq!(vec!(Some("12345".to_owned()), Some("123  ".to_owned()), None),
               res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
}

#[test]
fn test_citext_params() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
                            id SERIAL PRIMARY KEY,
                            b CITEXT
                           )", &[]));
    or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
                           &[&Some("foobar"), &Some("FooBar"), &None::<&'static str>]));
    let stmt = or_panic!(conn.prepare("SELECT id FROM foo WHERE b = 'FOOBAR' ORDER BY id"));
    let res = or_panic!(stmt.query(&[]));

    assert_eq!(vec!(Some(1i32), Some(2i32)), res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
}

#[test]
fn test_bytea_params() {
    test_type("BYTEA", &[(Some(vec!(0u8, 1, 2, 3, 254, 255)), "'\\x00010203feff'"),
                        (None, "NULL")]);
}

#[test]
fn test_hstore_params() {
    macro_rules! make_map {
        ($($k:expr => $v:expr),+) => ({
            let mut map = HashMap::new();
            $(map.insert($k, $v);)+
            map
        })
    }
    test_type("hstore",
              &[(Some(make_map!("a".to_owned() => Some("1".to_owned()))), "'a=>1'"),
               (Some(make_map!("hello".to_owned() => Some("world!".to_owned()),
                               "hola".to_owned() => Some("mundo!".to_owned()),
                               "what".to_owned() => None)),
                "'hello=>world!,hola=>mundo!,what=>NULL'"),
                (None, "NULL")]);
}

fn test_nan_param<T: PartialEq+ToSql+FromSql>(sql_type: &str) {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    let stmt = or_panic!(conn.prepare(&*format!("SELECT 'NaN'::{}", sql_type)));
    let result = or_panic!(stmt.query(&[]));
    let val: T = result.iter().next().unwrap().get(0);
    assert!(val != val);
}

#[test]
fn test_f32_nan_param() {
    test_nan_param::<f32>("REAL");
}

#[test]
fn test_f64_nan_param() {
    test_nan_param::<f64>("DOUBLE PRECISION");
}

#[test]
fn test_pg_database_datname() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    let stmt = or_panic!(conn.prepare("SELECT datname FROM pg_database"));
    let result = or_panic!(stmt.query(&[]));

    let next = result.iter().next().unwrap();
    or_panic!(next.get_opt::<_, String>(0).unwrap());
    or_panic!(next.get_opt::<_, String>("datname").unwrap());
}

#[test]
fn test_slice() {
    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();
    conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY, f VARCHAR);
                        INSERT INTO foo (f) VALUES ('a'), ('b'), ('c'), ('d');").unwrap();

    let stmt = conn.prepare("SELECT f FROM foo WHERE id = ANY($1)").unwrap();
    let result = stmt.query(&[&Slice(&[1i32, 3, 4])]).unwrap();
    assert_eq!(vec!["a".to_owned(), "c".to_owned(), "d".to_owned()],
               result.iter().map(|r| r.get::<_, String>(0)).collect::<Vec<_>>());
}

#[test]
fn test_slice_wrong_type() {
    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();
    conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY)").unwrap();

    let stmt = conn.prepare("SELECT * FROM foo WHERE id = ANY($1)").unwrap();
    match stmt.query(&[&Slice(&["hi"])]) {
        Ok(_) => panic!("Unexpected success"),
        Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
        Err(e) => panic!("Unexpected error {:?}", e),
    };
}

#[test]
fn test_slice_range() {
    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();

    let stmt = conn.prepare("SELECT $1::INT8RANGE").unwrap();
    match stmt.query(&[&Slice(&[1i64])]) {
        Ok(_) => panic!("Unexpected success"),
        Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
        Err(e) => panic!("Unexpected error {:?}", e),
    };
}

#[test]
fn domain() {
    #[derive(Debug, PartialEq)]
    struct SessionId(Vec<u8>);

    impl ToSql for SessionId {
        fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
            where W: Write
        {
            let inner = match *ty.kind() {
                Kind::Domain(ref inner) => inner,
                _ => unreachable!(),
            };
            self.0.to_sql(inner, out, ctx)
        }

        fn accepts(ty: &Type) -> bool {
            ty.name() == "session_id" && match *ty.kind() { Kind::Domain(_) => true, _ => false }
        }

        to_sql_checked!();
    }

    impl FromSql for SessionId {
        fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self> {
            Vec::<u8>::from_sql(ty, raw, ctx).map(SessionId)
        }

        fn accepts(ty: &Type) -> bool {
            // This is super weird!
            <Vec<u8> as FromSql>::accepts(ty)
        }
    }

    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();
    conn.batch_execute("CREATE DOMAIN pg_temp.session_id AS bytea CHECK(octet_length(VALUE) = 16);
                        CREATE TABLE pg_temp.foo (id pg_temp.session_id);")
        .unwrap();

    let id = SessionId(b"0123456789abcdef".to_vec());
    conn.execute("INSERT INTO pg_temp.foo (id) VALUES ($1)", &[&id]).unwrap();
    let rows = conn.query("SELECT id FROM pg_temp.foo", &[]).unwrap();
    assert_eq!(id, rows.get(0).get(0));
}
<commit_msg>Enable tests for macaddr<commit_after>use std::collections::HashMap;
use std::f32;
use std::f64;
use std::fmt;
use std::io::{Read, Write};

use postgres::{Connection, SslMode, Result};
use postgres::error::Error;
use postgres::types::{ToSql, FromSql, Slice, WrongType, Type, IsNull, Kind, SessionInfo};

#[cfg(feature = "bit-vec")]
mod bit_vec;
#[cfg(feature = "eui48")]
mod eui48;
#[cfg(feature = "uuid")]
mod uuid;
#[cfg(feature = "time")]
mod time;
#[cfg(feature = "rustc-serialize")]
mod rustc_serialize;
#[cfg(feature = "serde_json")]
mod serde_json;
#[cfg(feature = "chrono")]
mod chrono;

fn test_type<T: PartialEq+FromSql+ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    for &(ref val, ref repr) in checks.iter() {
        let stmt = or_panic!(conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)));
        let result = or_panic!(stmt.query(&[])).iter().next().unwrap().get(0);
        assert_eq!(val, &result);

        let stmt = or_panic!(conn.prepare(&*format!("SELECT $1::{}", sql_type)));
        let result = or_panic!(stmt.query(&[val])).iter().next().unwrap().get(0);
        assert_eq!(val, &result);
    }
}

#[test]
fn test_ref_tosql() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    let stmt = conn.prepare("SELECT $1::Int").unwrap();
    let num: &ToSql = &&7;
    stmt.query(&[num]).unwrap();
}

#[test]
fn test_bool_params() {
    test_type("BOOL", &[(Some(true), "'t'"), (Some(false), "'f'"),
                       (None, "NULL")]);
}

#[test]
fn test_i8_params() {
    test_type("\"char\"", &[(Some('a' as i8), "'a'"), (None, "NULL")]);
}

#[test]
fn test_name_params() {
    test_type("NAME", &[(Some("hello world".to_owned()), "'hello world'"),
                       (Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
                       (None, "NULL")]);
}

#[test]
fn test_i16_params() {
    test_type("SMALLINT", &[(Some(15001i16), "15001"),
                           (Some(-15001i16), "-15001"), (None, "NULL")]);
}

#[test]
fn test_i32_params() {
    test_type("INT", &[(Some(2147483548i32), "2147483548"),
                      (Some(-2147483548i32), "-2147483548"), (None, "NULL")]);
}

#[test]
fn test_oid_params() {
    test_type("OID", &[(Some(2147483548u32), "2147483548"),
                       (Some(4000000000), "4000000000"), (None, "NULL")]);
}

#[test]
fn test_i64_params() {
    test_type("BIGINT", &[(Some(9223372036854775708i64), "9223372036854775708"),
                         (Some(-9223372036854775708i64), "-9223372036854775708"),
                         (None, "NULL")]);
}

#[test]
fn test_f32_params() {
    test_type("REAL", &[(Some(f32::INFINITY), "'infinity'"),
                       (Some(f32::NEG_INFINITY), "'-infinity'"),
                       (Some(1000.55), "1000.55"), (None, "NULL")]);
}

#[test]
fn test_f64_params() {
    test_type("DOUBLE PRECISION", &[(Some(f64::INFINITY), "'infinity'"),
                                   (Some(f64::NEG_INFINITY), "'-infinity'"),
                                   (Some(10000.55), "10000.55"),
                                   (None, "NULL")]);
}

#[test]
fn test_varchar_params() {
    test_type("VARCHAR", &[(Some("hello world".to_owned()), "'hello world'"),
                          (Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
                          (None, "NULL")]);
}

#[test]
fn test_text_params() {
    test_type("TEXT", &[(Some("hello world".to_owned()), "'hello world'"),
                       (Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
                       (None, "NULL")]);
}

#[test]
fn test_bpchar_params() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
                            id SERIAL PRIMARY KEY,
                            b CHAR(5)
                           )", &[]));
    or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
                           &[&Some("12345"), &Some("123"), &None::<&'static str>]));
    let stmt = or_panic!(conn.prepare("SELECT b FROM foo ORDER BY id"));
    let res = or_panic!(stmt.query(&[]));

    assert_eq!(vec!(Some("12345".to_owned()), Some("123  ".to_owned()), None),
               res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
}

#[test]
fn test_citext_params() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
                            id SERIAL PRIMARY KEY,
                            b CITEXT
                           )", &[]));
    or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
                           &[&Some("foobar"), &Some("FooBar"), &None::<&'static str>]));
    let stmt = or_panic!(conn.prepare("SELECT id FROM foo WHERE b = 'FOOBAR' ORDER BY id"));
    let res = or_panic!(stmt.query(&[]));

    assert_eq!(vec!(Some(1i32), Some(2i32)), res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
}

#[test]
fn test_bytea_params() {
    test_type("BYTEA", &[(Some(vec!(0u8, 1, 2, 3, 254, 255)), "'\\x00010203feff'"),
                        (None, "NULL")]);
}

#[test]
fn test_hstore_params() {
    macro_rules! make_map {
        ($($k:expr => $v:expr),+) => ({
            let mut map = HashMap::new();
            $(map.insert($k, $v);)+
            map
        })
    }
    test_type("hstore",
              &[(Some(make_map!("a".to_owned() => Some("1".to_owned()))), "'a=>1'"),
               (Some(make_map!("hello".to_owned() => Some("world!".to_owned()),
                               "hola".to_owned() => Some("mundo!".to_owned()),
                               "what".to_owned() => None)),
                "'hello=>world!,hola=>mundo!,what=>NULL'"),
                (None, "NULL")]);
}

fn test_nan_param<T: PartialEq+ToSql+FromSql>(sql_type: &str) {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    let stmt = or_panic!(conn.prepare(&*format!("SELECT 'NaN'::{}", sql_type)));
    let result = or_panic!(stmt.query(&[]));
    let val: T = result.iter().next().unwrap().get(0);
    assert!(val != val);
}

#[test]
fn test_f32_nan_param() {
    test_nan_param::<f32>("REAL");
}

#[test]
fn test_f64_nan_param() {
    test_nan_param::<f64>("DOUBLE PRECISION");
}

#[test]
fn test_pg_database_datname() {
    let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
    let stmt = or_panic!(conn.prepare("SELECT datname FROM pg_database"));
    let result = or_panic!(stmt.query(&[]));

    let next = result.iter().next().unwrap();
    or_panic!(next.get_opt::<_, String>(0).unwrap());
    or_panic!(next.get_opt::<_, String>("datname").unwrap());
}

#[test]
fn test_slice() {
    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();
    conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY, f VARCHAR);
                        INSERT INTO foo (f) VALUES ('a'), ('b'), ('c'), ('d');").unwrap();

    let stmt = conn.prepare("SELECT f FROM foo WHERE id = ANY($1)").unwrap();
    let result = stmt.query(&[&Slice(&[1i32, 3, 4])]).unwrap();
    assert_eq!(vec!["a".to_owned(), "c".to_owned(), "d".to_owned()],
               result.iter().map(|r| r.get::<_, String>(0)).collect::<Vec<_>>());
}

#[test]
fn test_slice_wrong_type() {
    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();
    conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY)").unwrap();

    let stmt = conn.prepare("SELECT * FROM foo WHERE id = ANY($1)").unwrap();
    match stmt.query(&[&Slice(&["hi"])]) {
        Ok(_) => panic!("Unexpected success"),
        Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
        Err(e) => panic!("Unexpected error {:?}", e),
    };
}

#[test]
fn test_slice_range() {
    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();

    let stmt = conn.prepare("SELECT $1::INT8RANGE").unwrap();
    match stmt.query(&[&Slice(&[1i64])]) {
        Ok(_) => panic!("Unexpected success"),
        Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
        Err(e) => panic!("Unexpected error {:?}", e),
    };
}

#[test]
fn domain() {
    #[derive(Debug, PartialEq)]
    struct SessionId(Vec<u8>);

    impl ToSql for SessionId {
        fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
            where W: Write
        {
            let inner = match *ty.kind() {
                Kind::Domain(ref inner) => inner,
                _ => unreachable!(),
            };
            self.0.to_sql(inner, out, ctx)
        }

        fn accepts(ty: &Type) -> bool {
            ty.name() == "session_id" && match *ty.kind() { Kind::Domain(_) => true, _ => false }
        }

        to_sql_checked!();
    }

    impl FromSql for SessionId {
        fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self> {
            Vec::<u8>::from_sql(ty, raw, ctx).map(SessionId)
        }

        fn accepts(ty: &Type) -> bool {
            // This is super weird!
            <Vec<u8> as FromSql>::accepts(ty)
        }
    }

    let conn = Connection::connect("postgres://postgres@localhost", SslMode::None).unwrap();
    conn.batch_execute("CREATE DOMAIN pg_temp.session_id AS bytea CHECK(octet_length(VALUE) = 16);
                        CREATE TABLE pg_temp.foo (id pg_temp.session_id);")
        .unwrap();

    let id = SessionId(b"0123456789abcdef".to_vec());
    conn.execute("INSERT INTO pg_temp.foo (id) VALUES ($1)", &[&id]).unwrap();
    let rows = conn.query("SELECT id FROM pg_temp.foo", &[]).unwrap();
    assert_eq!(id, rows.get(0).get(0));
}
<|endoftext|>


<commit_before>use std::ops::Neg;
use std::{f32, f64};
use std::num::Wrapping;

use Num;

/// Useful functions for signed numbers (i.e. numbers that can be negative).
pub trait Signed: Sized + Num + Neg<Output = Self> {
    /// Computes the absolute value.
    ///
    /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
    ///
    /// For signed integers, `::MIN` will be returned if the number is `::MIN`.
    fn abs(&self) -> Self;

    /// The positive difference of two numbers.
    ///
    /// Returns `zero` if the number is less than or equal to `other`, otherwise the difference
    /// between `self` and `other` is returned.
    fn abs_sub(&self, other: &Self) -> Self;

    /// Returns the sign of the number.
    ///
    /// For `f32` and `f64`:
    ///
    /// * `1.0` if the number is positive, `+0.0` or `INFINITY`
    /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
    /// * `NaN` if the number is `NaN`
    ///
    /// For signed integers:
    ///
    /// * `0` if the number is zero
    /// * `1` if the number is positive
    /// * `-1` if the number is negative
    fn signum(&self) -> Self;

    /// Returns true if the number is positive and false if the number is zero or negative.
    fn is_positive(&self) -> bool;

    /// Returns true if the number is negative and false if the number is zero or positive.
    fn is_negative(&self) -> bool;
}

macro_rules! signed_impl {
    ($($t:ty)*) => ($(
        impl Signed for $t {
            #[inline]
            fn abs(&self) -> $t {
                if self.is_negative() { -*self } else { *self }
            }

            #[inline]
            fn abs_sub(&self, other: &$t) -> $t {
                if *self <= *other { 0 } else { *self - *other }
            }

            #[inline]
            fn signum(&self) -> $t {
                match *self {
                    n if n > 0 => 1,
                    0 => 0,
                    _ => -1,
                }
            }

            #[inline]
            fn is_positive(&self) -> bool { *self > 0 }

            #[inline]
            fn is_negative(&self) -> bool { *self < 0 }
        }
    )*)
}

signed_impl!(isize i8 i16 i32 i64);

impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Self>
{
    #[inline]
    fn abs(&self) -> Self {
        Wrapping(self.0.abs())
    }

    #[inline]
    fn abs_sub(&self, other: &Self) -> Self {
        Wrapping(self.0.abs_sub(&other.0))
    }

    #[inline]
    fn signum(&self) -> Self {
        Wrapping(self.0.signum())
    }

    #[inline]
    fn is_positive(&self) -> bool { self.0.is_positive() }

    #[inline]
    fn is_negative(&self) -> bool { self.0.is_negative() }
}

macro_rules! signed_float_impl {
    ($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => {
        impl Signed for $t {
            /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
            #[inline]
            fn abs(&self) -> $t {
                <$t>::abs(*self)
            }

            /// The positive difference of two numbers. Returns `0.0` if the number is
            /// less than or equal to `other`, otherwise the difference between`self`
            /// and `other` is returned.
            #[inline]
            #[allow(deprecated)]
            fn abs_sub(&self, other: &$t) -> $t {
                <$t>::abs_sub(*self, *other)
            }

            /// # Returns
            ///
            /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
            /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
            /// - `NAN` if the number is NaN
            #[inline]
            fn signum(&self) -> $t {
                <$t>::signum(*self)
            }

            /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
            #[inline]
            fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf }

            /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
            #[inline]
            fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == $neg_inf }
        }
    }
}

signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY);
signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY);

/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
///
/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
    value.abs()
}

/// The positive difference of two numbers.
///
/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
/// between `x` and `y` is returned.
#[inline(always)]
pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
    x.abs_sub(&y)
}

/// Returns the sign of the number.
///
/// For `f32` and `f64`:
///
/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
/// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
/// * `-1` if the number is negative
#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }

/// A trait for values which cannot be negative
pub trait Unsigned: Num {}

macro_rules! empty_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {}
    )*)
}

empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);

impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
<commit_msg>Small fix for older Rust versions<commit_after>use std::ops::Neg;
use std::{f32, f64};
use std::num::Wrapping;

use Num;

/// Useful functions for signed numbers (i.e. numbers that can be negative).
pub trait Signed: Sized + Num + Neg<Output = Self> {
    /// Computes the absolute value.
    ///
    /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
    ///
    /// For signed integers, `::MIN` will be returned if the number is `::MIN`.
    fn abs(&self) -> Self;

    /// The positive difference of two numbers.
    ///
    /// Returns `zero` if the number is less than or equal to `other`, otherwise the difference
    /// between `self` and `other` is returned.
    fn abs_sub(&self, other: &Self) -> Self;

    /// Returns the sign of the number.
    ///
    /// For `f32` and `f64`:
    ///
    /// * `1.0` if the number is positive, `+0.0` or `INFINITY`
    /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
    /// * `NaN` if the number is `NaN`
    ///
    /// For signed integers:
    ///
    /// * `0` if the number is zero
    /// * `1` if the number is positive
    /// * `-1` if the number is negative
    fn signum(&self) -> Self;

    /// Returns true if the number is positive and false if the number is zero or negative.
    fn is_positive(&self) -> bool;

    /// Returns true if the number is negative and false if the number is zero or positive.
    fn is_negative(&self) -> bool;
}

macro_rules! signed_impl {
    ($($t:ty)*) => ($(
        impl Signed for $t {
            #[inline]
            fn abs(&self) -> $t {
                if self.is_negative() { -*self } else { *self }
            }

            #[inline]
            fn abs_sub(&self, other: &$t) -> $t {
                if *self <= *other { 0 } else { *self - *other }
            }

            #[inline]
            fn signum(&self) -> $t {
                match *self {
                    n if n > 0 => 1,
                    0 => 0,
                    _ => -1,
                }
            }

            #[inline]
            fn is_positive(&self) -> bool { *self > 0 }

            #[inline]
            fn is_negative(&self) -> bool { *self < 0 }
        }
    )*)
}

signed_impl!(isize i8 i16 i32 i64);

impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapping<T>>
{
    #[inline]
    fn abs(&self) -> Self {
        Wrapping(self.0.abs())
    }

    #[inline]
    fn abs_sub(&self, other: &Self) -> Self {
        Wrapping(self.0.abs_sub(&other.0))
    }

    #[inline]
    fn signum(&self) -> Self {
        Wrapping(self.0.signum())
    }

    #[inline]
    fn is_positive(&self) -> bool { self.0.is_positive() }

    #[inline]
    fn is_negative(&self) -> bool { self.0.is_negative() }
}

macro_rules! signed_float_impl {
    ($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => {
        impl Signed for $t {
            /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
            #[inline]
            fn abs(&self) -> $t {
                <$t>::abs(*self)
            }

            /// The positive difference of two numbers. Returns `0.0` if the number is
            /// less than or equal to `other`, otherwise the difference between`self`
            /// and `other` is returned.
            #[inline]
            #[allow(deprecated)]
            fn abs_sub(&self, other: &$t) -> $t {
                <$t>::abs_sub(*self, *other)
            }

            /// # Returns
            ///
            /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
            /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
            /// - `NAN` if the number is NaN
            #[inline]
            fn signum(&self) -> $t {
                <$t>::signum(*self)
            }

            /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
            #[inline]
            fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf }

            /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
            #[inline]
            fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == $neg_inf }
        }
    }
}

signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY);
signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY);

/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
///
/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
    value.abs()
}

/// The positive difference of two numbers.
///
/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
/// between `x` and `y` is returned.
#[inline(always)]
pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
    x.abs_sub(&y)
}

/// Returns the sign of the number.
///
/// For `f32` and `f64`:
///
/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
/// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
/// * `-1` if the number is negative
#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }

/// A trait for values which cannot be negative
pub trait Unsigned: Num {}

macro_rules! empty_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {}
    )*)
}

empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);

impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
<|endoftext|>