<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct Cr2Decoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> Cr2Decoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> Cr2Decoder<'a> {
    Cr2Decoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for Cr2Decoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let (raw, offset) = {
      if let Some(raw) = self.tiff.find_first_ifd(Tag::Cr2Id) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(raw) = self.tiff.find_first_ifd(Tag::CFAPattern) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(off) = self.tiff.find_entry(Tag::Cr2OldOffset) {
        (&self.tiff, off.get_usize(0))
      } else {
        return Err("CR2: Couldn't find raw info".to_string())
      }
    };
    let src = &self.buffer[offset..];

    let (width, height, cpp, image) = {
      let decompressor = try!(LjpegDecompressor::new(src, true));
      let width = decompressor.width();
      let height = decompressor.height();
      let cpp = if decompressor.super_h() == 2 {3} else {1};
      let mut ljpegout = vec![0 as u16; width*height];
      try!(decompressor.decode(&mut ljpegout, 0, width, width, height));

      // Linearize the output (applies only to D2000 as far as I can tell)
      if camera.find_hint("linearization") {
        let table = {
          let linearization = fetch_tag!(self.tiff, Tag::GrayResponse);
          let mut t = [0 as u16;4096];
          for i in 0..t.len() {
            t[i] = linearization.get_u32(i) as u16;
          }
          LookupTable::new(&t)
        };

        let mut random = ljpegout[0] as u32;
        for o in ljpegout.chunks_mut(1) {
          o[0] = table.dither(o[0], &mut random);
        }
      }

      // Convert the YUV in sRAWs to RGB
      if cpp == 3 {
        try!(self.convert_to_rgb(camera, &mut ljpegout));
      }

      // Take each of the vertical fields and put them into the right location
      // FIXME: Doing this at the decode would reduce about 5% in runtime but I haven't
      //        been able to do it without hairy code
      if let Some(canoncol) = raw.find_entry(Tag::Cr2StripeWidths) {
        if canoncol.get_usize(0) == 0 {
          (width, height, cpp, ljpegout)
        } else {
          let mut out = vec![0 as u16; width*height];
          let mut fieldwidths = Vec::new();
          for _ in 0..canoncol.get_usize(0) {
            fieldwidths.push(canoncol.get_usize(1));
          }
          fieldwidths.push(canoncol.get_usize(2));

          if decompressor.super_v() == 2 {
            // We've decoded 2 lines at a time so we also need to copy two strips at a time
            let nfields = fieldwidths.len();
            let fieldwidth = fieldwidths[0];
            let mut fieldstart = 0;
            let mut inpos = 0;
            for _ in 0..nfields {
              let mut row = 0;
              while row < height {
                for _ in 0..nfields {
                  let outpos = row*width+fieldstart;
                  {
                    let outb = &mut out[outpos..outpos+fieldwidth];
                    let inb = &ljpegout[inpos..inpos+fieldwidth];
                    outb.copy_from_slice(inb);
                    row += 1;
                  }
                  let outpos = row*width+fieldstart;
                  let outb = &mut out[outpos..outpos+fieldwidth];
                  let inb = &ljpegout[inpos+width..inpos+width+fieldwidth];
                  outb.copy_from_slice(inb);
                  row += 1;
                  inpos += fieldwidth;
                }
                inpos += width; // skip the line we already used
              }
              fieldstart += fieldwidth;
            }
          } else {
            let sh = decompressor.super_h();
            let mut fieldstart = 0;
            let mut fieldpos = 0;
            for fieldwidth in fieldwidths {
              let fieldwidth = fieldwidth/sh*cpp;
              for row in 0..height {
                let outpos = row*width+fieldstart;
                let inpos = fieldpos+row*fieldwidth;
                let outb = &mut out[outpos..outpos+fieldwidth];
                let inb = &ljpegout[inpos..inpos+fieldwidth];
                outb.copy_from_slice(inb);
              }
              fieldstart += fieldwidth;
              fieldpos += fieldwidth*height;
            }
          }

          (width, height, cpp, out)
        }
      } else if camera.find_hint("double_line") {
        (width/2, height*2, cpp, ljpegout)
      } else {
        (width, height, cpp, ljpegout)
      }
    };

    let mut img = Image::new(camera, width, height, try!(self.get_wb(camera)), image);
    if cpp == 3 {
      img.cpp = 3;
      img.width /= 3;
      img.crops = [0,0,0,0];
      img.blacklevels = [0,0,0,0];
      img.whitelevels = [65535,65535,65535,65535];
    }
    Ok(img)
  }
}

impl<'a> Cr2Decoder<'a> {
  fn get_wb(&self, cam: &Camera) -> Result<[f32;4], String> {
    if let Some(levels) = self.tiff.find_entry(Tag::Cr2ColorData) {
      let offset = if cam.wb_offset != 0 {cam.wb_offset} else {63};
      Ok([levels.get_force_u16(offset) as f32, levels.get_force_u16(offset+1) as f32,
          levels.get_force_u16(offset+3) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2PowerShotWB) {
      Ok([levels.get_force_u32(3) as f32, levels.get_force_u32(2) as f32,
          levels.get_force_u32(4) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2OldWB) {
      Ok([levels.get_f32(0), levels.get_f32(1), levels.get_f32(2), NAN])
    } else {
      // At least the D2000 has no WB
      Ok([NAN,NAN,NAN,NAN])
    }
  }

  fn convert_to_rgb(&self, cam: &Camera, image: &mut [u16]) -> Result<(),String>{
    let coeffs = try!(self.get_wb(cam));
    let c1 = (1024.0*1024.0/coeffs[0]) as i32;
    let c2 = coeffs[1] as i32;
    let c3 = (1024.0*1024.0/coeffs[2]) as i32;

    for pix in image.chunks_mut(3) {
      let y = pix[0] as i32;
      let cb = pix[1] as i32 - 16380;
      let cr = pix[2] as i32 - 16380;

      let r = c1 * (y + cr);
      let g = c2 * (y + ((-778*cb - (cr<<11)) >> 12));
      let b = c3 * (y + cb);

      pix[0] = (r >> 8) as u16;
      pix[1] = (g >> 8) as u16;
      pix[2] = (b >> 8) as u16;
    }
    Ok(())
  }
}
<commit_msg>CR2: handle swapped width/height<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct Cr2Decoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> Cr2Decoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> Cr2Decoder<'a> {
    Cr2Decoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for Cr2Decoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let (raw, offset) = {
      if let Some(raw) = self.tiff.find_first_ifd(Tag::Cr2Id) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(raw) = self.tiff.find_first_ifd(Tag::CFAPattern) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(off) = self.tiff.find_entry(Tag::Cr2OldOffset) {
        (&self.tiff, off.get_usize(0))
      } else {
        return Err("CR2: Couldn't find raw info".to_string())
      }
    };
    let src = &self.buffer[offset..];

    let (width, height, cpp, image) = {
      let decompressor = try!(LjpegDecompressor::new(src, true));
      let mut width = decompressor.width();
      let mut height = decompressor.height();
      let cpp = if decompressor.super_h() == 2 {3} else {1};
      let mut ljpegout = vec![0 as u16; width*height];
      try!(decompressor.decode(&mut ljpegout, 0, width, width, height));

      // Linearize the output (applies only to D2000 as far as I can tell)
      if camera.find_hint("linearization") {
        let table = {
          let linearization = fetch_tag!(self.tiff, Tag::GrayResponse);
          let mut t = [0 as u16;4096];
          for i in 0..t.len() {
            t[i] = linearization.get_u32(i) as u16;
          }
          LookupTable::new(&t)
        };

        let mut random = ljpegout[0] as u32;
        for o in ljpegout.chunks_mut(1) {
          o[0] = table.dither(o[0], &mut random);
        }
      }

      // Convert the YUV in sRAWs to RGB
      if cpp == 3 {
        try!(self.convert_to_rgb(camera, &mut ljpegout));
        if width/cpp < height {
          let temp = width/cpp;
          width = height*cpp;
          height = temp;
        }
      }

      // Take each of the vertical fields and put them into the right location
      // FIXME: Doing this at the decode would reduce about 5% in runtime but I haven't
      //        been able to do it without hairy code
      if let Some(canoncol) = raw.find_entry(Tag::Cr2StripeWidths) {
        if canoncol.get_usize(0) == 0 {
          (width, height, cpp, ljpegout)
        } else {
          let mut out = vec![0 as u16; width*height];
          let mut fieldwidths = Vec::new();
          for _ in 0..canoncol.get_usize(0) {
            fieldwidths.push(canoncol.get_usize(1));
          }
          fieldwidths.push(canoncol.get_usize(2));

          if decompressor.super_v() == 2 {
            // We've decoded 2 lines at a time so we also need to copy two strips at a time
            let nfields = fieldwidths.len();
            let fieldwidth = fieldwidths[0];
            let mut fieldstart = 0;
            let mut inpos = 0;
            for _ in 0..nfields {
              let mut row = 0;
              while row < height {
                for _ in 0..nfields {
                  let outpos = row*width+fieldstart;
                  {
                    let outb = &mut out[outpos..outpos+fieldwidth];
                    let inb = &ljpegout[inpos..inpos+fieldwidth];
                    outb.copy_from_slice(inb);
                    row += 1;
                  }
                  let outpos = row*width+fieldstart;
                  let outb = &mut out[outpos..outpos+fieldwidth];
                  let inb = &ljpegout[inpos+width..inpos+width+fieldwidth];
                  outb.copy_from_slice(inb);
                  row += 1;
                  inpos += fieldwidth;
                }
                inpos += width; // skip the line we already used
              }
              fieldstart += fieldwidth;
            }
          } else {
            let sh = decompressor.super_h();
            let mut fieldstart = 0;
            let mut fieldpos = 0;
            for fieldwidth in fieldwidths {
              let fieldwidth = fieldwidth/sh*cpp;
              for row in 0..height {
                let outpos = row*width+fieldstart;
                let inpos = fieldpos+row*fieldwidth;
                let outb = &mut out[outpos..outpos+fieldwidth];
                let inb = &ljpegout[inpos..inpos+fieldwidth];
                outb.copy_from_slice(inb);
              }
              fieldstart += fieldwidth;
              fieldpos += fieldwidth*height;
            }
          }

          (width, height, cpp, out)
        }
      } else if camera.find_hint("double_line") {
        (width/2, height*2, cpp, ljpegout)
      } else {
        (width, height, cpp, ljpegout)
      }
    };

    let mut img = Image::new(camera, width, height, try!(self.get_wb(camera)), image);
    if cpp == 3 {
      img.cpp = 3;
      img.width /= 3;
      img.crops = [0,0,0,0];
      img.blacklevels = [0,0,0,0];
      img.whitelevels = [65535,65535,65535,65535];
    }
    Ok(img)
  }
}

impl<'a> Cr2Decoder<'a> {
  fn get_wb(&self, cam: &Camera) -> Result<[f32;4], String> {
    if let Some(levels) = self.tiff.find_entry(Tag::Cr2ColorData) {
      let offset = if cam.wb_offset != 0 {cam.wb_offset} else {63};
      Ok([levels.get_force_u16(offset) as f32, levels.get_force_u16(offset+1) as f32,
          levels.get_force_u16(offset+3) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2PowerShotWB) {
      Ok([levels.get_force_u32(3) as f32, levels.get_force_u32(2) as f32,
          levels.get_force_u32(4) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2OldWB) {
      Ok([levels.get_f32(0), levels.get_f32(1), levels.get_f32(2), NAN])
    } else {
      // At least the D2000 has no WB
      Ok([NAN,NAN,NAN,NAN])
    }
  }

  fn convert_to_rgb(&self, cam: &Camera, image: &mut [u16]) -> Result<(),String>{
    let coeffs = try!(self.get_wb(cam));
    let c1 = (1024.0*1024.0/coeffs[0]) as i32;
    let c2 = coeffs[1] as i32;
    let c3 = (1024.0*1024.0/coeffs[2]) as i32;

    for pix in image.chunks_mut(3) {
      let y = pix[0] as i32;
      let cb = pix[1] as i32 - 16380;
      let cr = pix[2] as i32 - 16380;

      let r = c1 * (y + cr);
      let g = c2 * (y + ((-778*cb - (cr<<11)) >> 12));
      let b = c3 * (y + cb);

      pix[0] = (r >> 8) as u16;
      pix[1] = (g >> 8) as u16;
      pix[2] = (b >> 8) as u16;
    }
    Ok(())
  }
}
<|endoftext|>


<commit_before>use pin_project::pin_project;
use rustls::{ClientConfig as TlsClientConfig,
             ServerConfig as TlsServerConfig,
             ServerName};
use std::{convert::TryFrom,
          pin::Pin,
          sync::Arc,
          task::{Context,
                 Poll}};
use tokio::{io::{self,
                 AsyncRead,
                 AsyncWrite,
                 ReadBuf},
            net::TcpStream};
use tokio_rustls::{TlsAcceptor,
                   TlsConnector,
                   TlsStream};

/// A wrapper type that can either be a raw TCP stream or a TCP stream with TLS.
#[pin_project(project = TcpOrTlsStreamProj)]
#[allow(clippy::large_enum_variant)]
pub enum TcpOrTlsStream {
    TcpStream(#[pin] TcpStream),
    TlsStream(#[pin] TlsStream<TcpStream>),
}

impl TcpOrTlsStream {
    /// Create a new `TcpStream`
    pub fn new(stream: TcpStream) -> Self { Self::TcpStream(stream) }

    /// Create a new `TlsStream` using server configuration
    pub async fn new_tls_server(stream: TcpStream,
                                tls_config: Arc<TlsServerConfig>)
                                -> Result<Self, (io::Error, TcpStream)> {
        let tcp_stream = Self::new(stream);
        tcp_stream.maybe_upgrade_to_tls_server(tls_config).await
    }

    /// Create a new `TlsStream` using client configuration
    pub async fn new_tls_client(stream: TcpStream,
                                tls_config: Arc<TlsClientConfig>,
                                domain: &str)
                                -> Result<Self, (io::Error, TcpStream)> {
        let tcp_stream = Self::new(stream);
        tcp_stream.maybe_upgrade_to_tls_client(tls_config, domain)
                  .await
    }

    /// Upgrade a `TcpStream` into a `TlsStream` using server configuration
    async fn maybe_upgrade_to_tls_server(self,
                                         tls_config: Arc<TlsServerConfig>)
                                         -> Result<Self, (io::Error, TcpStream)> {
        let tls_server_stream = match self {
            Self::TcpStream(stream) => {
                let tls_acceptor = TlsAcceptor::from(tls_config);
                let tls_stream = tls_acceptor.accept(stream).into_fallible().await?;
                Self::TlsStream(TlsStream::Server(tls_stream))
            }
            stream @ Self::TlsStream(_) => stream,
        };
        Ok(tls_server_stream)
    }

    /// Upgrade a `TcpStream` to a `TlsStream` using client configuration
    async fn maybe_upgrade_to_tls_client(self,
                                         tls_config: Arc<TlsClientConfig>,
                                         domain: &str)
                                         -> Result<Self, (io::Error, TcpStream)> {
        let tls_client_stream = match self {
            Self::TcpStream(stream) => {
                let tls_connector = TlsConnector::from(tls_config);
                let server_name = match ServerName::try_from(domain) {
                    Ok(name) => name,
                    Err(_) => {
                        let error = io::Error::new(io::ErrorKind::InvalidInput,
                                                   format!("invalid DNS name '{}'", domain));
                        return Err((error, stream));
                    }
                };
                let tls_stream = tls_connector.connect(server_name, stream)
                                              .into_fallible()
                                              .await?;
                Self::TlsStream(TlsStream::Client(tls_stream))
            }
            stream @ Self::TlsStream(_) => stream,
        };
        Ok(tls_client_stream)
    }
}

impl AsyncRead for TcpOrTlsStream {
    fn poll_read(self: Pin<&mut Self>,
                 cx: &mut Context,
                 buf: &mut ReadBuf<'_>)
                 -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_read(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for TcpOrTlsStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_write(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_flush(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_shutdown(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_shutdown(cx),
        }
    }
}
<commit_msg>handle UnexpectedEof in the case of speaking to an older supervisor<commit_after>use pin_project::pin_project;
use rustls::{ClientConfig as TlsClientConfig,
             ServerConfig as TlsServerConfig,
             ServerName};
use std::{convert::TryFrom,
          pin::Pin,
          sync::Arc,
          task::{Context,
                 Poll}};
use tokio::{io::{self,
                 AsyncRead,
                 AsyncWrite,
                 ReadBuf},
            net::TcpStream};
use tokio_rustls::{TlsAcceptor,
                   TlsConnector,
                   TlsStream};

/// A wrapper type that can either be a raw TCP stream or a TCP stream with TLS.
#[pin_project(project = TcpOrTlsStreamProj)]
#[allow(clippy::large_enum_variant)]
pub enum TcpOrTlsStream {
    TcpStream(#[pin] TcpStream),
    TlsStream(#[pin] TlsStream<TcpStream>),
}

impl TcpOrTlsStream {
    /// Create a new `TcpStream`
    pub fn new(stream: TcpStream) -> Self { Self::TcpStream(stream) }

    /// Create a new `TlsStream` using server configuration
    pub async fn new_tls_server(stream: TcpStream,
                                tls_config: Arc<TlsServerConfig>)
                                -> Result<Self, (io::Error, TcpStream)> {
        let tcp_stream = Self::new(stream);
        tcp_stream.maybe_upgrade_to_tls_server(tls_config).await
    }

    /// Create a new `TlsStream` using client configuration
    pub async fn new_tls_client(stream: TcpStream,
                                tls_config: Arc<TlsClientConfig>,
                                domain: &str)
                                -> Result<Self, (io::Error, TcpStream)> {
        let tcp_stream = Self::new(stream);
        tcp_stream.maybe_upgrade_to_tls_client(tls_config, domain)
                  .await
    }

    /// Upgrade a `TcpStream` into a `TlsStream` using server configuration
    async fn maybe_upgrade_to_tls_server(self,
                                         tls_config: Arc<TlsServerConfig>)
                                         -> Result<Self, (io::Error, TcpStream)> {
        let tls_server_stream = match self {
            Self::TcpStream(stream) => {
                let tls_acceptor = TlsAcceptor::from(tls_config);
                let tls_stream = tls_acceptor.accept(stream).into_fallible().await?;
                Self::TlsStream(TlsStream::Server(tls_stream))
            }
            stream @ Self::TlsStream(_) => stream,
        };
        Ok(tls_server_stream)
    }

    /// Upgrade a `TcpStream` to a `TlsStream` using client configuration
    async fn maybe_upgrade_to_tls_client(self,
                                         tls_config: Arc<TlsClientConfig>,
                                         domain: &str)
                                         -> Result<Self, (io::Error, TcpStream)> {
        let tls_client_stream = match self {
            Self::TcpStream(stream) => {
                let tls_connector = TlsConnector::from(tls_config);
                let server_name = match ServerName::try_from(domain) {
                    Ok(name) => name,
                    Err(_) => {
                        let error = io::Error::new(io::ErrorKind::InvalidInput,
                                                   format!("invalid DNS name '{}'", domain));
                        return Err((error, stream));
                    }
                };
                let tls_stream = tls_connector.connect(server_name, stream)
                                              .into_fallible()
                                              .await?;
                Self::TlsStream(TlsStream::Client(tls_stream))
            }
            stream @ Self::TlsStream(_) => stream,
        };
        Ok(tls_client_stream)
    }
}

impl AsyncRead for TcpOrTlsStream {
    fn poll_read(self: Pin<&mut Self>,
                 cx: &mut Context,
                 buf: &mut ReadBuf<'_>)
                 -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_read(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => {
                match stream.poll_read(cx, buf) {
                    // As of rustls 0.20.0, a UnexpectedEof is returned when reading from
                    // a connection that has not been cleanly closed. The supervisor now
                    // sends a close_notify by calling poll_shutdown on the stream when
                    // a message is sent from the ctl-gateway. While that avoids the
                    // UnexpectedEof, it is possible that a supervisor client in a hab cli
                    // using rustls > 0.20.0 will be communicating with a < 0.20.0 supervisor.
                    // For that case, we check here for a UnexpectedEof and return
                    // Poll::Ready(Ok(())) to mimic the 0.19 rustls behavior. We should
                    // consider removing this when releasing a habitat 2.0.
                    Poll::Ready(Err(err)) if err.kind() == io::ErrorKind::UnexpectedEof => {
                        Poll::Ready(Ok(()))
                    }
                    output => output,
                }
            }
        }
    }
}

impl AsyncWrite for TcpOrTlsStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_write(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_flush(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_shutdown(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_shutdown(cx),
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use euclid::point::{Point2D, TypedPoint2D};
use gecko_bindings::structs::{nsTimingFunction, nsTimingFunction_Type};
use properties::longhands::transition_timing_function::single_value::FunctionKeyword;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use properties::longhands::transition_timing_function::single_value::computed_value::StartEnd;
use properties::longhands::transition_timing_function::single_value::computed_value::T as ComputedTimingFunction;
use std::mem;

impl nsTimingFunction {
    fn set_as_step(&mut self, function_type: nsTimingFunction_Type, steps: u32) {
        debug_assert!(function_type == nsTimingFunction_Type::StepStart ||
                      function_type == nsTimingFunction_Type::StepEnd,
                      "function_type should be step-start or step-end");
        self.mType = function_type;
        unsafe {
            self.__bindgen_anon_1.__bindgen_anon_1.as_mut().mSteps = steps;
        }
    }

    fn set_as_cubic_bezier(&mut self, p1: Point2D<f32>, p2: Point2D<f32>) {
        self.mType = nsTimingFunction_Type::CubicBezier;
        unsafe {
            let ref mut gecko_cubic_bezier =
                unsafe { self.__bindgen_anon_1.mFunc.as_mut() };
            gecko_cubic_bezier.mX1 = p1.x;
            gecko_cubic_bezier.mY1 = p1.y;
            gecko_cubic_bezier.mX2 = p2.x;
            gecko_cubic_bezier.mY2 = p2.y;
        }
    }
}

impl From<ComputedTimingFunction> for nsTimingFunction {
    fn from(function: ComputedTimingFunction) -> nsTimingFunction {
        let mut tf: nsTimingFunction = unsafe { mem::zeroed() };

        match function {
            ComputedTimingFunction::Steps(steps, StartEnd::Start) => {
                tf.set_as_step(nsTimingFunction_Type::StepStart, steps);
            },
            ComputedTimingFunction::Steps(steps, StartEnd::End) => {
                tf.set_as_step(nsTimingFunction_Type::StepEnd, steps);
            },
            ComputedTimingFunction::CubicBezier(p1, p2) => {
                tf.set_as_cubic_bezier(p1, p2);
            },
        }
        tf
    }
}

impl From<SpecifiedTimingFunction> for nsTimingFunction {
    fn from(function: SpecifiedTimingFunction) -> nsTimingFunction {
        let mut tf: nsTimingFunction = unsafe { mem::zeroed() };

        match function {
            SpecifiedTimingFunction::Steps(steps, StartEnd::Start) => {
                tf.set_as_step(nsTimingFunction_Type::StepStart, steps);
            },
            SpecifiedTimingFunction::Steps(steps, StartEnd::End) => {
                tf.set_as_step(nsTimingFunction_Type::StepEnd, steps);
            },
            SpecifiedTimingFunction::CubicBezier(p1, p2) => {
                tf.set_as_cubic_bezier(p1, p2);
            },
            SpecifiedTimingFunction::Keyword(keyword) => {
                match keyword {
                    FunctionKeyword::Ease => tf.mType = nsTimingFunction_Type::Ease,
                    FunctionKeyword::Linear => tf.mType = nsTimingFunction_Type::Linear,
                    FunctionKeyword::EaseIn => tf.mType = nsTimingFunction_Type::EaseIn,
                    FunctionKeyword::EaseOut => tf.mType = nsTimingFunction_Type::EaseOut,
                    FunctionKeyword::EaseInOut => tf.mType = nsTimingFunction_Type::EaseInOut,
                    FunctionKeyword::StepStart => {
                        tf.set_as_step(nsTimingFunction_Type::StepStart, 1);
                    },
                    FunctionKeyword::StepEnd => {
                        tf.set_as_step(nsTimingFunction_Type::StepEnd, 1);
                    },
                }
            },
        }
        tf
    }
}

impl From<nsTimingFunction> for ComputedTimingFunction {
    fn from(function: nsTimingFunction) -> ComputedTimingFunction {
        match function.mType {
            nsTimingFunction_Type::StepStart => {
                ComputedTimingFunction::Steps(unsafe { function.__bindgen_anon_1.__bindgen_anon_1.as_ref().mSteps },
                                              StartEnd::Start)
            },
            nsTimingFunction_Type::StepEnd => {
                ComputedTimingFunction::Steps(unsafe { function.__bindgen_anon_1.__bindgen_anon_1.as_ref().mSteps },
                                              StartEnd::End)
            },
            nsTimingFunction_Type::Ease |
            nsTimingFunction_Type::Linear |
            nsTimingFunction_Type::EaseIn |
            nsTimingFunction_Type::EaseOut |
            nsTimingFunction_Type::EaseInOut |
            nsTimingFunction_Type::CubicBezier => {
                ComputedTimingFunction::CubicBezier(
                    TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX1 },
                                      unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY1 }),
                    TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX2 },
                                      unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY2 }))
            },
        }
    }
}
<commit_msg>Bug 1248340 - Update the step data member in ns_timing_function.rs.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use euclid::point::{Point2D, TypedPoint2D};
use gecko_bindings::structs::{nsTimingFunction, nsTimingFunction_Type};
use properties::longhands::transition_timing_function::single_value::FunctionKeyword;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use properties::longhands::transition_timing_function::single_value::computed_value::StartEnd;
use properties::longhands::transition_timing_function::single_value::computed_value::T as ComputedTimingFunction;
use std::mem;

impl nsTimingFunction {
    fn set_as_step(&mut self, function_type: nsTimingFunction_Type, steps: u32) {
        debug_assert!(function_type == nsTimingFunction_Type::StepStart ||
                      function_type == nsTimingFunction_Type::StepEnd,
                      "function_type should be step-start or step-end");
        self.mType = function_type;
        unsafe {
            self.__bindgen_anon_1.__bindgen_anon_1.as_mut().mStepsOrFrames = steps;
        }
    }

    fn set_as_cubic_bezier(&mut self, p1: Point2D<f32>, p2: Point2D<f32>) {
        self.mType = nsTimingFunction_Type::CubicBezier;
        unsafe {
            let ref mut gecko_cubic_bezier =
                unsafe { self.__bindgen_anon_1.mFunc.as_mut() };
            gecko_cubic_bezier.mX1 = p1.x;
            gecko_cubic_bezier.mY1 = p1.y;
            gecko_cubic_bezier.mX2 = p2.x;
            gecko_cubic_bezier.mY2 = p2.y;
        }
    }
}

impl From<ComputedTimingFunction> for nsTimingFunction {
    fn from(function: ComputedTimingFunction) -> nsTimingFunction {
        let mut tf: nsTimingFunction = unsafe { mem::zeroed() };

        match function {
            ComputedTimingFunction::Steps(steps, StartEnd::Start) => {
                tf.set_as_step(nsTimingFunction_Type::StepStart, steps);
            },
            ComputedTimingFunction::Steps(steps, StartEnd::End) => {
                tf.set_as_step(nsTimingFunction_Type::StepEnd, steps);
            },
            ComputedTimingFunction::CubicBezier(p1, p2) => {
                tf.set_as_cubic_bezier(p1, p2);
            },
        }
        tf
    }
}

impl From<SpecifiedTimingFunction> for nsTimingFunction {
    fn from(function: SpecifiedTimingFunction) -> nsTimingFunction {
        let mut tf: nsTimingFunction = unsafe { mem::zeroed() };

        match function {
            SpecifiedTimingFunction::Steps(steps, StartEnd::Start) => {
                tf.set_as_step(nsTimingFunction_Type::StepStart, steps);
            },
            SpecifiedTimingFunction::Steps(steps, StartEnd::End) => {
                tf.set_as_step(nsTimingFunction_Type::StepEnd, steps);
            },
            SpecifiedTimingFunction::CubicBezier(p1, p2) => {
                tf.set_as_cubic_bezier(p1, p2);
            },
            SpecifiedTimingFunction::Keyword(keyword) => {
                match keyword {
                    FunctionKeyword::Ease => tf.mType = nsTimingFunction_Type::Ease,
                    FunctionKeyword::Linear => tf.mType = nsTimingFunction_Type::Linear,
                    FunctionKeyword::EaseIn => tf.mType = nsTimingFunction_Type::EaseIn,
                    FunctionKeyword::EaseOut => tf.mType = nsTimingFunction_Type::EaseOut,
                    FunctionKeyword::EaseInOut => tf.mType = nsTimingFunction_Type::EaseInOut,
                    FunctionKeyword::StepStart => {
                        tf.set_as_step(nsTimingFunction_Type::StepStart, 1);
                    },
                    FunctionKeyword::StepEnd => {
                        tf.set_as_step(nsTimingFunction_Type::StepEnd, 1);
                    },
                }
            },
        }
        tf
    }
}

impl From<nsTimingFunction> for ComputedTimingFunction {
    fn from(function: nsTimingFunction) -> ComputedTimingFunction {
        match function.mType {
            nsTimingFunction_Type::StepStart => {
                ComputedTimingFunction::Steps(
                    unsafe { function.__bindgen_anon_1.__bindgen_anon_1.as_ref().mStepsOrFrames },
                    StartEnd::Start)
            },
            nsTimingFunction_Type::StepEnd => {
                ComputedTimingFunction::Steps(
                    unsafe { function.__bindgen_anon_1.__bindgen_anon_1.as_ref().mStepsOrFrames },
                    StartEnd::End)
            },
            nsTimingFunction_Type::Frames => {
                // https://github.com/servo/servo/issues/15740
                panic!("Frames timing function is not support yet");
            }
            nsTimingFunction_Type::Ease |
            nsTimingFunction_Type::Linear |
            nsTimingFunction_Type::EaseIn |
            nsTimingFunction_Type::EaseOut |
            nsTimingFunction_Type::EaseInOut |
            nsTimingFunction_Type::CubicBezier => {
                ComputedTimingFunction::CubicBezier(
                    TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX1 },
                                      unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY1 }),
                    TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX2 },
                                      unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY2 }))
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use super::GeneticAlgorithm;

/*
A multi-expression program represented using a series of operations that can reuse results of previous operations.
*/
pub struct Mep<Ins> {
    instructions: Vec<Ins>,
    unit_mutate_size: usize,
    crossover_points: usize,
}

impl<Ins> Clone for Mep<Ins>
    where Ins: Clone {
    fn clone(&self) -> Self {
        Mep{instructions: self.instructions.clone(), unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points}
    }
}

impl<Ins> Mep<Ins> {
    //Generates a new Mep with a particular size and takes a closure to generate random instructions
    pub fn new<I>(unit_mutate_size: usize, crossover_points: usize, instruction_iter: I) -> Mep<Ins>
        where I: Iterator<Item=Ins> {
        Mep{instructions: instruction_iter.collect(), unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points}
    }
}

impl<R, Ins> GeneticAlgorithm<R, Ins, Vec<Ins>> for Mep<Ins> where R: Rng, Ins: Clone {
    fn mate(parents: (&Mep<Ins>, &Mep<Ins>), rng: &mut R) -> Mep<Ins> {
        //Get the smallest of the two lengths
        let total_instructions = cmp::min(parents.0.instructions.len(), parents.1.instructions.len());
        Mep{instructions:
            //Generate a randomly sized sequence between 1 and half of the total possible crossover points
            (0..rng.gen_range(1, total_instructions / 2))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Add total_instructions at the end so we can generate a range with it
            //.insert(total_instructions)
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {parents.0} else {parents.1}}.instructions[range].iter().cloned()
            })
            //Collect all the groups from each parent
            .collect(),
            unit_mutate_size: if parents.0.unit_mutate_size < parents.1.unit_mutate_size {
                rng.gen_range(parents.0.unit_mutate_size, parents.1.unit_mutate_size + 1)
            } else {
                rng.gen_range(parents.1.unit_mutate_size, parents.0.unit_mutate_size + 1)
            },
            crossover_points: if parents.0.crossover_points < parents.1.crossover_points {
                rng.gen_range(parents.0.crossover_points, parents.1.crossover_points + 1)
            } else {
                rng.gen_range(parents.1.crossover_points, parents.0.crossover_points + 1)
            },
        }
    }

    /*
    The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions for
    which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside of
    mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable is
    implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations virtually
    never happen. Allowing this to mutate allows species to find the equilibrium between genomic adaptability and
    stability. If a species develops information gathering, then it can adapt intellegently, making it possibly more
    beneficial to operate at lower mutation rates. Setting the default mutation rate for species properly, or allowing
    it to adapt as the simulation continues, permits species to survive more frequently that are randomly generated.

    Likewise, the functions for random instruction generation and mutation can be adapted as the simulation continues
    to optimize the generation of more desireable random mutations and generations. For instance, instructions that
    occur more frequently should be generated randomly more frequently.
    */
    fn mutate<F>(&mut self, rng: &mut R, mut mutator: F) where F: FnMut(&mut Ins) {
        //Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => self.unit_mutate_size -= 1,
                _ => unreachable!(),
            }
            //It isnt allowed to be 0
            if self.unit_mutate_size == 0 {
                self.unit_mutate_size = 1;
            }
        }
        //Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => self.crossover_points -= 1,
                _ => unreachable!(),
            }
            //It isnt allowed to be 0
            if self.crossover_points == 0 {
                self.crossover_points = 1;
            }
        }

        //Mutate the instructions using the mutator
        loop {
            //Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.instructions.len()) + rng.gen_range(0, self.unit_mutate_size);
            //Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.instructions.len() {
                break;
            }
            //Mutate the valid location using the instruction mutator
            mutator(&mut self.instructions[choice]);
        }
    }

    fn call<F>(&self, program: F) where F: FnOnce(&Vec<Ins>) {
        program(&self.instructions);
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::GeneticAlgorithm;

    #[test]
    fn mep_new() {
        let a: Mep<u32> = Mep::new(3, 3, 0..8);

        assert_eq!(a.instructions, (0..8).collect::<Vec<_>>());
    }

    #[test]
    fn mep_crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let len = 10;
        let (a, b) = {
            let mut clos = || Mep::new(3, 3, rng.gen_iter::<u32>().map(|x| x % 10).take(len));
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<u32>().take(5).collect();
        let mut c = Mep::mate((&a, &b), &mut rng);
        //Ensure that rng was borrowed mutably
        assert!(rng.clone().gen_iter::<u32>().take(5).collect::<Vec<_>>() != old_rngs);

        c.mutate(&mut rng, |ins: &mut u32| *ins = 2);
        //c.call(|x: &Vec<u32>| println!("{}", x.len()));

        assert_eq!(c.instructions, [0, 7, 5, 4, 2, 8, 5, 6, 0, 2]);
    }
}
<commit_msg>pushed fixed tests barring Mep::call()<commit_after>use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use super::GeneticAlgorithm;

/*
A multi-expression program represented using a series of operations that can reuse results of previous operations.
*/
pub struct Mep<Ins> {
    instructions: Vec<Ins>,
    unit_mutate_size: usize,
    crossover_points: usize,
}

impl<Ins> Clone for Mep<Ins>
    where Ins: Clone {
    fn clone(&self) -> Self {
        Mep{instructions: self.instructions.clone(), unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points}
    }
}

impl<Ins> Mep<Ins> {
    //Generates a new Mep with a particular size and takes a closure to generate random instructions
    pub fn new<I>(unit_mutate_size: usize, crossover_points: usize, instruction_iter: I) -> Mep<Ins>
        where I: Iterator<Item=Ins> {
        Mep{instructions: instruction_iter.collect(), unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points}
    }
}

impl<R, Ins> GeneticAlgorithm<R, Ins, Vec<Ins>> for Mep<Ins> where R: Rng, Ins: Clone {
    fn mate(parents: (&Mep<Ins>, &Mep<Ins>), rng: &mut R) -> Mep<Ins> {
        //Get the smallest of the two lengths
        let total_instructions = cmp::min(parents.0.instructions.len(), parents.1.instructions.len());
        Mep{instructions:
            //Generate a randomly sized sequence between 1 and half of the total possible crossover points
            (0..rng.gen_range(1, total_instructions / 2))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Add total_instructions at the end so we can generate a range with it
            //.insert(total_instructions)
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {parents.0} else {parents.1}}.instructions[range].iter().cloned()
            })
            //Collect all the groups from each parent
            .collect(),
            unit_mutate_size: if parents.0.unit_mutate_size < parents.1.unit_mutate_size {
                rng.gen_range(parents.0.unit_mutate_size, parents.1.unit_mutate_size + 1)
            } else {
                rng.gen_range(parents.1.unit_mutate_size, parents.0.unit_mutate_size + 1)
            },
            crossover_points: if parents.0.crossover_points < parents.1.crossover_points {
                rng.gen_range(parents.0.crossover_points, parents.1.crossover_points + 1)
            } else {
                rng.gen_range(parents.1.crossover_points, parents.0.crossover_points + 1)
            },
        }
    }

    /*
    The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions for
    which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside of
    mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable is
    implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations virtually
    never happen. Allowing this to mutate allows species to find the equilibrium between genomic adaptability and
    stability. If a species develops information gathering, then it can adapt intellegently, making it possibly more
    beneficial to operate at lower mutation rates. Setting the default mutation rate for species properly, or allowing
    it to adapt as the simulation continues, permits species to survive more frequently that are randomly generated.

    Likewise, the functions for random instruction generation and mutation can be adapted as the simulation continues
    to optimize the generation of more desireable random mutations and generations. For instance, instructions that
    occur more frequently should be generated randomly more frequently.
    */
    fn mutate<F>(&mut self, rng: &mut R, mut mutator: F) where F: FnMut(&mut Ins) {
        //Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => if self.unit_mutate_size > 1 {self.unit_mutate_size -= 1},
                _ => unreachable!(),
            }
        }
        //Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => if self.crossover_points > 1 {self.crossover_points -= 1},
                _ => unreachable!(),
            }
        }

        //Mutate the instructions using the mutator
        loop {
            //Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.instructions.len()) + rng.gen_range(0, self.unit_mutate_size);
            //Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.instructions.len() {
                break;
            }
            //Mutate the valid location using the instruction mutator
            mutator(&mut self.instructions[choice]);
        }
    }

    fn call<F>(&self, program: F) where F: FnOnce(&Vec<Ins>) {
        program(&self.instructions);
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::GeneticAlgorithm;

    #[test]
    fn mep_new() {
        let a: Mep<u32> = Mep::new(3, 3, 0..8);

        assert_eq!(a.instructions, (0..8).collect::<Vec<_>>());
    }

    #[test]
    fn mep_crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let (a, b) = {
            let mut clos = || Mep::new(3, 3, rng.gen_iter::<u32>().map(|x| x % 10).take(10));
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<u32>().take(5).collect();
        let mut c = Mep::mate((&a, &b), &mut rng);
        //Ensure that rng was borrowed mutably
        assert!(rng.clone().gen_iter::<u32>().take(5).collect::<Vec<_>>() != old_rngs);

        c.mutate(&mut rng, |ins: &mut u32| *ins = 2);
        //c.call(|x: &Vec<u32>| panic!());

        assert_eq!(c.instructions, [0, 7, 5, 4, 2, 8, 5, 6, 0, 2]);
    }
}
<|endoftext|>


<commit_before>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]
#![macro_escape]

extern crate collections;

use std::fmt::Show;
use internal::*;
use internal::IResult::*;

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
);

macro_rules! o (
  ($name:ident<$i:ty,$o:ty> $f1:expr $($rest:tt)*) => (
    #[allow(unused_variables)]
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        IResult::Error(e)      => IResult::Error(e),
        IResult::Incomplete(i) => IResult::Incomplete(i),
        IResult::Done(i,o)     => {
          o_parser!(i o $($rest)*)
        }
      }
    }
  );
);

macro_rules! o_parser (
  ($i:expr $o:expr) => (Done($i,$o));

  ($i:expr $o:expr ~ $e:expr ~ $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        o_parser!(i o $($rest)*)
      }
    }

   );
  ($i:expr $o:expr $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,_)     => {
        o_parser!(i $o $($rest)*)
      }
    }
   );
);

macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
);

macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    IResult::Done($i, $assemble())
  )
);

macro_rules! alt (
  ($name:ident<$i:ty,$o:ty>, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      alt_parser!(i, $($rest)*)
    }
  );
);

macro_rules! alt_parser (
  ($i:expr, $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(_)      => alt_parser!($i, $($rest)*),
      IResult::Incomplete(_) => alt_parser!($i, $($rest)*),
      IResult::Done(i,o)     => IResult::Done(i,o)
    }
  );

  ($i:expr, ) => (
    IResult::Error(1)
  )
);

pub fn print<'a,T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! is_not(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        for &i in $arr.iter() {
          if input[idx] == i {
            return IResult::Done(input.slice_from(idx), input.slice(0, idx))
          }
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
);

#[macro_export]
macro_rules! is_a(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        var res = false
        for &i in $arr.iter() {
          if input[idx] == i {
            res = true
          }
        }
        if !res {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
);

#[macro_export]
macro_rules! filter(
  ($name:ident $f:ident) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        if !$f(input[idx]) {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
);

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
// public methods
//pub is_not!(line_ending "\r\n".as_bytes())
pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    for &i in "\r\n".as_bytes().iter() {
      if input[idx] == i {
        return Done(input.slice_from(idx), input.slice(0, idx))
      }
    }
  }
  Done("".as_bytes(), input)
}

pub fn is_alphabetic(chr:u8) -> bool {
  (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A)
}

pub fn is_digit(chr: u8) -> bool {
  chr >= 0x30 && chr <= 0x39
}

pub fn is_alphanumeric(chr: u8) -> bool {
  is_alphabetic(chr) || is_digit(chr)
}

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
//pub filter!(alpha is_alphabetic)
//pub filter!(digit is_digit)
//pub filter!(alphanumeric is_alphanumeric)
pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphabetic(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_digit(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphanumeric(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> {
  if input.len() == 0 {
    return Incomplete(0)
  }

  let len = input[0] as uint;

  if input.len() >= len + 1 {
    return Done(input.slice_from(len+1), input.slice(1, len+1))
  } else {
    return Incomplete(0)
  }
}

#[macro_export]
macro_rules! opt(
  ($name:ident<$i:ty,$o:ty> $f:ident) => (
    fn $name(input:$i) -> IResult<$i, Option<$o>> {
      match $f(input) {
        IResult::Done(i,o) => IResult::Done(i, Some(o)),
        _                  => IResult::Done(input, None)
      }
    }
  )
);

#[cfg(test)]
mod tests {
  use super::*;
  use map::*;
  use internal::IResult;
  use internal::IResult::*;

  #[test]
  fn character() {
    let empty = "".as_bytes();
    let a = "abcd".as_bytes();
    let b = "1234".as_bytes();
    let c = "a123".as_bytes();
    let d = "azé12".as_bytes();
    assert_eq!(Done((),a).flat_map(alpha), Done(empty, a));
    assert_eq!(Done((),b).flat_map(alpha), Done(b, empty));
    assert_eq!(Done((),c).flat_map(alpha), Done(c.slice_from(1), "a".as_bytes()));
    assert_eq!(Done((),d).flat_map(alpha), Done("é12".as_bytes(), "az".as_bytes()));
    assert_eq!(Done((),a).flat_map(digit), Done(a, empty));
    assert_eq!(Done((),b).flat_map(digit), Done(empty, b));
    assert_eq!(Done((),c).flat_map(digit), Done(c, empty));
    assert_eq!(Done((),d).flat_map(digit), Done(d, empty));
    assert_eq!(Done((),a).flat_map(alphanumeric), Done(empty, a));
    assert_eq!(Done((),b).flat_map(alphanumeric), Done(empty, b));
    assert_eq!(Done((),c).flat_map(alphanumeric), Done(empty, c));
    assert_eq!(Done((),d).flat_map(alphanumeric), Done("é12".as_bytes(), "az".as_bytes()));
  }

  #[test]
  fn is_not() {
    let a = "ab12cd\nefgh".as_bytes();
    assert_eq!(Done((), a).flat_map(line_ending), Done("\nefgh".as_bytes(), "ab12cd".as_bytes()))
  }

  #[test]
  fn buffer_with_size() {
    let arr:[u8, ..6] = [3, 4, 5, 6, 7, 8];
    let res = Done((), arr.as_slice()).flat_map(sized_buffer);
    let i = [7,8];
    let o = [4,5,6];
    assert_eq!(res, Done(i.as_slice(), o.as_slice()))
  }

  #[test]
  fn t1() {
    let v1:Vec<u8> = vec![1,2,3];
    let v2:Vec<u8> = vec![4,5,6];
    let d = Done(v1.as_slice(), v2.as_slice());
    let res = d.flat_map(print);
    assert_eq!(res, Done(v2.as_slice(), ()));
  }

  #[deriving(PartialEq,Eq,Show)]
  struct B {
    a: int,
    b: int
  }

  #[test]
  fn chain_and_ignore() {
    tag!(x "abcd".as_bytes());
    tag!(y "efgh".as_bytes());
    fn ret_int(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    //o!(z<&[u8], int>  x S x S retInt Z y);
    o!(z<&[u8], int>  x  x ~ret_int~ y);

    let r = Done((), "abcdabcdefgh".as_bytes()).flat_map(z);
    assert_eq!(r, Done("".as_bytes(), 1));
  }

  #[test]
  fn chain() {
    tag!(x "abcd".as_bytes());
    fn temp_ret_int1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    o!(ret_int1<&[u8],int> x ~ temp_ret_int1 ~);
    fn ret_int2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
    chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: ret_int1, bb: ret_int2,);

    let r = Done((), "abcde".as_bytes()).flat_map(f);
    assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
  }

  #[test]
  fn alt() {
    fn work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done("".as_bytes(), input)
    }

    #[allow(unused_variables)]
    fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Error(3)
    }

    fn work2(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done(input, "".as_bytes())
    }

    alt!(alt1<&[u8],&[u8]>, dont_work dont_work);
    alt!(alt2<&[u8],&[u8]>, dont_work work);
    alt!(alt3<&[u8],&[u8]>, dont_work dont_work work2 dont_work);

    let a = "abcd".as_bytes();
    assert_eq!(Done((), a).flat_map(alt1), Error(1));
    assert_eq!(Done((), a).flat_map(alt2), Done("".as_bytes(), a));
    assert_eq!(Done((), a).flat_map(alt3), Done(a, "".as_bytes()));
  }

#[test]
  fn opt() {
    tag!(x "abcd".as_bytes());
    opt!(o<&[u8],&[u8]> x);

    let a = "abcdef".as_bytes();
    let b = "bcdefg".as_bytes();
    assert_eq!(Done((),a).flat_map(o), Done("ef".as_bytes(), Some("".as_bytes())));
    assert_eq!(Done((),b).flat_map(o), Done("bcdefg".as_bytes(), None));
  }

  /* FIXME: this makes rustc weep
  fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
    Error(0)
  }

  #[test]
  fn rustc_panic_test() {
    FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
      let mut p = producer;
      p.push(pr);
    });
  }*/
}
<commit_msg>export more macros<commit_after>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]
#![macro_escape]

extern crate collections;

use std::fmt::Show;
use internal::*;
use internal::IResult::*;

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
);

#[macro_export]
macro_rules! o(
  ($name:ident<$i:ty,$o:ty> $f1:expr $($rest:tt)*) => (
    #[allow(unused_variables)]
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        IResult::Error(e)      => IResult::Error(e),
        IResult::Incomplete(i) => IResult::Incomplete(i),
        IResult::Done(i,o)     => {
          o_parser!(i o $($rest)*)
        }
      }
    }
  );
);

#[macro_export]
macro_rules! o_parser(
  ($i:expr $o:expr) => (Done($i,$o));

  ($i:expr $o:expr ~ $e:expr ~ $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        o_parser!(i o $($rest)*)
      }
    }

   );
  ($i:expr $o:expr $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,_)     => {
        o_parser!(i $o $($rest)*)
      }
    }
   );
);

#[macro_export]
macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
);

#[macro_export]
macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    IResult::Done($i, $assemble())
  )
);

#[macro_export]
macro_rules! alt (
  ($name:ident<$i:ty,$o:ty>, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      alt_parser!(i, $($rest)*)
    }
  );
);

#[macro_export]
macro_rules! alt_parser (
  ($i:expr, $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(_)      => alt_parser!($i, $($rest)*),
      IResult::Incomplete(_) => alt_parser!($i, $($rest)*),
      IResult::Done(i,o)     => IResult::Done(i,o)
    }
  );

  ($i:expr, ) => (
    IResult::Error(1)
  )
);

pub fn print<'a,T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! is_not(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        for &i in $arr.iter() {
          if input[idx] == i {
            return IResult::Done(input.slice_from(idx), input.slice(0, idx))
          }
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
);

#[macro_export]
macro_rules! is_a(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        var res = false
        for &i in $arr.iter() {
          if input[idx] == i {
            res = true
          }
        }
        if !res {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
);

#[macro_export]
macro_rules! filter(
  ($name:ident $f:ident) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        if !$f(input[idx]) {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
);

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
// public methods
//pub is_not!(line_ending "\r\n".as_bytes())
pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    for &i in "\r\n".as_bytes().iter() {
      if input[idx] == i {
        return Done(input.slice_from(idx), input.slice(0, idx))
      }
    }
  }
  Done("".as_bytes(), input)
}

pub fn is_alphabetic(chr:u8) -> bool {
  (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A)
}

pub fn is_digit(chr: u8) -> bool {
  chr >= 0x30 && chr <= 0x39
}

pub fn is_alphanumeric(chr: u8) -> bool {
  is_alphabetic(chr) || is_digit(chr)
}

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
//pub filter!(alpha is_alphabetic)
//pub filter!(digit is_digit)
//pub filter!(alphanumeric is_alphanumeric)
pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphabetic(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_digit(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphanumeric(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> {
  if input.len() == 0 {
    return Incomplete(0)
  }

  let len = input[0] as uint;

  if input.len() >= len + 1 {
    return Done(input.slice_from(len+1), input.slice(1, len+1))
  } else {
    return Incomplete(0)
  }
}

#[macro_export]
macro_rules! opt(
  ($name:ident<$i:ty,$o:ty> $f:ident) => (
    fn $name(input:$i) -> IResult<$i, Option<$o>> {
      match $f(input) {
        IResult::Done(i,o) => IResult::Done(i, Some(o)),
        _                  => IResult::Done(input, None)
      }
    }
  )
);

#[cfg(test)]
mod tests {
  use super::*;
  use map::*;
  use internal::IResult;
  use internal::IResult::*;

  #[test]
  fn character() {
    let empty = "".as_bytes();
    let a = "abcd".as_bytes();
    let b = "1234".as_bytes();
    let c = "a123".as_bytes();
    let d = "azé12".as_bytes();
    assert_eq!(Done((),a).flat_map(alpha), Done(empty, a));
    assert_eq!(Done((),b).flat_map(alpha), Done(b, empty));
    assert_eq!(Done((),c).flat_map(alpha), Done(c.slice_from(1), "a".as_bytes()));
    assert_eq!(Done((),d).flat_map(alpha), Done("é12".as_bytes(), "az".as_bytes()));
    assert_eq!(Done((),a).flat_map(digit), Done(a, empty));
    assert_eq!(Done((),b).flat_map(digit), Done(empty, b));
    assert_eq!(Done((),c).flat_map(digit), Done(c, empty));
    assert_eq!(Done((),d).flat_map(digit), Done(d, empty));
    assert_eq!(Done((),a).flat_map(alphanumeric), Done(empty, a));
    assert_eq!(Done((),b).flat_map(alphanumeric), Done(empty, b));
    assert_eq!(Done((),c).flat_map(alphanumeric), Done(empty, c));
    assert_eq!(Done((),d).flat_map(alphanumeric), Done("é12".as_bytes(), "az".as_bytes()));
  }

  #[test]
  fn is_not() {
    let a = "ab12cd\nefgh".as_bytes();
    assert_eq!(Done((), a).flat_map(line_ending), Done("\nefgh".as_bytes(), "ab12cd".as_bytes()))
  }

  #[test]
  fn buffer_with_size() {
    let arr:[u8, ..6] = [3, 4, 5, 6, 7, 8];
    let res = Done((), arr.as_slice()).flat_map(sized_buffer);
    let i = [7,8];
    let o = [4,5,6];
    assert_eq!(res, Done(i.as_slice(), o.as_slice()))
  }

  #[test]
  fn t1() {
    let v1:Vec<u8> = vec![1,2,3];
    let v2:Vec<u8> = vec![4,5,6];
    let d = Done(v1.as_slice(), v2.as_slice());
    let res = d.flat_map(print);
    assert_eq!(res, Done(v2.as_slice(), ()));
  }

  #[deriving(PartialEq,Eq,Show)]
  struct B {
    a: int,
    b: int
  }

  #[test]
  fn chain_and_ignore() {
    tag!(x "abcd".as_bytes());
    tag!(y "efgh".as_bytes());
    fn ret_int(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    //o!(z<&[u8], int>  x S x S retInt Z y);
    o!(z<&[u8], int>  x  x ~ret_int~ y);

    let r = Done((), "abcdabcdefgh".as_bytes()).flat_map(z);
    assert_eq!(r, Done("".as_bytes(), 1));
  }

  #[test]
  fn chain() {
    tag!(x "abcd".as_bytes());
    fn temp_ret_int1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    o!(ret_int1<&[u8],int> x ~ temp_ret_int1 ~);
    fn ret_int2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
    chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: ret_int1, bb: ret_int2,);

    let r = Done((), "abcde".as_bytes()).flat_map(f);
    assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
  }

  #[test]
  fn alt() {
    fn work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done("".as_bytes(), input)
    }

    #[allow(unused_variables)]
    fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Error(3)
    }

    fn work2(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done(input, "".as_bytes())
    }

    alt!(alt1<&[u8],&[u8]>, dont_work dont_work);
    alt!(alt2<&[u8],&[u8]>, dont_work work);
    alt!(alt3<&[u8],&[u8]>, dont_work dont_work work2 dont_work);

    let a = "abcd".as_bytes();
    assert_eq!(Done((), a).flat_map(alt1), Error(1));
    assert_eq!(Done((), a).flat_map(alt2), Done("".as_bytes(), a));
    assert_eq!(Done((), a).flat_map(alt3), Done(a, "".as_bytes()));
  }

#[test]
  fn opt() {
    tag!(x "abcd".as_bytes());
    opt!(o<&[u8],&[u8]> x);

    let a = "abcdef".as_bytes();
    let b = "bcdefg".as_bytes();
    assert_eq!(Done((),a).flat_map(o), Done("ef".as_bytes(), Some("".as_bytes())));
    assert_eq!(Done((),b).flat_map(o), Done("bcdefg".as_bytes(), None));
  }

  /* FIXME: this makes rustc weep
  fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
    Error(0)
  }

  #[test]
  fn rustc_panic_test() {
    FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
      let mut p = producer;
      p.push(pr);
    });
  }*/
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub fn prime_iter() -> Box<Iterator<Item = usize>> {
    let from_two = (1..)
        .into_iter()
        .map(|x| x * 2 + 1)
        .scan(HashMap::new(), |map, i| {
            let not_prime = map.contains_key(&i);
            let base: usize = if not_prime {
                map.remove(&i).unwrap()
            } else {
                i * 2
            };

            let new_key: usize =
                (1..).map(|x| x * base + i).filter(|x| !map.contains_key(x)).next().unwrap();
            map.insert(new_key, base);

            let op: Option<usize> = if !not_prime { Some(i) } else { None };

            Some(op)

        })
        .filter_map(|s| s);

    let it = (2..3).chain(from_two);

    Box::new(it)

}

pub fn combination_iter<E: Clone + 'static>(vec: Vec<E>,
                                            comb: usize)
                                            -> Box<Iterator<Item = Vec<E>>> {
    let it = combination_add(vec.len(), comb);

    let n = it.map(move |i: Vec<usize>| {
        let vc: Vec<E> = vec.clone();
        let v: Vec<E> = i.into_iter()
            .map(|j: usize| vc[j].clone())
            .collect();
        v
    });
    Box::new(n)
}

fn combination_add(length: usize, max: usize) -> Box<Iterator<Item = Vec<usize>>> {

    let mut it: Box<Iterator<Item = Vec<usize>>> =
        Box::new((0..length).into_iter().map(|x| vec![x]));

    for i in 0..length {
        let max_clone = max.clone();
        let i_clone = i.clone();
        it = Box::new(it.flat_map(move |x: Vec<usize>| {

            if &i_clone <= x.last().unwrap() || x.len() == max_clone {

                return vec![x].into_iter();
            }

            let mut v: Vec<Vec<usize>> = Vec::new();

            let mut clone: Vec<usize> = x.iter().cloned().collect();
            v.push(x);
            clone.push(i_clone);
            v.push(clone);
            return v.into_iter();

        }));
    }

    return Box::new(it.filter(move |x| {
        let len = x.len();
        len.eq(&max)
    }));
}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use std::collections::HashSet;

    #[test]
    fn combination_add_1() {
        let it = super::combination_add(4, 2);
        let vecs: Vec<Vec<usize>> = it.collect();
        assert_eq!(vecs.len(), 6);
    }
    #[test]
    fn combination_add_2() {
        let it = super::combination_add(4, 2);
        let vecs: HashSet<Vec<usize>> = it.collect();
        let result: HashSet<Vec<usize>> = [vec![0, 1], vec![0, 2], vec![0, 3], vec![1, 2],
                                           vec![1, 3], vec![2, 3]]
            .iter()
            .cloned()
            .collect();
        assert_eq!(vecs, result);

    }

    #[test]
    fn combination_1() {
        let it = super::combination_iter(vec![1, 5, 7, 8, 9], 3);
        let vecs: HashSet<Vec<usize>> = it.collect();
        let result: HashSet<Vec<usize>> = [vec![1, 5, 7],
                                           vec![1, 5, 8],
                                           vec![1, 5, 9],
                                           vec![1, 7, 8],
                                           vec![1, 7, 9],
                                           vec![1, 8, 9],
                                           vec![5, 7, 8],
                                           vec![5, 7, 9],
                                           vec![5, 8, 9],
                                           vec![7, 8, 9]]
            .iter()
            .cloned()
            .collect();
        assert_eq!(vecs, result);

    }

    #[bench]
    fn combination_add_bench(b: &mut Bencher) {
        b.iter(|| super::combination_add(100, 50).last());
    }
}
<commit_msg>combinationの最適化<commit_after>use std::collections::HashMap;

pub fn prime_iter() -> Box<Iterator<Item = usize>> {
    let from_two = (1..)
        .into_iter()
        .map(|x| x * 2 + 1)
        .scan(HashMap::new(), |map, i| {
            let not_prime = map.contains_key(&i);
            let base: usize = if not_prime {
                map.remove(&i).unwrap()
            } else {
                i * 2
            };

            let new_key: usize =
                (1..).map(|x| x * base + i).filter(|x| !map.contains_key(x)).next().unwrap();
            map.insert(new_key, base);

            let op: Option<usize> = if !not_prime { Some(i) } else { None };

            Some(op)

        })
        .filter_map(|s| s);

    let it = (2..3).chain(from_two);

    Box::new(it)

}

pub fn combination_iter<E: Clone + 'static>(vec: Vec<E>,
                                            comb: usize)
                                            -> Box<Iterator<Item = Vec<E>>> {
    let it = combination_add(vec.len(), comb);

    let n = it.map(move |i: Vec<usize>| {
        let vc: Vec<E> = vec.clone();
        let v: Vec<E> = i.into_iter()
            .map(|j: usize| vc[j].clone())
            .collect();
        v
    });
    Box::new(n)
}

fn combination_add(length: usize, max: usize) -> Box<Iterator<Item = Vec<usize>>> {
    let mut it: Box<Iterator<Item = Vec<usize>>> =
        Box::new((0..length).into_iter().map(|x| vec![x]));
    for _ in 1..max {
        it = combination_add_in(length, it);
    }
    it
}

fn combination_add_in(length: usize,
                      now: Box<Iterator<Item = Vec<usize>>>)
                      -> Box<Iterator<Item = Vec<usize>>> {
    Box::new(now.flat_map(move |v| {
        (1 + *v.last().unwrap()..length)
            .into_iter()
            .map(move |n| {
                let mut new_vec = v.to_vec();
                new_vec.push(n);
                new_vec
            })
    }))
}

#[cfg(test)]
mod tests {
    use test::Bencher;
    use std::collections::HashSet;

    #[test]
    fn combination_add_1() {
        let it = super::combination_add(4, 2);
        let vecs: Vec<Vec<usize>> = it.collect();
        assert_eq!(vecs.len(), 6);
    }
    #[test]
    fn combination_add_2() {
        let it = super::combination_add(4, 2);
        let vecs: HashSet<Vec<usize>> = it.collect();
        let result: HashSet<Vec<usize>> = [vec![0, 1], vec![0, 2], vec![0, 3], vec![1, 2],
                                           vec![1, 3], vec![2, 3]]
            .iter()
            .cloned()
            .collect();
        assert_eq!(vecs, result);

    }

    #[test]
    fn combination_1() {
        let it = super::combination_iter(vec![1, 5, 7, 8, 9], 3);
        let vecs: HashSet<Vec<usize>> = it.collect();
        let result: HashSet<Vec<usize>> = [vec![1, 5, 7],
                                           vec![1, 5, 8],
                                           vec![1, 5, 9],
                                           vec![1, 7, 8],
                                           vec![1, 7, 9],
                                           vec![1, 8, 9],
                                           vec![5, 7, 8],
                                           vec![5, 7, 9],
                                           vec![5, 8, 9],
                                           vec![7, 8, 9]]
            .iter()
            .cloned()
            .collect();
        assert_eq!(vecs, result);

    }

    #[bench]
    fn combination_add_4_2(b: &mut Bencher) {
        b.iter(|| super::combination_add(4, 2).last());
    }
    #[bench]
    fn combination_add_10_2(b: &mut Bencher) {
        b.iter(|| super::combination_add(10, 2).last());
    }
    #[bench]
    fn combination_add_5_4(b: &mut Bencher) {
        b.iter(|| super::combination_add(5, 4).last());
    }
    #[bench]
    fn combination_add_10_5(b: &mut Bencher) {
        b.iter(|| super::combination_add(10, 5).last());
    }

    #[bench]
    fn combination_add_c_1_2(b: &mut Bencher) {
        b.iter(|| super::combination_add(20, 10).last());
    }
}
<|endoftext|>


<commit_before>use lazysort::SortedBy;
use std::path::PathBuf;
use iron::modifiers::Header;
use self::super::{Options, Error};
use mime_guess::guess_mime_type_opt;
use iron::{headers, status, method, mime, IronResult, Listening, Response, TypeMap, Request, Handler, Iron};
use self::super::util::{url_path, html_response, file_contains, percent_decode, file_time_modified, USER_AGENT, ERROR_HTML, DIRECTORY_LISTING_HTML};

#[derive(Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct HttpHandler {
    pub hosted_directory: (String, PathBuf),
    pub follow_symlinks: bool,
}

impl HttpHandler {
    pub fn new(opts: &Options) -> HttpHandler {
        HttpHandler {
            hosted_directory: opts.hosted_directory.clone(),
            follow_symlinks: opts.follow_symlinks,
        }
    }
}

impl Handler for HttpHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match req.method {
            method::Options => self.handle_options(req),
            method::Get => self.handle_get(req),
            method::Head => {
                self.handle_get(req).map(|mut r| {
                    r.body = None;
                    r
                })
            }
            method::Trace => self.handle_trace(req),
            _ => self.handle_bad_method(req),
        }
    }
}

impl HttpHandler {
    fn handle_options(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} asked for options", req.remote_addr);
        Ok(Response::with((status::Ok,
                           Header(headers::Server(USER_AGENT.to_string())),
                           Header(headers::Allow(vec![method::Options, method::Get, method::Head, method::Trace])))))
    }

    fn handle_get(&self, req: &mut Request) -> IronResult<Response> {
        let (req_p, symlink, url_err) =
            req.url.path().into_iter().filter(|p| !p.is_empty()).fold((self.hosted_directory.1.clone(), false, false), |(mut cur, mut sk, mut err), pp| {
                if let Some(pp) = percent_decode(pp) {
                    cur.push(&*pp);
                } else {
                    err = true;
                }

                if let Ok(meta) = cur.metadata() {
                    sk = sk || meta.file_type().is_symlink();
                }

                (cur, sk, err)
            });

        if url_err {
            self.handle_invalid_url(req, "
Percent-encoding decoded to invalid UTF-8.
")
        } else if !req_p.exists() || (symlink && !self.follow_symlinks) {
            self.handle_get_nonexistant(req, req_p)
        } else if req_p.is_file() {
            self.handle_get_file(req, req_p)
        } else {
            self.handle_get_dir(req, req_p)
        }
    }

    fn handle_invalid_url(&self, req: &mut Request, cause: &str) -> IronResult<Response> {
        println!("{} requested with invalid URL {}", req.remote_addr, req.url);
        Ok(Response::with((status::BadRequest,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML, &["400 Bad Request", "The request URL couldn't be parsed.", cause]))))
    }

    fn handle_get_nonexistant(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        println!("{} requested nonexistant file {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::NotFound,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         &["404 Not Found", &format!("The requested entity \"{}\" doesn't exist.", url_path(&req.url)), ""]))))
    }

    fn handle_get_file(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let mime_type = guess_mime_type_opt(&req_p).unwrap_or_else(|| if file_contains(&req_p, 0) {
            "application/octet-stream".parse().unwrap()
        } else {
            "text/plain".parse().unwrap()
        });
        println!("{} was served file {} as {}", req.remote_addr, req_p.display(), mime_type);
        Ok(Response::with((status::Ok,
                           Header(headers::Server(USER_AGENT.to_string())),
                           Header(headers::LastModified(headers::HttpDate(file_time_modified(&req_p)))),
                           mime_type,
                           req_p)))
    }

    fn handle_get_dir(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let relpath = (url_path(&req.url) + "/").replace("//", "/");
        println!("{} was served directory listing for {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::Ok,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(DIRECTORY_LISTING_HTML,
                                         &[&relpath,
                                           &req_p.read_dir()
                                               .unwrap()
                                               .map(Result::unwrap)
                                               .filter(|f| self.follow_symlinks || !f.metadata().unwrap().file_type().is_symlink())
                                               .sorted_by(|lhs, rhs| {
                                                   (lhs.file_type().unwrap().is_file(), lhs.file_name().to_str().unwrap().to_lowercase())
                                                       .cmp(&(rhs.file_type().unwrap().is_file(), rhs.file_name().to_str().unwrap().to_lowercase()))
                                               })
                                               .fold("".to_string(), |cur, f| {
                let fname = f.file_name().into_string().unwrap() +
                            if !f.file_type().unwrap().is_file() {
                    "/"
                } else {
                    ""
                };
                cur + "
" + &fname + "
\n"
            })]))))
    }

    fn handle_trace(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} requested TRACE", req.remote_addr);

        let mut hdr = req.headers.clone();
        hdr.set(headers::ContentType("message/http".parse().unwrap()));

        Ok(Response {
            status: Some(status::Ok),
            headers: hdr,
            extensions: TypeMap::new(),
            body: None,
        })
    }

    fn handle_bad_method(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} used invalid request method {}", req.remote_addr, req.method);
        Ok(Response::with((status::NotImplemented,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         &["501 Not Implemented",
                                           "This operation was not implemented.",
                                           &format!("
Unsupported request method: {}.
Supported methods: OPTIONS, GET, HEAD and TRACE.
",
                                                    req.method)]))))
    }
}

pub fn try_ports<H: Handler + Clone>(hndlr: H, from: u16, up_to: u16) -> Result<Listening, Error> {
    for port in from..up_to {
        match Iron::new(hndlr.clone()).http(("0.0.0.0", port)) {
            Ok(server) => return Ok(server),
            Err(error) => {
                if !error.to_string().contains("port") {
                    return Err(Error::Io {
                        desc: "server",
                        op: "start",
                        more: None,
                    });
                }
            }
        }
    }

    Err(Error::Io {
        desc: "server",
        op: "start",
        more: Some("no free ports"),
    })
}
<commit_msg>Document try_ports. Fix bug in try_ports where it'd sweep one port not enough<commit_after>use lazysort::SortedBy;
use std::path::PathBuf;
use iron::modifiers::Header;
use self::super::{Options, Error};
use mime_guess::guess_mime_type_opt;
use iron::{headers, status, method, mime, IronResult, Listening, Response, TypeMap, Request, Handler, Iron};
use self::super::util::{url_path, html_response, file_contains, percent_decode, file_time_modified, USER_AGENT, ERROR_HTML, DIRECTORY_LISTING_HTML};

#[derive(Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct HttpHandler {
    pub hosted_directory: (String, PathBuf),
    pub follow_symlinks: bool,
}

impl HttpHandler {
    pub fn new(opts: &Options) -> HttpHandler {
        HttpHandler {
            hosted_directory: opts.hosted_directory.clone(),
            follow_symlinks: opts.follow_symlinks,
        }
    }
}

impl Handler for HttpHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match req.method {
            method::Options => self.handle_options(req),
            method::Get => self.handle_get(req),
            method::Head => {
                self.handle_get(req).map(|mut r| {
                    r.body = None;
                    r
                })
            }
            method::Trace => self.handle_trace(req),
            _ => self.handle_bad_method(req),
        }
    }
}

impl HttpHandler {
    fn handle_options(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} asked for options", req.remote_addr);
        Ok(Response::with((status::Ok,
                           Header(headers::Server(USER_AGENT.to_string())),
                           Header(headers::Allow(vec![method::Options, method::Get, method::Head, method::Trace])))))
    }

    fn handle_get(&self, req: &mut Request) -> IronResult<Response> {
        let (req_p, symlink, url_err) =
            req.url.path().into_iter().filter(|p| !p.is_empty()).fold((self.hosted_directory.1.clone(), false, false), |(mut cur, mut sk, mut err), pp| {
                if let Some(pp) = percent_decode(pp) {
                    cur.push(&*pp);
                } else {
                    err = true;
                }

                if let Ok(meta) = cur.metadata() {
                    sk = sk || meta.file_type().is_symlink();
                }

                (cur, sk, err)
            });

        if url_err {
            self.handle_invalid_url(req, "
Percent-encoding decoded to invalid UTF-8.
")
        } else if !req_p.exists() || (symlink && !self.follow_symlinks) {
            self.handle_get_nonexistant(req, req_p)
        } else if req_p.is_file() {
            self.handle_get_file(req, req_p)
        } else {
            self.handle_get_dir(req, req_p)
        }
    }

    fn handle_invalid_url(&self, req: &mut Request, cause: &str) -> IronResult<Response> {
        println!("{} requested with invalid URL {}", req.remote_addr, req.url);
        Ok(Response::with((status::BadRequest,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML, &["400 Bad Request", "The request URL couldn't be parsed.", cause]))))
    }

    fn handle_get_nonexistant(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        println!("{} requested nonexistant file {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::NotFound,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         &["404 Not Found", &format!("The requested entity \"{}\" doesn't exist.", url_path(&req.url)), ""]))))
    }

    fn handle_get_file(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let mime_type = guess_mime_type_opt(&req_p).unwrap_or_else(|| if file_contains(&req_p, 0) {
            "application/octet-stream".parse().unwrap()
        } else {
            "text/plain".parse().unwrap()
        });
        println!("{} was served file {} as {}", req.remote_addr, req_p.display(), mime_type);
        Ok(Response::with((status::Ok,
                           Header(headers::Server(USER_AGENT.to_string())),
                           Header(headers::LastModified(headers::HttpDate(file_time_modified(&req_p)))),
                           mime_type,
                           req_p)))
    }

    fn handle_get_dir(&self, req: &mut Request, req_p: PathBuf) -> IronResult<Response> {
        let relpath = (url_path(&req.url) + "/").replace("//", "/");
        println!("{} was served directory listing for {}", req.remote_addr, req_p.display());
        Ok(Response::with((status::Ok,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(DIRECTORY_LISTING_HTML,
                                         &[&relpath,
                                           &req_p.read_dir()
                                               .unwrap()
                                               .map(Result::unwrap)
                                               .filter(|f| self.follow_symlinks || !f.metadata().unwrap().file_type().is_symlink())
                                               .sorted_by(|lhs, rhs| {
                                                   (lhs.file_type().unwrap().is_file(), lhs.file_name().to_str().unwrap().to_lowercase())
                                                       .cmp(&(rhs.file_type().unwrap().is_file(), rhs.file_name().to_str().unwrap().to_lowercase()))
                                               })
                                               .fold("".to_string(), |cur, f| {
                let fname = f.file_name().into_string().unwrap() +
                            if !f.file_type().unwrap().is_file() {
                    "/"
                } else {
                    ""
                };
                cur + "
" + &fname + "
\n"
            })]))))
    }

    fn handle_trace(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} requested TRACE", req.remote_addr);

        let mut hdr = req.headers.clone();
        hdr.set(headers::ContentType("message/http".parse().unwrap()));

        Ok(Response {
            status: Some(status::Ok),
            headers: hdr,
            extensions: TypeMap::new(),
            body: None,
        })
    }

    fn handle_bad_method(&self, req: &mut Request) -> IronResult<Response> {
        println!("{} used invalid request method {}", req.remote_addr, req.method);
        Ok(Response::with((status::NotImplemented,
                           Header(headers::Server(USER_AGENT.to_string())),
                           "text/html;charset=utf-8".parse::<mime::Mime>().unwrap(),
                           html_response(ERROR_HTML,
                                         &["501 Not Implemented",
                                           "This operation was not implemented.",
                                           &format!("
Unsupported request method: {}.
Supported methods: OPTIONS, GET, HEAD and TRACE.
",
                                                    req.method)]))))
    }
}

/// Attempt to start a server on ports from `from` to `up_to`, inclusive, with the specified handler.
///
/// If an error other than the port being full is encountered it is returned.
///
/// If all ports from the range are not free an error is returned.
///
/// # Examples
///
/// ```
/// # extern crate https;
/// # extern crate iron;
/// # use https::ops::try_ports;
/// # use iron::{status, Response};
/// let server = try_ports(|req| Ok(Response::with((status::Ok, "Abolish the burgeoisie!"))), 8000, 8100).unwrap();
/// ```
pub fn try_ports<H: Handler + Clone>(hndlr: H, from: u16, up_to: u16) -> Result<Listening, Error> {
    for port in from..up_to + 1 {
        match Iron::new(hndlr.clone()).http(("0.0.0.0", port)) {
            Ok(server) => return Ok(server),
            Err(error) => {
                if !error.to_string().contains("port") {
                    return Err(Error::Io {
                        desc: "server",
                        op: "start",
                        more: None,
                    });
                }
            }
        }
    }

    Err(Error::Io {
        desc: "server",
        op: "start",
        more: Some("no free ports"),
    })
}
<|endoftext|>